diff --git a/exec.c b/exec.c index 963b91a018b7..587b489eefd5 100644 --- a/exec.c +++ b/exec.c @@ -630,7 +630,7 @@ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx) } #endif -void cpu_exec_exit(CPUState *cpu) +void cpu_exec_unrealizefn(CPUState *cpu) { CPUClass *cc = CPU_GET_CLASS(cpu); @@ -644,11 +644,8 @@ void cpu_exec_exit(CPUState *cpu) } } -void cpu_exec_init(CPUState *cpu, Error **errp) +void cpu_exec_initfn(CPUState *cpu) { - CPUClass *cc ATTRIBUTE_UNUSED = CPU_GET_CLASS(cpu); - Error *local_err ATTRIBUTE_UNUSED = NULL; - cpu->as = NULL; cpu->num_ases = 0; @@ -669,6 +666,11 @@ void cpu_exec_init(CPUState *cpu, Error **errp) cpu->memory = system_memory; object_ref(OBJECT(cpu->memory)); #endif +} + +void cpu_exec_realizefn(CPUState *cpu, Error **errp) +{ + CPUClass *cc ATTRIBUTE_UNUSED = CPU_GET_CLASS(cpu); cpu_list_add(cpu); diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 902f5c90a80c..5ac89fefafe2 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -531,6 +531,11 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, apic->flags = cpu_to_le32(1); break; } + case ACPI_APIC_LOCAL_X2APIC: { + AcpiMadtProcessorX2Apic *apic = (void *)madt_buf->data; + apic->flags = cpu_to_le32(1); + break; + } default: assert(0); } diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c index e19d90206376..f15a2402fcd9 100644 --- a/hw/acpi/cpu_hotplug.c +++ b/hw/acpi/cpu_hotplug.c @@ -15,6 +15,7 @@ #include "qapi/error.h" #include "qom/cpu.h" #include "hw/i386/pc.h" +#include "qemu/error-report.h" #define CPU_EJECT_METHOD "CPEJ" #define CPU_MAT_METHOD "CPMA" @@ -63,7 +64,8 @@ static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu, cpu_id = k->get_arch_id(cpu); if ((cpu_id / 8) >= ACPI_GPE_PROC_LEN) { - error_setg(errp, "acpi: invalid cpu id: %" PRIi64, cpu_id); + object_property_set_bool(g->device, false, "cpu-hotplug-legacy", + &error_abort); return; } @@ -85,13 +87,14 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, { CPUState *cpu; - CPU_FOREACH(cpu) { - acpi_set_cpu_present_bit(gpe_cpu, cpu, &error_abort); - } memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops, gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN); memory_region_add_subregion(parent, base, &gpe_cpu->io); gpe_cpu->device = owner; + + CPU_FOREACH(cpu) { + acpi_set_cpu_present_bit(gpe_cpu, cpu, &error_abort); + } } void acpi_switch_to_modern_cphp(AcpiCpuHotplug *gpe_cpu, @@ -234,7 +237,11 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine, /* The current AML generator can cover the APIC ID range [0..255], * inclusive, for VCPU hotplug. */ QEMU_BUILD_BUG_ON(ACPI_CPU_HOTPLUG_ID_LIMIT > 256); - g_assert(pcms->apic_id_limit <= ACPI_CPU_HOTPLUG_ID_LIMIT); + if (pcms->apic_id_limit > ACPI_CPU_HOTPLUG_ID_LIMIT) { + error_report("max_cpus is too large. APIC ID of last CPU is %u", + pcms->apic_id_limit - 1); + exit(1); + } /* create PCI0.PRES device and its _CRS to reserve CPU hotplug MMIO */ dev = aml_device("PCI0." stringify(CPU_HOTPLUG_RESOURCE_DEVICE)); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 47ec7ffa7345..070bbf89d419 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1494,7 +1494,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) * it later in machvirt_init, where we have more information about the * configuration of the particular instance. */ - mc->max_cpus = MAX_CPUMASK_BITS; + mc->max_cpus = 255; mc->has_dynamic_sysbus = true; mc->block_default_type = IF_VIRTIO; mc->no_cdrom = 1; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index e9996549cca8..93be96f89cf4 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -340,24 +340,38 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm, void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, CPUArchIdList *apic_ids, GArray *entry) { - int apic_id; - AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic); - - apic_id = apic_ids->cpus[uid].arch_id; - apic->type = ACPI_APIC_PROCESSOR; - apic->length = sizeof(*apic); - apic->processor_id = uid; - apic->local_apic_id = apic_id; - if (apic_ids->cpus[uid].cpu != NULL) { - apic->flags = cpu_to_le32(1); + uint32_t apic_id = apic_ids->cpus[uid].arch_id; + + /* ACPI spec says that LAPIC entry for non present + * CPU may be omitted from MADT or it must be marked + * as disabled. However omitting non present CPU from + * MADT breaks hotplug on linux. So possible CPUs + * should be put in MADT but kept disabled. + */ + if (apic_id < 255) { + AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic); + + apic->type = ACPI_APIC_PROCESSOR; + apic->length = sizeof(*apic); + apic->processor_id = uid; + apic->local_apic_id = apic_id; + if (apic_ids->cpus[uid].cpu != NULL) { + apic->flags = cpu_to_le32(1); + } else { + apic->flags = cpu_to_le32(0); + } } else { - /* ACPI spec says that LAPIC entry for non present - * CPU may be omitted from MADT or it must be marked - * as disabled. However omitting non present CPU from - * MADT breaks hotplug on linux. So possible CPUs - * should be put in MADT but kept disabled. - */ - apic->flags = cpu_to_le32(0); + AcpiMadtProcessorX2Apic *apic = acpi_data_push(entry, sizeof *apic); + + apic->type = ACPI_APIC_LOCAL_X2APIC; + apic->length = sizeof(*apic); + apic->uid = cpu_to_le32(uid); + apic->x2apic_id = cpu_to_le32(apic_id); + if (apic_ids->cpus[uid].cpu != NULL) { + apic->flags = cpu_to_le32(1); + } else { + apic->flags = cpu_to_le32(0); + } } } @@ -369,11 +383,11 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) int madt_start = table_data->len; AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(pcms->acpi_dev); AcpiDeviceIf *adev = ACPI_DEVICE_IF(pcms->acpi_dev); + bool x2apic_mode = false; AcpiMultipleApicTable *madt; AcpiMadtIoApic *io_apic; AcpiMadtIntsrcovr *intsrcovr; - AcpiMadtLocalNmi *local_nmi; int i; madt = acpi_data_push(table_data, sizeof *madt); @@ -382,6 +396,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) for (i = 0; i < apic_ids->len; i++) { adevc->madt_cpu(adev, i, apic_ids, table_data); + if (apic_ids->cpus[i].arch_id > 254) { + x2apic_mode = true; + } } g_free(apic_ids); @@ -414,12 +431,25 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */ } - local_nmi = acpi_data_push(table_data, sizeof *local_nmi); - local_nmi->type = ACPI_APIC_LOCAL_NMI; - local_nmi->length = sizeof(*local_nmi); - local_nmi->processor_id = 0xff; /* all processors */ - local_nmi->flags = cpu_to_le16(0); - local_nmi->lint = 1; /* ACPI_LINT1 */ + if (x2apic_mode) { + AcpiMadtLocalX2ApicNmi *local_nmi; + + local_nmi = acpi_data_push(table_data, sizeof *local_nmi); + local_nmi->type = ACPI_APIC_LOCAL_X2APIC_NMI; + local_nmi->length = sizeof(*local_nmi); + local_nmi->uid = 0xFFFFFFFF; /* all processors */ + local_nmi->flags = cpu_to_le16(0); + local_nmi->lint = 1; /* ACPI_LINT1 */ + } else { + AcpiMadtLocalNmi *local_nmi; + + local_nmi = acpi_data_push(table_data, sizeof *local_nmi); + local_nmi->type = ACPI_APIC_LOCAL_NMI; + local_nmi->length = sizeof(*local_nmi); + local_nmi->processor_id = 0xff; /* all processors */ + local_nmi->flags = cpu_to_le16(0); + local_nmi->lint = 1; /* ACPI_LINT1 */ + } build_header(linker, table_data, (void *)(table_data->data + madt_start), "APIC", @@ -2391,7 +2421,6 @@ static void build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) { AcpiSystemResourceAffinityTable *srat; - AcpiSratProcessorAffinity *core; AcpiSratMemoryAffinity *numamem; int i; @@ -2411,18 +2440,33 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) for (i = 0; i < apic_ids->len; i++) { int j = numa_get_node_for_cpu(i); - int apic_id = apic_ids->cpus[i].arch_id; + uint32_t apic_id = apic_ids->cpus[i].arch_id; - core = acpi_data_push(table_data, sizeof *core); - core->type = ACPI_SRAT_PROCESSOR_APIC; - core->length = sizeof(*core); - core->local_apic_id = apic_id; - if (j < nb_numa_nodes) { + if (apic_id < 255) { + AcpiSratProcessorAffinity *core; + + core = acpi_data_push(table_data, sizeof *core); + core->type = ACPI_SRAT_PROCESSOR_APIC; + core->length = sizeof(*core); + core->local_apic_id = apic_id; + if (j < nb_numa_nodes) { core->proximity_lo = j; + } + memset(core->proximity_hi, 0, 3); + core->local_sapic_eid = 0; + core->flags = cpu_to_le32(1); + } else { + AcpiSratProcessorX2ApicAffinity *core; + + core = acpi_data_push(table_data, sizeof *core); + core->type = ACPI_SRAT_PROCESSOR_x2APIC; + core->length = sizeof(*core); + core->x2apic_id = cpu_to_le32(apic_id); + if (j < nb_numa_nodes) { + core->proximity_domain = cpu_to_le32(j); + } + core->flags = cpu_to_le32(1); } - memset(core->proximity_hi, 0, 3); - core->local_sapic_eid = 0; - core->flags = cpu_to_le32(1); } diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index be55102c00ca..39b73e7b3d84 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -34,7 +34,11 @@ static void kvm_put_apic_state(APICCommonState *s, struct kvm_lapic_state *kapic int i; memset(kapic, 0, sizeof(*kapic)); - kvm_apic_set_reg(kapic, 0x2, s->id << 24); + if (kvm_has_x2apic_api() && s->apicbase & MSR_IA32_APICBASE_EXTD) { + kvm_apic_set_reg(kapic, 0x2, s->initial_apic_id); + } else { + kvm_apic_set_reg(kapic, 0x2, s->id << 24); + } kvm_apic_set_reg(kapic, 0x8, s->tpr); kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24); kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff); @@ -59,7 +63,11 @@ void kvm_get_apic_state(DeviceState *dev, struct kvm_lapic_state *kapic) APICCommonState *s = APIC_COMMON(dev); int i, v; - s->id = kvm_apic_get_reg(kapic, 0x2) >> 24; + if (kvm_has_x2apic_api() && s->apicbase & MSR_IA32_APICBASE_EXTD) { + assert(kvm_apic_get_reg(kapic, 0x2) == s->initial_apic_id); + } else { + s->id = kvm_apic_get_reg(kapic, 0x2) >> 24; + } s->tpr = kvm_apic_get_reg(kapic, 0x8); s->arb_id = kvm_apic_get_reg(kapic, 0x9); s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index fb8f29c34c17..f56ea0f87bde 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -68,6 +68,7 @@ #include "qapi-visit.h" #include "qom/cpu.h" #include "hw/nmi.h" +#include "hw/i386/intel_iommu.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -746,17 +747,15 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms) /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: * - * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug - * QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC - * ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the - * "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS - * may see". + * For machine types prior to 1.8, SeaBIOS needs FW_CFG_MAX_CPUS for + * building MPTable, ACPI MADT, ACPI CPU hotplug and ACPI SRAT table, + * that tables are based on xAPIC ID and QEMU<->SeaBIOS interface + * for CPU hotplug also uses APIC ID and not "CPU index". + * This means that FW_CFG_MAX_CPUS is not the "maximum number of CPUs", + * but the "limit to the APIC ID values SeaBIOS may see". * - * So, this means we must not use max_cpus, here, but the maximum possible - * APIC ID value, plus one. - * - * [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is - * the APIC ID, not the "CPU index" + * So for compatibility reasons with old BIOSes we are stuck with + * "etc/max-cpus" actually being apic_id_limit */ fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)pcms->apic_id_limit); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); @@ -1087,17 +1086,6 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static int pc_present_cpus_count(PCMachineState *pcms) -{ - int i, boot_cpus = 0; - for (i = 0; i < pcms->possible_cpus->len; i++) { - if (pcms->possible_cpus->cpus[i].cpu) { - boot_cpus++; - } - } - return boot_cpus; -} - static X86CPU *pc_new_cpu(const char *typename, int64_t apic_id, Error **errp) { @@ -1190,12 +1178,6 @@ void pc_cpus_init(PCMachineState *pcms) * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init(). */ pcms->apic_id_limit = x86_cpu_apic_id_from_index(max_cpus - 1) + 1; - if (pcms->apic_id_limit > ACPI_CPU_HOTPLUG_ID_LIMIT) { - error_report("max_cpus is too large. APIC ID of last CPU is %u", - pcms->apic_id_limit - 1); - exit(1); - } - pcms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + sizeof(CPUArchId) * max_cpus); for (i = 0; i < max_cpus; i++) { @@ -1240,6 +1222,19 @@ static void pc_build_feature_control_file(PCMachineState *pcms) fw_cfg_add_file(pcms->fw_cfg, "etc/msr_feature_control", val, sizeof(*val)); } +static void rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count) +{ + if (cpus_count > 0xff) { + /* If the number of CPUs can't be represented in 8 bits, the + * BIOS must use "etc/boot-cpus". Set RTC field to 0 just + * to make old BIOSes fail more predictably. + */ + rtc_set_memory(rtc, 0x5f, 0); + } else { + rtc_set_memory(rtc, 0x5f, cpus_count - 1); + } +} + static void pc_machine_done(Notifier *notifier, void *data) { @@ -1248,7 +1243,7 @@ void pc_machine_done(Notifier *notifier, void *data) PCIBus *bus = pcms->bus; /* set the number of CPUs */ - rtc_set_memory(pcms->rtc, 0x5f, pc_present_cpus_count(pcms) - 1); + rtc_set_cpus_count(pcms->rtc, le16_to_cpu(pcms->boot_cpus_le)); if (bus) { int extra_hosts = 0; @@ -1269,8 +1264,28 @@ void pc_machine_done(Notifier *notifier, void *data) acpi_setup(); if (pcms->fw_cfg) { + MachineClass *mc = MACHINE_GET_CLASS(pcms); + pc_build_smbios(pcms->fw_cfg); pc_build_feature_control_file(pcms); + + if (mc->max_cpus > 255) { + fw_cfg_add_file(pcms->fw_cfg, "etc/boot-cpus", &pcms->boot_cpus_le, + sizeof(pcms->boot_cpus_le)); + } + } + + if (pcms->apic_id_limit > 255) { + IntelIOMMUState *iommu = INTEL_IOMMU_DEVICE(x86_iommu_get_default()); + + if (!iommu || !iommu->x86_iommu.intr_supported || + iommu->intr_eim != ON_OFF_AUTO_ON) { + error_report("current -smp configuration requires " + "Extended Interrupt Mode enabled. " + "You can add an IOMMU using: " + "-device intel-iommu,intremap=on,eim=on"); + exit(EXIT_FAILURE); + } } } @@ -1794,9 +1809,11 @@ static void pc_cpu_plug(HotplugHandler *hotplug_dev, } } + /* increment the number of CPUs */ + pcms->boot_cpus_le = cpu_to_le16(le16_to_cpu(pcms->boot_cpus_le) + 1); if (dev->hotplugged) { - /* increment the number of CPUs */ - rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) + 1); + /* Update the number of CPUs in CMOS */ + rtc_set_cpus_count(pcms->rtc, le16_to_cpu(pcms->boot_cpus_le)); } found_cpu = pc_find_cpu_slot(pcms, CPU(dev), NULL); @@ -1850,7 +1867,10 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev, found_cpu->cpu = NULL; object_unparent(OBJECT(dev)); - rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) - 1); + /* decrement the number of CPUs */ + pcms->boot_cpus_le = cpu_to_le16(le16_to_cpu(pcms->boot_cpus_le) - 1); + /* Update the number of CPUs in CMOS */ + rtc_set_cpus_count(pcms->rtc, le16_to_cpu(pcms->boot_cpus_le)); out: error_propagate(errp, local_err); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 0b214f24c977..b40d19ee00da 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -291,6 +291,7 @@ static void pc_q35_machine_options(MachineClass *m) m->default_display = "std"; m->no_floppy = 1; m->has_dynamic_sysbus = true; + m->max_cpus = 288; } static void pc_q35_2_8_machine_options(MachineClass *m) @@ -306,6 +307,7 @@ static void pc_q35_2_7_machine_options(MachineClass *m) { pc_q35_2_8_machine_options(m); m->alias = NULL; + m->max_cpus = 255; SET_MACHINE_COMPAT(m, PC_COMPAT_2_7); } diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 8d01c9c8750e..d78c88550924 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -22,6 +22,7 @@ #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" +#include "qapi/visitor.h" #include "hw/i386/apic.h" #include "hw/i386/apic_internal.h" #include "trace.h" @@ -39,6 +40,11 @@ void cpu_set_apic_base(DeviceState *dev, uint64_t val) if (dev) { APICCommonState *s = APIC_COMMON(dev); APICCommonClass *info = APIC_COMMON_GET_CLASS(s); + /* switching to x2APIC, reset possibly modified xAPIC ID */ + if (!(s->apicbase & MSR_IA32_APICBASE_EXTD) && + (val & MSR_IA32_APICBASE_EXTD)) { + s->id = s->initial_apic_id; + } info->set_base(s, val); } } @@ -242,6 +248,7 @@ static void apic_reset_common(DeviceState *dev) bsp = s->apicbase & MSR_IA32_APICBASE_BSP; s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE; + s->id = s->initial_apic_id; s->vapic_paddr = 0; info->vapic_base_update(s); @@ -428,7 +435,6 @@ static const VMStateDescription vmstate_apic_common = { }; static Property apic_properties_common[] = { - DEFINE_PROP_UINT8("id", APICCommonState, id, -1), DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14), DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT, true), @@ -437,6 +443,49 @@ static Property apic_properties_common[] = { DEFINE_PROP_END_OF_LIST(), }; +static void apic_common_get_id(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + APICCommonState *s = APIC_COMMON(obj); + int64_t value; + + value = s->apicbase & MSR_IA32_APICBASE_EXTD ? s->initial_apic_id : s->id; + visit_type_int(v, name, &value, errp); +} + +static void apic_common_set_id(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + APICCommonState *s = APIC_COMMON(obj); + DeviceState *dev = DEVICE(obj); + Error *local_err = NULL; + int64_t value; + + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; + } + + visit_type_int(v, name, &value, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + s->initial_apic_id = value; + s->id = (uint8_t)value; +} + +static void apic_common_initfn(Object *obj) +{ + APICCommonState *s = APIC_COMMON(obj); + + s->id = s->initial_apic_id = -1; + object_property_add(obj, "id", "int", + apic_common_get_id, + apic_common_set_id, NULL, NULL, NULL); +} + static void apic_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -456,6 +505,7 @@ static const TypeInfo apic_common_type = { .name = TYPE_APIC_COMMON, .parent = TYPE_DEVICE, .instance_size = sizeof(APICCommonState), + .instance_init = apic_common_initfn, .class_size = sizeof(APICCommonClass), .class_init = apic_common_class_init, .abstract = true, diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ddb743843480..486f57d6f655 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2438,7 +2438,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->init = ppc_spapr_init; mc->reset = ppc_spapr_reset; mc->block_default_type = IF_SCSI; - mc->max_cpus = MAX_CPUMASK_BITS; + mc->max_cpus = 255; mc->no_parallel = 1; mc->default_boot_order = ""; mc->default_ram_size = 512 * M_BYTE; diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 336a57cde6bb..9797d556e838 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -57,7 +57,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, uint32_t flags, int cflags); -void cpu_exec_init(CPUState *cpu, Error **errp); void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 90a5353458de..d1d1d61fcb4c 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -343,6 +343,24 @@ struct AcpiMadtLocalNmi { } QEMU_PACKED; typedef struct AcpiMadtLocalNmi AcpiMadtLocalNmi; +struct AcpiMadtProcessorX2Apic { + ACPI_SUB_HEADER_DEF + uint16_t reserved; + uint32_t x2apic_id; /* Processor's local x2APIC ID */ + uint32_t flags; + uint32_t uid; /* Processor object _UID */ +} QEMU_PACKED; +typedef struct AcpiMadtProcessorX2Apic AcpiMadtProcessorX2Apic; + +struct AcpiMadtLocalX2ApicNmi { + ACPI_SUB_HEADER_DEF + uint16_t flags; /* MPS INTI flags */ + uint32_t uid; /* Processor object _UID */ + uint8_t lint; /* Local APIC LINT# */ + uint8_t reserved[3]; /* Local APIC LINT# */ +} QEMU_PACKED; +typedef struct AcpiMadtLocalX2ApicNmi AcpiMadtLocalX2ApicNmi; + struct AcpiMadtGenericInterrupt { ACPI_SUB_HEADER_DEF uint16_t reserved; @@ -485,6 +503,17 @@ struct AcpiSratProcessorAffinity } QEMU_PACKED; typedef struct AcpiSratProcessorAffinity AcpiSratProcessorAffinity; +struct AcpiSratProcessorX2ApicAffinity { + ACPI_SUB_HEADER_DEF + uint16_t reserved; + uint32_t proximity_domain; + uint32_t x2apic_id; + uint32_t flags; + uint32_t clk_domain; + uint32_t reserved2; +} QEMU_PACKED; +typedef struct AcpiSratProcessorX2ApicAffinity AcpiSratProcessorX2ApicAffinity; + struct AcpiSratMemoryAffinity { ACPI_SUB_HEADER_DEF diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index cdd11fb0938f..1209eb483ab6 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -160,7 +160,8 @@ struct APICCommonState { MemoryRegion io_memory; X86CPU *cpu; uint32_t apicbase; - uint8_t id; + uint8_t id; /* legacy APIC ID */ + uint32_t initial_apic_id; uint8_t version; uint8_t arb_id; uint8_t tpr; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index b16c448249ae..17fff80c8a7d 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -37,6 +37,7 @@ /** * PCMachineState: * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling + * @boot_cpus_le: number of present VCPUs, referenced by 'etc/boot-cpus' fw_cfg */ struct PCMachineState { /*< private >*/ @@ -69,6 +70,7 @@ struct PCMachineState { bool apic_xrupt_override; unsigned apic_id_limit; CPUArchIdList *possible_cpus; + uint16_t boot_cpus_le; /* NUMA information: */ uint64_t numa_nodes; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 6d481a1dc05b..633c3fc124b9 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -946,7 +946,9 @@ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx); void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...) GCC_FMT_ATTR(2, 3); -void cpu_exec_exit(CPUState *cpu); +void cpu_exec_initfn(CPUState *cpu); +void cpu_exec_realizefn(CPUState *cpu, Error **errp); +void cpu_exec_unrealizefn(CPUState *cpu); #ifdef CONFIG_SOFTMMU extern const struct VMStateDescription vmstate_cpu_common; diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index b66883328df2..66c6f1577e0c 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -173,7 +173,7 @@ extern int mem_prealloc; * * Note that cpu->get_arch_id() may be larger than MAX_CPUMASK_BITS. */ -#define MAX_CPUMASK_BITS 255 +#define MAX_CPUMASK_BITS 288 #define MAX_OPTION_ROMS 16 typedef struct QEMUOptionRom { diff --git a/qom/cpu.c b/qom/cpu.c index c40f774a0caa..03d9190f8ce8 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -345,6 +345,12 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) trace_init_vcpu(cpu); } +static void cpu_common_unrealizefn(DeviceState *dev, Error **errp) +{ + CPUState *cpu = CPU(dev); + cpu_exec_unrealizefn(cpu); +} + static void cpu_common_initfn(Object *obj) { CPUState *cpu = CPU(obj); @@ -362,12 +368,13 @@ static void cpu_common_initfn(Object *obj) QTAILQ_INIT(&cpu->watchpoints); cpu->trace_dstate = bitmap_new(trace_get_vcpu_event_count()); + + cpu_exec_initfn(cpu); } static void cpu_common_finalize(Object *obj) { CPUState *cpu = CPU(obj); - cpu_exec_exit(cpu); g_free(cpu->trace_dstate); } @@ -401,6 +408,7 @@ static void cpu_class_init(ObjectClass *klass, void *data) k->cpu_exec_exit = cpu_common_noop; k->cpu_exec_interrupt = cpu_common_exec_interrupt; dc->realize = cpu_common_realizefn; + dc->unrealize = cpu_common_unrealizefn; /* * Reason: CPUs still need special care by board code: wiring up * IRQs, adding reset handlers, halting non-first CPUs, ... diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 6d01d7f75e9e..30d77ce71caf 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -59,6 +59,13 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } qemu_init_vcpu(cs); @@ -266,7 +273,6 @@ static void alpha_cpu_initfn(Object *obj) CPUAlphaState *env = &cpu->env; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); tlb_flush(cs, 1); alpha_translate_init(); @@ -309,13 +315,6 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data) cc->disas_set_info = alpha_cpu_disas_set_info; cc->gdb_num_core_regs = 67; - - /* - * Reason: alpha_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo alpha_cpu_type_info = { diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 3991173d47f8..a42495bac941 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -80,9 +80,11 @@ void arm_gt_stimer_cb(void *opaque); #define ARM_AFF2_MASK (0xFFULL << ARM_AFF2_SHIFT) #define ARM_AFF3_SHIFT 32 #define ARM_AFF3_MASK (0xFFULL << ARM_AFF3_SHIFT) +#define ARM_DEFAULT_CPUS_PER_CLUSTER 8 #define ARM32_AFFINITY_MASK (ARM_AFF0_MASK|ARM_AFF1_MASK|ARM_AFF2_MASK) #define ARM64_AFFINITY_MASK \ (ARM_AFF0_MASK|ARM_AFF1_MASK|ARM_AFF2_MASK|ARM_AFF3_MASK) +#define ARM64_AFFINITY_INVALID (~ARM64_AFFINITY_MASK) #endif diff --git a/target-arm/cpu.c b/target-arm/cpu.c index c94a3245401e..2439ca57d000 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -434,29 +434,16 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) } } -#define ARM_CPUS_PER_CLUSTER 8 - static void arm_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); ARMCPU *cpu = ARM_CPU(obj); static bool inited; - uint32_t Aff1, Aff0; cs->env_ptr = &cpu->env; - cpu_exec_init(cs, &error_abort); cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); - /* This cpu-id-to-MPIDR affinity is used only for TCG; KVM will override it. - * We don't support setting cluster ID ([16..23]) (known as Aff2 - * in later ARM ARM versions), or any of the higher affinity level fields, - * so these bits always RAZ. - */ - Aff1 = cs->cpu_index / ARM_CPUS_PER_CLUSTER; - Aff0 = cs->cpu_index % ARM_CPUS_PER_CLUSTER; - cpu->mp_affinity = (Aff1 << ARM_AFF1_SHIFT) | Aff0; - #ifndef CONFIG_USER_ONLY /* Our inbound IRQ and FIQ lines */ if (kvm_enabled()) { @@ -577,6 +564,13 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) ARMCPUClass *acc = ARM_CPU_GET_CLASS(dev); CPUARMState *env = &cpu->env; int pagebits; + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } /* Some features automatically imply others: */ if (arm_feature(env, ARM_FEATURE_V8)) { @@ -655,6 +649,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) return; } + /* This cpu-id-to-MPIDR affinity is used only for TCG; KVM will override it. + * We don't support setting cluster ID ([16..23]) (known as Aff2 + * in later ARM ARM versions), or any of the higher affinity level fields, + * so these bits always RAZ. + */ + if (cpu->mp_affinity == ARM64_AFFINITY_INVALID) { + uint32_t Aff1 = cs->cpu_index / ARM_DEFAULT_CPUS_PER_CLUSTER; + uint32_t Aff0 = cs->cpu_index % ARM_DEFAULT_CPUS_PER_CLUSTER; + cpu->mp_affinity = (Aff1 << ARM_AFF1_SHIFT) | Aff0; + } + if (cpu->reset_hivecs) { cpu->reset_sctlr |= (1 << 13); } @@ -1485,7 +1490,8 @@ static Property arm_cpu_properties[] = { DEFINE_PROP_BOOL("start-powered-off", ARMCPU, start_powered_off, false), DEFINE_PROP_UINT32("psci-conduit", ARMCPU, psci_conduit, 0), DEFINE_PROP_UINT32("midr", ARMCPU, midr, 0), - DEFINE_PROP_UINT64("mp-affinity", ARMCPU, mp_affinity, 0), + DEFINE_PROP_UINT64("mp-affinity", ARMCPU, + mp_affinity, ARM64_AFFINITY_INVALID), DEFINE_PROP_END_OF_LIST() }; @@ -1557,17 +1563,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->debug_check_watchpoint = arm_debug_check_watchpoint; cc->disas_set_info = arm_disas_set_info; - - /* - * Reason: arm_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - * - * Once this is fixed, the devices that create ARM CPUs should be - * updated not to set cannot_destroy_with_object_finalize_yet, - * unless they still screw up something else. - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static void cpu_register(const ARMCPUInfo *info) diff --git a/target-cris/cpu.c b/target-cris/cpu.c index d680cfb52b34..2e9ab9700e8b 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -142,6 +142,13 @@ static void cris_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } cpu_reset(cs); qemu_init_vcpu(cs); @@ -187,7 +194,6 @@ static void cris_cpu_initfn(Object *obj) static bool tcg_initialized; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); env->pregs[PR_VR] = ccc->vr; @@ -326,13 +332,6 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_stop_before_watchpoint = true; cc->disas_set_info = cris_disas_set_info; - - /* - * Reason: cris_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo cris_cpu_type_info = { diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index e724004a785d..7c9a07ae6535 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -68,6 +68,7 @@ typedef struct X86CPUClass { const char *model_description; DeviceRealize parent_realize; + DeviceUnrealize parent_unrealize; void (*parent_reset)(CPUState *cpu); } X86CPUClass; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index d95514c7dd43..83998a85c1b8 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2945,7 +2945,7 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) OBJECT(cpu->apic_state), &error_abort); object_unref(OBJECT(cpu->apic_state)); - qdev_prop_set_uint8(cpu->apic_state, "id", cpu->apic_id); + qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id); /* TODO: convert to link<> */ apic = APIC_COMMON(cpu->apic_state); apic->cpu = cpu; @@ -3271,7 +3271,11 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) cpu->phys_bits = 32; } } - cpu_exec_init(cs, &error_abort); + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } if (tcg_enabled()) { tcg_x86_init(); @@ -3352,6 +3356,8 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp) { X86CPU *cpu = X86_CPU(dev); + X86CPUClass *xcc = X86_CPU_GET_CLASS(dev); + Error *local_err = NULL; #ifndef CONFIG_USER_ONLY cpu_remove_sync(CPU(dev)); @@ -3362,6 +3368,12 @@ static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp) object_unparent(OBJECT(cpu->apic_state)); cpu->apic_state = NULL; } + + xcc->parent_unrealize(dev, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } } typedef struct BitProperty { @@ -3636,6 +3648,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); xcc->parent_realize = dc->realize; + xcc->parent_unrealize = dc->unrealize; dc->realize = x86_cpu_realizefn; dc->unrealize = x86_cpu_unrealizefn; dc->props = x86_cpu_properties; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e64569854fec..6303d6593d07 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -325,6 +325,7 @@ #define MSR_IA32_APICBASE 0x1b #define MSR_IA32_APICBASE_BSP (1<<8) #define MSR_IA32_APICBASE_ENABLE (1<<11) +#define MSR_IA32_APICBASE_EXTD (1 << 10) #define MSR_IA32_APICBASE_BASE (0xfffffU<<12) #define MSR_IA32_FEATURE_CONTROL 0x0000003a #define MSR_TSC_ADJUST 0x0000003b diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 0472f45fd092..86b41a9c215f 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -129,9 +129,8 @@ static bool kvm_x2apic_api_set_flags(uint64_t flags) return !kvm_vm_enable_cap(s, KVM_CAP_X2APIC_API, 0, flags); } -#define MEMORIZE(fn) \ +#define MEMORIZE(fn, _result) \ ({ \ - static typeof(fn) _result; \ static bool _memorized; \ \ if (_memorized) { \ @@ -141,11 +140,19 @@ static bool kvm_x2apic_api_set_flags(uint64_t flags) _result = fn; \ }) +static bool has_x2apic_api; + +bool kvm_has_x2apic_api(void) +{ + return has_x2apic_api; +} + bool kvm_enable_x2apic(void) { return MEMORIZE( kvm_x2apic_api_set_flags(KVM_X2APIC_API_USE_32BIT_IDS | - KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)); + KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK), + has_x2apic_api); } static int kvm_get_tsc(CPUState *cs) diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h index 5c369b1c5b40..76079295b21e 100644 --- a/target-i386/kvm_i386.h +++ b/target-i386/kvm_i386.h @@ -44,4 +44,5 @@ int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id); void kvm_put_apicbase(X86CPU *cpu, uint64_t value); bool kvm_enable_x2apic(void); +bool kvm_has_x2apic_api(void); #endif diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index a783d461dd40..8d939a7779f2 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -144,6 +144,13 @@ static void lm32_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); LM32CPUClass *lcc = LM32_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } cpu_reset(cs); @@ -160,7 +167,6 @@ static void lm32_cpu_initfn(Object *obj) static bool tcg_initialized; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); env->flags = 0; @@ -285,13 +291,6 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_stop_before_watchpoint = true; cc->debug_excp_handler = lm32_debug_excp_handler; cc->disas_set_info = lm32_cpu_disas_set_info; - - /* - * Reason: lm32_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static void lm32_register_cpu_type(const LM32CPUInfo *info) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index 116b784e6371..17e4be293401 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -159,6 +159,13 @@ static void m68k_cpu_realizefn(DeviceState *dev, Error **errp) CPUState *cs = CPU(dev); M68kCPU *cpu = M68K_CPU(dev); M68kCPUClass *mcc = M68K_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } m68k_cpu_init_gdb(cpu); @@ -176,7 +183,6 @@ static void m68k_cpu_initfn(Object *obj) static bool inited; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); if (tcg_enabled() && !inited) { inited = true; @@ -222,13 +228,6 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) cc->gdb_core_xml_file = "cf-core.xml"; dc->vmsd = &vmstate_m68k_cpu; - - /* - * Reason: m68k_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static void register_cpu_type(const M68kCPUInfo *info) diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 8edc00a7963f..389c7b691ece 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -138,6 +138,13 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) CPUMBState *env = &cpu->env; uint8_t version_code = 0; int i = 0; + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } qemu_init_vcpu(cs); @@ -199,7 +206,6 @@ static void mb_cpu_initfn(Object *obj) static bool tcg_initialized; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); @@ -267,12 +273,6 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_num_core_regs = 32 + 5; cc->disas_set_info = mb_disas_set_info; - - /* - * Reason: mb_cpu_initfn() calls cpu_exec_init(), which saves the - * object in cpus -> dangling pointer after final object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo mb_cpu_type_info = { diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 64ad112f4de3..65ca607f88c0 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -124,6 +124,13 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } cpu_reset(cs); qemu_init_vcpu(cs); @@ -138,7 +145,6 @@ static void mips_cpu_initfn(Object *obj) CPUMIPSState *env = &cpu->env; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); if (tcg_enabled()) { mips_tcg_init(); @@ -177,13 +183,6 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) cc->gdb_num_core_regs = 73; cc->gdb_stop_before_watchpoint = true; - - /* - * Reason: mips_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo mips_cpu_type_info = { diff --git a/target-moxie/cpu.c b/target-moxie/cpu.c index 50a08994716c..b0be4a7551c1 100644 --- a/target-moxie/cpu.c +++ b/target-moxie/cpu.c @@ -61,6 +61,13 @@ static void moxie_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } qemu_init_vcpu(cs); cpu_reset(cs); @@ -75,7 +82,6 @@ static void moxie_cpu_initfn(Object *obj) static int inited; cs->env_ptr = &cpu->env; - cpu_exec_init(cs, &error_abort); if (tcg_enabled() && !inited) { inited = 1; @@ -124,13 +130,6 @@ static void moxie_cpu_class_init(ObjectClass *oc, void *data) cc->vmsd = &vmstate_moxie_cpu; #endif cc->disas_set_info = moxie_cpu_disas_set_info; - - /* - * Reason: moxie_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static void moxielite_initfn(Object *obj) diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index 155913f10795..698e87bb2596 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -81,6 +81,13 @@ static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } qemu_init_vcpu(cs); cpu_reset(cs); @@ -95,7 +102,6 @@ static void openrisc_cpu_initfn(Object *obj) static int inited; cs->env_ptr = &cpu->env; - cpu_exec_init(cs, &error_abort); #ifndef CONFIG_USER_ONLY cpu_openrisc_mmu_init(cpu); @@ -180,13 +186,6 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) dc->vmsd = &vmstate_openrisc_cpu; #endif cc->gdb_num_core_regs = 32 + 3; - - /* - * Reason: openrisc_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static void cpu_register(const OpenRISCCPUInfo *info) diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 713deef301db..d46c31a15d91 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -174,6 +174,7 @@ typedef struct PowerPCCPUClass { /*< public >*/ DeviceRealize parent_realize; + DeviceUnrealize parent_unrealize; void (*parent_reset)(CPUState *cpu); uint32_t pvr; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index b66b40b82f08..208fa1ea534c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9678,7 +9678,7 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) } #endif - cpu_exec_init(cs, &local_err); + cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; @@ -9906,11 +9906,17 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp) { PowerPCCPU *cpu = POWERPC_CPU(dev); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; + Error *local_err = NULL; opc_handler_t **table, **table_2; int i, j, k; - cpu_exec_exit(CPU(dev)); + pcc->parent_unrealize(dev, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) { if (env->opcodes[i] == &invalid_handler) { @@ -10521,6 +10527,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); pcc->parent_realize = dc->realize; + pcc->parent_unrealize = dc->unrealize; pcc->pvr_match = ppc_pvr_match_default; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_always; dc->realize = ppc_cpu_realizefn; diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 35ae2cec4b46..9e2f239cf139 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -207,7 +207,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) goto out; } - cpu_exec_init(cs, &err); + cpu_exec_realizefn(cs, &err); if (err != NULL) { goto out; } @@ -440,12 +440,6 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_core_xml_file = "s390x-core64.xml"; cc->gdb_arch_name = s390_gdb_arch_name; - /* - * Reason: s390_cpu_realizefn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; s390_cpu_model_class_register_props(oc); } diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index f589532e18eb..a38f6a6ded00 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -244,6 +244,13 @@ static void superh_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } cpu_reset(cs); qemu_init_vcpu(cs); @@ -258,7 +265,6 @@ static void superh_cpu_initfn(Object *obj) CPUSH4State *env = &cpu->env; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); env->movcal_backup_tail = &(env->movcal_backup); @@ -303,13 +309,6 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_num_core_regs = 59; dc->vmsd = &vmstate_sh_cpu; - - /* - * Reason: superh_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo superh_cpu_type_info = { diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 800a25aa5756..4e07b92fbd70 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -792,7 +792,9 @@ static bool sparc_cpu_has_work(CPUState *cs) static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) { + CPUState *cs = CPU(dev); SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(dev); + Error *local_err = NULL; #if defined(CONFIG_USER_ONLY) SPARCCPU *cpu = SPARC_CPU(dev); CPUSPARCState *env = &cpu->env; @@ -802,7 +804,13 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) } #endif - qemu_init_vcpu(CPU(dev)); + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + + qemu_init_vcpu(cs); scc->parent_realize(dev, errp); } @@ -814,7 +822,6 @@ static void sparc_cpu_initfn(Object *obj) CPUSPARCState *env = &cpu->env; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); if (tcg_enabled()) { gen_intermediate_code_init(env); @@ -867,13 +874,6 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) #else cc->gdb_num_core_regs = 72; #endif - - /* - * Reason: sparc_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo sparc_cpu_type_info = { diff --git a/target-tilegx/cpu.c b/target-tilegx/cpu.c index 7017cb6e1a7f..454793f94a13 100644 --- a/target-tilegx/cpu.c +++ b/target-tilegx/cpu.c @@ -92,6 +92,13 @@ static void tilegx_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); TileGXCPUClass *tcc = TILEGX_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } cpu_reset(cs); qemu_init_vcpu(cs); @@ -107,7 +114,6 @@ static void tilegx_cpu_initfn(Object *obj) static bool tcg_initialized; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); if (tcg_enabled() && !tcg_initialized) { tcg_initialized = true; @@ -162,13 +168,6 @@ static void tilegx_cpu_class_init(ObjectClass *oc, void *data) cc->set_pc = tilegx_cpu_set_pc; cc->handle_mmu_fault = tilegx_cpu_handle_mmu_fault; cc->gdb_num_core_regs = 0; - - /* - * Reason: tilegx_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo tilegx_cpu_type_info = { diff --git a/target-tricore/cpu.c b/target-tricore/cpu.c index 35d4ee4deacc..785b76bd3aa6 100644 --- a/target-tricore/cpu.c +++ b/target-tricore/cpu.c @@ -69,6 +69,13 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp) TriCoreCPU *cpu = TRICORE_CPU(dev); TriCoreCPUClass *tcc = TRICORE_CPU_GET_CLASS(dev); CPUTriCoreState *env = &cpu->env; + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } /* Some features automatically imply others */ if (tricore_feature(env, TRICORE_FEATURE_161)) { @@ -95,7 +102,6 @@ static void tricore_cpu_initfn(Object *obj) CPUTriCoreState *env = &cpu->env; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); if (tcg_enabled()) { tricore_tcg_init(); @@ -172,13 +178,6 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data) cc->dump_state = tricore_cpu_dump_state; cc->set_pc = tricore_cpu_set_pc; cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb; - - /* - * Reason: tricore_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static void cpu_register(const TriCoreCPUInfo *info) diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index e7a49842605b..c169972b59de 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -101,9 +101,17 @@ static const UniCore32CPUInfo uc32_cpus[] = { static void uc32_cpu_realizefn(DeviceState *dev, Error **errp) { + CPUState *cs = CPU(dev); UniCore32CPUClass *ucc = UNICORE32_CPU_GET_CLASS(dev); + Error *local_err = NULL; - qemu_init_vcpu(CPU(dev)); + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + + qemu_init_vcpu(cs); ucc->parent_realize(dev, errp); } @@ -116,7 +124,6 @@ static void uc32_cpu_initfn(Object *obj) static bool inited; cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); #ifdef CONFIG_USER_ONLY env->uncached_asr = ASR_MODE_USER; @@ -160,13 +167,6 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data) cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug; #endif dc->vmsd = &vmstate_uc32_cpu; - - /* - * Reason: uc32_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static void uc32_register_cpu_type(const UniCore32CPUInfo *info) diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index 5ad08a279990..e8e9f9175b80 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -99,6 +99,13 @@ static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs; @@ -117,7 +124,6 @@ static void xtensa_cpu_initfn(Object *obj) cs->env_ptr = env; env->config = xcc->config; - cpu_exec_init(cs, &error_abort); if (tcg_enabled() && !tcg_inited) { tcg_inited = true; @@ -158,13 +164,6 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) #endif cc->debug_excp_handler = xtensa_breakpoint_handler; dc->vmsd = &vmstate_xtensa_cpu; - - /* - * Reason: xtensa_cpu_initfn() calls cpu_exec_init(), which saves - * the object in cpus -> dangling pointer after final - * object_unref(). - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo xtensa_cpu_type_info = {