Message ID | 1445612242-79172-7-git-send-email-imammedo@redhat.com |
---|---|
State | New |
Headers | show |
On Fri, Oct 23, 2015 at 04:57:09PM +0200, Igor Mammedov wrote: > + /* copy AML table into ACPI tables blob and patch header there */ > + g_array_append_vals(table_data, table->buf->data, table->buf->len); > + build_header(linker, table_data, > + (void *)(table_data->data + table_data->len - table->buf->len), > + "MHPT", table->buf->len, 2); > + free_aml_allocator(); > +} Why not just put this in an SSDT? And what guarantees that there won't be an MHPT table in a future version of the spec, conflicting with this use?
On Fri, Oct 23, 2015 at 04:57:09PM +0200, Igor Mammedov wrote: > moves SSDT part to custom MHPT table, which is loaded > at runtime by OSPM if it supports ACPIv2 revision and > only if memory hotplug is enabled. > That should reduce ACPI tables blob size if memory > hotplug is not enabled (default case). With seabios, it's still in reserved memory. How does it help? And this trick likely breaks UEFI. I just checked, the only legal way to specify OEM specific tables seems to be using OEMX prefix. But there's a decent chance this will conflict with people using command line flags to load their own tables. This likely means this trick is off. > Checked for compatibility issues with: > * Windows XPsp3, Windows Server 2003: they don't load > the table as OSPM only reports revision 1 as supported. > And we don't care about memhp for these guests as they > do not support it anyway. > * Windows Server 2008, Windows Server 2008R2: > works as expected > > Signed-off-by: Igor Mammedov <imammedo@redhat.com> > --- > hw/acpi/Makefile.objs | 2 +- > hw/acpi/memory_hotplug_acpi_table.c | 138 ++++++++++++++++++++++++++++++++++++ > hw/i386/acpi-build.c | 130 +++++---------------------------- > include/hw/acpi/memory_hotplug.h | 3 + > 4 files changed, 159 insertions(+), 114 deletions(-) > create mode 100644 hw/acpi/memory_hotplug_acpi_table.c > > diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs > index 7d3230c..c04064e 100644 > --- a/hw/acpi/Makefile.objs > +++ b/hw/acpi/Makefile.objs > @@ -1,7 +1,7 @@ > common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o > common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o > common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o > -common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o > +common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o > common-obj-$(CONFIG_ACPI) += acpi_interface.o > common-obj-$(CONFIG_ACPI) += bios-linker-loader.o > common-obj-$(CONFIG_ACPI) += aml-build.o > diff --git a/hw/acpi/memory_hotplug_acpi_table.c b/hw/acpi/memory_hotplug_acpi_table.c > new file mode 100644 > index 0000000..28da13c > --- /dev/null > +++ b/hw/acpi/memory_hotplug_acpi_table.c > @@ -0,0 +1,138 @@ > +#include <stdbool.h> > +#include "hw/acpi/aml-build.h" > +#include "hw/acpi/memory_hotplug.h" > +#include "include/hw/acpi/pc-hotplug.h" > +#include "hw/boards.h" > + > +#define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." > + > +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, > + uint16_t io_base, uint16_t io_len) > +{ > + int i; > + Aml *table, *sb_scope, *dev, *method, *ifctx, *ctrl_dev; > + > + table = init_aml_allocator(); > + acpi_data_push(table->buf, sizeof(AcpiTableHeader)); > + > + /* scope for memory hotplug controller device node */ > + assert(nr_mem <= ACPI_MAX_RAM_SLOTS); > + ctrl_dev = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); > + { > + Aml *crs, *field; > + > + aml_append(ctrl_dev, > + aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) > + ); > + > + crs = aml_resource_template(); > + aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 0, io_len)); > + aml_append(ctrl_dev, aml_name_decl("_CRS", crs)); > + > + aml_append(ctrl_dev, aml_operation_region( > + stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, > + io_base, io_len) > + ); > + > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > + AML_PRESERVE); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); > + aml_append(ctrl_dev, field); > + > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, > + AML_WRITE_AS_ZEROS); > + aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); > + aml_append(field, /* 1 if enabled, read only */ > + aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); > + aml_append(field, > + /*(read) 1 if has a insert event. (write) 1 to clear event */ > + aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); > + aml_append(field, > + /* (read) 1 if has a remove event. (write) 1 to clear event */ > + aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); > + aml_append(field, > + /* initiates device eject, write only */ > + aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); > + aml_append(ctrl_dev, field); > + > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > + AML_PRESERVE); > + aml_append(field, /* DIMM selector, write only */ > + aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); > + aml_append(field, /* _OST event code, write only */ > + aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); > + aml_append(field, /* _OST status code, write only */ > + aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); > + aml_append(ctrl_dev, field); > + } > + aml_append(table, ctrl_dev); > + > + sb_scope = aml_scope("\\_SB"); > + for (i = 0; i < nr_mem; i++) { > + const char *s; > + > + dev = aml_device("MP%02X", i); > + aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); > + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); > + > + method = aml_method("_CRS", 0); > + s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > + aml_append(dev, method); > + > + method = aml_method("_STA", 0); > + s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > + aml_append(dev, method); > + > + method = aml_method("_PXM", 0); > + s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > + aml_append(dev, method); > + > + method = aml_method("_OST", 3); > + s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); > + aml_append(method, aml_return(aml_call4( > + s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) > + ))); > + aml_append(dev, method); > + > + method = aml_method("_EJ0", 1); > + s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); > + aml_append(method, aml_return(aml_call2( > + s, aml_name("_UID"), aml_arg(0)))); > + aml_append(dev, method); > + > + aml_append(sb_scope, dev); > + } > + > + /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { > + * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } > + */ > + method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); > + for (i = 0; i < nr_mem; i++) { > + ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); > + aml_append(ifctx, > + aml_notify(aml_name("MP%.02X", i), aml_arg(1)) > + ); > + aml_append(method, ifctx); > + } > + aml_append(sb_scope, method); > + aml_append(table, sb_scope); > + > + /* copy AML table into ACPI tables blob and patch header there */ > + g_array_append_vals(table_data, table->buf->data, table->buf->len); > + build_header(linker, table_data, > + (void *)(table_data->data + table_data->len - table->buf->len), > + "MHPT", table->buf->len, 2); > + free_aml_allocator(); > +} > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > index 95e0c65..8add4d9 100644 > --- a/hw/i386/acpi-build.c > +++ b/hw/i386/acpi-build.c > @@ -925,6 +925,16 @@ build_ssdt(GArray *table_data, GArray *linker, > /* Reserve space for header */ > acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader)); > > + sb_scope = aml_scope("\\_SB"); > + method = aml_method("_INI", 0); > + ifctx = aml_if(aml_lgreater_equal(aml_name("_REV"), aml_int(2))); > + if (nr_mem) { > + aml_append(ifctx, aml_load_table("MHPT")); > + } > + aml_append(method, ifctx); > + aml_append(sb_scope, method); > + aml_append(ssdt, sb_scope); > + > /* Extra PCI root buses are implemented only for i440fx */ > bus = find_i440fx(); > if (bus) { > @@ -1200,119 +1210,6 @@ build_ssdt(GArray *table_data, GArray *linker, > } > aml_append(sb_scope, aml_name_decl("CPON", pkg)); > > - /* build memory devices */ > - assert(nr_mem <= ACPI_MAX_RAM_SLOTS); > - scope = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); > - aml_append(scope, > - aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) > - ); > - > - crs = aml_resource_template(); > - aml_append(crs, > - aml_io(AML_DECODE16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0, > - pm->mem_hp_io_len) > - ); > - aml_append(scope, aml_name_decl("_CRS", crs)); > - > - aml_append(scope, aml_operation_region( > - stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, > - pm->mem_hp_io_base, pm->mem_hp_io_len) > - ); > - > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > - AML_PRESERVE); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); > - aml_append(scope, field); > - > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, > - AML_WRITE_AS_ZEROS); > - aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); > - aml_append(field, /* 1 if enabled, read only */ > - aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); > - aml_append(field, > - /*(read) 1 if has a insert event. (write) 1 to clear event */ > - aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); > - aml_append(field, > - /* (read) 1 if has a remove event. (write) 1 to clear event */ > - aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); > - aml_append(field, > - /* initiates device eject, write only */ > - aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); > - aml_append(scope, field); > - > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > - AML_PRESERVE); > - aml_append(field, /* DIMM selector, write only */ > - aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); > - aml_append(field, /* _OST event code, write only */ > - aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); > - aml_append(field, /* _OST status code, write only */ > - aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); > - aml_append(scope, field); > - > - aml_append(sb_scope, scope); > - > - for (i = 0; i < nr_mem; i++) { > - #define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." > - const char *s; > - > - dev = aml_device("MP%02X", i); > - aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); > - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); > - > - method = aml_method("_CRS", 0); > - s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > - aml_append(dev, method); > - > - method = aml_method("_STA", 0); > - s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > - aml_append(dev, method); > - > - method = aml_method("_PXM", 0); > - s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > - aml_append(dev, method); > - > - method = aml_method("_OST", 3); > - s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); > - aml_append(method, aml_return(aml_call4( > - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) > - ))); > - aml_append(dev, method); > - > - method = aml_method("_EJ0", 1); > - s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); > - aml_append(method, aml_return(aml_call2( > - s, aml_name("_UID"), aml_arg(0)))); > - aml_append(dev, method); > - > - aml_append(sb_scope, dev); > - } > - > - /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { > - * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } > - */ > - method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); > - for (i = 0; i < nr_mem; i++) { > - ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); > - aml_append(ifctx, > - aml_notify(aml_name("MP%.02X", i), aml_arg(1)) > - ); > - aml_append(method, ifctx); > - } > - aml_append(sb_scope, method); > - > { > Object *pci_host; > PCIBus *bus = NULL; > @@ -1671,6 +1568,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) > uint8_t *u; > size_t aml_len = 0; > GArray *tables_blob = tables->table_data; > + MachineState *machine = MACHINE(qdev_get_machine()); > > acpi_get_cpu_info(&cpu); > acpi_get_pm_info(&pm); > @@ -1742,6 +1640,12 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) > build_dmar_q35(tables_blob, tables->linker); > } > > + if (machine->ram_slots) { > + acpi_add_table(table_offsets, tables_blob); > + build_mhpt(tables_blob, tables->linker, machine->ram_slots, > + pm.mem_hp_io_base, pm.mem_hp_io_len); > + } > + > /* Add tables supplied by user (if any) */ > for (u = acpi_table_first(); u; u = acpi_table_next(u)) { > unsigned len = acpi_table_len(u); > diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h > index 1342adb..5fd2854 100644 > --- a/include/hw/acpi/memory_hotplug.h > +++ b/include/hw/acpi/memory_hotplug.h > @@ -45,4 +45,7 @@ extern const VMStateDescription vmstate_memory_hotplug; > vmstate_memory_hotplug, MemHotplugState) > > void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); > + > +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, > + uint16_t io_base, uint16_t io_len); > #endif > -- > 1.8.3.1
On Fri, Oct 23, 2015 at 04:57:09PM +0200, Igor Mammedov wrote: > moves SSDT part to custom MHPT table, which is loaded > at runtime by OSPM if it supports ACPIv2 revision and > only if memory hotplug is enabled. > That should reduce ACPI tables blob size if memory > hotplug is not enabled (default case). > > Checked for compatibility issues with: > * Windows XPsp3, Windows Server 2003: they don't load > the table as OSPM only reports revision 1 as supported. > And we don't care about memhp for these guests as they > do not support it anyway. > * Windows Server 2008, Windows Server 2008R2: > works as expected > > Signed-off-by: Igor Mammedov <imammedo@redhat.com> > --- > hw/acpi/Makefile.objs | 2 +- > hw/acpi/memory_hotplug_acpi_table.c | 138 ++++++++++++++++++++++++++++++++++++ > hw/i386/acpi-build.c | 130 +++++---------------------------- > include/hw/acpi/memory_hotplug.h | 3 + > 4 files changed, 159 insertions(+), 114 deletions(-) > create mode 100644 hw/acpi/memory_hotplug_acpi_table.c > > diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs > index 7d3230c..c04064e 100644 > --- a/hw/acpi/Makefile.objs > +++ b/hw/acpi/Makefile.objs > @@ -1,7 +1,7 @@ > common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o > common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o > common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o > -common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o > +common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o > common-obj-$(CONFIG_ACPI) += acpi_interface.o > common-obj-$(CONFIG_ACPI) += bios-linker-loader.o > common-obj-$(CONFIG_ACPI) += aml-build.o > diff --git a/hw/acpi/memory_hotplug_acpi_table.c b/hw/acpi/memory_hotplug_acpi_table.c > new file mode 100644 > index 0000000..28da13c This diff is pretty hard to read. Isn't there some way you could refactor this to make the diff smaller? E.g. move the part that isn't changed into a function first, then call it from a different place. > --- /dev/null > +++ b/hw/acpi/memory_hotplug_acpi_table.c > @@ -0,0 +1,138 @@ > +#include <stdbool.h> > +#include "hw/acpi/aml-build.h" > +#include "hw/acpi/memory_hotplug.h" > +#include "include/hw/acpi/pc-hotplug.h" > +#include "hw/boards.h" > + > +#define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." > + > +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, > + uint16_t io_base, uint16_t io_len) > +{ > + int i; > + Aml *table, *sb_scope, *dev, *method, *ifctx, *ctrl_dev; > + > + table = init_aml_allocator(); > + acpi_data_push(table->buf, sizeof(AcpiTableHeader)); > + > + /* scope for memory hotplug controller device node */ > + assert(nr_mem <= ACPI_MAX_RAM_SLOTS); > + ctrl_dev = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); > + { > + Aml *crs, *field; > + > + aml_append(ctrl_dev, > + aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) > + ); > + > + crs = aml_resource_template(); > + aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 0, io_len)); > + aml_append(ctrl_dev, aml_name_decl("_CRS", crs)); > + > + aml_append(ctrl_dev, aml_operation_region( > + stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, > + io_base, io_len) > + ); > + > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > + AML_PRESERVE); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); > + aml_append(field, /* read only */ > + aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); > + aml_append(ctrl_dev, field); > + > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, > + AML_WRITE_AS_ZEROS); > + aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); > + aml_append(field, /* 1 if enabled, read only */ > + aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); > + aml_append(field, > + /*(read) 1 if has a insert event. (write) 1 to clear event */ > + aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); > + aml_append(field, > + /* (read) 1 if has a remove event. (write) 1 to clear event */ > + aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); > + aml_append(field, > + /* initiates device eject, write only */ > + aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); > + aml_append(ctrl_dev, field); > + > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > + AML_PRESERVE); > + aml_append(field, /* DIMM selector, write only */ > + aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); > + aml_append(field, /* _OST event code, write only */ > + aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); > + aml_append(field, /* _OST status code, write only */ > + aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); > + aml_append(ctrl_dev, field); > + } > + aml_append(table, ctrl_dev); > + > + sb_scope = aml_scope("\\_SB"); > + for (i = 0; i < nr_mem; i++) { > + const char *s; > + > + dev = aml_device("MP%02X", i); > + aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); > + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); > + > + method = aml_method("_CRS", 0); > + s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > + aml_append(dev, method); > + > + method = aml_method("_STA", 0); > + s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > + aml_append(dev, method); > + > + method = aml_method("_PXM", 0); > + s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > + aml_append(dev, method); > + > + method = aml_method("_OST", 3); > + s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); > + aml_append(method, aml_return(aml_call4( > + s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) > + ))); > + aml_append(dev, method); > + > + method = aml_method("_EJ0", 1); > + s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); > + aml_append(method, aml_return(aml_call2( > + s, aml_name("_UID"), aml_arg(0)))); > + aml_append(dev, method); > + > + aml_append(sb_scope, dev); > + } > + > + /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { > + * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } > + */ > + method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); > + for (i = 0; i < nr_mem; i++) { > + ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); > + aml_append(ifctx, > + aml_notify(aml_name("MP%.02X", i), aml_arg(1)) > + ); > + aml_append(method, ifctx); > + } > + aml_append(sb_scope, method); > + aml_append(table, sb_scope); > + > + /* copy AML table into ACPI tables blob and patch header there */ > + g_array_append_vals(table_data, table->buf->data, table->buf->len); > + build_header(linker, table_data, > + (void *)(table_data->data + table_data->len - table->buf->len), > + "MHPT", table->buf->len, 2); > + free_aml_allocator(); > +} > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > index 95e0c65..8add4d9 100644 > --- a/hw/i386/acpi-build.c > +++ b/hw/i386/acpi-build.c > @@ -925,6 +925,16 @@ build_ssdt(GArray *table_data, GArray *linker, > /* Reserve space for header */ > acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader)); > > + sb_scope = aml_scope("\\_SB"); > + method = aml_method("_INI", 0); > + ifctx = aml_if(aml_lgreater_equal(aml_name("_REV"), aml_int(2))); > + if (nr_mem) { > + aml_append(ifctx, aml_load_table("MHPT")); > + } > + aml_append(method, ifctx); > + aml_append(sb_scope, method); > + aml_append(ssdt, sb_scope); > + > /* Extra PCI root buses are implemented only for i440fx */ > bus = find_i440fx(); > if (bus) { > @@ -1200,119 +1210,6 @@ build_ssdt(GArray *table_data, GArray *linker, > } > aml_append(sb_scope, aml_name_decl("CPON", pkg)); > > - /* build memory devices */ > - assert(nr_mem <= ACPI_MAX_RAM_SLOTS); > - scope = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); > - aml_append(scope, > - aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) > - ); > - > - crs = aml_resource_template(); > - aml_append(crs, > - aml_io(AML_DECODE16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0, > - pm->mem_hp_io_len) > - ); > - aml_append(scope, aml_name_decl("_CRS", crs)); > - > - aml_append(scope, aml_operation_region( > - stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, > - pm->mem_hp_io_base, pm->mem_hp_io_len) > - ); > - > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > - AML_PRESERVE); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); > - aml_append(field, /* read only */ > - aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); > - aml_append(scope, field); > - > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, > - AML_WRITE_AS_ZEROS); > - aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); > - aml_append(field, /* 1 if enabled, read only */ > - aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); > - aml_append(field, > - /*(read) 1 if has a insert event. (write) 1 to clear event */ > - aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); > - aml_append(field, > - /* (read) 1 if has a remove event. (write) 1 to clear event */ > - aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); > - aml_append(field, > - /* initiates device eject, write only */ > - aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); > - aml_append(scope, field); > - > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > - AML_PRESERVE); > - aml_append(field, /* DIMM selector, write only */ > - aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); > - aml_append(field, /* _OST event code, write only */ > - aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); > - aml_append(field, /* _OST status code, write only */ > - aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); > - aml_append(scope, field); > - > - aml_append(sb_scope, scope); > - > - for (i = 0; i < nr_mem; i++) { > - #define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." > - const char *s; > - > - dev = aml_device("MP%02X", i); > - aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); > - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); > - > - method = aml_method("_CRS", 0); > - s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > - aml_append(dev, method); > - > - method = aml_method("_STA", 0); > - s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > - aml_append(dev, method); > - > - method = aml_method("_PXM", 0); > - s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > - aml_append(dev, method); > - > - method = aml_method("_OST", 3); > - s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); > - aml_append(method, aml_return(aml_call4( > - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) > - ))); > - aml_append(dev, method); > - > - method = aml_method("_EJ0", 1); > - s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); > - aml_append(method, aml_return(aml_call2( > - s, aml_name("_UID"), aml_arg(0)))); > - aml_append(dev, method); > - > - aml_append(sb_scope, dev); > - } > - > - /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { > - * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } > - */ > - method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); > - for (i = 0; i < nr_mem; i++) { > - ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); > - aml_append(ifctx, > - aml_notify(aml_name("MP%.02X", i), aml_arg(1)) > - ); > - aml_append(method, ifctx); > - } > - aml_append(sb_scope, method); > - > { > Object *pci_host; > PCIBus *bus = NULL; > @@ -1671,6 +1568,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) > uint8_t *u; > size_t aml_len = 0; > GArray *tables_blob = tables->table_data; > + MachineState *machine = MACHINE(qdev_get_machine()); > > acpi_get_cpu_info(&cpu); > acpi_get_pm_info(&pm); > @@ -1742,6 +1640,12 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) > build_dmar_q35(tables_blob, tables->linker); > } > > + if (machine->ram_slots) { > + acpi_add_table(table_offsets, tables_blob); > + build_mhpt(tables_blob, tables->linker, machine->ram_slots, > + pm.mem_hp_io_base, pm.mem_hp_io_len); > + } > + > /* Add tables supplied by user (if any) */ > for (u = acpi_table_first(); u; u = acpi_table_next(u)) { > unsigned len = acpi_table_len(u); > diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h > index 1342adb..5fd2854 100644 > --- a/include/hw/acpi/memory_hotplug.h > +++ b/include/hw/acpi/memory_hotplug.h > @@ -45,4 +45,7 @@ extern const VMStateDescription vmstate_memory_hotplug; > vmstate_memory_hotplug, MemHotplugState) > > void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); > + > +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, > + uint16_t io_base, uint16_t io_len); > #endif > -- > 1.8.3.1
On 10/24/15 19:59, Michael S. Tsirkin wrote: > On Fri, Oct 23, 2015 at 04:57:09PM +0200, Igor Mammedov wrote: >> moves SSDT part to custom MHPT table, which is loaded >> at runtime by OSPM if it supports ACPIv2 revision and >> only if memory hotplug is enabled. >> That should reduce ACPI tables blob size if memory >> hotplug is not enabled (default case). > > With seabios, it's still in reserved memory. How does it help? > > And this trick likely breaks UEFI. It does; see my response to the blurb. In any case, I might send an email to the USWG list because I think better cooperation is needed between the ACPI and UEFI specs for supporting LoadTable and DataTableRegion. In particular, EFI_ACPI_TABLE2_PROTOCOL.InstallTable() should take the EFI memory type to install the table in. Luckily these two specs belong to the same organization now. Thanks Laszlo > I just checked, the only legal way to specify OEM > specific tables seems to be using OEMX prefix. > > But there's a decent chance this will conflict with > people using command line flags to load their own > tables. > > This likely means this trick is off. > > > >> Checked for compatibility issues with: >> * Windows XPsp3, Windows Server 2003: they don't load >> the table as OSPM only reports revision 1 as supported. >> And we don't care about memhp for these guests as they >> do not support it anyway. >> * Windows Server 2008, Windows Server 2008R2: >> works as expected >> >> Signed-off-by: Igor Mammedov <imammedo@redhat.com> >> --- >> hw/acpi/Makefile.objs | 2 +- >> hw/acpi/memory_hotplug_acpi_table.c | 138 ++++++++++++++++++++++++++++++++++++ >> hw/i386/acpi-build.c | 130 +++++---------------------------- >> include/hw/acpi/memory_hotplug.h | 3 + >> 4 files changed, 159 insertions(+), 114 deletions(-) >> create mode 100644 hw/acpi/memory_hotplug_acpi_table.c >> >> diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs >> index 7d3230c..c04064e 100644 >> --- a/hw/acpi/Makefile.objs >> +++ b/hw/acpi/Makefile.objs >> @@ -1,7 +1,7 @@ >> common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o >> common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o >> common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o >> -common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o >> +common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o >> common-obj-$(CONFIG_ACPI) += acpi_interface.o >> common-obj-$(CONFIG_ACPI) += bios-linker-loader.o >> common-obj-$(CONFIG_ACPI) += aml-build.o >> diff --git a/hw/acpi/memory_hotplug_acpi_table.c b/hw/acpi/memory_hotplug_acpi_table.c >> new file mode 100644 >> index 0000000..28da13c >> --- /dev/null >> +++ b/hw/acpi/memory_hotplug_acpi_table.c >> @@ -0,0 +1,138 @@ >> +#include <stdbool.h> >> +#include "hw/acpi/aml-build.h" >> +#include "hw/acpi/memory_hotplug.h" >> +#include "include/hw/acpi/pc-hotplug.h" >> +#include "hw/boards.h" >> + >> +#define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." >> + >> +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, >> + uint16_t io_base, uint16_t io_len) >> +{ >> + int i; >> + Aml *table, *sb_scope, *dev, *method, *ifctx, *ctrl_dev; >> + >> + table = init_aml_allocator(); >> + acpi_data_push(table->buf, sizeof(AcpiTableHeader)); >> + >> + /* scope for memory hotplug controller device node */ >> + assert(nr_mem <= ACPI_MAX_RAM_SLOTS); >> + ctrl_dev = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); >> + { >> + Aml *crs, *field; >> + >> + aml_append(ctrl_dev, >> + aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) >> + ); >> + >> + crs = aml_resource_template(); >> + aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 0, io_len)); >> + aml_append(ctrl_dev, aml_name_decl("_CRS", crs)); >> + >> + aml_append(ctrl_dev, aml_operation_region( >> + stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, >> + io_base, io_len) >> + ); >> + >> + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, >> + AML_PRESERVE); >> + aml_append(field, /* read only */ >> + aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); >> + aml_append(field, /* read only */ >> + aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); >> + aml_append(field, /* read only */ >> + aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); >> + aml_append(field, /* read only */ >> + aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); >> + aml_append(field, /* read only */ >> + aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); >> + aml_append(ctrl_dev, field); >> + >> + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, >> + AML_WRITE_AS_ZEROS); >> + aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); >> + aml_append(field, /* 1 if enabled, read only */ >> + aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); >> + aml_append(field, >> + /*(read) 1 if has a insert event. (write) 1 to clear event */ >> + aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); >> + aml_append(field, >> + /* (read) 1 if has a remove event. (write) 1 to clear event */ >> + aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); >> + aml_append(field, >> + /* initiates device eject, write only */ >> + aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); >> + aml_append(ctrl_dev, field); >> + >> + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, >> + AML_PRESERVE); >> + aml_append(field, /* DIMM selector, write only */ >> + aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); >> + aml_append(field, /* _OST event code, write only */ >> + aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); >> + aml_append(field, /* _OST status code, write only */ >> + aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); >> + aml_append(ctrl_dev, field); >> + } >> + aml_append(table, ctrl_dev); >> + >> + sb_scope = aml_scope("\\_SB"); >> + for (i = 0; i < nr_mem; i++) { >> + const char *s; >> + >> + dev = aml_device("MP%02X", i); >> + aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); >> + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); >> + >> + method = aml_method("_CRS", 0); >> + s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); >> + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); >> + aml_append(dev, method); >> + >> + method = aml_method("_STA", 0); >> + s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); >> + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); >> + aml_append(dev, method); >> + >> + method = aml_method("_PXM", 0); >> + s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); >> + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); >> + aml_append(dev, method); >> + >> + method = aml_method("_OST", 3); >> + s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); >> + aml_append(method, aml_return(aml_call4( >> + s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) >> + ))); >> + aml_append(dev, method); >> + >> + method = aml_method("_EJ0", 1); >> + s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); >> + aml_append(method, aml_return(aml_call2( >> + s, aml_name("_UID"), aml_arg(0)))); >> + aml_append(dev, method); >> + >> + aml_append(sb_scope, dev); >> + } >> + >> + /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { >> + * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } >> + */ >> + method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); >> + for (i = 0; i < nr_mem; i++) { >> + ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); >> + aml_append(ifctx, >> + aml_notify(aml_name("MP%.02X", i), aml_arg(1)) >> + ); >> + aml_append(method, ifctx); >> + } >> + aml_append(sb_scope, method); >> + aml_append(table, sb_scope); >> + >> + /* copy AML table into ACPI tables blob and patch header there */ >> + g_array_append_vals(table_data, table->buf->data, table->buf->len); >> + build_header(linker, table_data, >> + (void *)(table_data->data + table_data->len - table->buf->len), >> + "MHPT", table->buf->len, 2); >> + free_aml_allocator(); >> +} >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c >> index 95e0c65..8add4d9 100644 >> --- a/hw/i386/acpi-build.c >> +++ b/hw/i386/acpi-build.c >> @@ -925,6 +925,16 @@ build_ssdt(GArray *table_data, GArray *linker, >> /* Reserve space for header */ >> acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader)); >> >> + sb_scope = aml_scope("\\_SB"); >> + method = aml_method("_INI", 0); >> + ifctx = aml_if(aml_lgreater_equal(aml_name("_REV"), aml_int(2))); >> + if (nr_mem) { >> + aml_append(ifctx, aml_load_table("MHPT")); >> + } >> + aml_append(method, ifctx); >> + aml_append(sb_scope, method); >> + aml_append(ssdt, sb_scope); >> + >> /* Extra PCI root buses are implemented only for i440fx */ >> bus = find_i440fx(); >> if (bus) { >> @@ -1200,119 +1210,6 @@ build_ssdt(GArray *table_data, GArray *linker, >> } >> aml_append(sb_scope, aml_name_decl("CPON", pkg)); >> >> - /* build memory devices */ >> - assert(nr_mem <= ACPI_MAX_RAM_SLOTS); >> - scope = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); >> - aml_append(scope, >> - aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) >> - ); >> - >> - crs = aml_resource_template(); >> - aml_append(crs, >> - aml_io(AML_DECODE16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0, >> - pm->mem_hp_io_len) >> - ); >> - aml_append(scope, aml_name_decl("_CRS", crs)); >> - >> - aml_append(scope, aml_operation_region( >> - stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, >> - pm->mem_hp_io_base, pm->mem_hp_io_len) >> - ); >> - >> - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, >> - AML_PRESERVE); >> - aml_append(field, /* read only */ >> - aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); >> - aml_append(field, /* read only */ >> - aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); >> - aml_append(field, /* read only */ >> - aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); >> - aml_append(field, /* read only */ >> - aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); >> - aml_append(field, /* read only */ >> - aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); >> - aml_append(scope, field); >> - >> - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, >> - AML_WRITE_AS_ZEROS); >> - aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); >> - aml_append(field, /* 1 if enabled, read only */ >> - aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); >> - aml_append(field, >> - /*(read) 1 if has a insert event. (write) 1 to clear event */ >> - aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); >> - aml_append(field, >> - /* (read) 1 if has a remove event. (write) 1 to clear event */ >> - aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); >> - aml_append(field, >> - /* initiates device eject, write only */ >> - aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); >> - aml_append(scope, field); >> - >> - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, >> - AML_PRESERVE); >> - aml_append(field, /* DIMM selector, write only */ >> - aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); >> - aml_append(field, /* _OST event code, write only */ >> - aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); >> - aml_append(field, /* _OST status code, write only */ >> - aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); >> - aml_append(scope, field); >> - >> - aml_append(sb_scope, scope); >> - >> - for (i = 0; i < nr_mem; i++) { >> - #define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." >> - const char *s; >> - >> - dev = aml_device("MP%02X", i); >> - aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); >> - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); >> - >> - method = aml_method("_CRS", 0); >> - s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); >> - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); >> - aml_append(dev, method); >> - >> - method = aml_method("_STA", 0); >> - s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); >> - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); >> - aml_append(dev, method); >> - >> - method = aml_method("_PXM", 0); >> - s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); >> - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); >> - aml_append(dev, method); >> - >> - method = aml_method("_OST", 3); >> - s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); >> - aml_append(method, aml_return(aml_call4( >> - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) >> - ))); >> - aml_append(dev, method); >> - >> - method = aml_method("_EJ0", 1); >> - s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); >> - aml_append(method, aml_return(aml_call2( >> - s, aml_name("_UID"), aml_arg(0)))); >> - aml_append(dev, method); >> - >> - aml_append(sb_scope, dev); >> - } >> - >> - /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { >> - * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } >> - */ >> - method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); >> - for (i = 0; i < nr_mem; i++) { >> - ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); >> - aml_append(ifctx, >> - aml_notify(aml_name("MP%.02X", i), aml_arg(1)) >> - ); >> - aml_append(method, ifctx); >> - } >> - aml_append(sb_scope, method); >> - >> { >> Object *pci_host; >> PCIBus *bus = NULL; >> @@ -1671,6 +1568,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) >> uint8_t *u; >> size_t aml_len = 0; >> GArray *tables_blob = tables->table_data; >> + MachineState *machine = MACHINE(qdev_get_machine()); >> >> acpi_get_cpu_info(&cpu); >> acpi_get_pm_info(&pm); >> @@ -1742,6 +1640,12 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) >> build_dmar_q35(tables_blob, tables->linker); >> } >> >> + if (machine->ram_slots) { >> + acpi_add_table(table_offsets, tables_blob); >> + build_mhpt(tables_blob, tables->linker, machine->ram_slots, >> + pm.mem_hp_io_base, pm.mem_hp_io_len); >> + } >> + >> /* Add tables supplied by user (if any) */ >> for (u = acpi_table_first(); u; u = acpi_table_next(u)) { >> unsigned len = acpi_table_len(u); >> diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h >> index 1342adb..5fd2854 100644 >> --- a/include/hw/acpi/memory_hotplug.h >> +++ b/include/hw/acpi/memory_hotplug.h >> @@ -45,4 +45,7 @@ extern const VMStateDescription vmstate_memory_hotplug; >> vmstate_memory_hotplug, MemHotplugState) >> >> void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); >> + >> +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, >> + uint16_t io_base, uint16_t io_len); >> #endif >> -- >> 1.8.3.1
On Sat, 24 Oct 2015 20:59:07 +0300 "Michael S. Tsirkin" <mst@redhat.com> wrote: > On Fri, Oct 23, 2015 at 04:57:09PM +0200, Igor Mammedov wrote: > > moves SSDT part to custom MHPT table, which is loaded > > at runtime by OSPM if it supports ACPIv2 revision and > > only if memory hotplug is enabled. > > That should reduce ACPI tables blob size if memory > > hotplug is not enabled (default case). > > With seabios, it's still in reserved memory. How does it help? > > And this trick likely breaks UEFI. > > I just checked, the only legal way to specify OEM > specific tables seems to be using OEMX prefix. > > But there's a decent chance this will conflict with > people using command line flags to load their own > tables. > > This likely means this trick is off. Ok, I'll drop LoadTable and keep it in SSDT, there is no hard req to use a separate table since all memhp code is rev1.0 compatible for now and even when it's switched to 64-bit math it shouldn't affect XP unless someone would try hotplug memory on it. > > > > > Checked for compatibility issues with: > > * Windows XPsp3, Windows Server 2003: they don't load > > the table as OSPM only reports revision 1 as supported. > > And we don't care about memhp for these guests as they > > do not support it anyway. > > * Windows Server 2008, Windows Server 2008R2: > > works as expected > > > > Signed-off-by: Igor Mammedov <imammedo@redhat.com> > > --- > > hw/acpi/Makefile.objs | 2 +- > > hw/acpi/memory_hotplug_acpi_table.c | 138 ++++++++++++++++++++++++++++++++++++ > > hw/i386/acpi-build.c | 130 +++++---------------------------- > > include/hw/acpi/memory_hotplug.h | 3 + > > 4 files changed, 159 insertions(+), 114 deletions(-) > > create mode 100644 hw/acpi/memory_hotplug_acpi_table.c > > > > diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs > > index 7d3230c..c04064e 100644 > > --- a/hw/acpi/Makefile.objs > > +++ b/hw/acpi/Makefile.objs > > @@ -1,7 +1,7 @@ > > common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o > > common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o > > common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o > > -common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o > > +common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o > > common-obj-$(CONFIG_ACPI) += acpi_interface.o > > common-obj-$(CONFIG_ACPI) += bios-linker-loader.o > > common-obj-$(CONFIG_ACPI) += aml-build.o > > diff --git a/hw/acpi/memory_hotplug_acpi_table.c b/hw/acpi/memory_hotplug_acpi_table.c > > new file mode 100644 > > index 0000000..28da13c > > --- /dev/null > > +++ b/hw/acpi/memory_hotplug_acpi_table.c > > @@ -0,0 +1,138 @@ > > +#include <stdbool.h> > > +#include "hw/acpi/aml-build.h" > > +#include "hw/acpi/memory_hotplug.h" > > +#include "include/hw/acpi/pc-hotplug.h" > > +#include "hw/boards.h" > > + > > +#define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." > > + > > +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, > > + uint16_t io_base, uint16_t io_len) > > +{ > > + int i; > > + Aml *table, *sb_scope, *dev, *method, *ifctx, *ctrl_dev; > > + > > + table = init_aml_allocator(); > > + acpi_data_push(table->buf, sizeof(AcpiTableHeader)); > > + > > + /* scope for memory hotplug controller device node */ > > + assert(nr_mem <= ACPI_MAX_RAM_SLOTS); > > + ctrl_dev = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); > > + { > > + Aml *crs, *field; > > + > > + aml_append(ctrl_dev, > > + aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) > > + ); > > + > > + crs = aml_resource_template(); > > + aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 0, io_len)); > > + aml_append(ctrl_dev, aml_name_decl("_CRS", crs)); > > + > > + aml_append(ctrl_dev, aml_operation_region( > > + stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, > > + io_base, io_len) > > + ); > > + > > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > > + AML_PRESERVE); > > + aml_append(field, /* read only */ > > + aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); > > + aml_append(field, /* read only */ > > + aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); > > + aml_append(field, /* read only */ > > + aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); > > + aml_append(field, /* read only */ > > + aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); > > + aml_append(field, /* read only */ > > + aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); > > + aml_append(ctrl_dev, field); > > + > > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, > > + AML_WRITE_AS_ZEROS); > > + aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); > > + aml_append(field, /* 1 if enabled, read only */ > > + aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); > > + aml_append(field, > > + /*(read) 1 if has a insert event. (write) 1 to clear event */ > > + aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); > > + aml_append(field, > > + /* (read) 1 if has a remove event. (write) 1 to clear event */ > > + aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); > > + aml_append(field, > > + /* initiates device eject, write only */ > > + aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); > > + aml_append(ctrl_dev, field); > > + > > + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > > + AML_PRESERVE); > > + aml_append(field, /* DIMM selector, write only */ > > + aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); > > + aml_append(field, /* _OST event code, write only */ > > + aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); > > + aml_append(field, /* _OST status code, write only */ > > + aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); > > + aml_append(ctrl_dev, field); > > + } > > + aml_append(table, ctrl_dev); > > + > > + sb_scope = aml_scope("\\_SB"); > > + for (i = 0; i < nr_mem; i++) { > > + const char *s; > > + > > + dev = aml_device("MP%02X", i); > > + aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); > > + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); > > + > > + method = aml_method("_CRS", 0); > > + s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); > > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > > + aml_append(dev, method); > > + > > + method = aml_method("_STA", 0); > > + s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); > > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > > + aml_append(dev, method); > > + > > + method = aml_method("_PXM", 0); > > + s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); > > + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > > + aml_append(dev, method); > > + > > + method = aml_method("_OST", 3); > > + s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); > > + aml_append(method, aml_return(aml_call4( > > + s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) > > + ))); > > + aml_append(dev, method); > > + > > + method = aml_method("_EJ0", 1); > > + s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); > > + aml_append(method, aml_return(aml_call2( > > + s, aml_name("_UID"), aml_arg(0)))); > > + aml_append(dev, method); > > + > > + aml_append(sb_scope, dev); > > + } > > + > > + /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { > > + * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } > > + */ > > + method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); > > + for (i = 0; i < nr_mem; i++) { > > + ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); > > + aml_append(ifctx, > > + aml_notify(aml_name("MP%.02X", i), aml_arg(1)) > > + ); > > + aml_append(method, ifctx); > > + } > > + aml_append(sb_scope, method); > > + aml_append(table, sb_scope); > > + > > + /* copy AML table into ACPI tables blob and patch header there */ > > + g_array_append_vals(table_data, table->buf->data, table->buf->len); > > + build_header(linker, table_data, > > + (void *)(table_data->data + table_data->len - table->buf->len), > > + "MHPT", table->buf->len, 2); > > + free_aml_allocator(); > > +} > > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > > index 95e0c65..8add4d9 100644 > > --- a/hw/i386/acpi-build.c > > +++ b/hw/i386/acpi-build.c > > @@ -925,6 +925,16 @@ build_ssdt(GArray *table_data, GArray *linker, > > /* Reserve space for header */ > > acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader)); > > > > + sb_scope = aml_scope("\\_SB"); > > + method = aml_method("_INI", 0); > > + ifctx = aml_if(aml_lgreater_equal(aml_name("_REV"), aml_int(2))); > > + if (nr_mem) { > > + aml_append(ifctx, aml_load_table("MHPT")); > > + } > > + aml_append(method, ifctx); > > + aml_append(sb_scope, method); > > + aml_append(ssdt, sb_scope); > > + > > /* Extra PCI root buses are implemented only for i440fx */ > > bus = find_i440fx(); > > if (bus) { > > @@ -1200,119 +1210,6 @@ build_ssdt(GArray *table_data, GArray *linker, > > } > > aml_append(sb_scope, aml_name_decl("CPON", pkg)); > > > > - /* build memory devices */ > > - assert(nr_mem <= ACPI_MAX_RAM_SLOTS); > > - scope = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); > > - aml_append(scope, > > - aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) > > - ); > > - > > - crs = aml_resource_template(); > > - aml_append(crs, > > - aml_io(AML_DECODE16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0, > > - pm->mem_hp_io_len) > > - ); > > - aml_append(scope, aml_name_decl("_CRS", crs)); > > - > > - aml_append(scope, aml_operation_region( > > - stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, > > - pm->mem_hp_io_base, pm->mem_hp_io_len) > > - ); > > - > > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > > - AML_PRESERVE); > > - aml_append(field, /* read only */ > > - aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); > > - aml_append(field, /* read only */ > > - aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); > > - aml_append(field, /* read only */ > > - aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); > > - aml_append(field, /* read only */ > > - aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); > > - aml_append(field, /* read only */ > > - aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); > > - aml_append(scope, field); > > - > > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, > > - AML_WRITE_AS_ZEROS); > > - aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); > > - aml_append(field, /* 1 if enabled, read only */ > > - aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); > > - aml_append(field, > > - /*(read) 1 if has a insert event. (write) 1 to clear event */ > > - aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); > > - aml_append(field, > > - /* (read) 1 if has a remove event. (write) 1 to clear event */ > > - aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); > > - aml_append(field, > > - /* initiates device eject, write only */ > > - aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); > > - aml_append(scope, field); > > - > > - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, > > - AML_PRESERVE); > > - aml_append(field, /* DIMM selector, write only */ > > - aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); > > - aml_append(field, /* _OST event code, write only */ > > - aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); > > - aml_append(field, /* _OST status code, write only */ > > - aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); > > - aml_append(scope, field); > > - > > - aml_append(sb_scope, scope); > > - > > - for (i = 0; i < nr_mem; i++) { > > - #define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." > > - const char *s; > > - > > - dev = aml_device("MP%02X", i); > > - aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); > > - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); > > - > > - method = aml_method("_CRS", 0); > > - s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); > > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > > - aml_append(dev, method); > > - > > - method = aml_method("_STA", 0); > > - s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); > > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > > - aml_append(dev, method); > > - > > - method = aml_method("_PXM", 0); > > - s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); > > - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); > > - aml_append(dev, method); > > - > > - method = aml_method("_OST", 3); > > - s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); > > - aml_append(method, aml_return(aml_call4( > > - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) > > - ))); > > - aml_append(dev, method); > > - > > - method = aml_method("_EJ0", 1); > > - s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); > > - aml_append(method, aml_return(aml_call2( > > - s, aml_name("_UID"), aml_arg(0)))); > > - aml_append(dev, method); > > - > > - aml_append(sb_scope, dev); > > - } > > - > > - /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { > > - * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } > > - */ > > - method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); > > - for (i = 0; i < nr_mem; i++) { > > - ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); > > - aml_append(ifctx, > > - aml_notify(aml_name("MP%.02X", i), aml_arg(1)) > > - ); > > - aml_append(method, ifctx); > > - } > > - aml_append(sb_scope, method); > > - > > { > > Object *pci_host; > > PCIBus *bus = NULL; > > @@ -1671,6 +1568,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) > > uint8_t *u; > > size_t aml_len = 0; > > GArray *tables_blob = tables->table_data; > > + MachineState *machine = MACHINE(qdev_get_machine()); > > > > acpi_get_cpu_info(&cpu); > > acpi_get_pm_info(&pm); > > @@ -1742,6 +1640,12 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) > > build_dmar_q35(tables_blob, tables->linker); > > } > > > > + if (machine->ram_slots) { > > + acpi_add_table(table_offsets, tables_blob); > > + build_mhpt(tables_blob, tables->linker, machine->ram_slots, > > + pm.mem_hp_io_base, pm.mem_hp_io_len); > > + } > > + > > /* Add tables supplied by user (if any) */ > > for (u = acpi_table_first(); u; u = acpi_table_next(u)) { > > unsigned len = acpi_table_len(u); > > diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h > > index 1342adb..5fd2854 100644 > > --- a/include/hw/acpi/memory_hotplug.h > > +++ b/include/hw/acpi/memory_hotplug.h > > @@ -45,4 +45,7 @@ extern const VMStateDescription vmstate_memory_hotplug; > > vmstate_memory_hotplug, MemHotplugState) > > > > void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); > > + > > +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, > > + uint16_t io_base, uint16_t io_len); > > #endif > > -- > > 1.8.3.1
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index 7d3230c..c04064e 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -1,7 +1,7 @@ common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o -common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o +common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o common-obj-$(CONFIG_ACPI) += acpi_interface.o common-obj-$(CONFIG_ACPI) += bios-linker-loader.o common-obj-$(CONFIG_ACPI) += aml-build.o diff --git a/hw/acpi/memory_hotplug_acpi_table.c b/hw/acpi/memory_hotplug_acpi_table.c new file mode 100644 index 0000000..28da13c --- /dev/null +++ b/hw/acpi/memory_hotplug_acpi_table.c @@ -0,0 +1,138 @@ +#include <stdbool.h> +#include "hw/acpi/aml-build.h" +#include "hw/acpi/memory_hotplug.h" +#include "include/hw/acpi/pc-hotplug.h" +#include "hw/boards.h" + +#define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." + +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, + uint16_t io_base, uint16_t io_len) +{ + int i; + Aml *table, *sb_scope, *dev, *method, *ifctx, *ctrl_dev; + + table = init_aml_allocator(); + acpi_data_push(table->buf, sizeof(AcpiTableHeader)); + + /* scope for memory hotplug controller device node */ + assert(nr_mem <= ACPI_MAX_RAM_SLOTS); + ctrl_dev = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); + { + Aml *crs, *field; + + aml_append(ctrl_dev, + aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) + ); + + crs = aml_resource_template(); + aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 0, io_len)); + aml_append(ctrl_dev, aml_name_decl("_CRS", crs)); + + aml_append(ctrl_dev, aml_operation_region( + stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, + io_base, io_len) + ); + + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, + AML_PRESERVE); + aml_append(field, /* read only */ + aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); + aml_append(field, /* read only */ + aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); + aml_append(field, /* read only */ + aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); + aml_append(field, /* read only */ + aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); + aml_append(field, /* read only */ + aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); + aml_append(ctrl_dev, field); + + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, + AML_WRITE_AS_ZEROS); + aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); + aml_append(field, /* 1 if enabled, read only */ + aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); + aml_append(field, + /*(read) 1 if has a insert event. (write) 1 to clear event */ + aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); + aml_append(field, + /* (read) 1 if has a remove event. (write) 1 to clear event */ + aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); + aml_append(field, + /* initiates device eject, write only */ + aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); + aml_append(ctrl_dev, field); + + field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, + AML_PRESERVE); + aml_append(field, /* DIMM selector, write only */ + aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); + aml_append(field, /* _OST event code, write only */ + aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); + aml_append(field, /* _OST status code, write only */ + aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); + aml_append(ctrl_dev, field); + } + aml_append(table, ctrl_dev); + + sb_scope = aml_scope("\\_SB"); + for (i = 0; i < nr_mem; i++) { + const char *s; + + dev = aml_device("MP%02X", i); + aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); + + method = aml_method("_CRS", 0); + s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_STA", 0); + s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_PXM", 0); + s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_OST", 3); + s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); + aml_append(method, aml_return(aml_call4( + s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) + ))); + aml_append(dev, method); + + method = aml_method("_EJ0", 1); + s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); + aml_append(method, aml_return(aml_call2( + s, aml_name("_UID"), aml_arg(0)))); + aml_append(dev, method); + + aml_append(sb_scope, dev); + } + + /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { + * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } + */ + method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); + for (i = 0; i < nr_mem; i++) { + ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); + aml_append(ifctx, + aml_notify(aml_name("MP%.02X", i), aml_arg(1)) + ); + aml_append(method, ifctx); + } + aml_append(sb_scope, method); + aml_append(table, sb_scope); + + /* copy AML table into ACPI tables blob and patch header there */ + g_array_append_vals(table_data, table->buf->data, table->buf->len); + build_header(linker, table_data, + (void *)(table_data->data + table_data->len - table->buf->len), + "MHPT", table->buf->len, 2); + free_aml_allocator(); +} diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 95e0c65..8add4d9 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -925,6 +925,16 @@ build_ssdt(GArray *table_data, GArray *linker, /* Reserve space for header */ acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader)); + sb_scope = aml_scope("\\_SB"); + method = aml_method("_INI", 0); + ifctx = aml_if(aml_lgreater_equal(aml_name("_REV"), aml_int(2))); + if (nr_mem) { + aml_append(ifctx, aml_load_table("MHPT")); + } + aml_append(method, ifctx); + aml_append(sb_scope, method); + aml_append(ssdt, sb_scope); + /* Extra PCI root buses are implemented only for i440fx */ bus = find_i440fx(); if (bus) { @@ -1200,119 +1210,6 @@ build_ssdt(GArray *table_data, GArray *linker, } aml_append(sb_scope, aml_name_decl("CPON", pkg)); - /* build memory devices */ - assert(nr_mem <= ACPI_MAX_RAM_SLOTS); - scope = aml_scope("\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE)); - aml_append(scope, - aml_name_decl(stringify(MEMORY_SLOTS_NUMBER), aml_int(nr_mem)) - ); - - crs = aml_resource_template(); - aml_append(crs, - aml_io(AML_DECODE16, pm->mem_hp_io_base, pm->mem_hp_io_base, 0, - pm->mem_hp_io_len) - ); - aml_append(scope, aml_name_decl("_CRS", crs)); - - aml_append(scope, aml_operation_region( - stringify(MEMORY_HOTPLUG_IO_REGION), AML_SYSTEM_IO, - pm->mem_hp_io_base, pm->mem_hp_io_len) - ); - - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, - AML_PRESERVE); - aml_append(field, /* read only */ - aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32)); - aml_append(field, /* read only */ - aml_named_field(stringify(MEMORY_SLOT_ADDR_HIGH), 32)); - aml_append(field, /* read only */ - aml_named_field(stringify(MEMORY_SLOT_SIZE_LOW), 32)); - aml_append(field, /* read only */ - aml_named_field(stringify(MEMORY_SLOT_SIZE_HIGH), 32)); - aml_append(field, /* read only */ - aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32)); - aml_append(scope, field); - - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_BYTE_ACC, - AML_WRITE_AS_ZEROS); - aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); - aml_append(field, /* 1 if enabled, read only */ - aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1)); - aml_append(field, - /*(read) 1 if has a insert event. (write) 1 to clear event */ - aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1)); - aml_append(field, - /* (read) 1 if has a remove event. (write) 1 to clear event */ - aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1)); - aml_append(field, - /* initiates device eject, write only */ - aml_named_field(stringify(MEMORY_SLOT_EJECT), 1)); - aml_append(scope, field); - - field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), AML_DWORD_ACC, - AML_PRESERVE); - aml_append(field, /* DIMM selector, write only */ - aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32)); - aml_append(field, /* _OST event code, write only */ - aml_named_field(stringify(MEMORY_SLOT_OST_EVENT), 32)); - aml_append(field, /* _OST status code, write only */ - aml_named_field(stringify(MEMORY_SLOT_OST_STATUS), 32)); - aml_append(scope, field); - - aml_append(sb_scope, scope); - - for (i = 0; i < nr_mem; i++) { - #define BASEPATH "\\_SB.PCI0." stringify(MEMORY_HOTPLUG_DEVICE) "." - const char *s; - - dev = aml_device("MP%02X", i); - aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); - - method = aml_method("_CRS", 0); - s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD); - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - aml_append(dev, method); - - method = aml_method("_STA", 0); - s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD); - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - aml_append(dev, method); - - method = aml_method("_PXM", 0); - s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD); - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - aml_append(dev, method); - - method = aml_method("_OST", 3); - s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD); - aml_append(method, aml_return(aml_call4( - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) - ))); - aml_append(dev, method); - - method = aml_method("_EJ0", 1); - s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD); - aml_append(method, aml_return(aml_call2( - s, aml_name("_UID"), aml_arg(0)))); - aml_append(dev, method); - - aml_append(sb_scope, dev); - } - - /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { - * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } - */ - method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2); - for (i = 0; i < nr_mem; i++) { - ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); - aml_append(ifctx, - aml_notify(aml_name("MP%.02X", i), aml_arg(1)) - ); - aml_append(method, ifctx); - } - aml_append(sb_scope, method); - { Object *pci_host; PCIBus *bus = NULL; @@ -1671,6 +1568,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) uint8_t *u; size_t aml_len = 0; GArray *tables_blob = tables->table_data; + MachineState *machine = MACHINE(qdev_get_machine()); acpi_get_cpu_info(&cpu); acpi_get_pm_info(&pm); @@ -1742,6 +1640,12 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) build_dmar_q35(tables_blob, tables->linker); } + if (machine->ram_slots) { + acpi_add_table(table_offsets, tables_blob); + build_mhpt(tables_blob, tables->linker, machine->ram_slots, + pm.mem_hp_io_base, pm.mem_hp_io_len); + } + /* Add tables supplied by user (if any) */ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { unsigned len = acpi_table_len(u); diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h index 1342adb..5fd2854 100644 --- a/include/hw/acpi/memory_hotplug.h +++ b/include/hw/acpi/memory_hotplug.h @@ -45,4 +45,7 @@ extern const VMStateDescription vmstate_memory_hotplug; vmstate_memory_hotplug, MemHotplugState) void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); + +void build_mhpt(GArray *table_data, GArray *linker, uint32_t nr_mem, + uint16_t io_base, uint16_t io_len); #endif
moves SSDT part to custom MHPT table, which is loaded at runtime by OSPM if it supports ACPIv2 revision and only if memory hotplug is enabled. That should reduce ACPI tables blob size if memory hotplug is not enabled (default case). Checked for compatibility issues with: * Windows XPsp3, Windows Server 2003: they don't load the table as OSPM only reports revision 1 as supported. And we don't care about memhp for these guests as they do not support it anyway. * Windows Server 2008, Windows Server 2008R2: works as expected Signed-off-by: Igor Mammedov <imammedo@redhat.com> --- hw/acpi/Makefile.objs | 2 +- hw/acpi/memory_hotplug_acpi_table.c | 138 ++++++++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 130 +++++---------------------------- include/hw/acpi/memory_hotplug.h | 3 + 4 files changed, 159 insertions(+), 114 deletions(-) create mode 100644 hw/acpi/memory_hotplug_acpi_table.c