The memory device generation is guided by qemu paravirt info. Seabios first uses the info to setup SRAT entries for the hotplug-able memory slots. Afterwards, build_memssdt uses the created SRAT entries to generate appropriate memory device objects. One memory device (and corresponding SRAT entry) is generated for each hotplug-able qemu memslot. Currently no SSDT memory device is created for initial system memory (the method can be generalized to all memory though).
Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovi...@profitbricks.com> --- src/acpi.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 147 insertions(+), 4 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index 30888b9..5580099 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -484,6 +484,131 @@ build_ssdt(void) return ssdt; } +static unsigned char ssdt_mem[] = { + 0x5b,0x82,0x47,0x07,0x4d,0x50,0x41,0x41, + 0x08,0x49,0x44,0x5f,0x5f,0x0a,0xaa,0x08, + 0x5f,0x48,0x49,0x44,0x0c,0x41,0xd0,0x0c, + 0x80,0x08,0x5f,0x50,0x58,0x4d,0x0a,0xaa, + 0x08,0x5f,0x43,0x52,0x53,0x11,0x33,0x0a, + 0x30,0x8a,0x2b,0x00,0x00,0x0d,0x03,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xef, + 0xbe,0xad,0xde,0x00,0x00,0x00,0x00,0xee, + 0xbe,0xad,0xe6,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x79, + 0x00,0x14,0x0f,0x5f,0x53,0x54,0x41,0x00, + 0xa4,0x43,0x4d,0x53,0x54,0x49,0x44,0x5f, + 0x5f,0x14,0x0f,0x5f,0x45,0x4a,0x30,0x01, + 0x4d,0x50,0x45,0x4a,0x49,0x44,0x5f,0x5f, + 0x68 +}; + +#define SD_OFFSET_MEMHEX 6 +#define SD_OFFSET_MEMID 14 +#define SD_OFFSET_PXMID 31 +#define SD_OFFSET_MEMSTART 55 +#define SD_OFFSET_MEMEND 63 +#define SD_OFFSET_MEMSIZE 79 + +u64 nb_hp_memslots = 0; +struct srat_memory_affinity *mem; + +static void build_memdev(u8 *ssdt_ptr, int i, u64 mem_base, u64 mem_len, u8 node) +{ + memcpy(ssdt_ptr, ssdt_mem, sizeof(ssdt_mem)); + ssdt_ptr[SD_OFFSET_MEMHEX] = getHex(i >> 4); + ssdt_ptr[SD_OFFSET_MEMHEX+1] = getHex(i); + ssdt_ptr[SD_OFFSET_MEMID] = i; + ssdt_ptr[SD_OFFSET_PXMID] = node; + *(u64*)(ssdt_ptr + SD_OFFSET_MEMSTART) = mem_base; + *(u64*)(ssdt_ptr + SD_OFFSET_MEMEND) = mem_base + mem_len; + *(u64*)(ssdt_ptr + SD_OFFSET_MEMSIZE) = mem_len; +} + +static void* +build_memssdt(void) +{ + u64 mem_base; + u64 mem_len; + u8 node; + int i; + struct srat_memory_affinity *entry = mem; + u64 nb_memdevs = nb_hp_memslots; + + int length = ((1+3+4) + + (nb_memdevs * sizeof(ssdt_mem)) + + (1+2+5+(12*nb_memdevs)) + + (6+2+1+(1*nb_memdevs))); + u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length); + if (! ssdt) { + warn_noalloc(); + return NULL; + } + u8 *ssdt_ptr = ssdt + sizeof(struct acpi_table_header); + + // build Scope(_SB_) header + *(ssdt_ptr++) = 0x10; // ScopeOp + ssdt_ptr = encodeLen(ssdt_ptr, length-1, 3); + *(ssdt_ptr++) = '_'; + *(ssdt_ptr++) = 'S'; + *(ssdt_ptr++) = 'B'; + *(ssdt_ptr++) = '_'; + + for (i = 0; i < nb_memdevs; i++) { + mem_base = (((u64)(entry->base_addr_high) << 32 )| entry->base_addr_low); + mem_len = (((u64)(entry->length_high) << 32 )| entry->length_low); + node = entry->proximity[0]; + build_memdev(ssdt_ptr, i, mem_base, mem_len, node); + ssdt_ptr += sizeof(ssdt_mem); + entry++; + } + + // build "Method(MTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CM00, Arg1)} ...}" + *(ssdt_ptr++) = 0x14; // MethodOp + ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*nb_memdevs), 2); + *(ssdt_ptr++) = 'M'; + *(ssdt_ptr++) = 'T'; + *(ssdt_ptr++) = 'F'; + *(ssdt_ptr++) = 'Y'; + *(ssdt_ptr++) = 0x02; + for (i=0; i<nb_memdevs; i++) { + *(ssdt_ptr++) = 0xA0; // IfOp + ssdt_ptr = encodeLen(ssdt_ptr, 11, 1); + *(ssdt_ptr++) = 0x93; // LEqualOp + *(ssdt_ptr++) = 0x68; // Arg0Op + *(ssdt_ptr++) = 0x0A; // BytePrefix + *(ssdt_ptr++) = i; + *(ssdt_ptr++) = 0x86; // NotifyOp + *(ssdt_ptr++) = 'M'; + *(ssdt_ptr++) = 'P'; + *(ssdt_ptr++) = getHex(i >> 4); + *(ssdt_ptr++) = getHex(i); + *(ssdt_ptr++) = 0x69; // Arg1Op + } + + // build "Name(MEON, Package() { One, One, ..., Zero, Zero, ... })" + *(ssdt_ptr++) = 0x08; // NameOp + *(ssdt_ptr++) = 'M'; + *(ssdt_ptr++) = 'E'; + *(ssdt_ptr++) = 'O'; + *(ssdt_ptr++) = 'N'; + *(ssdt_ptr++) = 0x12; // PackageOp + ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*nb_memdevs), 2); + *(ssdt_ptr++) = nb_memdevs; + + entry = mem; + + for (i = 0; i < nb_memdevs; i++) { + mem_base = (((u64)(entry->base_addr_high) << 32 )| entry->base_addr_low); + mem_len = (((u64)(entry->length_high) << 32 )| entry->length_low); + *(ssdt_ptr++) = 0x00; + entry++; + } + build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1); + + return ssdt; +} + #include "ssdt-pcihp.hex" #define PCI_RMV_BASE 0xae0c @@ -580,18 +705,21 @@ build_srat(void) if (nb_numa_nodes == 0) return NULL; - u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes)); + qemu_cfg_get_numa_data(&nb_hp_memslots, 1); + + u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes + + 3 * nb_hp_memslots)); if (!numadata) { warn_noalloc(); return NULL; } - qemu_cfg_get_numa_data(numadata, MaxCountCPUs + nb_numa_nodes); + qemu_cfg_get_numa_data(numadata, MaxCountCPUs + nb_numa_nodes + 3 * nb_hp_memslots); struct system_resource_affinity_table *srat; int srat_size = sizeof(*srat) + sizeof(struct srat_processor_affinity) * MaxCountCPUs + - sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2); + sizeof(struct srat_memory_affinity) * (nb_numa_nodes + nb_hp_memslots + 2); srat = malloc_high(srat_size); if (!srat) { @@ -627,6 +755,7 @@ build_srat(void) */ struct srat_memory_affinity *numamem = (void*)core; int slots = 0; + int node; u64 mem_len, mem_base, next_base = 0; acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1); @@ -653,10 +782,23 @@ build_srat(void) next_base += (1ULL << 32) - RamSize; } acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1); + + numamem++; + slots++; + + } + mem = (void*)numamem; + + for (i = 1; i < nb_hp_memslots + 1; ++i) { + mem_base = *numadata++; + mem_len = *numadata++; + node = *numadata++; + acpi_build_srat_memory(numamem, mem_base, mem_len, node, 1); + dprintf(1, "hotplug memory slot %d on node %d\n", i, node); numamem++; slots++; } - for (; slots < nb_numa_nodes + 2; slots++) { + for (; slots < nb_numa_nodes + nb_hp_memslots + 2; slots++) { acpi_build_srat_memory(numamem, 0, 0, 0, 0); numamem++; } @@ -707,6 +849,7 @@ acpi_bios_init(void) ACPI_INIT_TABLE(build_madt()); ACPI_INIT_TABLE(build_hpet()); ACPI_INIT_TABLE(build_srat()); + ACPI_INIT_TABLE(build_memssdt()); ACPI_INIT_TABLE(build_pcihp()); u16 i, external_tables = qemu_cfg_acpi_additional_tables(); -- 1.7.9