From ee97f198b42d50437f87aa4111d478eca2a5be16 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Wed, 22 Feb 2023 02:27:37 +0000 Subject: [PATCH] Support SMBIOS v3 for 64-bit entry systems Summary: Under QEMU on arm64 systems, the smbios table is above 4GB requiring a 64-bit address to access. Reviewers: manu Subscribers: imp, bcran, dab Differential Revision: https://reviews.freebsd.org/D38721 --- stand/efi/loader/main.c | 3 ++- stand/libsa/smbios.c | 54 +++++++++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 446c267a517a..9ff5f1dd7674 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -1187,7 +1187,8 @@ main(int argc, CHAR16 *argv[]) #if !defined(__arm__) for (k = 0; k < ST->NumberOfTableEntries; k++) { guid = &ST->ConfigurationTable[k].VendorGuid; - if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) { + if (!memcmp(guid, &smbios, sizeof(EFI_GUID)) || + !memcmp(guid, &smbios3, sizeof(EFI_GUID))) { char buf[40]; snprintf(buf, sizeof(buf), "%p", diff --git a/stand/libsa/smbios.c b/stand/libsa/smbios.c index 61bd82f9d6f0..15c5c7e50565 100644 --- a/stand/libsa/smbios.c +++ b/stand/libsa/smbios.c @@ -32,6 +32,11 @@ __FBSDID("$FreeBSD$"); #define PTOV(x) ptov(x) +/* Only enable 64-bit entry point if it makes sense */ +#if __SIZEOF_POINTER__ > 4 +#define HAS_SMBV3 1 +#endif + /* * Detect SMBIOS and export information about the SMBIOS into the * environment. @@ -53,11 +58,13 @@ __FBSDID("$FreeBSD$"); #define SMBIOS_LENGTH 0x10000 #define SMBIOS_STEP 0x10 #define SMBIOS_SIG "_SM_" +#define SMBIOS3_SIG "_SM3_" #define SMBIOS_DMI_SIG "_DMI_" #define SMBIOS_GET8(base, off) (*(uint8_t *)((base) + (off))) #define SMBIOS_GET16(base, off) (*(uint16_t *)((base) + (off))) #define SMBIOS_GET32(base, off) (*(uint32_t *)((base) + (off))) +#define SMBIOS_GET64(base, off) (*(uint64_t *)((base) + (off))) #define SMBIOS_GETLEN(base) SMBIOS_GET8(base, 0x01) #define SMBIOS_GETSTR(base) ((base) + SMBIOS_GETLEN(base)) @@ -80,6 +87,9 @@ struct smbios_attr { }; static struct smbios_attr smbios; +#ifdef HAS_SMBV3 +static int isv3; +#endif static uint8_t smbios_checksum(const caddr_t addr, const uint8_t len) @@ -98,12 +108,23 @@ smbios_sigsearch(const caddr_t addr, const uint32_t len) caddr_t cp; /* Search on 16-byte boundaries. */ - for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) - if (strncmp(cp, SMBIOS_SIG, 4) == 0 && + for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) { + /* v2.1, 32-bit Entry point */ + if (strncmp(cp, SMBIOS_SIG, sizeof(SMBIOS_SIG) - 1) == 0 && smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 && strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5) == 0 && smbios_checksum(cp + 0x10, 0x0f) == 0) return (cp); + +#ifdef HAS_SMBV3 + /* v3.0, 64-bit Entry point */ + if (strncmp(cp, SMBIOS3_SIG, sizeof(SMBIOS3_SIG) - 1) == 0 && + smbios_checksum(cp, SMBIOS_GET8(cp, 0x06)) == 0) { + isv3 = 1; + return (cp); + } +#endif + } return (NULL); } @@ -450,6 +471,8 @@ smbios_probe(const caddr_t addr) { caddr_t saddr, info; uintptr_t paddr; + int maj_off; + int min_off; if (smbios.probed) return; @@ -461,10 +484,25 @@ smbios_probe(const caddr_t addr) if (saddr == NULL) return; - smbios.length = SMBIOS_GET16(saddr, 0x16); /* Structure Table Length */ - paddr = SMBIOS_GET32(saddr, 0x18); /* Structure Table Address */ - smbios.count = SMBIOS_GET16(saddr, 0x1c); /* No of SMBIOS Structures */ - smbios.ver = SMBIOS_GET8(saddr, 0x1e); /* SMBIOS BCD Revision */ +#ifdef HAS_SMBV3 + if (isv3) { + smbios.length = SMBIOS_GET16(saddr, 0x0c); /* Structure Table Length */ + paddr = SMBIOS_GET64(saddr, 0x10); /* Structure Table Address */ + smbios.count = -1; /* not present in V3 */ + smbios.ver = 0; /* not present in V3 */ + maj_off = 0x07; + min_off = 0x08; + } else +#endif + { + smbios.length = SMBIOS_GET16(saddr, 0x16); /* Structure Table Length */ + paddr = SMBIOS_GET32(saddr, 0x18); /* Structure Table Address */ + smbios.count = SMBIOS_GET16(saddr, 0x1c); /* No of SMBIOS Structures */ + smbios.ver = SMBIOS_GET8(saddr, 0x1e); /* SMBIOS BCD Revision */ + maj_off = 0x06; + min_off = 0x07; + } + if (smbios.ver != 0) { smbios.major = smbios.ver >> 4; @@ -473,8 +511,8 @@ smbios_probe(const caddr_t addr) smbios.ver = 0; } if (smbios.ver == 0) { - smbios.major = SMBIOS_GET8(saddr, 0x06);/* SMBIOS Major Version */ - smbios.minor = SMBIOS_GET8(saddr, 0x07);/* SMBIOS Minor Version */ + smbios.major = SMBIOS_GET8(saddr, maj_off);/* SMBIOS Major Version */ + smbios.minor = SMBIOS_GET8(saddr, min_off);/* SMBIOS Minor Version */ } smbios.ver = (smbios.major << 8) | smbios.minor; smbios.addr = PTOV(paddr);