[SeaBIOS] [RFC 1/3] Basic NVDIMM PMEM support
Marc Marí
markmb at redhat.com
Mon Sep 21 13:14:05 CET 2015
Follows the ACPI NFIT specification.
Signed-off-by: Marc Marí <markmb at 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 at 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;
--
2.4.3
More information about the SeaBIOS
mailing list