Merge remote-tracking branch 'afaerber/qom-cpu' into staging

# By Igor Mammedov (21) and others
# Via Andreas Färber
* afaerber/qom-cpu: (29 commits)
  Drop redundant resume_all_vcpus() from main()
  cpus: Fix pausing TCG CPUs while in vCPU thread
  target-i386: Replace cpuid_*features fields with a feature word array
  target-i386: Break CPUID feature definition lines
  target-i386/kvm.c: Code formatting changes
  target-i386: Group together level, xlevel, xlevel2 fields
  pc: Implement QEMUMachine::hot_add_cpu hook
  QMP: Add cpu-add command
  Add hot_add_cpu hook to QEMUMachine
  target-i386: Move APIC to ICC bus
  target-i386: Attach ICC bus to CPU on its creation
  target-i386: Introduce ICC bus/device/bridge
  cpu: Move cpu_write_elfXX_note() functions to CPUState
  kvmvapic: Make dependency on sysbus.h explicit
  target-i386: Replace MSI_SPACE_SIZE with APIC_SPACE_SIZE
  target-i386: Do not allow to set apic-id once CPU is realized
  target-i386: Introduce apic-id CPU property
  target-i386: Introduce feat2prop() for CPU properties
  acpi_piix4: Add infrastructure to send CPU hot-plug GPE to guest
  cpu: Add helper cpu_exists(), to check if CPU with specified id exists
  ...
This commit is contained in:
Anthony Liguori
2013-05-02 10:57:01 -05:00
52 changed files with 1162 additions and 327 deletions
+6
View File
@@ -644,6 +644,12 @@ F: qom/cpu.c
F: include/qemu/cpu.h
F: target-i386/cpu.c
ICC Bus
M: Igor Mammedov <imammedo@redhat.com>
S: Supported
F: include/hw/cpu/icc_bus.h
F: hw/cpu/icc_bus.c
Device Tree
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
M: Alexander Graf <agraf@suse.de>
+7 -7
View File
@@ -60,6 +60,12 @@ all: $(PROGS) stap
# Dummy command so that make thinks it has done something
@true
CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y)
CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)
#########################################################
# cpu emulator library
obj-y = exec.o translate-all.o cpu-exec.o
@@ -70,6 +76,7 @@ obj-y += fpu/softfloat.o
obj-y += target-$(TARGET_BASE_ARCH)/
obj-y += disas.o
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
#########################################################
# Linux user emulator target
@@ -98,18 +105,11 @@ endif #CONFIG_BSD_USER
#########################################################
# System emulator target
ifdef CONFIG_SOFTMMU
CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y)
CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)
obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o
obj-y += qtest.o
obj-y += hw/
obj-$(CONFIG_FDT) += device_tree.o
obj-$(CONFIG_KVM) += kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += memory.o savevm.o cputlb.o
obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o
obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o
+1 -1
View File
@@ -110,7 +110,7 @@ static const char *get_elf_platform(void)
static uint32_t get_elf_hwcap(void)
{
return thread_env->cpuid_features;
return thread_env->features[FEAT_1_EDX];
}
#ifdef TARGET_X86_64
+2 -2
View File
@@ -1004,13 +1004,13 @@ int main(int argc, char **argv)
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
if (env->cpuid_features & CPUID_SSE) {
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
env->cr[4] |= CR4_OSFXSR_MASK;
env->hflags |= HF_OSFXSR_MASK;
}
#ifndef TARGET_ABI32
/* enable 64 bit mode if possible */
if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
exit(1);
}
+17 -10
View File
@@ -812,6 +812,12 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
static void tcg_exec_all(void);
static void tcg_signal_cpu_creation(CPUState *cpu, void *data)
{
cpu->thread_id = qemu_get_thread_id();
cpu->created = true;
}
static void *qemu_tcg_cpu_thread_fn(void *arg)
{
CPUState *cpu = arg;
@@ -820,13 +826,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
qemu_tcg_init_cpu_signals();
qemu_thread_get_self(cpu->thread);
/* signal CPU creation */
qemu_mutex_lock(&qemu_global_mutex);
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = ENV_GET_CPU(env);
cpu->thread_id = qemu_get_thread_id();
cpu->created = true;
}
qemu_for_each_cpu(tcg_signal_cpu_creation, NULL);
qemu_cond_signal(&qemu_cpu_cond);
/* wait for initial kick-off after machine start */
@@ -973,9 +974,10 @@ void pause_all_vcpus(void)
if (qemu_in_vcpu_thread()) {
cpu_stop_current();
if (!kvm_enabled()) {
penv = first_cpu;
while (penv) {
CPUState *pcpu = ENV_GET_CPU(penv);
pcpu->stop = 0;
pcpu->stop = false;
pcpu->stopped = true;
penv = penv->next_cpu;
}
@@ -993,6 +995,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 +1009,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;
}
}
+1
View File
@@ -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
+1
View File
@@ -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
+22
View File
@@ -0,0 +1,22 @@
QEMU<->ACPI BIOS CPU hotplug interface
--------------------------------------
QEMU supports CPU hotplug via ACPI. This document
describes the interface between QEMU and the ACPI BIOS.
ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
-----------------------------------------
Generic ACPI GPE block. Bit 2 (GPE.2) used to notify CPU
hot-add/remove event to ACPI BIOS, via SCI interrupt.
CPU present bitmap (IO port 0xaf00-0xae1f, 1-byte access):
---------------------------------------------------------------
One bit per CPU. Bit position reflects corresponding CPU APIC ID.
Read-only.
CPU hot-add/remove notification:
-----------------------------------------------------
QEMU sets/clears corresponding CPU bit on hot-add/remove event.
CPU present map read by ACPI BIOS GPE.2 handler to notify OS of CPU
hot-(un)plug events.
-28
View File
@@ -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;
+4 -4
View File
@@ -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;
+10
View File
@@ -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);
+88 -2
View File
@@ -48,19 +48,28 @@
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
#define PIIX4_PROC_BASE 0xaf00
#define PIIX4_PROC_LEN 32
#define PIIX4_PCI_HOTPLUG_STATUS 2
#define PIIX4_CPU_HOTPLUG_STATUS 4
struct pci_status {
uint32_t up; /* deprecated, maintained for migration compatibility */
uint32_t down;
};
typedef struct CPUStatus {
uint8_t sts[PIIX4_PROC_LEN];
} CPUStatus;
typedef struct PIIX4PMState {
PCIDevice dev;
MemoryRegion io;
MemoryRegion io_gpe;
MemoryRegion io_pci;
MemoryRegion io_cpu;
ACPIREGS ar;
APMState apm;
@@ -82,6 +91,9 @@ typedef struct PIIX4PMState {
uint8_t disable_s3;
uint8_t disable_s4;
uint8_t s4_val;
CPUStatus gpe_cpu;
Notifier cpu_added_notifier;
} PIIX4PMState;
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
@@ -100,8 +112,8 @@ static void pm_update_sci(PIIX4PMState *s)
ACPI_BITMASK_POWER_BUTTON_ENABLE |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
(((s->ar.gpe.sts[0] & s->ar.gpe.en[0])
& PIIX4_PCI_HOTPLUG_STATUS) != 0);
(((s->ar.gpe.sts[0] & s->ar.gpe.en[0]) &
(PIIX4_PCI_HOTPLUG_STATUS | PIIX4_CPU_HOTPLUG_STATUS)) != 0);
qemu_set_irq(s->irq, sci_level);
/* schedule a timer interruption if needed */
@@ -585,6 +597,73 @@ static const MemoryRegionOps piix4_pci_ops = {
},
};
static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size)
{
PIIX4PMState *s = opaque;
CPUStatus *cpus = &s->gpe_cpu;
uint64_t val = cpus->sts[addr];
return val;
}
static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
/* TODO: implement VCPU removal on guest signal that CPU can be removed */
}
static const MemoryRegionOps cpu_hotplug_ops = {
.read = cpu_status_read,
.write = cpu_status_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 1,
},
};
typedef enum {
PLUG,
UNPLUG,
} HotplugEventType;
static void piix4_cpu_hotplug_req(PIIX4PMState *s, CPUState *cpu,
HotplugEventType action)
{
CPUStatus *g = &s->gpe_cpu;
ACPIGPE *gpe = &s->ar.gpe;
CPUClass *k = CPU_GET_CLASS(cpu);
int64_t cpu_id;
assert(s != NULL);
*gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
cpu_id = k->get_arch_id(CPU(cpu));
if (action == PLUG) {
g->sts[cpu_id / 8] |= (1 << (cpu_id % 8));
} else {
g->sts[cpu_id / 8] &= ~(1 << (cpu_id % 8));
}
pm_update_sci(s);
}
static void piix4_cpu_added_req(Notifier *n, void *opaque)
{
PIIX4PMState *s = container_of(n, PIIX4PMState, cpu_added_notifier);
piix4_cpu_hotplug_req(s, CPU(opaque), PLUG);
}
static void piix4_init_cpu_status(CPUState *cpu, void *data)
{
CPUStatus *g = (CPUStatus *)data;
CPUClass *k = CPU_GET_CLASS(cpu);
int64_t id = k->get_arch_id(cpu);
g_assert((id / 8) < PIIX4_PROC_LEN);
g->sts[id / 8] |= (1 << (id % 8));
}
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
@@ -600,6 +679,13 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
&s->io_pci);
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
qemu_for_each_cpu(piix4_init_cpu_status, &s->gpe_cpu);
memory_region_init_io(&s->io_cpu, &cpu_hotplug_ops, s, "apci-cpu-hotplug",
PIIX4_PROC_LEN);
memory_region_add_subregion(parent, PIIX4_PROC_BASE, &s->io_cpu);
s->cpu_added_notifier.notify = piix4_cpu_added_req;
qemu_register_cpu_added_notifier(&s->cpu_added_notifier);
}
static void enable_device(PIIX4PMState *s, int slot)
+1
View File
@@ -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
+119
View File
@@ -0,0 +1,119 @@
/* icc_bus.c
* emulate x86 ICC (Interrupt Controller Communications) bus
*
* Copyright (c) 2013 Red Hat, Inc
*
* Authors:
* Igor Mammedov <imammedo@redhat.com>
*
* 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 <http://www.gnu.org/licenses/>
*/
#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;
MemoryRegion apic_container;
} ICCBridgeState;
#define ICC_BRIGDE(obj) OBJECT_CHECK(ICCBridgeState, (obj), TYPE_ICC_BRIDGE)
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 = {
.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)
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -129,7 +129,7 @@ static const TypeInfo kvmclock_info = {
void kvmclock_create(void)
{
if (kvm_enabled() &&
first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
first_cpu->features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
(1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
sysbus_create_simple("kvmclock", -1, NULL);
}
+1
View File
@@ -12,6 +12,7 @@
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "hw/i386/apic_internal.h"
#include "hw/sysbus.h"
#define VAPIC_IO_PORT 0x7e
+86 -2
View File
@@ -53,6 +53,8 @@
#include "qemu/bitmap.h"
#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
@@ -338,6 +340,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 +363,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 +402,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)) {
@@ -874,9 +896,59 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
}
}
void pc_cpus_init(const char *cpu_model)
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, icc_bridge, errp);
if (!cpu) {
return cpu;
}
object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err);
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
if (local_err) {
if (cpu != NULL) {
object_unref(OBJECT(cpu));
cpu = NULL;
}
error_propagate(errp, local_err);
}
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;
X86CPU *cpu = NULL;
Error *error = NULL;
/* init CPUs */
if (cpu_model == NULL) {
@@ -886,12 +958,24 @@ void pc_cpus_init(const char *cpu_model)
cpu_model = "qemu32";
#endif
}
current_cpu_model = cpu_model;
for (i = 0; i < smp_cpus; i++) {
if (!cpu_x86_init(cpu_model)) {
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)
+9 -1
View File
@@ -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,9 +88,14 @@ static void pc_init1(MemoryRegion *system_memory,
MemoryRegion *ram_memory;
MemoryRegion *pci_memory;
MemoryRegion *rom_memory;
DeviceState *icc_bridge;
void *fw_cfg = NULL;
pc_cpus_init(cpu_model);
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, icc_bridge);
pc_acpi_init("acpi-dsdt.aml");
if (kvmclock_enabled) {
@@ -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]);
@@ -328,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,
+9 -1
View File
@@ -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,8 +76,13 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
int i;
ICH9LPCState *ich9_lpc;
PCIDevice *ahci;
DeviceState *icc_bridge;
pc_cpus_init(cpu_model);
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, icc_bridge);
pc_acpi_init("q35-acpi-dsdt.aml");
kvmclock_create();
@@ -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]);
@@ -213,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,
};

Some files were not shown because too many files have changed in this diff Show More