summaryrefslogtreecommitdiffstats
path: root/hw/i386/acpi-build.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/i386/acpi-build.c')
-rw-r--r--hw/i386/acpi-build.c75
1 files changed, 68 insertions, 7 deletions
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 1e0aa09..ebc5f03 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -37,6 +37,7 @@
#include "bios-linker-loader.h"
#include "hw/loader.h"
#include "hw/isa/isa.h"
+#include "hw/acpi/memory_hotplug.h"
/* Supported chipsets: */
#include "hw/acpi/piix4.h"
@@ -667,6 +668,14 @@ static inline char acpi_get_hex(uint32_t val)
#define ACPI_PCIQXL_SIZEOF (*ssdt_pciqxl_end - *ssdt_pciqxl_start)
#define ACPI_PCIQXL_AML (ssdp_pcihp_aml + *ssdt_pciqxl_start)
+#include "hw/i386/ssdt-mem.hex"
+
+/* 0x5B 0x82 DeviceOp PkgLength NameString DimmID */
+#define ACPI_MEM_OFFSET_HEX (*ssdt_mem_name - *ssdt_mem_start + 2)
+#define ACPI_MEM_OFFSET_ID (*ssdt_mem_id - *ssdt_mem_start + 7)
+#define ACPI_MEM_SIZEOF (*ssdt_mem_end - *ssdt_mem_start)
+#define ACPI_MEM_AML (ssdm_mem_aml + *ssdt_mem_start)
+
#define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */
#define ACPI_SSDT_HEADER_LENGTH 36
@@ -1003,6 +1012,8 @@ build_ssdt(GArray *table_data, GArray *linker,
AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
PcPciInfo *pci, PcGuestInfo *guest_info)
{
+ MachineState *machine = MACHINE(qdev_get_machine());
+ uint32_t nr_mem = machine->ram_slots;
unsigned acpi_cpus = guest_info->apic_id_limit;
int ssdt_start = table_data->len;
uint8_t *ssdt_ptr;
@@ -1031,6 +1042,9 @@ 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);
+ ACPI_BUILD_SET_LE(ssdt_ptr, sizeof(ssdp_misc_aml),
+ ssdt_mctrl_nr_slots[0], 32, nr_mem);
+
{
GArray *sb_scope = build_alloc_array();
uint8_t op = 0x10; /* ScopeOp */
@@ -1084,6 +1098,27 @@ build_ssdt(GArray *table_data, GArray *linker,
build_free_array(package);
}
+ if (nr_mem) {
+ assert(nr_mem <= ACPI_MAX_RAM_SLOTS);
+ /* build memory devices */
+ for (i = 0; i < nr_mem; i++) {
+ char id[3];
+ uint8_t *mem = acpi_data_push(sb_scope, ACPI_MEM_SIZEOF);
+
+ snprintf(id, sizeof(id), "%02X", i);
+ memcpy(mem, ACPI_MEM_AML, ACPI_MEM_SIZEOF);
+ memcpy(mem + ACPI_MEM_OFFSET_HEX, id, 2);
+ memcpy(mem + ACPI_MEM_OFFSET_ID, id, 2);
+ }
+
+ /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
+ * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ...
+ */
+ build_append_notify_method(sb_scope,
+ stringify(MEMORY_SLOT_NOTIFY_METHOD),
+ "MP%0.02X", nr_mem);
+ }
+
{
AcpiBuildPciBusHotplugState hotplug_state;
Object *pci_host;
@@ -1132,15 +1167,22 @@ build_hpet(GArray *table_data, GArray *linker)
(void *)hpet, "HPET", sizeof(*hpet), 1);
}
+typedef enum {
+ MEM_AFFINITY_NOFLAGS = 0,
+ MEM_AFFINITY_ENABLED = (1 << 0),
+ MEM_AFFINITY_HOTPLUGGABLE = (1 << 1),
+ MEM_AFFINITY_NON_VOLATILE = (1 << 2),
+} MemoryAffinityFlags;
+
static void
-acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem,
- uint64_t base, uint64_t len, int node, int enabled)
+acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
+ uint64_t len, int node, MemoryAffinityFlags flags)
{
numamem->type = ACPI_SRAT_MEMORY;
numamem->length = sizeof(*numamem);
memset(numamem->proximity, 0, 4);
numamem->proximity[0] = node;
- numamem->flags = cpu_to_le32(!!enabled);
+ numamem->flags = cpu_to_le32(flags);
numamem->base_addr = cpu_to_le64(base);
numamem->range_length = cpu_to_le64(len);
}
@@ -1157,6 +1199,10 @@ build_srat(GArray *table_data, GArray *linker,
uint64_t curnode;
int srat_start, numa_start, slots;
uint64_t mem_len, mem_base, next_base;
+ PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+ ram_addr_t hotplugabble_address_space_size =
+ object_property_get_int(OBJECT(pcms), PC_MACHINE_MEMHP_REGION_SIZE,
+ NULL);
srat_start = table_data->len;
@@ -1188,7 +1234,7 @@ build_srat(GArray *table_data, GArray *linker,
numa_start = table_data->len;
numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
+ acpi_build_srat_memory(numamem, 0, 640*1024, 0, MEM_AFFINITY_ENABLED);
next_base = 1024 * 1024;
for (i = 1; i < guest_info->numa_nodes + 1; ++i) {
mem_base = next_base;
@@ -1204,19 +1250,34 @@ build_srat(GArray *table_data, GArray *linker,
mem_len -= next_base - guest_info->ram_size_below_4g;
if (mem_len > 0) {
numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1,
+ MEM_AFFINITY_ENABLED);
}
mem_base = 1ULL << 32;
mem_len = next_base - guest_info->ram_size_below_4g;
next_base += (1ULL << 32) - guest_info->ram_size_below_4g;
}
numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1, 1);
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1,
+ MEM_AFFINITY_ENABLED);
}
slots = (table_data->len - numa_start) / sizeof *numamem;
for (; slots < guest_info->numa_nodes + 2; slots++) {
numamem = acpi_data_push(table_data, sizeof *numamem);
- acpi_build_srat_memory(numamem, 0, 0, 0, 0);
+ acpi_build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
+ }
+
+ /*
+ * Entry is required for Windows to enable memory hotplug in OS.
+ * Memory devices may override proximity set by this entry,
+ * providing _PXM method if necessary.
+ */
+ if (hotplugabble_address_space_size) {
+ numamem = acpi_data_push(table_data, sizeof *numamem);
+ acpi_build_srat_memory(numamem, pcms->hotplug_memory_base,
+ hotplugabble_address_space_size, 0,
+ MEM_AFFINITY_HOTPLUGGABLE |
+ MEM_AFFINITY_ENABLED);
}
build_header(linker, table_data,
OpenPOWER on IntegriCloud