Follows the ACPI NFIT specification.
Signed-off-by: Marc Marí markmb@redhat.com --- Makefile | 3 +- src/fw/biostables.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hw/nvdimm.c | 21 ++++++++++++++ src/hw/nvdimm.h | 11 ++++++++ src/post.c | 2 ++ src/std/acpi.h | 40 +++++++++++++++++++++++++++ src/util.h | 2 ++ 7 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/hw/nvdimm.c create mode 100644 src/hw/nvdimm.h
diff --git a/Makefile b/Makefile index 3a0d2e8..69a85a1 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,8 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \ hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \ hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \ hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \ - hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c + hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c \ + hw/nvdimm.c SRC16=$(SRCBOTH) SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \ pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c sha1.c \ diff --git a/src/fw/biostables.c b/src/fw/biostables.c index 71a1a0d..cb0f768 100644 --- a/src/fw/biostables.c +++ b/src/fw/biostables.c @@ -17,6 +17,7 @@ #include "string.h" // memcpy #include "util.h" // copy_table #include "x86.h" // outb +#include "hw/nvdimm.h"
struct pir_header *PirAddr VARFSEG;
@@ -172,6 +173,29 @@ find_resume_vector(void) return facs->firmware_waking_vector; }
+static struct nfit_descriptor * +find_nfit(void) +{ + dprintf(4, "rsdp=%p\n", RsdpAddr); + if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE) + return NULL; + struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address; + dprintf(4, "rsdt=%p\n", rsdt); + if (!rsdt || rsdt->signature != RSDT_SIGNATURE) + return NULL; + void *end = (void*)rsdt + rsdt->length; + int i; + for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) { + struct nfit_descriptor *nfit = (void*)rsdt->table_offset_entry[i]; + if (!nfit || nfit->signature != NFIT_SIGNATURE) + continue; + dprintf(4, "nfit=%p\n", nfit); + return nfit; + } + dprintf(4, "no nfit found\n"); + return NULL; +} + static struct acpi_20_generic_address acpi_reset_reg; static u8 acpi_reset_val; u32 acpi_pm1a_cnt VARFSEG; @@ -456,6 +480,62 @@ smbios_setup(void) smbios_legacy_setup(); }
+/**************************************************************** + * NFIT + ****************************************************************/ + +#define NVDIMM_MAX 10 /* To avoid using dynamic arrays. Any nicer solution? */ +struct nfit_descriptor *NfitAddr; +struct nvdimm_addr NvdimmAddr[NVDIMM_MAX + 1]; + +int nfit_setup(void) { + if (NfitAddr) { + return 1; + } + + NfitAddr = find_nfit(); + + if (!NfitAddr) { + return 0; + } + + void *addr = (void *)NfitAddr + sizeof(*NfitAddr); + struct nfit_spa *spa; + int index_nvdimm = 0; + + while (addr < ((void *)NfitAddr + NfitAddr->length)) { + u16 type = *((u16 *)addr); + u16 length = *((u16 *)(addr + 2)); + if (type == NFIT_TABLE_SPA) { + spa = addr; + + if (*(u64 *)(&spa->type_guid[0]) == *(u64 *)(&type_guid_pmem[0]) && + *(u64 *)(&spa->type_guid[8]) == *(u64 *)(&type_guid_pmem[8])) { + + NvdimmAddr[index_nvdimm].addr = spa->spa_base; + NvdimmAddr[index_nvdimm].length = spa->spa_length; + dprintf(1, "Found NVDIMM at address 0x%llx, size %llx\n", + spa->spa_base, spa->spa_length); + ++index_nvdimm; + + if (index_nvdimm == NVDIMM_MAX) { + dprintf(1, "Too many NVDIMMs. No more will be processed\n"); + return 1; + } + } + } + + addr += length; + } + + return 1; +} + +struct nvdimm_addr *nfit_get_pmem_addr(void) +{ + return NvdimmAddr; +} + void copy_table(void *pos) { diff --git a/src/hw/nvdimm.c b/src/hw/nvdimm.c new file mode 100644 index 0000000..f7c91a1 --- /dev/null +++ b/src/hw/nvdimm.c @@ -0,0 +1,21 @@ +// Support for finding and booting from NVDIMM +// +// Copyright (C) 2015 Marc Marí markmb@redhat.com +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "std/acpi.h" +#include "util.h" +#include "output.h" +#include "memmap.h" +#include "malloc.h" + +void nvdimm_setup(void) +{ + if (!nfit_setup()) { + dprintf(1, "No NVDIMMs found\n"); + return; + } + + dprintf(1, "NVDIMMs found\n"); +} diff --git a/src/hw/nvdimm.h b/src/hw/nvdimm.h new file mode 100644 index 0000000..1591b97 --- /dev/null +++ b/src/hw/nvdimm.h @@ -0,0 +1,11 @@ +#ifndef __NVDIMM_H +#define __NVDIMM_H + +struct nvdimm_addr { + u64 addr; + u64 length; +}; + +void nvdimm_setup(void); + +#endif diff --git a/src/post.c b/src/post.c index 6803585..a4d9737 100644 --- a/src/post.c +++ b/src/post.c @@ -23,6 +23,7 @@ #include "hw/usb.h" // usb_setup #include "hw/virtio-blk.h" // virtio_blk_setup #include "hw/virtio-scsi.h" // virtio_scsi_setup +#include "hw/nvdimm.h" // nvdimm setup #include "malloc.h" // malloc_init #include "memmap.h" // add_e820 #include "output.h" // dprintf @@ -153,6 +154,7 @@ device_hardware_setup(void) esp_scsi_setup(); megasas_setup(); pvscsi_setup(); + nvdimm_setup(); }
static void diff --git a/src/std/acpi.h b/src/std/acpi.h index b672bbe..2562976 100644 --- a/src/std/acpi.h +++ b/src/std/acpi.h @@ -313,5 +313,45 @@ struct tcpa_descriptor_rev2 #define TCPA_ACPI_CLASS_CLIENT 0 #define TCPA_ACPI_CLASS_SERVER 1
+/* + * NFIT (NVDIMM firmware interface) table + */ + +enum { + NFIT_TABLE_SPA = 0, + NFIT_TABLE_MEM = 1, + NFIT_TABLE_IDT = 2, + NFIT_TABLE_SMBIOS = 3, + NFIT_TABLE_DCR = 4, + NFIT_TABLE_BDW = 5, + NFIT_TABLE_FLUSH = 6, +}; + +#define NFIT_SIGNATURE 0x5449464E // NFIT +struct nfit_descriptor +{ + ACPI_TABLE_HEADER_DEF + u32 reserved; +} PACKED; + +/* + * struct nfit_spa - System Physical Address Range Structure + */ +struct nfit_spa { + u16 type; + u16 length; + u16 spa_index; + u16 flags; + u32 reserved; + u32 proximity_domain; + u8 type_guid[16]; + u64 spa_base; + u64 spa_length; + u64 mem_attr; +} PACKED; + +/* Converted into little endian */ +static const u8 type_guid_pmem[16] = {0x79, 0xD3, 0xF0, 0x66, 0xF3, 0xB4, 0x74, 0x40, + 0xAC, 0x43, 0x0D, 0x33, 0x18, 0xB7, 0x8C, 0xDB};
#endif // acpi.h diff --git a/src/util.h b/src/util.h index 327abeb..84478f8 100644 --- a/src/util.h +++ b/src/util.h @@ -80,6 +80,8 @@ void copy_smbios(void *pos); void display_uuid(void); void copy_table(void *pos); void smbios_setup(void); +int nfit_setup(void); +struct nvdimm_addr *nfit_get_pmem_addr(void);
// fw/coreboot.c extern const char *CBvendor, *CBpart;