[SeaBIOS] [RFC PATCH v2 04/21] acpi: generate hotplug memory devices
Wen Congyang
wency at cn.fujitsu.com
Wed Jul 11 12:48:38 CEST 2012
At 07/11/2012 06:31 PM, Vasilis Liaskovitis Wrote:
> 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 at profitbricks.com>
> ---
> src/acpi.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 files changed, 152 insertions(+), 6 deletions(-)
>
> 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);
add_e820() is declared in memmap.h. You should include this header file,
otherwise, seabios cannot be built.
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();
More information about the SeaBIOS
mailing list