Patchwork [RFC,v2,04/21,SeaBIOS] acpi: generate hotplug memory devices

login
register
mail settings
Submitter Vasilis Liaskovitis
Date July 11, 2012, 10:31 a.m.
Message ID <1342002726-18258-5-git-send-email-vasilis.liaskovitis@profitbricks.com>
Download mbox | patch
Permalink /patch/170443/
State New
Headers show

Comments

Vasilis Liaskovitis - July 11, 2012, 10:31 a.m.
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.

Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
---
 src/acpi.c |  158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 152 insertions(+), 6 deletions(-)
Vasilis Liaskovitis - July 11, 2012, 4:39 p.m.
Hi,

On Wed, Jul 11, 2012 at 06:48:38PM +0800, Wen Congyang wrote:
> > +        if (enabled)
> > +            add_e820(mem_base, mem_len, E820_RAM);
> 
> add_e820() is declared in memmap.h. You should include this header file,
> otherwise, seabios cannot be built.

thanks. you had the same comment on v1 but I forgot to address it. I will
update.

- Vasilis
> 
> Thanks
> Wen Congyang
> 
> > +        memslot_status = memslot_status >> 1;
> > +        entry++;
> > +    }
> > +    build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
> > +
> > +    return ssdt;
> > +}
> > +
> >  #include "ssdt-pcihp.hex"
> >  
> >  #define PCI_RMV_BASE 0xae0c
> > @@ -618,9 +739,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();
> > @@ -629,10 +747,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) {
> > @@ -667,7 +786,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);
> > @@ -694,10 +813,36 @@ 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;
> > +
> > +    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 + 2; slots++) {
> > +
> > +    for (; slots < nb_numa_nodes + nb_hp_memslots + 2; slots++) {
> >          acpi_build_srat_memory(numamem, 0, 0, 0, 0);
> >          numamem++;
> >      }
> > @@ -748,6 +893,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();
>

Patch

diff --git a/src/acpi.c b/src/acpi.c
index 55e4607..c83e8c7 100644
--- a/src/acpi.c
+++ b/src/acpi.c
@@ -510,6 +510,127 @@  build_ssdt(void)
     return ssdt;
 }
 
+#include "ssdt-mem.hex"
+
+/* 0x5B 0x82 DeviceOp PkgLength NameString DimmID */
+#define MEM_BASE 0xaf80
+#define SD_MEM (ssdm_mem_aml + *ssdt_mem_start)
+#define SD_MEMSIZEOF (*ssdt_mem_end - *ssdt_mem_start)
+#define SD_OFFSET_MEMHEX (*ssdt_mem_name - *ssdt_mem_start + 2)
+#define SD_OFFSET_MEMID (*ssdt_mem_id - *ssdt_mem_start)
+#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, SD_MEM, SD_MEMSIZEOF);
+    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;
+    u8  memslot_status, enabled;
+
+    int length = ((1+3+4)
+                  + (nb_memdevs * SD_MEMSIZEOF)
+                  + (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 += SD_MEMSIZEOF;
+        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;
+}
+
 #include "ssdt-pcihp.hex"
 
 #define PCI_RMV_BASE 0xae0c
@@ -618,9 +739,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();
@@ -629,10 +747,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) {
@@ -667,7 +786,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);
@@ -694,10 +813,36 @@  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;
+
+    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 + 2; slots++) {
+
+    for (; slots < nb_numa_nodes + nb_hp_memslots + 2; slots++) {
         acpi_build_srat_memory(numamem, 0, 0, 0, 0);
         numamem++;
     }
@@ -748,6 +893,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();