From c4cfef5e8a6371aa5e6577f2b980315c2dc46cfb Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 23 Apr 2013 10:29:35 +0200 Subject: cpu: Make kvm-stub.o available outside softmmu It will provide stubs for *-user targets once softmmu-specific calls are attempted from common CPU code. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- include/sysemu/kvm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 75bd7d9934..2bc1f6ba80 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -144,10 +144,10 @@ int kvm_cpu_exec(CPUArchState *env); #if !defined(CONFIG_USER_ONLY) void *kvm_vmalloc(ram_addr_t size); void *kvm_arch_vmalloc(ram_addr_t size); -void kvm_setup_guest_memory(void *start, size_t size); +#endif +void kvm_setup_guest_memory(void *start, size_t size); void kvm_flush_coalesced_mmio_buffer(void); -#endif int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, target_ulong len, int type); -- cgit v1.2.3-55-g7522 From 13eed94ed5617b98e657163490584dc2a0cc4b32 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 23 Apr 2013 10:29:36 +0200 Subject: cpu: Call cpu_synchronize_post_init() from DeviceClass::realize() If hotplugged, synchronize CPU state to KVM. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- include/sysemu/kvm.h | 20 ++++++++++---------- kvm-all.c | 1 + kvm-stub.c | 1 + qom/cpu.c | 6 ++++++ vl.c | 1 - 5 files changed, 18 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 2bc1f6ba80..9735c1dee6 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -250,8 +250,6 @@ int kvm_check_extension(KVMState *s, unsigned int extension); uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function, uint32_t index, int reg); void kvm_cpu_synchronize_state(CPUArchState *env); -void kvm_cpu_synchronize_post_reset(CPUState *cpu); -void kvm_cpu_synchronize_post_init(CPUState *cpu); /* generic hooks - to be moved/refactored once there are more users */ @@ -262,6 +260,16 @@ static inline void cpu_synchronize_state(CPUArchState *env) } } +#if !defined(CONFIG_USER_ONLY) +int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr, + hwaddr *phys_addr); +#endif + +#endif /* NEED_CPU_H */ + +void kvm_cpu_synchronize_post_reset(CPUState *cpu); +void kvm_cpu_synchronize_post_init(CPUState *cpu); + static inline void cpu_synchronize_post_reset(CPUState *cpu) { if (kvm_enabled()) { @@ -276,14 +284,6 @@ static inline void cpu_synchronize_post_init(CPUState *cpu) } } - -#if !defined(CONFIG_USER_ONLY) -int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr, - hwaddr *phys_addr); -#endif - -#endif - int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg); int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg); void kvm_irqchip_release_virq(KVMState *s, int virq); diff --git a/kvm-all.c b/kvm-all.c index 2d927217bd..f6c0f4a087 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -109,6 +109,7 @@ bool kvm_async_interrupts_allowed; bool kvm_irqfds_allowed; bool kvm_msi_via_irqfd_allowed; bool kvm_gsi_routing_allowed; +bool kvm_allowed; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), diff --git a/kvm-stub.c b/kvm-stub.c index b22837828e..b2c8f9b02d 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -25,6 +25,7 @@ bool kvm_async_interrupts_allowed; bool kvm_irqfds_allowed; bool kvm_msi_via_irqfd_allowed; bool kvm_gsi_routing_allowed; +bool kvm_allowed; int kvm_init_vcpu(CPUState *cpu) { diff --git a/qom/cpu.c b/qom/cpu.c index e242dcbeb4..66f7c00c29 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -20,6 +20,7 @@ #include "qom/cpu.h" #include "qemu-common.h" +#include "sysemu/kvm.h" void cpu_reset_interrupt(CPUState *cpu, int mask) { @@ -57,6 +58,11 @@ static ObjectClass *cpu_common_class_by_name(const char *cpu_model) static void cpu_common_realizefn(DeviceState *dev, Error **errp) { + CPUState *cpu = CPU(dev); + + if (dev->hotplugged) { + cpu_synchronize_post_init(cpu); + } } static void cpu_class_init(ObjectClass *klass, void *data) diff --git a/vl.c b/vl.c index b5a547e7e5..41c367db0a 100644 --- a/vl.c +++ b/vl.c @@ -267,7 +267,6 @@ static NotifierList machine_init_done_notifiers = NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers); static bool tcg_allowed = true; -bool kvm_allowed; bool xen_allowed; uint32_t xen_domid; enum xen_mode xen_mode = XEN_EMULATE; -- cgit v1.2.3-55-g7522 From 2993683b0fde0f836777c945baaddcaa5937903f Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 23 Apr 2013 10:29:37 +0200 Subject: cpu: Introduce cpu_resume(), for single CPU Also add a stub for it, to make possible to use it in qom/cpu.c, which is shared with user emulators. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- cpus.c | 11 ++++++++--- include/qom/cpu.h | 7 +++++++ stubs/Makefile.objs | 1 + stubs/cpus.c | 5 +++++ 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 stubs/cpus.c (limited to 'include') diff --git a/cpus.c b/cpus.c index 5a98a370df..1d8876157c 100644 --- a/cpus.c +++ b/cpus.c @@ -993,6 +993,13 @@ void pause_all_vcpus(void) } } +void cpu_resume(CPUState *cpu) +{ + cpu->stop = false; + cpu->stopped = false; + qemu_cpu_kick(cpu); +} + void resume_all_vcpus(void) { CPUArchState *penv = first_cpu; @@ -1000,9 +1007,7 @@ void resume_all_vcpus(void) qemu_clock_enable(vm_clock, true); while (penv) { CPUState *pcpu = ENV_GET_CPU(penv); - pcpu->stop = false; - pcpu->stopped = false; - qemu_cpu_kick(pcpu); + cpu_resume(pcpu); penv = penv->next_cpu; } } diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 3664a1b631..ac93dcec66 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -256,5 +256,12 @@ void cpu_interrupt(CPUState *cpu, int mask); */ void cpu_reset_interrupt(CPUState *cpu, int mask); +/** + * cpu_resume: + * @cpu: The CPU to resume. + * + * Resumes CPU, i.e. puts CPU into runnable state. + */ +void cpu_resume(CPUState *cpu); #endif diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 9c55b34354..03dff202e4 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -23,3 +23,4 @@ stub-obj-y += sysbus.o stub-obj-y += vm-stop.o stub-obj-y += vmstate.o stub-obj-$(CONFIG_WIN32) += fd-register.o +stub-obj-y += cpus.o diff --git a/stubs/cpus.c b/stubs/cpus.c new file mode 100644 index 0000000000..37000dd611 --- /dev/null +++ b/stubs/cpus.c @@ -0,0 +1,5 @@ +#include "qom/cpu.h" + +void cpu_resume(CPUState *cpu) +{ +} -- cgit v1.2.3-55-g7522 From 066e9b2710be887f435e0e899fa71f1f4314f702 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 23 Apr 2013 10:29:39 +0200 Subject: cpu: Introduce CPU hot-plug notifier Hot-add CPU event will be distributed to acpi_piix4 and rtc_cmos. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- include/sysemu/sysemu.h | 3 +++ qom/cpu.c | 12 ++++++++++++ 2 files changed, 15 insertions(+) (limited to 'include') diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 010e412f0c..2fb71afa25 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -153,6 +153,9 @@ void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict); /* generic hotplug */ void drive_hot_add(Monitor *mon, const QDict *qdict); +/* CPU hotplug */ +void qemu_register_cpu_added_notifier(Notifier *notifier); + /* pcie aer error injection */ void pcie_aer_inject_error_print(Monitor *mon, const QObject *data); int do_pcie_aer_inject_error(Monitor *mon, diff --git a/qom/cpu.c b/qom/cpu.c index b91213e6b1..34fa8054b2 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -21,6 +21,17 @@ #include "qom/cpu.h" #include "qemu-common.h" #include "sysemu/kvm.h" +#include "qemu/notify.h" +#include "sysemu/sysemu.h" + +/* CPU hot-plug notifiers */ +static NotifierList cpu_added_notifiers = + NOTIFIER_LIST_INITIALIZER(cpu_add_notifiers); + +void qemu_register_cpu_added_notifier(Notifier *notifier) +{ + notifier_list_add(&cpu_added_notifiers, notifier); +} void cpu_reset_interrupt(CPUState *cpu, int mask) { @@ -62,6 +73,7 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) if (dev->hotplugged) { cpu_synchronize_post_init(cpu); + notifier_list_notify(&cpu_added_notifiers, dev); cpu_resume(cpu); } } -- cgit v1.2.3-55-g7522 From b8b7456d6ab7edb450ae5ec6473d3cd9a80412f4 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 23 Apr 2013 10:29:40 +0200 Subject: pc: Update rtc_cmos on CPU hot-plug It provides updated currently available CPUs count to BIOS on reboot. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- hw/i386/pc.c | 20 ++++++++++++++++++++ hw/timer/mc146818rtc.c | 7 +++++++ include/hw/timer/mc146818rtc.h | 1 + 3 files changed, 28 insertions(+) (limited to 'include') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 29d2703330..867add7ab0 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -338,6 +338,21 @@ static void pc_cmos_init_late(void *opaque) qemu_unregister_reset(pc_cmos_init_late, opaque); } +typedef struct RTCCPUHotplugArg { + Notifier cpu_added_notifier; + ISADevice *rtc_state; +} RTCCPUHotplugArg; + +static void rtc_notify_cpu_added(Notifier *notifier, void *data) +{ + RTCCPUHotplugArg *arg = container_of(notifier, RTCCPUHotplugArg, + cpu_added_notifier); + ISADevice *s = arg->rtc_state; + + /* increment the number of CPUs */ + rtc_set_memory(s, 0x5f, rtc_get_memory(s, 0x5f) + 1); +} + void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, const char *boot_device, ISADevice *floppy, BusState *idebus0, BusState *idebus1, @@ -346,6 +361,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, int val, nb, i; FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE }; static pc_cmos_init_late_arg arg; + static RTCCPUHotplugArg cpu_hotplug_cb; /* various important CMOS locations needed by PC/Bochs bios */ @@ -384,6 +400,10 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, /* set the number of CPU */ rtc_set_memory(s, 0x5f, smp_cpus - 1); + /* init CPU hotplug notifier */ + cpu_hotplug_cb.rtc_state = s; + cpu_hotplug_cb.cpu_added_notifier.notify = rtc_notify_cpu_added; + qemu_register_cpu_added_notifier(&cpu_hotplug_cb.cpu_added_notifier); /* set boot devices, and disable floppy signature check if requested */ if (set_boot_dev(s, boot_device, fd_bootchk)) { diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index afbd0db298..481604de35 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -680,6 +680,13 @@ void rtc_set_memory(ISADevice *dev, int addr, int val) s->cmos_data[addr] = val; } +int rtc_get_memory(ISADevice *dev, int addr) +{ + RTCState *s = MC146818_RTC(dev); + assert(addr >= 0 && addr <= 127); + return s->cmos_data[addr]; +} + static void rtc_set_date_from_host(ISADevice *dev) { RTCState *s = MC146818_RTC(dev); diff --git a/include/hw/timer/mc146818rtc.h b/include/hw/timer/mc146818rtc.h index 425bd179a4..753dda6ae7 100644 --- a/include/hw/timer/mc146818rtc.h +++ b/include/hw/timer/mc146818rtc.h @@ -8,6 +8,7 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); +int rtc_get_memory(ISADevice *dev, int addr); void rtc_set_date(ISADevice *dev, const struct tm *tm); #endif /* !MC146818RTC_H */ -- cgit v1.2.3-55-g7522 From 997395d3888fcde6ce41535a8208d7aa919d824b Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 23 Apr 2013 10:29:41 +0200 Subject: cpu: Introduce get_arch_id() method and override it for X86CPU get_arch_id() adds possibility for generic code to get a guest-visible CPU ID without accessing CPUArchState. If derived classes don't override it, it will return cpu_index. Override it on target-i386 in X86CPU to return the APIC ID. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Reviewed-by: liguang Acked-by: Michael S. Tsirkin Signed-off-by: Andreas Färber --- include/qom/cpu.h | 2 ++ qom/cpu.c | 6 ++++++ target-i386/cpu.c | 10 ++++++++++ 3 files changed, 18 insertions(+) (limited to 'include') diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ac93dcec66..1b4de17415 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -45,6 +45,7 @@ typedef struct CPUState CPUState; * instantiatable CPU type. * @reset: Callback to reset the #CPUState to its initial state. * @do_interrupt: Callback for interrupt handling. + * @get_arch_id: Callback for getting architecture-dependent CPU ID. * @vmsd: State description for migration. * * Represents a CPU family or model. @@ -58,6 +59,7 @@ typedef struct CPUClass { void (*reset)(CPUState *cpu); void (*do_interrupt)(CPUState *cpu); + int64_t (*get_arch_id)(CPUState *cpu); const struct VMStateDescription *vmsd; } CPUClass; diff --git a/qom/cpu.c b/qom/cpu.c index 34fa8054b2..9a4457ba1b 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -78,6 +78,11 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) } } +static int64_t cpu_common_get_arch_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + static void cpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -85,6 +90,7 @@ static void cpu_class_init(ObjectClass *klass, void *data) k->class_by_name = cpu_common_class_by_name; k->reset = cpu_common_reset; + k->get_arch_id = cpu_common_get_arch_id; dc->realize = cpu_common_realizefn; dc->no_user = 1; } diff --git a/target-i386/cpu.c b/target-i386/cpu.c index e2302d8b05..f34ba23dad 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2272,6 +2272,14 @@ static void x86_cpu_initfn(Object *obj) } } +static int64_t x86_cpu_get_arch_id(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + return env->cpuid_apic_id; +} + static void x86_cpu_common_class_init(ObjectClass *oc, void *data) { X86CPUClass *xcc = X86_CPU_CLASS(oc); @@ -2286,6 +2294,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->do_interrupt = x86_cpu_do_interrupt; cpu_class_set_vmsd(cc, &vmstate_x86_cpu); + + cc->get_arch_id = x86_cpu_get_arch_id; } static const TypeInfo x86_cpu_type_info = { -- cgit v1.2.3-55-g7522 From d6b9e0d60cc511eca210834428bb74508cff3d33 Mon Sep 17 00:00:00 2001 From: Michael S. Tsirkin Date: Wed, 24 Apr 2013 22:58:04 +0200 Subject: cpu: Add qemu_for_each_cpu() Wrapper to avoid open-coded loops and to make CPUState iteration independent of CPUArchState. Signed-off-by: Michael S. Tsirkin Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- exec.c | 10 ++++++++++ include/qom/cpu.h | 9 +++++++++ 2 files changed, 19 insertions(+) (limited to 'include') diff --git a/exec.c b/exec.c index fa1e0c3d73..19725dbc05 100644 --- a/exec.c +++ b/exec.c @@ -265,6 +265,16 @@ CPUState *qemu_get_cpu(int index) return env ? cpu : NULL; } +void qemu_for_each_cpu(void (*func)(CPUState *cpu, void *data), void *data) +{ + CPUArchState *env = first_cpu; + + while (env) { + func(ENV_GET_CPU(env), data); + env = env->next_cpu; + } +} + void cpu_exec_init(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 1b4de17415..a28e5ffee2 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -215,6 +215,15 @@ bool cpu_is_stopped(CPUState *cpu); */ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data); +/** + * qemu_for_each_cpu: + * @func: The function to be executed. + * @data: Data to pass to the function. + * + * Executes @func for each CPU. + */ +void qemu_for_each_cpu(void (*func)(CPUState *cpu, void *data), void *data); + /** * qemu_get_cpu: * @index: The CPUState@cpu_index value of the CPU to obtain. -- cgit v1.2.3-55-g7522 From 69e5ff067ae724155fd7465119ee6db5721288b6 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 25 Apr 2013 16:05:24 +0200 Subject: cpu: Add helper cpu_exists(), to check if CPU with specified id exists Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- include/qom/cpu.h | 10 ++++++++++ qom/cpu.c | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'include') diff --git a/include/qom/cpu.h b/include/qom/cpu.h index a28e5ffee2..e54579bd4f 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -234,6 +234,16 @@ void qemu_for_each_cpu(void (*func)(CPUState *cpu, void *data), void *data); */ CPUState *qemu_get_cpu(int index); +/** + * cpu_exists: + * @id: Guest-exposed CPU ID to lookup. + * + * Search for CPU with specified ID. + * + * Returns: %true - CPU is found, %false - CPU isn't found. + */ +bool cpu_exists(int64_t id); + #ifndef CONFIG_USER_ONLY typedef void (*CPUInterruptHandler)(CPUState *, int); diff --git a/qom/cpu.c b/qom/cpu.c index 9a4457ba1b..3dc8208a73 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -24,6 +24,32 @@ #include "qemu/notify.h" #include "sysemu/sysemu.h" +typedef struct CPUExistsArgs { + int64_t id; + bool found; +} CPUExistsArgs; + +static void cpu_exist_cb(CPUState *cpu, void *data) +{ + CPUClass *klass = CPU_GET_CLASS(cpu); + CPUExistsArgs *arg = data; + + if (klass->get_arch_id(cpu) == arg->id) { + arg->found = true; + } +} + +bool cpu_exists(int64_t id) +{ + CPUExistsArgs data = { + .id = id, + .found = false, + }; + + qemu_for_each_cpu(cpu_exist_cb, &data); + return data.found; +} + /* CPU hot-plug notifiers */ static NotifierList cpu_added_notifiers = NOTIFIER_LIST_INITIALIZER(cpu_add_notifiers); -- cgit v1.2.3-55-g7522 From baaeda08ff34ad17150b50a6f52d0faec9f3db36 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 25 Apr 2013 16:05:29 +0200 Subject: target-i386: Replace MSI_SPACE_SIZE with APIC_SPACE_SIZE Put APIC_SPACE_SIZE in a public header so that it can be reused elsewhere later. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- hw/i386/kvm/apic.c | 2 +- hw/intc/apic.c | 2 +- hw/xen/xen_apic.c | 2 +- include/hw/i386/apic_internal.h | 2 -- target-i386/cpu.h | 1 + 5 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index c6ff9821e3..8f80425ccc 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -174,7 +174,7 @@ static const MemoryRegionOps kvm_apic_io_ops = { static void kvm_apic_init(APICCommonState *s) { memory_region_init_io(&s->io_memory, &kvm_apic_io_ops, s, "kvm-apic-msi", - MSI_SPACE_SIZE); + APIC_SPACE_SIZE); if (kvm_has_gsi_routing()) { msi_supported = true; diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 2d79a9ea7f..756dff008d 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -874,7 +874,7 @@ static const MemoryRegionOps apic_io_ops = { static void apic_init(APICCommonState *s) { memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi", - MSI_SPACE_SIZE); + APIC_SPACE_SIZE); s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s); local_apics[s->idx] = s; diff --git a/hw/xen/xen_apic.c b/hw/xen/xen_apic.c index a2eb8a159a..a958782272 100644 --- a/hw/xen/xen_apic.c +++ b/hw/xen/xen_apic.c @@ -39,7 +39,7 @@ static const MemoryRegionOps xen_apic_io_ops = { static void xen_apic_init(APICCommonState *s) { memory_region_init_io(&s->io_memory, &xen_apic_io_ops, s, "xen-apic-msi", - MSI_SPACE_SIZE); + APIC_SPACE_SIZE); #if defined(CONFIG_XEN_CTRL_INTERFACE_VERSION) \ && CONFIG_XEN_CTRL_INTERFACE_VERSION >= 420 diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index 578241f861..aac62902b7 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -66,8 +66,6 @@ #define MAX_APICS 255 -#define MSI_SPACE_SIZE 0x100000 - typedef struct APICCommonState APICCommonState; #define TYPE_APIC_COMMON "apic-common" diff --git a/target-i386/cpu.h b/target-i386/cpu.h index a1614e8e50..ab151d5414 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1270,5 +1270,6 @@ uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index); void enable_compat_apic_id_mode(void); #define APIC_DEFAULT_ADDRESS 0xfee00000 +#define APIC_SPACE_SIZE 0x100000 #endif /* CPU_I386_H */ -- cgit v1.2.3-55-g7522 From c72bf468259935a80ea185f2cbe807c3da9c1bbd Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Fri, 19 Apr 2013 16:45:06 +0200 Subject: cpu: Move cpu_write_elfXX_note() functions to CPUState Convert cpu_write_elfXX_note() functions to CPUClass methods and pass CPUState as argument. Update target-i386 accordingly. Signed-off-by: Jens Freimann [AF: Retain stubs as CPUClass' default method implementation; style changes] Signed-off-by: Andreas Färber --- dump-stub.c | 28 ---------------------- dump.c | 8 +++---- include/qom/cpu.h | 49 ++++++++++++++++++++++++++++++++++++++ include/sysemu/dump.h | 9 ------- qom/cpu.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/arch_dump.c | 38 ++++++++++++++++------------- target-i386/cpu-qom.h | 9 +++++++ target-i386/cpu.c | 6 +++++ 8 files changed, 153 insertions(+), 57 deletions(-) (limited to 'include') diff --git a/dump-stub.c b/dump-stub.c index a9d0b3c67b..b3f42cb2f1 100644 --- a/dump-stub.c +++ b/dump-stub.c @@ -24,34 +24,6 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, error_set(errp, QERR_UNSUPPORTED); } -int cpu_write_elf64_note(write_core_dump_function f, - CPUArchState *env, int cpuid, - void *opaque) -{ - return -1; -} - -int cpu_write_elf32_note(write_core_dump_function f, - CPUArchState *env, int cpuid, - void *opaque) -{ - return -1; -} - -int cpu_write_elf64_qemunote(write_core_dump_function f, - CPUArchState *env, - void *opaque) -{ - return -1; -} - -int cpu_write_elf32_qemunote(write_core_dump_function f, - CPUArchState *env, - void *opaque) -{ - return -1; -} - int cpu_get_dump_info(ArchDumpInfo *info) { return -1; diff --git a/dump.c b/dump.c index b34f143c42..c0d3da515b 100644 --- a/dump.c +++ b/dump.c @@ -282,7 +282,7 @@ static int write_elf64_notes(DumpState *s) for (env = first_cpu; env != NULL; env = env->next_cpu) { cpu = ENV_GET_CPU(env); id = cpu_index(cpu); - ret = cpu_write_elf64_note(fd_write_vmcore, env, id, s); + ret = cpu_write_elf64_note(fd_write_vmcore, cpu, id, s); if (ret < 0) { dump_error(s, "dump: failed to write elf notes.\n"); return -1; @@ -290,7 +290,7 @@ static int write_elf64_notes(DumpState *s) } for (env = first_cpu; env != NULL; env = env->next_cpu) { - ret = cpu_write_elf64_qemunote(fd_write_vmcore, env, s); + ret = cpu_write_elf64_qemunote(fd_write_vmcore, cpu, s); if (ret < 0) { dump_error(s, "dump: failed to write CPU status.\n"); return -1; @@ -334,7 +334,7 @@ static int write_elf32_notes(DumpState *s) for (env = first_cpu; env != NULL; env = env->next_cpu) { cpu = ENV_GET_CPU(env); id = cpu_index(cpu); - ret = cpu_write_elf32_note(fd_write_vmcore, env, id, s); + ret = cpu_write_elf32_note(fd_write_vmcore, cpu, id, s); if (ret < 0) { dump_error(s, "dump: failed to write elf notes.\n"); return -1; @@ -342,7 +342,7 @@ static int write_elf32_notes(DumpState *s) } for (env = first_cpu; env != NULL; env = env->next_cpu) { - ret = cpu_write_elf32_qemunote(fd_write_vmcore, env, s); + ret = cpu_write_elf32_qemunote(fd_write_vmcore, cpu, s); if (ret < 0) { dump_error(s, "dump: failed to write CPU status.\n"); return -1; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index e54579bd4f..7cd9442503 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -24,6 +24,8 @@ #include "hw/qdev-core.h" #include "qemu/thread.h" +typedef int (*WriteCoreDumpFunction)(void *buf, size_t size, void *opaque); + /** * SECTION:cpu * @section_id: QEMU-cpu @@ -62,6 +64,14 @@ typedef struct CPUClass { int64_t (*get_arch_id)(CPUState *cpu); const struct VMStateDescription *vmsd; + int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque); + int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque); + int (*write_elf32_note)(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque); + int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque); } CPUClass; struct KVMState; @@ -127,6 +137,45 @@ struct CPUState { uint32_t halted; /* used by alpha, cris, ppc TCG */ }; +/** + * cpu_write_elf64_note: + * @f: pointer to a function that writes memory to a file + * @cpu: The CPU whose memory is to be dumped + * @cpuid: ID number of the CPU + * @opaque: pointer to the CPUState struct + */ +int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque); + +/** + * cpu_write_elf64_qemunote: + * @f: pointer to a function that writes memory to a file + * @cpu: The CPU whose memory is to be dumped + * @cpuid: ID number of the CPU + * @opaque: pointer to the CPUState struct + */ +int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque); + +/** + * cpu_write_elf32_note: + * @f: pointer to a function that writes memory to a file + * @cpu: The CPU whose memory is to be dumped + * @cpuid: ID number of the CPU + * @opaque: pointer to the CPUState struct + */ +int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque); + +/** + * cpu_write_elf32_qemunote: + * @f: pointer to a function that writes memory to a file + * @cpu: The CPU whose memory is to be dumped + * @cpuid: ID number of the CPU + * @opaque: pointer to the CPUState struct + */ +int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque); /** * cpu_reset: diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index e25b7cfb73..b8c770f8d9 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -20,15 +20,6 @@ typedef struct ArchDumpInfo { int d_class; /* ELFCLASS32 or ELFCLASS64 */ } ArchDumpInfo; -typedef int (*write_core_dump_function)(void *buf, size_t size, void *opaque); -int cpu_write_elf64_note(write_core_dump_function f, CPUArchState *env, - int cpuid, void *opaque); -int cpu_write_elf32_note(write_core_dump_function f, CPUArchState *env, - int cpuid, void *opaque); -int cpu_write_elf64_qemunote(write_core_dump_function f, CPUArchState *env, - void *opaque); -int cpu_write_elf32_qemunote(write_core_dump_function f, CPUArchState *env, - void *opaque); int cpu_get_dump_info(ArchDumpInfo *info); ssize_t cpu_get_note_size(int class, int machine, int nr_cpus); diff --git a/qom/cpu.c b/qom/cpu.c index 3dc8208a73..04aefbb956 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -64,6 +64,65 @@ void cpu_reset_interrupt(CPUState *cpu, int mask) cpu->interrupt_request &= ~mask; } +int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf32_qemunote)(f, cpu, opaque); +} + +static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return -1; +} + +int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf32_note)(f, cpu, cpuid, opaque); +} + +static int cpu_common_write_elf32_note(WriteCoreDumpFunction f, + CPUState *cpu, int cpuid, + void *opaque) +{ + return -1; +} + +int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf64_qemunote)(f, cpu, opaque); +} + +static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return -1; +} + +int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf64_note)(f, cpu, cpuid, opaque); +} + +static int cpu_common_write_elf64_note(WriteCoreDumpFunction f, + CPUState *cpu, int cpuid, + void *opaque) +{ + return -1; +} + + void cpu_reset(CPUState *cpu) { CPUClass *klass = CPU_GET_CLASS(cpu); @@ -117,6 +176,10 @@ static void cpu_class_init(ObjectClass *klass, void *data) k->class_by_name = cpu_common_class_by_name; k->reset = cpu_common_reset; k->get_arch_id = cpu_common_get_arch_id; + k->write_elf32_qemunote = cpu_common_write_elf32_qemunote; + k->write_elf32_note = cpu_common_write_elf32_note; + k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; + k->write_elf64_note = cpu_common_write_elf64_note; dc->realize = cpu_common_realizefn; dc->no_user = 1; } diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c index 2cd2f7f09e..83898cd00f 100644 --- a/target-i386/arch_dump.c +++ b/target-i386/arch_dump.c @@ -34,7 +34,7 @@ typedef struct { char pad3[8]; } x86_64_elf_prstatus; -static int x86_64_write_elf64_note(write_core_dump_function f, +static int x86_64_write_elf64_note(WriteCoreDumpFunction f, CPUArchState *env, int id, void *opaque) { @@ -144,7 +144,7 @@ static void x86_fill_elf_prstatus(x86_elf_prstatus *prstatus, CPUArchState *env, prstatus->pid = id; } -static int x86_write_elf64_note(write_core_dump_function f, CPUArchState *env, +static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUArchState *env, int id, void *opaque) { x86_elf_prstatus prstatus; @@ -179,18 +179,19 @@ static int x86_write_elf64_note(write_core_dump_function f, CPUArchState *env, return 0; } -int cpu_write_elf64_note(write_core_dump_function f, CPUArchState *env, - int cpuid, void *opaque) +int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque) { + X86CPU *cpu = X86_CPU(cs); int ret; #ifdef TARGET_X86_64 bool lma = !!(first_cpu->hflags & HF_LMA_MASK); if (lma) { - ret = x86_64_write_elf64_note(f, env, cpuid, opaque); + ret = x86_64_write_elf64_note(f, &cpu->env, cpuid, opaque); } else { #endif - ret = x86_write_elf64_note(f, env, cpuid, opaque); + ret = x86_write_elf64_note(f, &cpu->env, cpuid, opaque); #ifdef TARGET_X86_64 } #endif @@ -198,9 +199,10 @@ int cpu_write_elf64_note(write_core_dump_function f, CPUArchState *env, return ret; } -int cpu_write_elf32_note(write_core_dump_function f, CPUArchState *env, - int cpuid, void *opaque) +int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque) { + X86CPU *cpu = X86_CPU(cs); x86_elf_prstatus prstatus; Elf32_Nhdr *note; char *buf; @@ -208,7 +210,7 @@ int cpu_write_elf32_note(write_core_dump_function f, CPUArchState *env, const char *name = "CORE"; int ret; - x86_fill_elf_prstatus(&prstatus, env, cpuid); + x86_fill_elf_prstatus(&prstatus, &cpu->env, cpuid); descsz = sizeof(x86_elf_prstatus); note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 + (descsz + 3) / 4) * 4; @@ -317,7 +319,7 @@ static void qemu_get_cpustate(QEMUCPUState *s, CPUArchState *env) s->cr[4] = env->cr[4]; } -static inline int cpu_write_qemu_note(write_core_dump_function f, +static inline int cpu_write_qemu_note(WriteCoreDumpFunction f, CPUArchState *env, void *opaque, int type) @@ -370,16 +372,20 @@ static inline int cpu_write_qemu_note(write_core_dump_function f, return 0; } -int cpu_write_elf64_qemunote(write_core_dump_function f, CPUArchState *env, - void *opaque) +int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cs, + void *opaque) { - return cpu_write_qemu_note(f, env, opaque, 1); + X86CPU *cpu = X86_CPU(cs); + + return cpu_write_qemu_note(f, &cpu->env, opaque, 1); } -int cpu_write_elf32_qemunote(write_core_dump_function f, CPUArchState *env, - void *opaque) +int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cs, + void *opaque) { - return cpu_write_qemu_note(f, env, opaque, 0); + X86CPU *cpu = X86_CPU(cs); + + return cpu_write_qemu_note(f, &cpu->env, opaque, 0); } int cpu_get_dump_info(ArchDumpInfo *info) diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 08f9eb67b2..f890f1c912 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -86,4 +86,13 @@ extern const struct VMStateDescription vmstate_x86_cpu; */ void x86_cpu_do_interrupt(CPUState *cpu); +int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque); +int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque); +int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque); +int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque); + #endif diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0d9493d1cc..40d51be9f2 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2351,6 +2351,12 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->reset = x86_cpu_reset; cc->do_interrupt = x86_cpu_do_interrupt; +#ifndef CONFIG_USER_ONLY + cc->write_elf64_note = x86_cpu_write_elf64_note; + cc->write_elf64_qemunote = x86_cpu_write_elf64_qemunote; + cc->write_elf32_note = x86_cpu_write_elf32_note; + cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote; +#endif cpu_class_set_vmsd(cc, &vmstate_x86_cpu); cc->get_arch_id = x86_cpu_get_arch_id; -- cgit v1.2.3-55-g7522 From f0513d2c0156799e0c75a108ab9a049eea4f9607 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 29 Apr 2013 17:02:50 +0200 Subject: target-i386: Introduce ICC bus/device/bridge Provides a hotpluggable bus for APIC and CPU. * icc-bridge will serve as a parent for icc-bus and provide mmio mapping services to child icc-devices. * icc-device will replace SysBusDevice as a parent of APIC and IOAPIC devices. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- MAINTAINERS | 6 ++ default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + hw/cpu/Makefile.objs | 1 + hw/cpu/icc_bus.c | 109 +++++++++++++++++++++++++++++++++++++ hw/i386/pc_piix.c | 7 +++ hw/i386/pc_q35.c | 7 +++ include/hw/cpu/icc_bus.h | 79 +++++++++++++++++++++++++++ 8 files changed, 211 insertions(+) create mode 100644 hw/cpu/icc_bus.c create mode 100644 include/hw/cpu/icc_bus.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index 4dfd8bf7ab..be02724e6e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -644,6 +644,12 @@ F: qom/cpu.c F: include/qemu/cpu.h F: target-i386/cpu.c +ICC Bus +M: Igor Mammedov +S: Supported +F: include/hw/cpu/icc_bus.h +F: hw/cpu/icc_bus.c + Device Tree M: Peter Crosthwaite M: Alexander Graf diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 4e30505ae3..03deca2dcb 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -44,4 +44,5 @@ CONFIG_LPC_ICH9=y CONFIG_PCI_Q35=y CONFIG_APIC=y CONFIG_IOAPIC=y +CONFIG_ICC_BUS=y CONFIG_PVPANIC=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 5af8fd3c0b..599b63071f 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -44,4 +44,5 @@ CONFIG_LPC_ICH9=y CONFIG_PCI_Q35=y CONFIG_APIC=y CONFIG_IOAPIC=y +CONFIG_ICC_BUS=y CONFIG_PVPANIC=y diff --git a/hw/cpu/Makefile.objs b/hw/cpu/Makefile.objs index a49ca04282..4461eceee8 100644 --- a/hw/cpu/Makefile.objs +++ b/hw/cpu/Makefile.objs @@ -1,4 +1,5 @@ obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o obj-$(CONFIG_ARM9MPCORE) += a9mpcore.o obj-$(CONFIG_ARM15MPCORE) += a15mpcore.o +obj-$(CONFIG_ICC_BUS) += icc_bus.o diff --git a/hw/cpu/icc_bus.c b/hw/cpu/icc_bus.c new file mode 100644 index 0000000000..3ac8eebbdf --- /dev/null +++ b/hw/cpu/icc_bus.c @@ -0,0 +1,109 @@ +/* icc_bus.c + * emulate x86 ICC (Interrupt Controller Communications) bus + * + * Copyright (c) 2013 Red Hat, Inc + * + * Authors: + * Igor Mammedov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ +#include "hw/cpu/icc_bus.h" +#include "hw/sysbus.h" + +/* icc-bridge implementation */ + +static void icc_bus_init(Object *obj) +{ + BusState *b = BUS(obj); + + b->allow_hotplug = true; +} + +static const TypeInfo icc_bus_info = { + .name = TYPE_ICC_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(ICCBus), + .instance_init = icc_bus_init, +}; + + +/* icc-device implementation */ + +static void icc_device_realize(DeviceState *dev, Error **errp) +{ + ICCDevice *id = ICC_DEVICE(dev); + ICCDeviceClass *idc = ICC_DEVICE_GET_CLASS(id); + + if (idc->init) { + if (idc->init(id) < 0) { + error_setg(errp, "%s initialization failed.", + object_get_typename(OBJECT(dev))); + } + } +} + +static void icc_device_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = icc_device_realize; + dc->bus_type = TYPE_ICC_BUS; +} + +static const TypeInfo icc_device_info = { + .name = TYPE_ICC_DEVICE, + .parent = TYPE_DEVICE, + .abstract = true, + .instance_size = sizeof(ICCDevice), + .class_size = sizeof(ICCDeviceClass), + .class_init = icc_device_class_init, +}; + + +/* icc-bridge implementation */ + +typedef struct ICCBridgeState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + ICCBus icc_bus; +} ICCBridgeState; + +#define ICC_BRIGDE(obj) OBJECT_CHECK(ICCBridgeState, (obj), TYPE_ICC_BRIDGE) + +static void icc_bridge_init(Object *obj) +{ + ICCBridgeState *s = ICC_BRIGDE(obj); + + qbus_create_inplace(&s->icc_bus, TYPE_ICC_BUS, DEVICE(s), "icc"); +} + +static const TypeInfo icc_bridge_info = { + .name = TYPE_ICC_BRIDGE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = icc_bridge_init, + .instance_size = sizeof(ICCBridgeState), +}; + + +static void icc_bus_register_types(void) +{ + type_register_static(&icc_bus_info); + type_register_static(&icc_device_info); + type_register_static(&icc_bridge_info); +} + +type_init(icc_bus_register_types) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 852d63ba2e..0ce3fc206b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -37,6 +37,7 @@ #include "hw/kvm/clock.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" +#include "hw/cpu/icc_bus.h" #include "sysemu/arch_init.h" #include "sysemu/blockdev.h" #include "hw/i2c/smbus.h" @@ -87,8 +88,13 @@ static void pc_init1(MemoryRegion *system_memory, MemoryRegion *ram_memory; MemoryRegion *pci_memory; MemoryRegion *rom_memory; + DeviceState *icc_bridge; void *fw_cfg = NULL; + icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE); + object_property_add_child(qdev_get_machine(), "icc-bridge", + OBJECT(icc_bridge), NULL); + pc_cpus_init(cpu_model); pc_acpi_init("acpi-dsdt.aml"); @@ -163,6 +169,7 @@ static void pc_init1(MemoryRegion *system_memory, if (pci_enabled) { ioapic_init_gsi(gsi_state, "i440fx"); } + qdev_init_nofail(icc_bridge); pc_register_ferr_irq(gsi[13]); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index d094041462..a6ba809ed3 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -41,6 +41,7 @@ #include "hw/ide/pci.h" #include "hw/ide/ahci.h" #include "hw/usb.h" +#include "hw/cpu/icc_bus.h" /* ICH9 AHCI has 6 ports */ #define MAX_SATA_PORTS 6 @@ -75,6 +76,11 @@ static void pc_q35_init(QEMUMachineInitArgs *args) int i; ICH9LPCState *ich9_lpc; PCIDevice *ahci; + DeviceState *icc_bridge; + + icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE); + object_property_add_child(qdev_get_machine(), "icc-bridge", + OBJECT(icc_bridge), NULL); pc_cpus_init(cpu_model); pc_acpi_init("q35-acpi-dsdt.aml"); @@ -158,6 +164,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) if (pci_enabled) { ioapic_init_gsi(gsi_state, NULL); } + qdev_init_nofail(icc_bridge); pc_register_ferr_irq(gsi[13]); diff --git a/include/hw/cpu/icc_bus.h b/include/hw/cpu/icc_bus.h new file mode 100644 index 0000000000..d728a7de3e --- /dev/null +++ b/include/hw/cpu/icc_bus.h @@ -0,0 +1,79 @@ +/* icc_bus.h + * emulate x86 ICC (Interrupt Controller Communications) bus + * + * Copyright (c) 2013 Red Hat, Inc + * + * Authors: + * Igor Mammedov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ +#ifndef ICC_BUS_H +#define ICC_BUS_H + +#include "hw/qdev-core.h" + +#define TYPE_ICC_BUS "icc-bus" + +#ifndef CONFIG_USER_ONLY + +/** + * ICCBus: + * + * ICC bus + */ +typedef struct ICCBus { + /*< private >*/ + BusState parent_obj; + /*< public >*/ +} ICCBus; + +#define ICC_BUS(obj) OBJECT_CHECK(ICCBus, (obj), TYPE_ICC_BUS) + +/** + * ICCDevice: + * + * ICC device + */ +typedef struct ICCDevice { + /*< private >*/ + DeviceState qdev; + /*< public >*/ +} ICCDevice; + +/** + * ICCDeviceClass: + * @init: Initialization callback for derived classes. + * + * ICC device class + */ +typedef struct ICCDeviceClass { + /*< private >*/ + DeviceClass parent_class; + /*< public >*/ + + int (*init)(ICCDevice *dev); /* TODO replace with QOM realize */ +} ICCDeviceClass; + +#define TYPE_ICC_DEVICE "icc-device" +#define ICC_DEVICE(obj) OBJECT_CHECK(ICCDevice, (obj), TYPE_ICC_DEVICE) +#define ICC_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(ICCDeviceClass, (klass), TYPE_ICC_DEVICE) +#define ICC_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ICCDeviceClass, (obj), TYPE_ICC_DEVICE) + +#define TYPE_ICC_BRIDGE "icc-bridge" + +#endif /* CONFIG_USER_ONLY */ +#endif -- cgit v1.2.3-55-g7522 From 62fc403f11523169eb4264de31279745f48e3ecc Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 29 Apr 2013 18:54:13 +0200 Subject: target-i386: Attach ICC bus to CPU on its creation X86CPU should have parent bus so it could provide bus for child APIC. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- hw/i386/pc.c | 10 ++++++---- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- include/hw/i386/pc.h | 2 +- target-i386/cpu.c | 15 +++++++++++++-- target-i386/cpu.h | 3 ++- 6 files changed, 24 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 656817322e..c4c4e35251 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -894,12 +894,13 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id, Error **errp) +static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id, + DeviceState *icc_bridge, Error **errp) { X86CPU *cpu; Error *local_err = NULL; - cpu = cpu_x86_create(cpu_model, errp); + cpu = cpu_x86_create(cpu_model, icc_bridge, errp); if (!cpu) { return cpu; } @@ -917,7 +918,7 @@ static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id, Error **errp) return cpu; } -void pc_cpus_init(const char *cpu_model) +void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge) { int i; Error *error = NULL; @@ -932,7 +933,8 @@ void pc_cpus_init(const char *cpu_model) } for (i = 0; i < smp_cpus; i++) { - pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i), &error); + pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i), + icc_bridge, &error); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); error_free(error); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 0ce3fc206b..251e18f9a3 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -95,7 +95,7 @@ static void pc_init1(MemoryRegion *system_memory, object_property_add_child(qdev_get_machine(), "icc-bridge", OBJECT(icc_bridge), NULL); - pc_cpus_init(cpu_model); + pc_cpus_init(cpu_model, icc_bridge); pc_acpi_init("acpi-dsdt.aml"); if (kvmclock_enabled) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index a6ba809ed3..f46295b490 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -82,7 +82,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) object_property_add_child(qdev_get_machine(), "icc-bridge", OBJECT(icc_bridge), NULL); - pc_cpus_init(cpu_model); + pc_cpus_init(cpu_model, icc_bridge); pc_acpi_init("q35-acpi-dsdt.aml"); kvmclock_create(); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index dd6bc249bf..d0bc97281f 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -78,7 +78,7 @@ extern int fd_bootchk; void pc_register_ferr_irq(qemu_irq irq); void pc_acpi_smi_interrupt(void *opaque, int irq, int level); -void pc_cpus_init(const char *cpu_model); +void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge); void pc_acpi_init(const char *default_dsdt); void *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 40d51be9f2..a165bcf0a7 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -41,6 +41,7 @@ #endif #include "sysemu/sysemu.h" +#include "hw/cpu/icc_bus.h" #ifndef CONFIG_USER_ONLY #include "hw/xen/xen.h" #include "hw/sysbus.h" @@ -1618,7 +1619,8 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp) object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp); } -X86CPU *cpu_x86_create(const char *cpu_model, Error **errp) +X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge, + Error **errp) { X86CPU *cpu = NULL; CPUX86State *env; @@ -1635,6 +1637,14 @@ X86CPU *cpu_x86_create(const char *cpu_model, Error **errp) features = model_pieces[1]; cpu = X86_CPU(object_new(TYPE_X86_CPU)); +#ifndef CONFIG_USER_ONLY + if (icc_bridge == NULL) { + error_setg(&error, "Invalid icc-bridge value"); + goto out; + } + qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc")); + object_unref(OBJECT(cpu)); +#endif env = &cpu->env; env->cpu_model_str = cpu_model; @@ -1659,7 +1669,7 @@ X86CPU *cpu_x86_init(const char *cpu_model) Error *error = NULL; X86CPU *cpu; - cpu = cpu_x86_create(cpu_model, &error); + cpu = cpu_x86_create(cpu_model, NULL, &error); if (error) { goto out; } @@ -2346,6 +2356,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) xcc->parent_realize = dc->realize; dc->realize = x86_cpu_realizefn; + dc->bus_type = TYPE_ICC_BUS; xcc->parent_reset = cc->reset; cc->reset = x86_cpu_reset; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index ab151d5414..f193752e5e 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -897,7 +897,8 @@ typedef struct CPUX86State { #include "cpu-qom.h" X86CPU *cpu_x86_init(const char *cpu_model); -X86CPU *cpu_x86_create(const char *cpu_model, Error **errp); +X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge, + Error **errp); int cpu_x86_exec(CPUX86State *s); void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf); void x86_cpudef_setup(void); -- cgit v1.2.3-55-g7522 From 53a89e262bd3e97b2da3afec0a60e5466770ae8c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 29 Apr 2013 19:03:01 +0200 Subject: target-i386: Move APIC to ICC bus It allows APIC to be hotplugged. * map APIC's mmio at board level if it is present * do not register mmio region for each APIC, since only one is used/mapped Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- hw/cpu/icc_bus.c | 10 ++++++++++ hw/i386/pc.c | 13 +++++++++++-- hw/intc/apic_common.c | 18 ++++++++++++------ include/hw/cpu/icc_bus.h | 3 +++ include/hw/i386/apic_internal.h | 6 +++--- target-i386/cpu.c | 16 +++------------- 6 files changed, 42 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/hw/cpu/icc_bus.c b/hw/cpu/icc_bus.c index 3ac8eebbdf..73a1dc985f 100644 --- a/hw/cpu/icc_bus.c +++ b/hw/cpu/icc_bus.c @@ -80,6 +80,7 @@ typedef struct ICCBridgeState { /*< public >*/ ICCBus icc_bus; + MemoryRegion apic_container; } ICCBridgeState; #define ICC_BRIGDE(obj) OBJECT_CHECK(ICCBridgeState, (obj), TYPE_ICC_BRIDGE) @@ -87,8 +88,17 @@ typedef struct ICCBridgeState { static void icc_bridge_init(Object *obj) { ICCBridgeState *s = ICC_BRIGDE(obj); + SysBusDevice *sb = SYS_BUS_DEVICE(obj); qbus_create_inplace(&s->icc_bus, TYPE_ICC_BUS, DEVICE(s), "icc"); + + /* Do not change order of registering regions, + * APIC must be first registered region, board maps it by 0 index + */ + memory_region_init(&s->apic_container, "icc-apic-container", + APIC_SPACE_SIZE); + sysbus_init_mmio(sb, &s->apic_container); + s->icc_bus.apic_address_space = &s->apic_container; } static const TypeInfo icc_bridge_info = { diff --git a/hw/i386/pc.c b/hw/i386/pc.c index c4c4e35251..28f958dee6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -53,6 +53,7 @@ #include "qemu/bitmap.h" #include "qemu/config-file.h" #include "hw/acpi/acpi.h" +#include "hw/cpu/icc_bus.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -921,6 +922,7 @@ static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id, void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge) { int i; + X86CPU *cpu = NULL; Error *error = NULL; /* init CPUs */ @@ -933,14 +935,21 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge) } for (i = 0; i < smp_cpus; i++) { - pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i), - icc_bridge, &error); + cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i), + icc_bridge, &error); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); error_free(error); exit(1); } } + + /* map APIC MMIO area if CPU has APIC */ + if (cpu && cpu->env.apic_state) { + /* XXX: what if the base changes? */ + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(icc_bridge), 0, + APIC_DEFAULT_ADDRESS, 0x1000); + } } void pc_acpi_init(const char *default_dsdt) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index e0ae07afd5..b03e904a7a 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -21,6 +21,8 @@ #include "hw/i386/apic_internal.h" #include "trace.h" #include "sysemu/kvm.h" +#include "hw/qdev.h" +#include "hw/sysbus.h" static int apic_irq_delivered; bool apic_report_tpr_access; @@ -282,12 +284,13 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id) return 0; } -static int apic_init_common(SysBusDevice *dev) +static int apic_init_common(ICCDevice *dev) { APICCommonState *s = APIC_COMMON(dev); APICCommonClass *info; static DeviceState *vapic; static int apic_no; + static bool mmio_registered; if (apic_no >= MAX_APICS) { return -1; @@ -296,8 +299,11 @@ static int apic_init_common(SysBusDevice *dev) info = APIC_COMMON_GET_CLASS(s); info->init(s); - - sysbus_init_mmio(dev, &s->io_memory); + if (!mmio_registered) { + ICCBus *b = ICC_BUS(qdev_get_parent_bus(DEVICE(dev))); + memory_region_add_subregion(b->apic_address_space, 0, &s->io_memory); + mmio_registered = true; + } /* Note: We need at least 1M to map the VAPIC option ROM */ if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK && @@ -375,19 +381,19 @@ static Property apic_properties_common[] = { static void apic_common_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass); + ICCDeviceClass *idc = ICC_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_apic_common; dc->reset = apic_reset_common; dc->no_user = 1; dc->props = apic_properties_common; - sc->init = apic_init_common; + idc->init = apic_init_common; } static const TypeInfo apic_common_type = { .name = TYPE_APIC_COMMON, - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_ICC_DEVICE, .instance_size = sizeof(APICCommonState), .class_size = sizeof(APICCommonClass), .class_init = apic_common_class_init, diff --git a/include/hw/cpu/icc_bus.h b/include/hw/cpu/icc_bus.h index d728a7de3e..b5500708dc 100644 --- a/include/hw/cpu/icc_bus.h +++ b/include/hw/cpu/icc_bus.h @@ -22,6 +22,7 @@ #ifndef ICC_BUS_H #define ICC_BUS_H +#include "exec/memory.h" #include "hw/qdev-core.h" #define TYPE_ICC_BUS "icc-bus" @@ -37,6 +38,8 @@ typedef struct ICCBus { /*< private >*/ BusState parent_obj; /*< public >*/ + + MemoryRegion *apic_address_space; } ICCBus; #define ICC_BUS(obj) OBJECT_CHECK(ICCBus, (obj), TYPE_ICC_BUS) diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index aac62902b7..1b0a7fbfad 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -21,7 +21,7 @@ #define QEMU_APIC_INTERNAL_H #include "exec/memory.h" -#include "hw/sysbus.h" +#include "hw/cpu/icc_bus.h" #include "qemu/timer.h" /* APIC Local Vector Table */ @@ -78,7 +78,7 @@ typedef struct APICCommonState APICCommonState; typedef struct APICCommonClass { - SysBusDeviceClass parent_class; + ICCDeviceClass parent_class; void (*init)(APICCommonState *s); void (*set_base)(APICCommonState *s, uint64_t val); @@ -92,7 +92,7 @@ typedef struct APICCommonClass } APICCommonClass; struct APICCommonState { - SysBusDevice busdev; + ICCDevice busdev; MemoryRegion io_memory; X86CPU *cpu; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index a165bcf0a7..bba41fec69 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -41,10 +41,10 @@ #endif #include "sysemu/sysemu.h" +#include "hw/qdev-properties.h" #include "hw/cpu/icc_bus.h" #ifndef CONFIG_USER_ONLY #include "hw/xen/xen.h" -#include "hw/sysbus.h" #include "hw/i386/apic_internal.h" #endif @@ -2131,6 +2131,7 @@ static void mce_init(X86CPU *cpu) static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) { CPUX86State *env = &cpu->env; + DeviceState *dev = DEVICE(cpu); APICCommonState *apic; const char *apic_type = "apic"; @@ -2140,7 +2141,7 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) apic_type = "xen-apic"; } - env->apic_state = qdev_try_create(NULL, apic_type); + env->apic_state = qdev_try_create(qdev_get_parent_bus(dev), apic_type); if (env->apic_state == NULL) { error_setg(errp, "APIC device '%s' could not be created", apic_type); return; @@ -2157,7 +2158,6 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) { CPUX86State *env = &cpu->env; - static int apic_mapped; if (env->apic_state == NULL) { return; @@ -2168,16 +2168,6 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) object_get_typename(OBJECT(env->apic_state))); return; } - - /* XXX: mapping more APICs at the same memory location */ - if (apic_mapped == 0) { - /* NOTE: the APIC is directly connected to the CPU - it is not - on the global memory bus. */ - /* XXX: what if the base changes? */ - sysbus_mmio_map_overlap(SYS_BUS_DEVICE(env->apic_state), 0, - APIC_DEFAULT_ADDRESS, 0x1000); - apic_mapped = 1; - } } #else static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) -- cgit v1.2.3-55-g7522 From b4fc7b4326112538e0dbdc7fd019652ba8cc3281 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 30 Apr 2013 15:41:24 +0200 Subject: Add hot_add_cpu hook to QEMUMachine Hook should be set by machines that implement CPU hot-add via cpu-add QMP command. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- include/hw/boards.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/hw/boards.h b/include/hw/boards.h index 425bdc74a8..fb7c6f1243 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -22,12 +22,15 @@ typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args); typedef void QEMUMachineResetFunc(void); +typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp); + typedef struct QEMUMachine { const char *name; const char *alias; const char *desc; QEMUMachineInitFunc *init; QEMUMachineResetFunc *reset; + QEMUMachineHotAddCPUFunc *hot_add_cpu; BlockInterfaceType block_default_type; int max_cpus; unsigned int no_serial:1, -- cgit v1.2.3-55-g7522 From c649983b582687bbdb4019e308f015913e31065e Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 30 Apr 2013 18:00:53 +0200 Subject: pc: Implement QEMUMachine::hot_add_cpu hook Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/i386/pc.c | 26 ++++++++++++++++++++++++++ hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + include/hw/i386/pc.h | 1 + 4 files changed, 29 insertions(+) (limited to 'include') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 28f958dee6..197d218715 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -54,6 +54,7 @@ #include "qemu/config-file.h" #include "hw/acpi/acpi.h" #include "hw/cpu/icc_bus.h" +#include "hw/boards.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -919,6 +920,30 @@ static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id, return cpu; } +static const char *current_cpu_model; + +void pc_hot_add_cpu(const int64_t id, Error **errp) +{ + DeviceState *icc_bridge; + int64_t apic_id = x86_cpu_apic_id_from_index(id); + + if (cpu_exists(apic_id)) { + error_setg(errp, "Unable to add CPU: %" PRIi64 + ", it already exists", id); + return; + } + + if (id >= max_cpus) { + error_setg(errp, "Unable to add CPU: %" PRIi64 + ", max allowed: %d", id, max_cpus - 1); + return; + } + + icc_bridge = DEVICE(object_resolve_path_type("icc-bridge", + TYPE_ICC_BRIDGE, NULL)); + pc_new_cpu(current_cpu_model, apic_id, icc_bridge, errp); +} + void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge) { int i; @@ -933,6 +958,7 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge) cpu_model = "qemu32"; #endif } + current_cpu_model = cpu_model; for (i = 0; i < smp_cpus; i++) { cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i), diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 251e18f9a3..fe52e5f94b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -335,6 +335,7 @@ static QEMUMachine pc_i440fx_machine_v1_5 = { .alias = "pc", .desc = "Standard PC (i440FX + PIIX, 1996)", .init = pc_init_pci, + .hot_add_cpu = pc_hot_add_cpu, .max_cpus = 255, .is_default = 1, DEFAULT_MACHINE_OPTIONS, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index f46295b490..52511e2b69 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -220,6 +220,7 @@ static QEMUMachine pc_q35_machine_v1_5 = { .alias = "q35", .desc = "Standard PC (Q35 + ICH9, 2009)", .init = pc_q35_init, + .hot_add_cpu = pc_hot_add_cpu, .max_cpus = 255, DEFAULT_MACHINE_OPTIONS, }; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index d0bc97281f..41869e56e9 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -79,6 +79,7 @@ void pc_register_ferr_irq(qemu_irq irq); void pc_acpi_smi_interrupt(void *opaque, int irq, int level); void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge); +void pc_hot_add_cpu(const int64_t id, Error **errp); void pc_acpi_init(const char *default_dsdt); void *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, -- cgit v1.2.3-55-g7522