[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH v4 04/30] [SeaBIOS] acpi: generate hotplug memor
From: |
Vasilis Liaskovitis |
Subject: |
[Qemu-devel] [RFC PATCH v4 04/30] [SeaBIOS] acpi: generate hotplug memory devices |
Date: |
Tue, 18 Dec 2012 13:41:32 +0100 |
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.
We only support up to 255 DIMMs for now (PackageOp used for the MEON array can
only describe an array of at most 255 elements. VarPackageOp would be needed to
support more than 255 devices)
v1->v2:
Seabios reads mems_sts from qemu to build e820_map
SSDT size and some offsets are calculated with extraction macros.
---
src/acpi.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 152 insertions(+), 6 deletions(-)
diff --git a/src/acpi.c b/src/acpi.c
index 6267d7b..82231da 100644
--- a/src/acpi.c
+++ b/src/acpi.c
@@ -14,6 +14,7 @@
#include "ioport.h" // inl
#include "paravirt.h" // qemu_cfg_irq0_override
#include "dev-q35.h" // qemu_cfg_irq0_override
+#include "memmap.h"
/****************************************************/
/* ACPI tables init */
@@ -446,11 +447,26 @@ encodeLen(u8 *ssdt_ptr, int length, int bytes)
#define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)
#define PCI_SLOTS 32
+/* 0x5B 0x82 DeviceOp PkgLength NameString DimmID */
+#define MEM_BASE 0xaf80
+#define MEM_AML (ssdm_mem_aml + *ssdt_mem_start)
+#define MEM_SIZEOF (*ssdt_mem_end - *ssdt_mem_start)
+#define MEM_OFFSET_HEX (*ssdt_mem_name - *ssdt_mem_start + 2)
+#define MEM_OFFSET_ID (*ssdt_mem_id - *ssdt_mem_start)
+#define MEM_OFFSET_PXM 31
+#define MEM_OFFSET_START 55
+#define MEM_OFFSET_END 63
+#define MEM_OFFSET_SIZE 79
+
+u64 nb_hp_memslots = 0;
+struct srat_memory_affinity *mem;
+
#define SSDT_SIGNATURE 0x54445353 // SSDT
#define SSDT_HEADER_LENGTH 36
#include "ssdt-susp.hex"
#include "ssdt-pcihp.hex"
+#include "ssdt-mem.hex"
#define PCI_RMV_BASE 0xae0c
@@ -502,6 +518,111 @@ static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject)
}
}
+static void build_memdev(u8 *ssdt_ptr, int i, u64 mem_base, u64 mem_len, u8
node)
+{
+ memcpy(ssdt_ptr, MEM_AML, MEM_SIZEOF);
+ ssdt_ptr[MEM_OFFSET_HEX] = getHex(i >> 4);
+ ssdt_ptr[MEM_OFFSET_HEX+1] = getHex(i);
+ ssdt_ptr[MEM_OFFSET_ID] = i;
+ ssdt_ptr[MEM_OFFSET_PXM] = node;
+ *(u64*)(ssdt_ptr + MEM_OFFSET_START) = mem_base;
+ *(u64*)(ssdt_ptr + MEM_OFFSET_END) = mem_base + mem_len;
+ *(u64*)(ssdt_ptr + MEM_OFFSET_SIZE) = 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;
+ u8 memslot_status, enabled;
+
+ int length = ((1+3+4)
+ + (nb_memdevs * MEM_SIZEOF)
+ + (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 += MEM_SIZEOF;
+ 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;
+ memslot_status = 0;
+
+ for (i = 0; i < nb_memdevs; i++) {
+ enabled = 0;
+ if (i % 8 == 0)
+ memslot_status = inb(MEM_BASE + i/8);
+ enabled = memslot_status & 1;
+ mem_base = (((u64)(entry->base_addr_high) << 32 )|
entry->base_addr_low);
+ mem_len = (((u64)(entry->length_high) << 32 )| entry->length_low);
+ *(ssdt_ptr++) = enabled ? 0x01 : 0x00;
+ if (enabled)
+ add_e820(mem_base, mem_len, E820_RAM);
+ memslot_status = memslot_status >> 1;
+ entry++;
+ }
+ build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
+
+ return ssdt;
+}
+
static void*
build_ssdt(void)
{
@@ -674,9 +795,6 @@ build_srat(void)
{
int nb_numa_nodes = qemu_cfg_get_numa_nodes();
- if (nb_numa_nodes == 0)
- return NULL;
-
u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs +
nb_numa_nodes));
if (!numadata) {
warn_noalloc();
@@ -685,10 +803,11 @@ build_srat(void)
qemu_cfg_get_numa_data(numadata, MaxCountCPUs + nb_numa_nodes);
+ qemu_cfg_get_numa_data(&nb_hp_memslots, 1);
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) {
@@ -723,7 +842,7 @@ build_srat(void)
* from 640k-1M and possibly another one from 3.5G-4G.
*/
struct srat_memory_affinity *numamem = (void*)core;
- int slots = 0;
+ int slots = 0, node;
u64 mem_len, mem_base, next_base = 0;
acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
@@ -750,10 +869,36 @@ build_srat(void)
next_base += (1ULL << 32) - RamSize;
}
acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+
numamem++;
slots++;
+
}
- for (; slots < nb_numa_nodes + 2; slots++) {
+ mem = (void*)numamem;
+
+ if (nb_hp_memslots) {
+ u64 *hpmemdata = malloc_tmphigh(sizeof(u64) * (3 * nb_hp_memslots));
+ if (!hpmemdata) {
+ warn_noalloc();
+ free(hpmemdata);
+ free(numadata);
+ return NULL;
+ }
+
+ qemu_cfg_get_numa_data(hpmemdata, 3 * nb_hp_memslots);
+
+ for (i = 1; i < nb_hp_memslots + 1; ++i) {
+ mem_base = *hpmemdata++;
+ mem_len = *hpmemdata++;
+ node = *hpmemdata++;
+ acpi_build_srat_memory(numamem, mem_base, mem_len, node, 1);
+ numamem++;
+ slots++;
+ }
+ free(hpmemdata);
+ }
+
+ for (; slots < nb_numa_nodes + nb_hp_memslots + 2; slots++) {
acpi_build_srat_memory(numamem, 0, 0, 0, 0);
numamem++;
}
@@ -825,6 +970,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());
if (pci->device == PCI_DEVICE_ID_INTEL_ICH9_LPC)
ACPI_INIT_TABLE(build_mcfg_q35());
--
1.7.9
- [Qemu-devel] [RFC PATCH v4 00/30] ACPI memory hotplug, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 01/30] [SeaBIOS] Add ACPI_EXTRACT_DEVICE* macros, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 03/30] [SeaBIOS] acpi-dsdt: Implement functions for memory hotplug, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 02/30] [SeaBIOS] Add SSDT memory device support, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 04/30] [SeaBIOS] acpi: generate hotplug memory devices,
Vasilis Liaskovitis <=
- [Qemu-devel] [RFC PATCH v4 05/30] [SeaBIOS] q35: Add memory hotplug handler, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 06/30] qapi: make visit_type_size fallback to type_int, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 07/30] Add SIZE type to qdev properties, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 08/30] qemu-option: export parse_option_number, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 10/30] vl: handle "-device dimm", Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 09/30] Implement dimm device abstraction, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 12/30] acpi_ich9 : Implement memory device hotplug registers, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 17/30] [SeaBIOS] pci: Use paravirt interface for pcimem_start and pcimem64_start, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 13/30] piix_pci and pc_piix: refactor, Vasilis Liaskovitis, 2012/12/18
- [Qemu-devel] [RFC PATCH v4 15/30] q35: Add i440fx dram controller initialization, Vasilis Liaskovitis, 2012/12/18