Message ID | 1413726188-29285-2-git-send-email-ghammer@redhat.com |
---|---|
State | New |
Headers | show |
On Sun, Oct 19, 2014 at 04:43:07PM +0300, Gal Hammer wrote: > Based on Microsoft's sepecifications (paper can be dowloaded from > http://go.microsoft.com/fwlink/?LinkId=260709), add a device > description to the SSDT ACPI table and its implementation. > > The GUID is set using a global "vmgenid.uuid" parameter. > > Signed-off-by: Gal Hammer <ghammer@redhat.com> > > --- > default-configs/i386-softmmu.mak | 1 + > default-configs/x86_64-softmmu.mak | 1 + > hw/acpi/core.c | 8 +++ > hw/acpi/ich9.c | 8 +++ > hw/acpi/piix4.c | 8 +++ > hw/i386/acpi-build.c | 8 +++ > hw/i386/acpi-dsdt.dsl | 4 +- > hw/i386/acpi-dsdt.hex.generated | 6 +- > hw/i386/pc.c | 8 +++ > hw/i386/q35-acpi-dsdt.dsl | 5 +- > hw/i386/q35-acpi-dsdt.hex.generated | 8 +-- > hw/i386/ssdt-misc.dsl | 36 +++++++++++ > hw/i386/ssdt-misc.hex.generated | 8 +-- > hw/isa/lpc_ich9.c | 1 + > hw/misc/Makefile.objs | 1 + > hw/misc/vmgenid.c | 116 +++++++++++++++++++++++++++++++++++ > include/hw/acpi/acpi.h | 2 + > include/hw/acpi/acpi_dev_interface.h | 4 ++ > include/hw/acpi/ich9.h | 2 + > include/hw/i386/pc.h | 3 + > include/hw/misc/vmgenid.h | 21 +++++++ > 21 files changed, 246 insertions(+), 13 deletions(-) > create mode 100644 hw/misc/vmgenid.c > create mode 100644 include/hw/misc/vmgenid.h Please document the host/guest API. It seems that you are using a hard-coded hardware address, and using up a GPE. > > diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak > index 8e08841..bd33c75 100644 > --- a/default-configs/i386-softmmu.mak > +++ b/default-configs/i386-softmmu.mak > @@ -45,3 +45,4 @@ CONFIG_IOAPIC=y > CONFIG_ICC_BUS=y > CONFIG_PVPANIC=y > CONFIG_MEM_HOTPLUG=y > +CONFIG_VMGENID=y > diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak > index 66557ac..006fc7c 100644 > --- a/default-configs/x86_64-softmmu.mak > +++ b/default-configs/x86_64-softmmu.mak > @@ -45,3 +45,4 @@ CONFIG_IOAPIC=y > CONFIG_ICC_BUS=y > CONFIG_PVPANIC=y > CONFIG_MEM_HOTPLUG=y > +CONFIG_VMGENID=y > diff --git a/hw/acpi/core.c b/hw/acpi/core.c > index a7368fb..a01c980 100644 > --- a/hw/acpi/core.c > +++ b/hw/acpi/core.c > @@ -28,6 +28,8 @@ > #include "qapi-visit.h" > #include "qapi-event.h" > > +#define ACPI_VM_GENERATION_ID_CHANGED_STATUS 1 > + > struct acpi_table_header { > uint16_t _length; /* our length, not actual part of the hdr */ > /* allows easier parsing for fw_cfg clients */ > @@ -680,3 +682,9 @@ void acpi_update_sci(ACPIREGS *regs, qemu_irq irq) > (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && > !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS)); > } > + > +void acpi_vm_generation_id_changed(ACPIREGS *acpi_regs, qemu_irq irq) > +{ > + acpi_regs->gpe.sts[0] |= ACPI_VM_GENERATION_ID_CHANGED_STATUS; > + acpi_update_sci(acpi_regs, irq); > +} > diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c > index 7b14bbb..5501c0e 100644 > --- a/hw/acpi/ich9.c > +++ b/hw/acpi/ich9.c > @@ -316,3 +316,11 @@ void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) > > acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); > } > + > +void ich9_vm_generation_id_changed(AcpiDeviceIf *adev) > +{ > + ICH9LPCState *s = ICH9_LPC_DEVICE(adev); > + ICH9LPCPMRegs *pm = &s->pm; > + > + acpi_vm_generation_id_changed(&pm->acpi_regs, pm->irq); > +} > diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c > index 0bfa814..ad0ef68 100644 > --- a/hw/acpi/piix4.c > +++ b/hw/acpi/piix4.c > @@ -580,6 +580,13 @@ static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) > acpi_memory_ospm_status(&s->acpi_memory_hotplug, list); > } > > +static void piix4_vm_generation_id_changed(AcpiDeviceIf *adev) > +{ > + PIIX4PMState *s = PIIX4_PM(adev); > + > + acpi_vm_generation_id_changed(&s->ar, s->irq); > +} > + > static Property piix4_pm_properties[] = { > DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), > DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0), > @@ -617,6 +624,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) > hc->plug = piix4_device_plug_cb; > hc->unplug_request = piix4_device_unplug_request_cb; > adevc->ospm_status = piix4_ospm_status; > + adevc->vm_generation_id_changed = piix4_vm_generation_id_changed; > } > > static const TypeInfo piix4_pm_info = { > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > index 00be4bb..27d0494 100644 > --- a/hw/i386/acpi-build.c > +++ b/hw/i386/acpi-build.c > @@ -42,6 +42,7 @@ > #include "hw/acpi/memory_hotplug.h" > #include "sysemu/tpm.h" > #include "hw/acpi/tpm.h" > +#include "hw/misc/vmgenid.h" > > /* Supported chipsets: */ > #include "hw/acpi/piix4.h" > @@ -96,6 +97,7 @@ typedef struct AcpiMiscInfo { > const unsigned char *dsdt_code; > unsigned dsdt_size; > uint16_t pvpanic_port; > + bool vm_generation_id_set; > } AcpiMiscInfo; > > typedef struct AcpiBuildPciBusHotplugState { > @@ -216,6 +218,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info) > info->has_hpet = hpet_find(); > info->has_tpm = tpm_find(); > info->pvpanic_port = pvpanic_port(); > + info->vm_generation_id_set = vm_generation_id_set(); > } > > static void acpi_get_pci_info(PcPciInfo *info) > @@ -1088,6 +1091,11 @@ build_ssdt(GArray *table_data, GArray *linker, > ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), > ssdt_isa_pest[0], 16, misc->pvpanic_port); > > + if (!misc->vm_generation_id_set) { > + ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), > + ssdt_acpi_vm_gid_addr[0], 32, 0); > + } > + > ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), > ssdt_mctrl_nr_slots[0], 32, nr_mem); > > diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl > index 559f4b6..10b4afb 100644 > --- a/hw/i386/acpi-dsdt.dsl > +++ b/hw/i386/acpi-dsdt.dsl > @@ -307,7 +307,9 @@ DefinitionBlock ( > Scope(\_GPE) { > Name(_HID, "ACPI0006") > > - Method(_L00) { > + External(\_SB.VMGI, DeviceObj) > + Method(_E00) { > + Notify(\_SB.VMGI, 0x80) > } > Method(_E01) { > // PCI hotplug event > diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated > index a21bf41..3fd06d2 100644 > --- a/hw/i386/acpi-dsdt.hex.generated > +++ b/hw/i386/acpi-dsdt.hex.generated > @@ -8,7 +8,7 @@ static unsigned char AcpiDsdtAmlCode[] = { > 0x0, > 0x0, > 0x1, > -0x1f, > +0x18, > 0x42, > 0x58, > 0x50, > @@ -32,8 +32,8 @@ static unsigned char AcpiDsdtAmlCode[] = { > 0x54, > 0x4c, > 0x28, > -0x5, > -0x10, > +0x8, > +0x14, > 0x20, > 0x10, > 0x49, > diff --git a/hw/i386/pc.c b/hw/i386/pc.c > index d045e8b..95ec233 100644 > --- a/hw/i386/pc.c > +++ b/hw/i386/pc.c > @@ -59,6 +59,7 @@ > #include "hw/pci/pci_host.h" > #include "acpi-build.h" > #include "hw/mem/pc-dimm.h" > +#include "hw/misc/vmgenid.h" > #include "trace.h" > #include "qapi/visitor.h" > > @@ -1361,6 +1362,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, > int i; > DriveInfo *fd[MAX_FD]; > DeviceState *hpet = NULL; > + DeviceState *vmgenid; > int pit_isa_irq = 0; > qemu_irq pit_alt_irq = NULL; > qemu_irq rtc_irq = NULL; > @@ -1459,6 +1461,12 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, > fd[i] = drive_get(IF_FLOPPY, 0, i); > } > *floppy = fdctrl_init_isa(isa_bus, fd); > + > + vmgenid = qdev_try_create(NULL, VMGENID_DEVICE); > + if (vmgenid) { > + qdev_init_nofail(vmgenid); > + sysbus_mmio_map(SYS_BUS_DEVICE(vmgenid), 0, VMGENID_BASE_ADDRESS); > + } > } > > void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) > diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl > index 054b035..b1d04e2 100644 > --- a/hw/i386/q35-acpi-dsdt.dsl > +++ b/hw/i386/q35-acpi-dsdt.dsl > @@ -415,7 +415,10 @@ DefinitionBlock ( > Scope(\_GPE) { > Name(_HID, "ACPI0006") > > - Method(_L00) { > + External(\_SB.VMGI, DeviceObj) > + Method(_E00) > + { > + Notify(\_SB.VMGI, 0x80) > } > Method(_L01) { > } > diff --git a/hw/i386/q35-acpi-dsdt.hex.generated b/hw/i386/q35-acpi-dsdt.hex.generated > index c9eb4ac..866e648 100644 > --- a/hw/i386/q35-acpi-dsdt.hex.generated > +++ b/hw/i386/q35-acpi-dsdt.hex.generated > @@ -8,7 +8,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { > 0x0, > 0x0, > 0x1, > -0xb7, > +0xac, > 0x42, > 0x58, > 0x50, > @@ -31,9 +31,9 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { > 0x4e, > 0x54, > 0x4c, > -0x15, > -0x11, > -0x13, > +0x28, > +0x8, > +0x14, > 0x20, > 0x10, > 0x49, > diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl > index 0fd4480..6ae09fb 100644 > --- a/hw/i386/ssdt-misc.dsl > +++ b/hw/i386/ssdt-misc.dsl > @@ -13,6 +13,7 @@ > * with this program; if not, see <http://www.gnu.org/licenses/>. > */ > #include "hw/acpi/pc-hotplug.h" > +#include "hw/misc/vmgenid.h" > > ACPI_EXTRACT_ALL_CODE ssdp_misc_aml > > @@ -118,6 +119,41 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1) > } > } > > + Scope(\_SB) { > + Device(VMGI) { > + Name(_HID, "QEMU0002") > + Name(_CID, "VM_Gen_Counter") > + Name(_DDN, "VM_Gen_Counter") > + > + ACPI_EXTRACT_NAME_DWORD_CONST ssdt_acpi_vm_gid_addr > + Name(VGIA, VMGENID_BASE_ADDRESS) > + > + OperationRegion(VGID, SystemMemory, > + VMGENID_BASE_ADDRESS, VMGENID_BASE_ADDR_LEN) > + > + Name(_CRS, ResourceTemplate() { > + Memory32Fixed(ReadOnly, > + VMGENID_BASE_ADDRESS, VMGENID_BASE_ADDR_LEN) > + }) > + > + Method(_STA, 0, NotSerialized) { > + Store(VGIA, Local0) > + If (LEqual(Local0, Zero)) { > + Return (0x00) > + } Else { > + Return (0x0F) > + } > + } > + > + Method(ADDR, 0, Serialized) { > + Store(Package(2) { }, Local0) > + Store(VGIA, Index(Local0, 0)) > + Store(0x0000, Index(Local0, 1)) > + return (Local0) > + } > + } > + } > + > External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj) > Scope(\_SB.PCI0) { > Device(MEMORY_HOTPLUG_DEVICE) { > diff --git a/hw/i386/ssdt-misc.hex.generated b/hw/i386/ssdt-misc.hex.generated > index ba4268a..f0b7a27 100644 > --- a/hw/i386/ssdt-misc.hex.generated > +++ b/hw/i386/ssdt-misc.hex.generated > @@ -26,7 +26,7 @@ static unsigned char ssdp_misc_aml[] = { > 0x0, > 0x0, > 0x1, > -0x8b, > +0x80, > 0x42, > 0x58, > 0x50, > @@ -49,9 +49,9 @@ static unsigned char ssdp_misc_aml[] = { > 0x4e, > 0x54, > 0x4c, > -0x15, > -0x11, > -0x13, > +0x28, > +0x8, > +0x14, > 0x20, > 0x10, > 0x42, > diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c > index 530b074..3a012fa 100644 > --- a/hw/isa/lpc_ich9.c > +++ b/hw/isa/lpc_ich9.c > @@ -678,6 +678,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) > hc->plug = ich9_device_plug_cb; > hc->unplug_request = ich9_device_unplug_request_cb; > adevc->ospm_status = ich9_pm_ospm_status; > + adevc->vm_generation_id_changed = ich9_vm_generation_id_changed; > } > > static const TypeInfo ich9_lpc_info = { > diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs > index 979e532..c18b800 100644 > --- a/hw/misc/Makefile.objs > +++ b/hw/misc/Makefile.objs > @@ -41,3 +41,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o > obj-$(CONFIG_ZYNQ) += zynq_slcr.o > > obj-$(CONFIG_PVPANIC) += pvpanic.o > +obj-$(CONFIG_VMGENID) += vmgenid.o > diff --git a/hw/misc/vmgenid.c b/hw/misc/vmgenid.c > new file mode 100644 > index 0000000..01aacd4 > --- /dev/null > +++ b/hw/misc/vmgenid.c > @@ -0,0 +1,116 @@ > +/* > + * Virtual Machine Generation ID Device > + * > + * Copyright (C) 2014 Red Hat Inc. > + * > + * Authors: Gal Hammer <ghammer@redhat.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + * > + */ > + > +#include "hw/i386/pc.h" > +#include "hw/sysbus.h" > +#include "hw/misc/vmgenid.h" > +#include "hw/acpi/acpi_dev_interface.h" > + > +#define PROPERTY_UUID "uuid" > + > +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE) > + > +typedef struct VmGenIdState { > + SysBusDevice parent_obj; > + MemoryRegion iomem; > + uint8_t guid[16]; > + bool guid_set; > +} VmGenIdState; > + > +bool vm_generation_id_set(void) > +{ > + Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL); > + VmGenIdState *s = VMGENID(obj); > + > + if (!obj) { > + return false; > + } > + return s->guid_set; > +} > + > +static uint64_t vmgenid_ram_read(void *opaque, hwaddr addr, > + unsigned size) > +{ > + VmGenIdState *s = VMGENID(opaque); > + uint64_t value; > + > + memcpy(&value, s->guid + addr, size); > + return value; > +} > + > +static const MemoryRegionOps vmgenid_ram_ops = { > + .read = vmgenid_ram_read, > + .valid = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > + .endianness = DEVICE_NATIVE_ENDIAN, > +}; > + > +static void vmgenid_set_uuid(Object *obj, const char *value, Error **errp) > +{ > + VmGenIdState *s = VMGENID(obj); > + Object *acpi_obj; > + bool first_set = !s->guid_set; > + > + if (qemu_uuid_parse(value, s->guid) < 0) { > + error_setg(errp, "Fail to parse UUID string."); > + return; > + } > + s->guid_set = true; > + > + /* Skip the acpi notification when setting the vm generation id for the > + * first time. This is done because in a q35 machine the gpe register is > + * allocated after the device is initialized. */ > + if (!first_set) { > + acpi_obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); > + if (acpi_obj) { > + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(acpi_obj); > + AcpiDeviceIf *adev = ACPI_DEVICE_IF(acpi_obj); > + > + adevc->vm_generation_id_changed(adev); > + } > + } > +} > + > +static void vmgenid_init(Object *obj) > +{ > + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); > + VmGenIdState *s = VMGENID(obj); > + > + memory_region_init_io(&s->iomem, obj, &vmgenid_ram_ops, s, "vgid", 16); > + sysbus_init_mmio(sbd, &s->iomem); This will cause an exit on each access to the GID. I'm guessing this is too expensive. > + > + object_property_add_str(obj, PROPERTY_UUID, NULL, vmgenid_set_uuid, NULL); > +} > + > +static void vmgenid_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + set_bit(DEVICE_CATEGORY_MISC, dc->categories); > +} > + > +static const TypeInfo vmgenid_device_info = { > + .name = VMGENID_DEVICE, > + .parent = TYPE_SYS_BUS_DEVICE, > + .instance_size = sizeof(VmGenIdState), > + .instance_init = vmgenid_init, > + .class_init = vmgenid_class_init, > +}; > + > +static void vmgenid_register_types(void) > +{ > + type_register_static(&vmgenid_device_info); > +} > + > +type_init(vmgenid_register_types) > diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h > index 1f678b4..9373b4d 100644 > --- a/include/hw/acpi/acpi.h > +++ b/include/hw/acpi/acpi.h > @@ -185,4 +185,6 @@ unsigned acpi_table_len(void *current); > void acpi_table_add(const QemuOpts *opts, Error **errp); > void acpi_table_add_builtin(const QemuOpts *opts, Error **errp); > > +void acpi_vm_generation_id_changed(ACPIREGS *acpi_regs, qemu_irq irq); > + > #endif /* !QEMU_HW_ACPI_H */ > diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h > index f245f8d..757ce60 100644 > --- a/include/hw/acpi/acpi_dev_interface.h > +++ b/include/hw/acpi/acpi_dev_interface.h > @@ -28,6 +28,9 @@ typedef struct AcpiDeviceIf { > * ospm_status: returns status of ACPI device objects, reported > * via _OST method if device supports it. > * > + * vm_generation_id_changed: notify the guest that it generation > + * id was changed. > + * > * Interface is designed for providing unified interface > * to generic ACPI functionality that could be used without > * knowledge about internals of actual device that implements > @@ -39,5 +42,6 @@ typedef struct AcpiDeviceIfClass { > > /* <public> */ > void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); > + void (*vm_generation_id_changed)(AcpiDeviceIf *adev); > } AcpiDeviceIfClass; > #endif > diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h > index 7e42448..3b4eed5 100644 > --- a/include/hw/acpi/ich9.h > +++ b/include/hw/acpi/ich9.h > @@ -62,4 +62,6 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp); > void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp); > > void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); > + > +void ich9_vm_generation_id_changed(AcpiDeviceIf *adev); > #endif /* HW_ACPI_ICH9_H */ > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h > index 1c2602e..87912b2 100644 > --- a/include/hw/i386/pc.h > +++ b/include/hw/i386/pc.h > @@ -290,6 +290,9 @@ void pc_system_firmware_init(MemoryRegion *rom_memory, > /* pvpanic.c */ > uint16_t pvpanic_port(void); > > +/* vmgenid.c */ > +bool vm_generation_id_set(void); > + > /* e820 types */ > #define E820_RAM 1 > #define E820_RESERVED 2 > diff --git a/include/hw/misc/vmgenid.h b/include/hw/misc/vmgenid.h > new file mode 100644 > index 0000000..3d44421 > --- /dev/null > +++ b/include/hw/misc/vmgenid.h > @@ -0,0 +1,21 @@ > +/* > + * Virtual Machine Generation ID Device > + * > + * Copyright (C) 2014 Red Hat Inc. > + * > + * Authors: Gal Hammer <ghammer@redhat.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + * > + */ > + > +#ifndef HW_MISC_VMGENID_H > +#define HW_MISC_VMGENID_H > + > +#define VMGENID_DEVICE "vmgenid" > + > +#define VMGENID_BASE_ADDRESS 0xfedf0000 > +#define VMGENID_BASE_ADDR_LEN 16 > + > +#endif > -- > 1.9.3
On 19/10/2014 18:14, Michael S. Tsirkin wrote: > On Sun, Oct 19, 2014 at 04:43:07PM +0300, Gal Hammer wrote: >> Based on Microsoft's sepecifications (paper can be dowloaded from >> http://go.microsoft.com/fwlink/?LinkId=260709), add a device >> description to the SSDT ACPI table and its implementation. >> >> The GUID is set using a global "vmgenid.uuid" parameter. >> >> Signed-off-by: Gal Hammer <ghammer@redhat.com> >> >> --- >> default-configs/i386-softmmu.mak | 1 + >> default-configs/x86_64-softmmu.mak | 1 + >> hw/acpi/core.c | 8 +++ >> hw/acpi/ich9.c | 8 +++ >> hw/acpi/piix4.c | 8 +++ >> hw/i386/acpi-build.c | 8 +++ >> hw/i386/acpi-dsdt.dsl | 4 +- >> hw/i386/acpi-dsdt.hex.generated | 6 +- >> hw/i386/pc.c | 8 +++ >> hw/i386/q35-acpi-dsdt.dsl | 5 +- >> hw/i386/q35-acpi-dsdt.hex.generated | 8 +-- >> hw/i386/ssdt-misc.dsl | 36 +++++++++++ >> hw/i386/ssdt-misc.hex.generated | 8 +-- >> hw/isa/lpc_ich9.c | 1 + >> hw/misc/Makefile.objs | 1 + >> hw/misc/vmgenid.c | 116 +++++++++++++++++++++++++++++++++++ >> include/hw/acpi/acpi.h | 2 + >> include/hw/acpi/acpi_dev_interface.h | 4 ++ >> include/hw/acpi/ich9.h | 2 + >> include/hw/i386/pc.h | 3 + >> include/hw/misc/vmgenid.h | 21 +++++++ >> 21 files changed, 246 insertions(+), 13 deletions(-) >> create mode 100644 hw/misc/vmgenid.c >> create mode 100644 include/hw/misc/vmgenid.h > > Please document the host/guest API. > It seems that you are using a hard-coded hardware address, > and using up a GPE. I'll add a document file which describes the device's implementation. > > >> >> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak >> index 8e08841..bd33c75 100644 >> --- a/default-configs/i386-softmmu.mak >> +++ b/default-configs/i386-softmmu.mak >> @@ -45,3 +45,4 @@ CONFIG_IOAPIC=y >> CONFIG_ICC_BUS=y >> CONFIG_PVPANIC=y >> CONFIG_MEM_HOTPLUG=y >> +CONFIG_VMGENID=y >> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak >> index 66557ac..006fc7c 100644 >> --- a/default-configs/x86_64-softmmu.mak >> +++ b/default-configs/x86_64-softmmu.mak >> @@ -45,3 +45,4 @@ CONFIG_IOAPIC=y >> CONFIG_ICC_BUS=y >> CONFIG_PVPANIC=y >> CONFIG_MEM_HOTPLUG=y >> +CONFIG_VMGENID=y >> diff --git a/hw/acpi/core.c b/hw/acpi/core.c >> index a7368fb..a01c980 100644 >> --- a/hw/acpi/core.c >> +++ b/hw/acpi/core.c >> @@ -28,6 +28,8 @@ >> #include "qapi-visit.h" >> #include "qapi-event.h" >> >> +#define ACPI_VM_GENERATION_ID_CHANGED_STATUS 1 >> + >> struct acpi_table_header { >> uint16_t _length; /* our length, not actual part of the hdr */ >> /* allows easier parsing for fw_cfg clients */ >> @@ -680,3 +682,9 @@ void acpi_update_sci(ACPIREGS *regs, qemu_irq irq) >> (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && >> !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS)); >> } >> + >> +void acpi_vm_generation_id_changed(ACPIREGS *acpi_regs, qemu_irq irq) >> +{ >> + acpi_regs->gpe.sts[0] |= ACPI_VM_GENERATION_ID_CHANGED_STATUS; >> + acpi_update_sci(acpi_regs, irq); >> +} >> diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c >> index 7b14bbb..5501c0e 100644 >> --- a/hw/acpi/ich9.c >> +++ b/hw/acpi/ich9.c >> @@ -316,3 +316,11 @@ void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) >> >> acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); >> } >> + >> +void ich9_vm_generation_id_changed(AcpiDeviceIf *adev) >> +{ >> + ICH9LPCState *s = ICH9_LPC_DEVICE(adev); >> + ICH9LPCPMRegs *pm = &s->pm; >> + >> + acpi_vm_generation_id_changed(&pm->acpi_regs, pm->irq); >> +} >> diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c >> index 0bfa814..ad0ef68 100644 >> --- a/hw/acpi/piix4.c >> +++ b/hw/acpi/piix4.c >> @@ -580,6 +580,13 @@ static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) >> acpi_memory_ospm_status(&s->acpi_memory_hotplug, list); >> } >> >> +static void piix4_vm_generation_id_changed(AcpiDeviceIf *adev) >> +{ >> + PIIX4PMState *s = PIIX4_PM(adev); >> + >> + acpi_vm_generation_id_changed(&s->ar, s->irq); >> +} >> + >> static Property piix4_pm_properties[] = { >> DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), >> DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0), >> @@ -617,6 +624,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) >> hc->plug = piix4_device_plug_cb; >> hc->unplug_request = piix4_device_unplug_request_cb; >> adevc->ospm_status = piix4_ospm_status; >> + adevc->vm_generation_id_changed = piix4_vm_generation_id_changed; >> } >> >> static const TypeInfo piix4_pm_info = { >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c >> index 00be4bb..27d0494 100644 >> --- a/hw/i386/acpi-build.c >> +++ b/hw/i386/acpi-build.c >> @@ -42,6 +42,7 @@ >> #include "hw/acpi/memory_hotplug.h" >> #include "sysemu/tpm.h" >> #include "hw/acpi/tpm.h" >> +#include "hw/misc/vmgenid.h" >> >> /* Supported chipsets: */ >> #include "hw/acpi/piix4.h" >> @@ -96,6 +97,7 @@ typedef struct AcpiMiscInfo { >> const unsigned char *dsdt_code; >> unsigned dsdt_size; >> uint16_t pvpanic_port; >> + bool vm_generation_id_set; >> } AcpiMiscInfo; >> >> typedef struct AcpiBuildPciBusHotplugState { >> @@ -216,6 +218,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info) >> info->has_hpet = hpet_find(); >> info->has_tpm = tpm_find(); >> info->pvpanic_port = pvpanic_port(); >> + info->vm_generation_id_set = vm_generation_id_set(); >> } >> >> static void acpi_get_pci_info(PcPciInfo *info) >> @@ -1088,6 +1091,11 @@ build_ssdt(GArray *table_data, GArray *linker, >> ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), >> ssdt_isa_pest[0], 16, misc->pvpanic_port); >> >> + if (!misc->vm_generation_id_set) { >> + ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), >> + ssdt_acpi_vm_gid_addr[0], 32, 0); >> + } >> + >> ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), >> ssdt_mctrl_nr_slots[0], 32, nr_mem); >> >> diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl >> index 559f4b6..10b4afb 100644 >> --- a/hw/i386/acpi-dsdt.dsl >> +++ b/hw/i386/acpi-dsdt.dsl >> @@ -307,7 +307,9 @@ DefinitionBlock ( >> Scope(\_GPE) { >> Name(_HID, "ACPI0006") >> >> - Method(_L00) { >> + External(\_SB.VMGI, DeviceObj) >> + Method(_E00) { >> + Notify(\_SB.VMGI, 0x80) >> } >> Method(_E01) { >> // PCI hotplug event >> diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated >> index a21bf41..3fd06d2 100644 >> --- a/hw/i386/acpi-dsdt.hex.generated >> +++ b/hw/i386/acpi-dsdt.hex.generated >> @@ -8,7 +8,7 @@ static unsigned char AcpiDsdtAmlCode[] = { >> 0x0, >> 0x0, >> 0x1, >> -0x1f, >> +0x18, >> 0x42, >> 0x58, >> 0x50, >> @@ -32,8 +32,8 @@ static unsigned char AcpiDsdtAmlCode[] = { >> 0x54, >> 0x4c, >> 0x28, >> -0x5, >> -0x10, >> +0x8, >> +0x14, >> 0x20, >> 0x10, >> 0x49, >> diff --git a/hw/i386/pc.c b/hw/i386/pc.c >> index d045e8b..95ec233 100644 >> --- a/hw/i386/pc.c >> +++ b/hw/i386/pc.c >> @@ -59,6 +59,7 @@ >> #include "hw/pci/pci_host.h" >> #include "acpi-build.h" >> #include "hw/mem/pc-dimm.h" >> +#include "hw/misc/vmgenid.h" >> #include "trace.h" >> #include "qapi/visitor.h" >> >> @@ -1361,6 +1362,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, >> int i; >> DriveInfo *fd[MAX_FD]; >> DeviceState *hpet = NULL; >> + DeviceState *vmgenid; >> int pit_isa_irq = 0; >> qemu_irq pit_alt_irq = NULL; >> qemu_irq rtc_irq = NULL; >> @@ -1459,6 +1461,12 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, >> fd[i] = drive_get(IF_FLOPPY, 0, i); >> } >> *floppy = fdctrl_init_isa(isa_bus, fd); >> + >> + vmgenid = qdev_try_create(NULL, VMGENID_DEVICE); >> + if (vmgenid) { >> + qdev_init_nofail(vmgenid); >> + sysbus_mmio_map(SYS_BUS_DEVICE(vmgenid), 0, VMGENID_BASE_ADDRESS); >> + } >> } >> >> void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) >> diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl >> index 054b035..b1d04e2 100644 >> --- a/hw/i386/q35-acpi-dsdt.dsl >> +++ b/hw/i386/q35-acpi-dsdt.dsl >> @@ -415,7 +415,10 @@ DefinitionBlock ( >> Scope(\_GPE) { >> Name(_HID, "ACPI0006") >> >> - Method(_L00) { >> + External(\_SB.VMGI, DeviceObj) >> + Method(_E00) >> + { >> + Notify(\_SB.VMGI, 0x80) >> } >> Method(_L01) { >> } >> diff --git a/hw/i386/q35-acpi-dsdt.hex.generated b/hw/i386/q35-acpi-dsdt.hex.generated >> index c9eb4ac..866e648 100644 >> --- a/hw/i386/q35-acpi-dsdt.hex.generated >> +++ b/hw/i386/q35-acpi-dsdt.hex.generated >> @@ -8,7 +8,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { >> 0x0, >> 0x0, >> 0x1, >> -0xb7, >> +0xac, >> 0x42, >> 0x58, >> 0x50, >> @@ -31,9 +31,9 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { >> 0x4e, >> 0x54, >> 0x4c, >> -0x15, >> -0x11, >> -0x13, >> +0x28, >> +0x8, >> +0x14, >> 0x20, >> 0x10, >> 0x49, >> diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl >> index 0fd4480..6ae09fb 100644 >> --- a/hw/i386/ssdt-misc.dsl >> +++ b/hw/i386/ssdt-misc.dsl >> @@ -13,6 +13,7 @@ >> * with this program; if not, see <http://www.gnu.org/licenses/>. >> */ >> #include "hw/acpi/pc-hotplug.h" >> +#include "hw/misc/vmgenid.h" >> >> ACPI_EXTRACT_ALL_CODE ssdp_misc_aml >> >> @@ -118,6 +119,41 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1) >> } >> } >> >> + Scope(\_SB) { >> + Device(VMGI) { >> + Name(_HID, "QEMU0002") >> + Name(_CID, "VM_Gen_Counter") >> + Name(_DDN, "VM_Gen_Counter") >> + >> + ACPI_EXTRACT_NAME_DWORD_CONST ssdt_acpi_vm_gid_addr >> + Name(VGIA, VMGENID_BASE_ADDRESS) >> + >> + OperationRegion(VGID, SystemMemory, >> + VMGENID_BASE_ADDRESS, VMGENID_BASE_ADDR_LEN) >> + >> + Name(_CRS, ResourceTemplate() { >> + Memory32Fixed(ReadOnly, >> + VMGENID_BASE_ADDRESS, VMGENID_BASE_ADDR_LEN) >> + }) >> + >> + Method(_STA, 0, NotSerialized) { >> + Store(VGIA, Local0) >> + If (LEqual(Local0, Zero)) { >> + Return (0x00) >> + } Else { >> + Return (0x0F) >> + } >> + } >> + >> + Method(ADDR, 0, Serialized) { >> + Store(Package(2) { }, Local0) >> + Store(VGIA, Index(Local0, 0)) >> + Store(0x0000, Index(Local0, 1)) >> + return (Local0) >> + } >> + } >> + } >> + >> External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj) >> Scope(\_SB.PCI0) { >> Device(MEMORY_HOTPLUG_DEVICE) { >> diff --git a/hw/i386/ssdt-misc.hex.generated b/hw/i386/ssdt-misc.hex.generated >> index ba4268a..f0b7a27 100644 >> --- a/hw/i386/ssdt-misc.hex.generated >> +++ b/hw/i386/ssdt-misc.hex.generated >> @@ -26,7 +26,7 @@ static unsigned char ssdp_misc_aml[] = { >> 0x0, >> 0x0, >> 0x1, >> -0x8b, >> +0x80, >> 0x42, >> 0x58, >> 0x50, >> @@ -49,9 +49,9 @@ static unsigned char ssdp_misc_aml[] = { >> 0x4e, >> 0x54, >> 0x4c, >> -0x15, >> -0x11, >> -0x13, >> +0x28, >> +0x8, >> +0x14, >> 0x20, >> 0x10, >> 0x42, >> diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c >> index 530b074..3a012fa 100644 >> --- a/hw/isa/lpc_ich9.c >> +++ b/hw/isa/lpc_ich9.c >> @@ -678,6 +678,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) >> hc->plug = ich9_device_plug_cb; >> hc->unplug_request = ich9_device_unplug_request_cb; >> adevc->ospm_status = ich9_pm_ospm_status; >> + adevc->vm_generation_id_changed = ich9_vm_generation_id_changed; >> } >> >> static const TypeInfo ich9_lpc_info = { >> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs >> index 979e532..c18b800 100644 >> --- a/hw/misc/Makefile.objs >> +++ b/hw/misc/Makefile.objs >> @@ -41,3 +41,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o >> obj-$(CONFIG_ZYNQ) += zynq_slcr.o >> >> obj-$(CONFIG_PVPANIC) += pvpanic.o >> +obj-$(CONFIG_VMGENID) += vmgenid.o >> diff --git a/hw/misc/vmgenid.c b/hw/misc/vmgenid.c >> new file mode 100644 >> index 0000000..01aacd4 >> --- /dev/null >> +++ b/hw/misc/vmgenid.c >> @@ -0,0 +1,116 @@ >> +/* >> + * Virtual Machine Generation ID Device >> + * >> + * Copyright (C) 2014 Red Hat Inc. >> + * >> + * Authors: Gal Hammer <ghammer@redhat.com> >> + * >> + * This work is licensed under the terms of the GNU GPL, version 2 or later. >> + * See the COPYING file in the top-level directory. >> + * >> + */ >> + >> +#include "hw/i386/pc.h" >> +#include "hw/sysbus.h" >> +#include "hw/misc/vmgenid.h" >> +#include "hw/acpi/acpi_dev_interface.h" >> + >> +#define PROPERTY_UUID "uuid" >> + >> +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE) >> + >> +typedef struct VmGenIdState { >> + SysBusDevice parent_obj; >> + MemoryRegion iomem; >> + uint8_t guid[16]; >> + bool guid_set; >> +} VmGenIdState; >> + >> +bool vm_generation_id_set(void) >> +{ >> + Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL); >> + VmGenIdState *s = VMGENID(obj); >> + >> + if (!obj) { >> + return false; >> + } >> + return s->guid_set; >> +} >> + >> +static uint64_t vmgenid_ram_read(void *opaque, hwaddr addr, >> + unsigned size) >> +{ >> + VmGenIdState *s = VMGENID(opaque); >> + uint64_t value; >> + >> + memcpy(&value, s->guid + addr, size); >> + return value; >> +} >> + >> +static const MemoryRegionOps vmgenid_ram_ops = { >> + .read = vmgenid_ram_read, >> + .valid = { >> + .min_access_size = 4, >> + .max_access_size = 4, >> + }, >> + .endianness = DEVICE_NATIVE_ENDIAN, >> +}; >> + >> +static void vmgenid_set_uuid(Object *obj, const char *value, Error **errp) >> +{ >> + VmGenIdState *s = VMGENID(obj); >> + Object *acpi_obj; >> + bool first_set = !s->guid_set; >> + >> + if (qemu_uuid_parse(value, s->guid) < 0) { >> + error_setg(errp, "Fail to parse UUID string."); >> + return; >> + } >> + s->guid_set = true; >> + >> + /* Skip the acpi notification when setting the vm generation id for the >> + * first time. This is done because in a q35 machine the gpe register is >> + * allocated after the device is initialized. */ >> + if (!first_set) { >> + acpi_obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); >> + if (acpi_obj) { >> + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(acpi_obj); >> + AcpiDeviceIf *adev = ACPI_DEVICE_IF(acpi_obj); >> + >> + adevc->vm_generation_id_changed(adev); >> + } >> + } >> +} >> + >> +static void vmgenid_init(Object *obj) >> +{ >> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); >> + VmGenIdState *s = VMGENID(obj); >> + >> + memory_region_init_io(&s->iomem, obj, &vmgenid_ram_ops, s, "vgid", 16); >> + sysbus_init_mmio(sbd, &s->iomem); > > This will cause an exit on each access to the GID. > I'm guessing this is too expensive. Yes, it does cause an exit, but I don't think it is critical because the GID is rarely read by the guest OS. As far as I can tell it is only accessed on reboot and when the GID is changed. Do you prefer that I'll use the cpu_physical_memory_write function? Or do you have a diffrent idea on how to implement it? > > >> + >> + object_property_add_str(obj, PROPERTY_UUID, NULL, vmgenid_set_uuid, NULL); >> +} >> + >> +static void vmgenid_class_init(ObjectClass *klass, void *data) >> +{ >> + DeviceClass *dc = DEVICE_CLASS(klass); >> + >> + set_bit(DEVICE_CATEGORY_MISC, dc->categories); >> +} >> + >> +static const TypeInfo vmgenid_device_info = { >> + .name = VMGENID_DEVICE, >> + .parent = TYPE_SYS_BUS_DEVICE, >> + .instance_size = sizeof(VmGenIdState), >> + .instance_init = vmgenid_init, >> + .class_init = vmgenid_class_init, >> +}; >> + >> +static void vmgenid_register_types(void) >> +{ >> + type_register_static(&vmgenid_device_info); >> +} >> + >> +type_init(vmgenid_register_types) >> diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h >> index 1f678b4..9373b4d 100644 >> --- a/include/hw/acpi/acpi.h >> +++ b/include/hw/acpi/acpi.h >> @@ -185,4 +185,6 @@ unsigned acpi_table_len(void *current); >> void acpi_table_add(const QemuOpts *opts, Error **errp); >> void acpi_table_add_builtin(const QemuOpts *opts, Error **errp); >> >> +void acpi_vm_generation_id_changed(ACPIREGS *acpi_regs, qemu_irq irq); >> + >> #endif /* !QEMU_HW_ACPI_H */ >> diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h >> index f245f8d..757ce60 100644 >> --- a/include/hw/acpi/acpi_dev_interface.h >> +++ b/include/hw/acpi/acpi_dev_interface.h >> @@ -28,6 +28,9 @@ typedef struct AcpiDeviceIf { >> * ospm_status: returns status of ACPI device objects, reported >> * via _OST method if device supports it. >> * >> + * vm_generation_id_changed: notify the guest that it generation >> + * id was changed. >> + * >> * Interface is designed for providing unified interface >> * to generic ACPI functionality that could be used without >> * knowledge about internals of actual device that implements >> @@ -39,5 +42,6 @@ typedef struct AcpiDeviceIfClass { >> >> /* <public> */ >> void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); >> + void (*vm_generation_id_changed)(AcpiDeviceIf *adev); >> } AcpiDeviceIfClass; >> #endif >> diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h >> index 7e42448..3b4eed5 100644 >> --- a/include/hw/acpi/ich9.h >> +++ b/include/hw/acpi/ich9.h >> @@ -62,4 +62,6 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp); >> void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp); >> >> void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); >> + >> +void ich9_vm_generation_id_changed(AcpiDeviceIf *adev); >> #endif /* HW_ACPI_ICH9_H */ >> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h >> index 1c2602e..87912b2 100644 >> --- a/include/hw/i386/pc.h >> +++ b/include/hw/i386/pc.h >> @@ -290,6 +290,9 @@ void pc_system_firmware_init(MemoryRegion *rom_memory, >> /* pvpanic.c */ >> uint16_t pvpanic_port(void); >> >> +/* vmgenid.c */ >> +bool vm_generation_id_set(void); >> + >> /* e820 types */ >> #define E820_RAM 1 >> #define E820_RESERVED 2 >> diff --git a/include/hw/misc/vmgenid.h b/include/hw/misc/vmgenid.h >> new file mode 100644 >> index 0000000..3d44421 >> --- /dev/null >> +++ b/include/hw/misc/vmgenid.h >> @@ -0,0 +1,21 @@ >> +/* >> + * Virtual Machine Generation ID Device >> + * >> + * Copyright (C) 2014 Red Hat Inc. >> + * >> + * Authors: Gal Hammer <ghammer@redhat.com> >> + * >> + * This work is licensed under the terms of the GNU GPL, version 2 or later. >> + * See the COPYING file in the top-level directory. >> + * >> + */ >> + >> +#ifndef HW_MISC_VMGENID_H >> +#define HW_MISC_VMGENID_H >> + >> +#define VMGENID_DEVICE "vmgenid" >> + >> +#define VMGENID_BASE_ADDRESS 0xfedf0000 >> +#define VMGENID_BASE_ADDR_LEN 16 >> + >> +#endif >> -- >> 1.9.3
On Mon, Oct 20, 2014 at 08:57:05AM +0300, Gal Hammer wrote: > On 19/10/2014 18:14, Michael S. Tsirkin wrote: > >On Sun, Oct 19, 2014 at 04:43:07PM +0300, Gal Hammer wrote: > >>Based on Microsoft's sepecifications (paper can be dowloaded from > >>http://go.microsoft.com/fwlink/?LinkId=260709), add a device > >>description to the SSDT ACPI table and its implementation. > >> > >>The GUID is set using a global "vmgenid.uuid" parameter. > >> > >>Signed-off-by: Gal Hammer <ghammer@redhat.com> > >> > >>--- > >> default-configs/i386-softmmu.mak | 1 + > >> default-configs/x86_64-softmmu.mak | 1 + > >> hw/acpi/core.c | 8 +++ > >> hw/acpi/ich9.c | 8 +++ > >> hw/acpi/piix4.c | 8 +++ > >> hw/i386/acpi-build.c | 8 +++ > >> hw/i386/acpi-dsdt.dsl | 4 +- > >> hw/i386/acpi-dsdt.hex.generated | 6 +- > >> hw/i386/pc.c | 8 +++ > >> hw/i386/q35-acpi-dsdt.dsl | 5 +- > >> hw/i386/q35-acpi-dsdt.hex.generated | 8 +-- > >> hw/i386/ssdt-misc.dsl | 36 +++++++++++ > >> hw/i386/ssdt-misc.hex.generated | 8 +-- > >> hw/isa/lpc_ich9.c | 1 + > >> hw/misc/Makefile.objs | 1 + > >> hw/misc/vmgenid.c | 116 +++++++++++++++++++++++++++++++++++ > >> include/hw/acpi/acpi.h | 2 + > >> include/hw/acpi/acpi_dev_interface.h | 4 ++ > >> include/hw/acpi/ich9.h | 2 + > >> include/hw/i386/pc.h | 3 + > >> include/hw/misc/vmgenid.h | 21 +++++++ > >> 21 files changed, 246 insertions(+), 13 deletions(-) > >> create mode 100644 hw/misc/vmgenid.c > >> create mode 100644 include/hw/misc/vmgenid.h > > > >Please document the host/guest API. > >It seems that you are using a hard-coded hardware address, > >and using up a GPE. > > I'll add a document file which describes the device's implementation. > > > > > > >> > >>diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak > >>index 8e08841..bd33c75 100644 > >>--- a/default-configs/i386-softmmu.mak > >>+++ b/default-configs/i386-softmmu.mak > >>@@ -45,3 +45,4 @@ CONFIG_IOAPIC=y > >> CONFIG_ICC_BUS=y > >> CONFIG_PVPANIC=y > >> CONFIG_MEM_HOTPLUG=y > >>+CONFIG_VMGENID=y > >>diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak > >>index 66557ac..006fc7c 100644 > >>--- a/default-configs/x86_64-softmmu.mak > >>+++ b/default-configs/x86_64-softmmu.mak > >>@@ -45,3 +45,4 @@ CONFIG_IOAPIC=y > >> CONFIG_ICC_BUS=y > >> CONFIG_PVPANIC=y > >> CONFIG_MEM_HOTPLUG=y > >>+CONFIG_VMGENID=y > >>diff --git a/hw/acpi/core.c b/hw/acpi/core.c > >>index a7368fb..a01c980 100644 > >>--- a/hw/acpi/core.c > >>+++ b/hw/acpi/core.c > >>@@ -28,6 +28,8 @@ > >> #include "qapi-visit.h" > >> #include "qapi-event.h" > >> > >>+#define ACPI_VM_GENERATION_ID_CHANGED_STATUS 1 > >>+ > >> struct acpi_table_header { > >> uint16_t _length; /* our length, not actual part of the hdr */ > >> /* allows easier parsing for fw_cfg clients */ > >>@@ -680,3 +682,9 @@ void acpi_update_sci(ACPIREGS *regs, qemu_irq irq) > >> (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && > >> !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS)); > >> } > >>+ > >>+void acpi_vm_generation_id_changed(ACPIREGS *acpi_regs, qemu_irq irq) > >>+{ > >>+ acpi_regs->gpe.sts[0] |= ACPI_VM_GENERATION_ID_CHANGED_STATUS; > >>+ acpi_update_sci(acpi_regs, irq); > >>+} > >>diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c > >>index 7b14bbb..5501c0e 100644 > >>--- a/hw/acpi/ich9.c > >>+++ b/hw/acpi/ich9.c > >>@@ -316,3 +316,11 @@ void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) > >> > >> acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); > >> } > >>+ > >>+void ich9_vm_generation_id_changed(AcpiDeviceIf *adev) > >>+{ > >>+ ICH9LPCState *s = ICH9_LPC_DEVICE(adev); > >>+ ICH9LPCPMRegs *pm = &s->pm; > >>+ > >>+ acpi_vm_generation_id_changed(&pm->acpi_regs, pm->irq); > >>+} > >>diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c > >>index 0bfa814..ad0ef68 100644 > >>--- a/hw/acpi/piix4.c > >>+++ b/hw/acpi/piix4.c > >>@@ -580,6 +580,13 @@ static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) > >> acpi_memory_ospm_status(&s->acpi_memory_hotplug, list); > >> } > >> > >>+static void piix4_vm_generation_id_changed(AcpiDeviceIf *adev) > >>+{ > >>+ PIIX4PMState *s = PIIX4_PM(adev); > >>+ > >>+ acpi_vm_generation_id_changed(&s->ar, s->irq); > >>+} > >>+ > >> static Property piix4_pm_properties[] = { > >> DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), > >> DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0), > >>@@ -617,6 +624,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) > >> hc->plug = piix4_device_plug_cb; > >> hc->unplug_request = piix4_device_unplug_request_cb; > >> adevc->ospm_status = piix4_ospm_status; > >>+ adevc->vm_generation_id_changed = piix4_vm_generation_id_changed; > >> } > >> > >> static const TypeInfo piix4_pm_info = { > >>diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > >>index 00be4bb..27d0494 100644 > >>--- a/hw/i386/acpi-build.c > >>+++ b/hw/i386/acpi-build.c > >>@@ -42,6 +42,7 @@ > >> #include "hw/acpi/memory_hotplug.h" > >> #include "sysemu/tpm.h" > >> #include "hw/acpi/tpm.h" > >>+#include "hw/misc/vmgenid.h" > >> > >> /* Supported chipsets: */ > >> #include "hw/acpi/piix4.h" > >>@@ -96,6 +97,7 @@ typedef struct AcpiMiscInfo { > >> const unsigned char *dsdt_code; > >> unsigned dsdt_size; > >> uint16_t pvpanic_port; > >>+ bool vm_generation_id_set; > >> } AcpiMiscInfo; > >> > >> typedef struct AcpiBuildPciBusHotplugState { > >>@@ -216,6 +218,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info) > >> info->has_hpet = hpet_find(); > >> info->has_tpm = tpm_find(); > >> info->pvpanic_port = pvpanic_port(); > >>+ info->vm_generation_id_set = vm_generation_id_set(); > >> } > >> > >> static void acpi_get_pci_info(PcPciInfo *info) > >>@@ -1088,6 +1091,11 @@ build_ssdt(GArray *table_data, GArray *linker, > >> ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), > >> ssdt_isa_pest[0], 16, misc->pvpanic_port); > >> > >>+ if (!misc->vm_generation_id_set) { > >>+ ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), > >>+ ssdt_acpi_vm_gid_addr[0], 32, 0); > >>+ } > >>+ > >> ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), > >> ssdt_mctrl_nr_slots[0], 32, nr_mem); > >> > >>diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl > >>index 559f4b6..10b4afb 100644 > >>--- a/hw/i386/acpi-dsdt.dsl > >>+++ b/hw/i386/acpi-dsdt.dsl > >>@@ -307,7 +307,9 @@ DefinitionBlock ( > >> Scope(\_GPE) { > >> Name(_HID, "ACPI0006") > >> > >>- Method(_L00) { > >>+ External(\_SB.VMGI, DeviceObj) > >>+ Method(_E00) { > >>+ Notify(\_SB.VMGI, 0x80) > >> } > >> Method(_E01) { > >> // PCI hotplug event > >>diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated > >>index a21bf41..3fd06d2 100644 > >>--- a/hw/i386/acpi-dsdt.hex.generated > >>+++ b/hw/i386/acpi-dsdt.hex.generated > >>@@ -8,7 +8,7 @@ static unsigned char AcpiDsdtAmlCode[] = { > >> 0x0, > >> 0x0, > >> 0x1, > >>-0x1f, > >>+0x18, > >> 0x42, > >> 0x58, > >> 0x50, > >>@@ -32,8 +32,8 @@ static unsigned char AcpiDsdtAmlCode[] = { > >> 0x54, > >> 0x4c, > >> 0x28, > >>-0x5, > >>-0x10, > >>+0x8, > >>+0x14, > >> 0x20, > >> 0x10, > >> 0x49, > >>diff --git a/hw/i386/pc.c b/hw/i386/pc.c > >>index d045e8b..95ec233 100644 > >>--- a/hw/i386/pc.c > >>+++ b/hw/i386/pc.c > >>@@ -59,6 +59,7 @@ > >> #include "hw/pci/pci_host.h" > >> #include "acpi-build.h" > >> #include "hw/mem/pc-dimm.h" > >>+#include "hw/misc/vmgenid.h" > >> #include "trace.h" > >> #include "qapi/visitor.h" > >> > >>@@ -1361,6 +1362,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, > >> int i; > >> DriveInfo *fd[MAX_FD]; > >> DeviceState *hpet = NULL; > >>+ DeviceState *vmgenid; > >> int pit_isa_irq = 0; > >> qemu_irq pit_alt_irq = NULL; > >> qemu_irq rtc_irq = NULL; > >>@@ -1459,6 +1461,12 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, > >> fd[i] = drive_get(IF_FLOPPY, 0, i); > >> } > >> *floppy = fdctrl_init_isa(isa_bus, fd); > >>+ > >>+ vmgenid = qdev_try_create(NULL, VMGENID_DEVICE); > >>+ if (vmgenid) { > >>+ qdev_init_nofail(vmgenid); > >>+ sysbus_mmio_map(SYS_BUS_DEVICE(vmgenid), 0, VMGENID_BASE_ADDRESS); > >>+ } > >> } > >> > >> void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) > >>diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl > >>index 054b035..b1d04e2 100644 > >>--- a/hw/i386/q35-acpi-dsdt.dsl > >>+++ b/hw/i386/q35-acpi-dsdt.dsl > >>@@ -415,7 +415,10 @@ DefinitionBlock ( > >> Scope(\_GPE) { > >> Name(_HID, "ACPI0006") > >> > >>- Method(_L00) { > >>+ External(\_SB.VMGI, DeviceObj) > >>+ Method(_E00) > >>+ { > >>+ Notify(\_SB.VMGI, 0x80) > >> } > >> Method(_L01) { > >> } > >>diff --git a/hw/i386/q35-acpi-dsdt.hex.generated b/hw/i386/q35-acpi-dsdt.hex.generated > >>index c9eb4ac..866e648 100644 > >>--- a/hw/i386/q35-acpi-dsdt.hex.generated > >>+++ b/hw/i386/q35-acpi-dsdt.hex.generated > >>@@ -8,7 +8,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { > >> 0x0, > >> 0x0, > >> 0x1, > >>-0xb7, > >>+0xac, > >> 0x42, > >> 0x58, > >> 0x50, > >>@@ -31,9 +31,9 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { > >> 0x4e, > >> 0x54, > >> 0x4c, > >>-0x15, > >>-0x11, > >>-0x13, > >>+0x28, > >>+0x8, > >>+0x14, > >> 0x20, > >> 0x10, > >> 0x49, > >>diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl > >>index 0fd4480..6ae09fb 100644 > >>--- a/hw/i386/ssdt-misc.dsl > >>+++ b/hw/i386/ssdt-misc.dsl > >>@@ -13,6 +13,7 @@ > >> * with this program; if not, see <http://www.gnu.org/licenses/>. > >> */ > >> #include "hw/acpi/pc-hotplug.h" > >>+#include "hw/misc/vmgenid.h" > >> > >> ACPI_EXTRACT_ALL_CODE ssdp_misc_aml > >> > >>@@ -118,6 +119,41 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1) > >> } > >> } > >> > >>+ Scope(\_SB) { > >>+ Device(VMGI) { > >>+ Name(_HID, "QEMU0002") > >>+ Name(_CID, "VM_Gen_Counter") > >>+ Name(_DDN, "VM_Gen_Counter") > >>+ > >>+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_acpi_vm_gid_addr > >>+ Name(VGIA, VMGENID_BASE_ADDRESS) > >>+ > >>+ OperationRegion(VGID, SystemMemory, > >>+ VMGENID_BASE_ADDRESS, VMGENID_BASE_ADDR_LEN) > >>+ > >>+ Name(_CRS, ResourceTemplate() { > >>+ Memory32Fixed(ReadOnly, > >>+ VMGENID_BASE_ADDRESS, VMGENID_BASE_ADDR_LEN) > >>+ }) > >>+ > >>+ Method(_STA, 0, NotSerialized) { > >>+ Store(VGIA, Local0) > >>+ If (LEqual(Local0, Zero)) { > >>+ Return (0x00) > >>+ } Else { > >>+ Return (0x0F) > >>+ } > >>+ } > >>+ > >>+ Method(ADDR, 0, Serialized) { > >>+ Store(Package(2) { }, Local0) > >>+ Store(VGIA, Index(Local0, 0)) > >>+ Store(0x0000, Index(Local0, 1)) > >>+ return (Local0) > >>+ } > >>+ } > >>+ } > >>+ > >> External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj) > >> Scope(\_SB.PCI0) { > >> Device(MEMORY_HOTPLUG_DEVICE) { > >>diff --git a/hw/i386/ssdt-misc.hex.generated b/hw/i386/ssdt-misc.hex.generated > >>index ba4268a..f0b7a27 100644 > >>--- a/hw/i386/ssdt-misc.hex.generated > >>+++ b/hw/i386/ssdt-misc.hex.generated > >>@@ -26,7 +26,7 @@ static unsigned char ssdp_misc_aml[] = { > >> 0x0, > >> 0x0, > >> 0x1, > >>-0x8b, > >>+0x80, > >> 0x42, > >> 0x58, > >> 0x50, > >>@@ -49,9 +49,9 @@ static unsigned char ssdp_misc_aml[] = { > >> 0x4e, > >> 0x54, > >> 0x4c, > >>-0x15, > >>-0x11, > >>-0x13, > >>+0x28, > >>+0x8, > >>+0x14, > >> 0x20, > >> 0x10, > >> 0x42, > >>diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c > >>index 530b074..3a012fa 100644 > >>--- a/hw/isa/lpc_ich9.c > >>+++ b/hw/isa/lpc_ich9.c > >>@@ -678,6 +678,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) > >> hc->plug = ich9_device_plug_cb; > >> hc->unplug_request = ich9_device_unplug_request_cb; > >> adevc->ospm_status = ich9_pm_ospm_status; > >>+ adevc->vm_generation_id_changed = ich9_vm_generation_id_changed; > >> } > >> > >> static const TypeInfo ich9_lpc_info = { > >>diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs > >>index 979e532..c18b800 100644 > >>--- a/hw/misc/Makefile.objs > >>+++ b/hw/misc/Makefile.objs > >>@@ -41,3 +41,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o > >> obj-$(CONFIG_ZYNQ) += zynq_slcr.o > >> > >> obj-$(CONFIG_PVPANIC) += pvpanic.o > >>+obj-$(CONFIG_VMGENID) += vmgenid.o > >>diff --git a/hw/misc/vmgenid.c b/hw/misc/vmgenid.c > >>new file mode 100644 > >>index 0000000..01aacd4 > >>--- /dev/null > >>+++ b/hw/misc/vmgenid.c > >>@@ -0,0 +1,116 @@ > >>+/* > >>+ * Virtual Machine Generation ID Device > >>+ * > >>+ * Copyright (C) 2014 Red Hat Inc. > >>+ * > >>+ * Authors: Gal Hammer <ghammer@redhat.com> > >>+ * > >>+ * This work is licensed under the terms of the GNU GPL, version 2 or later. > >>+ * See the COPYING file in the top-level directory. > >>+ * > >>+ */ > >>+ > >>+#include "hw/i386/pc.h" > >>+#include "hw/sysbus.h" > >>+#include "hw/misc/vmgenid.h" > >>+#include "hw/acpi/acpi_dev_interface.h" > >>+ > >>+#define PROPERTY_UUID "uuid" > >>+ > >>+#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE) > >>+ > >>+typedef struct VmGenIdState { > >>+ SysBusDevice parent_obj; > >>+ MemoryRegion iomem; > >>+ uint8_t guid[16]; > >>+ bool guid_set; > >>+} VmGenIdState; > >>+ > >>+bool vm_generation_id_set(void) > >>+{ > >>+ Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL); > >>+ VmGenIdState *s = VMGENID(obj); > >>+ > >>+ if (!obj) { > >>+ return false; > >>+ } > >>+ return s->guid_set; > >>+} > >>+ > >>+static uint64_t vmgenid_ram_read(void *opaque, hwaddr addr, > >>+ unsigned size) > >>+{ > >>+ VmGenIdState *s = VMGENID(opaque); > >>+ uint64_t value; > >>+ > >>+ memcpy(&value, s->guid + addr, size); > >>+ return value; > >>+} > >>+ > >>+static const MemoryRegionOps vmgenid_ram_ops = { > >>+ .read = vmgenid_ram_read, > >>+ .valid = { > >>+ .min_access_size = 4, > >>+ .max_access_size = 4, > >>+ }, > >>+ .endianness = DEVICE_NATIVE_ENDIAN, > >>+}; > >>+ > >>+static void vmgenid_set_uuid(Object *obj, const char *value, Error **errp) > >>+{ > >>+ VmGenIdState *s = VMGENID(obj); > >>+ Object *acpi_obj; > >>+ bool first_set = !s->guid_set; > >>+ > >>+ if (qemu_uuid_parse(value, s->guid) < 0) { > >>+ error_setg(errp, "Fail to parse UUID string."); > >>+ return; > >>+ } > >>+ s->guid_set = true; > >>+ > >>+ /* Skip the acpi notification when setting the vm generation id for the > >>+ * first time. This is done because in a q35 machine the gpe register is > >>+ * allocated after the device is initialized. */ > >>+ if (!first_set) { > >>+ acpi_obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); > >>+ if (acpi_obj) { > >>+ AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(acpi_obj); > >>+ AcpiDeviceIf *adev = ACPI_DEVICE_IF(acpi_obj); > >>+ > >>+ adevc->vm_generation_id_changed(adev); > >>+ } > >>+ } > >>+} > >>+ > >>+static void vmgenid_init(Object *obj) > >>+{ > >>+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj); > >>+ VmGenIdState *s = VMGENID(obj); > >>+ > >>+ memory_region_init_io(&s->iomem, obj, &vmgenid_ram_ops, s, "vgid", 16); > >>+ sysbus_init_mmio(sbd, &s->iomem); > > > >This will cause an exit on each access to the GID. > >I'm guessing this is too expensive. > > Yes, it does cause an exit, but I don't think it is critical because the GID > is rarely read by the guest OS. As far as I can tell it is only accessed on > reboot and when the GID is changed. > > Do you prefer that I'll use the cpu_physical_memory_write function? Or do > you have a diffrent idea on how to implement it? I think you need to get hold of some RAM, and use that. For example, allocate a buffer, pass the address to host in _INI. > > > > > >>+ > >>+ object_property_add_str(obj, PROPERTY_UUID, NULL, vmgenid_set_uuid, NULL); > >>+} > >>+ > >>+static void vmgenid_class_init(ObjectClass *klass, void *data) > >>+{ > >>+ DeviceClass *dc = DEVICE_CLASS(klass); > >>+ > >>+ set_bit(DEVICE_CATEGORY_MISC, dc->categories); > >>+} > >>+ > >>+static const TypeInfo vmgenid_device_info = { > >>+ .name = VMGENID_DEVICE, > >>+ .parent = TYPE_SYS_BUS_DEVICE, > >>+ .instance_size = sizeof(VmGenIdState), > >>+ .instance_init = vmgenid_init, > >>+ .class_init = vmgenid_class_init, > >>+}; > >>+ > >>+static void vmgenid_register_types(void) > >>+{ > >>+ type_register_static(&vmgenid_device_info); > >>+} > >>+ > >>+type_init(vmgenid_register_types) > >>diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h > >>index 1f678b4..9373b4d 100644 > >>--- a/include/hw/acpi/acpi.h > >>+++ b/include/hw/acpi/acpi.h > >>@@ -185,4 +185,6 @@ unsigned acpi_table_len(void *current); > >> void acpi_table_add(const QemuOpts *opts, Error **errp); > >> void acpi_table_add_builtin(const QemuOpts *opts, Error **errp); > >> > >>+void acpi_vm_generation_id_changed(ACPIREGS *acpi_regs, qemu_irq irq); > >>+ > >> #endif /* !QEMU_HW_ACPI_H */ > >>diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h > >>index f245f8d..757ce60 100644 > >>--- a/include/hw/acpi/acpi_dev_interface.h > >>+++ b/include/hw/acpi/acpi_dev_interface.h > >>@@ -28,6 +28,9 @@ typedef struct AcpiDeviceIf { > >> * ospm_status: returns status of ACPI device objects, reported > >> * via _OST method if device supports it. > >> * > >>+ * vm_generation_id_changed: notify the guest that it generation > >>+ * id was changed. > >>+ * > >> * Interface is designed for providing unified interface > >> * to generic ACPI functionality that could be used without > >> * knowledge about internals of actual device that implements > >>@@ -39,5 +42,6 @@ typedef struct AcpiDeviceIfClass { > >> > >> /* <public> */ > >> void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); > >>+ void (*vm_generation_id_changed)(AcpiDeviceIf *adev); > >> } AcpiDeviceIfClass; > >> #endif > >>diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h > >>index 7e42448..3b4eed5 100644 > >>--- a/include/hw/acpi/ich9.h > >>+++ b/include/hw/acpi/ich9.h > >>@@ -62,4 +62,6 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp); > >> void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp); > >> > >> void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); > >>+ > >>+void ich9_vm_generation_id_changed(AcpiDeviceIf *adev); > >> #endif /* HW_ACPI_ICH9_H */ > >>diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h > >>index 1c2602e..87912b2 100644 > >>--- a/include/hw/i386/pc.h > >>+++ b/include/hw/i386/pc.h > >>@@ -290,6 +290,9 @@ void pc_system_firmware_init(MemoryRegion *rom_memory, > >> /* pvpanic.c */ > >> uint16_t pvpanic_port(void); > >> > >>+/* vmgenid.c */ > >>+bool vm_generation_id_set(void); > >>+ > >> /* e820 types */ > >> #define E820_RAM 1 > >> #define E820_RESERVED 2 > >>diff --git a/include/hw/misc/vmgenid.h b/include/hw/misc/vmgenid.h > >>new file mode 100644 > >>index 0000000..3d44421 > >>--- /dev/null > >>+++ b/include/hw/misc/vmgenid.h > >>@@ -0,0 +1,21 @@ > >>+/* > >>+ * Virtual Machine Generation ID Device > >>+ * > >>+ * Copyright (C) 2014 Red Hat Inc. > >>+ * > >>+ * Authors: Gal Hammer <ghammer@redhat.com> > >>+ * > >>+ * This work is licensed under the terms of the GNU GPL, version 2 or later. > >>+ * See the COPYING file in the top-level directory. > >>+ * > >>+ */ > >>+ > >>+#ifndef HW_MISC_VMGENID_H > >>+#define HW_MISC_VMGENID_H > >>+ > >>+#define VMGENID_DEVICE "vmgenid" > >>+ > >>+#define VMGENID_BASE_ADDRESS 0xfedf0000 > >>+#define VMGENID_BASE_ADDR_LEN 16 > >>+ > >>+#endif > >>-- > >>1.9.3
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 8e08841..bd33c75 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -45,3 +45,4 @@ CONFIG_IOAPIC=y CONFIG_ICC_BUS=y CONFIG_PVPANIC=y CONFIG_MEM_HOTPLUG=y +CONFIG_VMGENID=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 66557ac..006fc7c 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -45,3 +45,4 @@ CONFIG_IOAPIC=y CONFIG_ICC_BUS=y CONFIG_PVPANIC=y CONFIG_MEM_HOTPLUG=y +CONFIG_VMGENID=y diff --git a/hw/acpi/core.c b/hw/acpi/core.c index a7368fb..a01c980 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -28,6 +28,8 @@ #include "qapi-visit.h" #include "qapi-event.h" +#define ACPI_VM_GENERATION_ID_CHANGED_STATUS 1 + struct acpi_table_header { uint16_t _length; /* our length, not actual part of the hdr */ /* allows easier parsing for fw_cfg clients */ @@ -680,3 +682,9 @@ void acpi_update_sci(ACPIREGS *regs, qemu_irq irq) (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS)); } + +void acpi_vm_generation_id_changed(ACPIREGS *acpi_regs, qemu_irq irq) +{ + acpi_regs->gpe.sts[0] |= ACPI_VM_GENERATION_ID_CHANGED_STATUS; + acpi_update_sci(acpi_regs, irq); +} diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 7b14bbb..5501c0e 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -316,3 +316,11 @@ void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); } + +void ich9_vm_generation_id_changed(AcpiDeviceIf *adev) +{ + ICH9LPCState *s = ICH9_LPC_DEVICE(adev); + ICH9LPCPMRegs *pm = &s->pm; + + acpi_vm_generation_id_changed(&pm->acpi_regs, pm->irq); +} diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 0bfa814..ad0ef68 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -580,6 +580,13 @@ static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) acpi_memory_ospm_status(&s->acpi_memory_hotplug, list); } +static void piix4_vm_generation_id_changed(AcpiDeviceIf *adev) +{ + PIIX4PMState *s = PIIX4_PM(adev); + + acpi_vm_generation_id_changed(&s->ar, s->irq); +} + static Property piix4_pm_properties[] = { DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0), @@ -617,6 +624,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) hc->plug = piix4_device_plug_cb; hc->unplug_request = piix4_device_unplug_request_cb; adevc->ospm_status = piix4_ospm_status; + adevc->vm_generation_id_changed = piix4_vm_generation_id_changed; } static const TypeInfo piix4_pm_info = { diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 00be4bb..27d0494 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -42,6 +42,7 @@ #include "hw/acpi/memory_hotplug.h" #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" +#include "hw/misc/vmgenid.h" /* Supported chipsets: */ #include "hw/acpi/piix4.h" @@ -96,6 +97,7 @@ typedef struct AcpiMiscInfo { const unsigned char *dsdt_code; unsigned dsdt_size; uint16_t pvpanic_port; + bool vm_generation_id_set; } AcpiMiscInfo; typedef struct AcpiBuildPciBusHotplugState { @@ -216,6 +218,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info) info->has_hpet = hpet_find(); info->has_tpm = tpm_find(); info->pvpanic_port = pvpanic_port(); + info->vm_generation_id_set = vm_generation_id_set(); } static void acpi_get_pci_info(PcPciInfo *info) @@ -1088,6 +1091,11 @@ build_ssdt(GArray *table_data, GArray *linker, ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), ssdt_isa_pest[0], 16, misc->pvpanic_port); + if (!misc->vm_generation_id_set) { + ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), + ssdt_acpi_vm_gid_addr[0], 32, 0); + } + ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml), ssdt_mctrl_nr_slots[0], 32, nr_mem); diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl index 559f4b6..10b4afb 100644 --- a/hw/i386/acpi-dsdt.dsl +++ b/hw/i386/acpi-dsdt.dsl @@ -307,7 +307,9 @@ DefinitionBlock ( Scope(\_GPE) { Name(_HID, "ACPI0006") - Method(_L00) { + External(\_SB.VMGI, DeviceObj) + Method(_E00) { + Notify(\_SB.VMGI, 0x80) } Method(_E01) { // PCI hotplug event diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated index a21bf41..3fd06d2 100644 --- a/hw/i386/acpi-dsdt.hex.generated +++ b/hw/i386/acpi-dsdt.hex.generated @@ -8,7 +8,7 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x0, 0x0, 0x1, -0x1f, +0x18, 0x42, 0x58, 0x50, @@ -32,8 +32,8 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x54, 0x4c, 0x28, -0x5, -0x10, +0x8, +0x14, 0x20, 0x10, 0x49, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d045e8b..95ec233 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -59,6 +59,7 @@ #include "hw/pci/pci_host.h" #include "acpi-build.h" #include "hw/mem/pc-dimm.h" +#include "hw/misc/vmgenid.h" #include "trace.h" #include "qapi/visitor.h" @@ -1361,6 +1362,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, int i; DriveInfo *fd[MAX_FD]; DeviceState *hpet = NULL; + DeviceState *vmgenid; int pit_isa_irq = 0; qemu_irq pit_alt_irq = NULL; qemu_irq rtc_irq = NULL; @@ -1459,6 +1461,12 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, fd[i] = drive_get(IF_FLOPPY, 0, i); } *floppy = fdctrl_init_isa(isa_bus, fd); + + vmgenid = qdev_try_create(NULL, VMGENID_DEVICE); + if (vmgenid) { + qdev_init_nofail(vmgenid); + sysbus_mmio_map(SYS_BUS_DEVICE(vmgenid), 0, VMGENID_BASE_ADDRESS); + } } void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl index 054b035..b1d04e2 100644 --- a/hw/i386/q35-acpi-dsdt.dsl +++ b/hw/i386/q35-acpi-dsdt.dsl @@ -415,7 +415,10 @@ DefinitionBlock ( Scope(\_GPE) { Name(_HID, "ACPI0006") - Method(_L00) { + External(\_SB.VMGI, DeviceObj) + Method(_E00) + { + Notify(\_SB.VMGI, 0x80) } Method(_L01) { } diff --git a/hw/i386/q35-acpi-dsdt.hex.generated b/hw/i386/q35-acpi-dsdt.hex.generated index c9eb4ac..866e648 100644 --- a/hw/i386/q35-acpi-dsdt.hex.generated +++ b/hw/i386/q35-acpi-dsdt.hex.generated @@ -8,7 +8,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x0, 0x0, 0x1, -0xb7, +0xac, 0x42, 0x58, 0x50, @@ -31,9 +31,9 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x4e, 0x54, 0x4c, -0x15, -0x11, -0x13, +0x28, +0x8, +0x14, 0x20, 0x10, 0x49, diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl index 0fd4480..6ae09fb 100644 --- a/hw/i386/ssdt-misc.dsl +++ b/hw/i386/ssdt-misc.dsl @@ -13,6 +13,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw/acpi/pc-hotplug.h" +#include "hw/misc/vmgenid.h" ACPI_EXTRACT_ALL_CODE ssdp_misc_aml @@ -118,6 +119,41 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1) } } + Scope(\_SB) { + Device(VMGI) { + Name(_HID, "QEMU0002") + Name(_CID, "VM_Gen_Counter") + Name(_DDN, "VM_Gen_Counter") + + ACPI_EXTRACT_NAME_DWORD_CONST ssdt_acpi_vm_gid_addr + Name(VGIA, VMGENID_BASE_ADDRESS) + + OperationRegion(VGID, SystemMemory, + VMGENID_BASE_ADDRESS, VMGENID_BASE_ADDR_LEN) + + Name(_CRS, ResourceTemplate() { + Memory32Fixed(ReadOnly, + VMGENID_BASE_ADDRESS, VMGENID_BASE_ADDR_LEN) + }) + + Method(_STA, 0, NotSerialized) { + Store(VGIA, Local0) + If (LEqual(Local0, Zero)) { + Return (0x00) + } Else { + Return (0x0F) + } + } + + Method(ADDR, 0, Serialized) { + Store(Package(2) { }, Local0) + Store(VGIA, Index(Local0, 0)) + Store(0x0000, Index(Local0, 1)) + return (Local0) + } + } + } + External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj) Scope(\_SB.PCI0) { Device(MEMORY_HOTPLUG_DEVICE) { diff --git a/hw/i386/ssdt-misc.hex.generated b/hw/i386/ssdt-misc.hex.generated index ba4268a..f0b7a27 100644 --- a/hw/i386/ssdt-misc.hex.generated +++ b/hw/i386/ssdt-misc.hex.generated @@ -26,7 +26,7 @@ static unsigned char ssdp_misc_aml[] = { 0x0, 0x0, 0x1, -0x8b, +0x80, 0x42, 0x58, 0x50, @@ -49,9 +49,9 @@ static unsigned char ssdp_misc_aml[] = { 0x4e, 0x54, 0x4c, -0x15, -0x11, -0x13, +0x28, +0x8, +0x14, 0x20, 0x10, 0x42, diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 530b074..3a012fa 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -678,6 +678,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) hc->plug = ich9_device_plug_cb; hc->unplug_request = ich9_device_unplug_request_cb; adevc->ospm_status = ich9_pm_ospm_status; + adevc->vm_generation_id_changed = ich9_vm_generation_id_changed; } static const TypeInfo ich9_lpc_info = { diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 979e532..c18b800 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -41,3 +41,4 @@ obj-$(CONFIG_SLAVIO) += slavio_misc.o obj-$(CONFIG_ZYNQ) += zynq_slcr.o obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-$(CONFIG_VMGENID) += vmgenid.o diff --git a/hw/misc/vmgenid.c b/hw/misc/vmgenid.c new file mode 100644 index 0000000..01aacd4 --- /dev/null +++ b/hw/misc/vmgenid.c @@ -0,0 +1,116 @@ +/* + * Virtual Machine Generation ID Device + * + * Copyright (C) 2014 Red Hat Inc. + * + * Authors: Gal Hammer <ghammer@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "hw/i386/pc.h" +#include "hw/sysbus.h" +#include "hw/misc/vmgenid.h" +#include "hw/acpi/acpi_dev_interface.h" + +#define PROPERTY_UUID "uuid" + +#define VMGENID(obj) OBJECT_CHECK(VmGenIdState, (obj), VMGENID_DEVICE) + +typedef struct VmGenIdState { + SysBusDevice parent_obj; + MemoryRegion iomem; + uint8_t guid[16]; + bool guid_set; +} VmGenIdState; + +bool vm_generation_id_set(void) +{ + Object *obj = object_resolve_path_type("", VMGENID_DEVICE, NULL); + VmGenIdState *s = VMGENID(obj); + + if (!obj) { + return false; + } + return s->guid_set; +} + +static uint64_t vmgenid_ram_read(void *opaque, hwaddr addr, + unsigned size) +{ + VmGenIdState *s = VMGENID(opaque); + uint64_t value; + + memcpy(&value, s->guid + addr, size); + return value; +} + +static const MemoryRegionOps vmgenid_ram_ops = { + .read = vmgenid_ram_read, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void vmgenid_set_uuid(Object *obj, const char *value, Error **errp) +{ + VmGenIdState *s = VMGENID(obj); + Object *acpi_obj; + bool first_set = !s->guid_set; + + if (qemu_uuid_parse(value, s->guid) < 0) { + error_setg(errp, "Fail to parse UUID string."); + return; + } + s->guid_set = true; + + /* Skip the acpi notification when setting the vm generation id for the + * first time. This is done because in a q35 machine the gpe register is + * allocated after the device is initialized. */ + if (!first_set) { + acpi_obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); + if (acpi_obj) { + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(acpi_obj); + AcpiDeviceIf *adev = ACPI_DEVICE_IF(acpi_obj); + + adevc->vm_generation_id_changed(adev); + } + } +} + +static void vmgenid_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + VmGenIdState *s = VMGENID(obj); + + memory_region_init_io(&s->iomem, obj, &vmgenid_ram_ops, s, "vgid", 16); + sysbus_init_mmio(sbd, &s->iomem); + + object_property_add_str(obj, PROPERTY_UUID, NULL, vmgenid_set_uuid, NULL); +} + +static void vmgenid_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo vmgenid_device_info = { + .name = VMGENID_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(VmGenIdState), + .instance_init = vmgenid_init, + .class_init = vmgenid_class_init, +}; + +static void vmgenid_register_types(void) +{ + type_register_static(&vmgenid_device_info); +} + +type_init(vmgenid_register_types) diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h index 1f678b4..9373b4d 100644 --- a/include/hw/acpi/acpi.h +++ b/include/hw/acpi/acpi.h @@ -185,4 +185,6 @@ unsigned acpi_table_len(void *current); void acpi_table_add(const QemuOpts *opts, Error **errp); void acpi_table_add_builtin(const QemuOpts *opts, Error **errp); +void acpi_vm_generation_id_changed(ACPIREGS *acpi_regs, qemu_irq irq); + #endif /* !QEMU_HW_ACPI_H */ diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h index f245f8d..757ce60 100644 --- a/include/hw/acpi/acpi_dev_interface.h +++ b/include/hw/acpi/acpi_dev_interface.h @@ -28,6 +28,9 @@ typedef struct AcpiDeviceIf { * ospm_status: returns status of ACPI device objects, reported * via _OST method if device supports it. * + * vm_generation_id_changed: notify the guest that it generation + * id was changed. + * * Interface is designed for providing unified interface * to generic ACPI functionality that could be used without * knowledge about internals of actual device that implements @@ -39,5 +42,6 @@ typedef struct AcpiDeviceIfClass { /* <public> */ void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); + void (*vm_generation_id_changed)(AcpiDeviceIf *adev); } AcpiDeviceIfClass; #endif diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index 7e42448..3b4eed5 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -62,4 +62,6 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp); void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp); void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); + +void ich9_vm_generation_id_changed(AcpiDeviceIf *adev); #endif /* HW_ACPI_ICH9_H */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 1c2602e..87912b2 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -290,6 +290,9 @@ void pc_system_firmware_init(MemoryRegion *rom_memory, /* pvpanic.c */ uint16_t pvpanic_port(void); +/* vmgenid.c */ +bool vm_generation_id_set(void); + /* e820 types */ #define E820_RAM 1 #define E820_RESERVED 2 diff --git a/include/hw/misc/vmgenid.h b/include/hw/misc/vmgenid.h new file mode 100644 index 0000000..3d44421 --- /dev/null +++ b/include/hw/misc/vmgenid.h @@ -0,0 +1,21 @@ +/* + * Virtual Machine Generation ID Device + * + * Copyright (C) 2014 Red Hat Inc. + * + * Authors: Gal Hammer <ghammer@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_MISC_VMGENID_H +#define HW_MISC_VMGENID_H + +#define VMGENID_DEVICE "vmgenid" + +#define VMGENID_BASE_ADDRESS 0xfedf0000 +#define VMGENID_BASE_ADDR_LEN 16 + +#endif
Based on Microsoft's sepecifications (paper can be dowloaded from http://go.microsoft.com/fwlink/?LinkId=260709), add a device description to the SSDT ACPI table and its implementation. The GUID is set using a global "vmgenid.uuid" parameter. Signed-off-by: Gal Hammer <ghammer@redhat.com> --- default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + hw/acpi/core.c | 8 +++ hw/acpi/ich9.c | 8 +++ hw/acpi/piix4.c | 8 +++ hw/i386/acpi-build.c | 8 +++ hw/i386/acpi-dsdt.dsl | 4 +- hw/i386/acpi-dsdt.hex.generated | 6 +- hw/i386/pc.c | 8 +++ hw/i386/q35-acpi-dsdt.dsl | 5 +- hw/i386/q35-acpi-dsdt.hex.generated | 8 +-- hw/i386/ssdt-misc.dsl | 36 +++++++++++ hw/i386/ssdt-misc.hex.generated | 8 +-- hw/isa/lpc_ich9.c | 1 + hw/misc/Makefile.objs | 1 + hw/misc/vmgenid.c | 116 +++++++++++++++++++++++++++++++++++ include/hw/acpi/acpi.h | 2 + include/hw/acpi/acpi_dev_interface.h | 4 ++ include/hw/acpi/ich9.h | 2 + include/hw/i386/pc.h | 3 + include/hw/misc/vmgenid.h | 21 +++++++ 21 files changed, 246 insertions(+), 13 deletions(-) create mode 100644 hw/misc/vmgenid.c create mode 100644 include/hw/misc/vmgenid.h