在 2013-04-05五的 16:37 +0200,Igor Mammedov写道: > * introduce processor status bitmask visible to guest at 0xaf00 addr, > where Seabios expects it > * set bit corresponding to APIC ID in processor status bitmask on > receiving CPU hot-plug notification > * trigger CPU hot-plug SCI, expected by Seabios on receiving CPU > hot-plug notification
expected by seabios? IMHO, seems you are saying ACPI's asl code which just wrapped in seabios. > > Signed-off-by: Igor Mammedov <imamm...@redhat.com> > --- > v2: > * use CPUClass.get_firmware_id() to make code target independent > * bump up vmstate_acpi version > --- > hw/acpi_piix4.c | 114 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 111 insertions(+), 3 deletions(-) > > diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c > index 48a32b5..ccfc028 100644 > --- a/hw/acpi_piix4.c > +++ b/hw/acpi_piix4.c > @@ -48,19 +48,28 @@ > #define PCI_EJ_BASE 0xae08 > #define PCI_RMV_BASE 0xae0c > > +#define PROC_BASE 0xaf00 > +#define 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; > }; > > +struct cpu_status { > + uint8_t sts[PROC_LEN]; > +}; > + > 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; > + > + struct cpu_status gpe_cpu; > + Notifier cpu_add_notifier; seems you named cpu_added_notifier at [PATCH 10/22], should the notifer's name be unified? > } 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 */ > @@ -257,6 +269,17 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int > version_id) > return ret; > } > > +#define VMSTATE_CPU_STATUS_ARRAY(_field, _state) > \ > + { > \ > + .name = (stringify(_field)), > \ > + .version_id = 0, > \ > + .num = PROC_LEN, > \ > + .info = &vmstate_info_uint8, > \ > + .size = sizeof(uint8_t), > \ > + .flags = VMS_ARRAY, > \ > + .offset = vmstate_offset_array(_state, _field, uint8_t, PROC_LEN), > \ > + } > + > /* qemu-kvm 1.2 uses version 3 but advertised as 2 > * To support incoming qemu-kvm 1.2 migration, change version_id > * and minimum_version_id to 2 below (which breaks migration from > @@ -265,7 +288,7 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int > version_id) > */ > static const VMStateDescription vmstate_acpi = { > .name = "piix4_pm", > - .version_id = 3, > + .version_id = 4, > .minimum_version_id = 3, > .minimum_version_id_old = 1, > .load_state_old = acpi_load_old, > @@ -281,6 +304,7 @@ static const VMStateDescription vmstate_acpi = { > VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), > VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, > struct pci_status), > + VMSTATE_CPU_STATUS_ARRAY(gpe_cpu.sts, PIIX4PMState), > VMSTATE_END_OF_LIST() > } > }; > @@ -585,6 +609,83 @@ static const MemoryRegionOps piix4_pci_ops = { > }, > }; > > +static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned width) > +{ > + PIIX4PMState *s = opaque; > + struct cpu_status *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) > +{ > + struct cpu_status *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_firmware_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_add_req(Notifier *n, void *opaque) > +{ > + PIIX4PMState *s = container_of(n, PIIX4PMState, cpu_add_notifier); > + piix4_cpu_hotplug_req(s, CPU(opaque), PLUG); > +} > + > +static int piix4_init_cpu_status(Object *obj, void *opaque) > +{ > + struct cpu_status *g = (struct cpu_status *)opaque; > + Object *cpu_obj = object_dynamic_cast(obj, TYPE_CPU); > + > + if (cpu_obj) { > + struct Error *error = NULL; > + CPUClass *k = CPU_GET_CLASS(cpu_obj); > + int64_t id = k->get_firmware_id(CPU(cpu_obj)); > + > + if (error) { > + fprintf(stderr, "failed to initilize CPU status for ACPI: %s\n", > + error_get_pretty(error)); > + error_free(error); > + abort(); > + } > + g_assert((id / 8) < PROC_LEN); > + g->sts[id / 8] |= (1 << (id % 8)); > + } > + return object_child_foreach(obj, piix4_init_cpu_status, opaque); > +} > + > static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, > PCIHotplugState state); > > @@ -600,6 +701,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); > + > + piix4_init_cpu_status(qdev_get_machine(), &s->gpe_cpu); > + memory_region_init_io(&s->io_cpu, &cpu_hotplug_ops, s, > "apci-cpu-hotplug", > + PROC_LEN); > + memory_region_add_subregion(parent, PROC_BASE, &s->io_cpu); > + s->cpu_add_notifier.notify = piix4_cpu_add_req; > + qemu_register_cpu_added_notifier(&s->cpu_add_notifier); > } > > static void enable_device(PIIX4PMState *s, int slot)