Index: sys/dev/smbios/smbios.h =================================================================== --- sys/dev/smbios/smbios.h +++ sys/dev/smbios/smbios.h @@ -40,6 +40,8 @@ #define SMBIOS_OFF 0 #define SMBIOS_LEN 4 #define SMBIOS_SIG "_SM_" +#define SMBIOS3_LEN 5 +#define SMBIOS3_SIG "_SM3_" struct smbios_eps { uint8_t anchor_string[4]; /* '_SM_' */ @@ -58,6 +60,19 @@ uint8_t BCD_revision; }; +struct smbios3_eps { + uint8_t anchor_string[5]; /* '_SM3_' */ + uint8_t checksum; + uint8_t length; + uint8_t major_version; + uint8_t minor_version; + uint8_t docrev; + uint8_t entry_point_revision; + uint8_t reserved; + uint32_t structure_table_max_size; + uint64_t structure_table_address; +}; + struct smbios_structure_header { uint8_t type; uint8_t length; Index: sys/dev/smbios/smbios.c =================================================================== --- sys/dev/smbios/smbios.c +++ sys/dev/smbios/smbios.c @@ -61,10 +61,15 @@ struct resource * res; int rid; - struct smbios_eps * eps; + union { + struct smbios_eps * eps; + struct smbios3_eps * eps3; + }; + bool eps_64bit; }; #define RES2EPS(res) ((struct smbios_eps *)rman_get_virtual(res)) +#define RES2EPS3(res) ((struct smbios3_eps *)rman_get_virtual(res)) static devclass_t smbios_devclass; @@ -74,33 +79,49 @@ static int smbios_detach (device_t); static int smbios_modevent (module_t, int, void *); -static int smbios_cksum (struct smbios_eps *); +static bool smbios_eps_64bit(void *); +static int smbios_cksum (void *); static void smbios_identify (driver_t *driver, device_t parent) { + struct smbios3_eps *eps3; struct smbios_eps *eps; device_t child; vm_paddr_t addr; int length; int rid; + bool eps_64bit; if (!device_is_alive(parent)) return; #if defined(__amd64__) || defined(__i386__) - addr = bios_sigsearch(SMBIOS_START, SMBIOS_SIG, SMBIOS_LEN, + addr = bios_sigsearch(SMBIOS_START, SMBIOS3_SIG, SMBIOS3_LEN, SMBIOS_STEP, SMBIOS_OFF); + + if (addr != 0) { + eps_64bit = true; + } else { + eps_64bit = false; + addr = bios_sigsearch(SMBIOS_START, SMBIOS_SIG, SMBIOS_LEN, + SMBIOS_STEP, SMBIOS_OFF); + } #else addr = 0; #endif if (addr != 0) { - eps = pmap_mapbios(addr, 0x1f); + if (eps_64bit) { + eps3 = pmap_mapbios(addr, 0x18); + length = eps3->length; + } else { + eps = pmap_mapbios(addr, 0x1f); + length = eps->length; + } rid = 0; - length = eps->length; - if (length != 0x1f) { + if (!eps_64bit && length != 0x1f) { u_int8_t major, minor; major = eps->major_version; @@ -117,7 +138,11 @@ device_set_driver(child, driver); bus_set_resource(child, SYS_RES_MEMORY, rid, addr, length); device_set_desc(child, "System Management BIOS"); - pmap_unmapbios((vm_offset_t)eps, 0x1f); + + if (eps_64bit) + pmap_unmapbios((vm_offset_t)eps3, 0x18); + else + pmap_unmapbios((vm_offset_t)eps, 0x1f); } return; @@ -139,7 +164,7 @@ goto bad; } - if (smbios_cksum(RES2EPS(res))) { + if (smbios_cksum(rman_get_virtual(res))) { device_printf(dev, "SMBIOS checksum failed.\n"); error = ENXIO; goto bad; @@ -169,14 +194,21 @@ error = ENOMEM; goto bad; } - sc->eps = RES2EPS(sc->res); - - device_printf(dev, "Version: %u.%u", - sc->eps->major_version, sc->eps->minor_version); - if (bcd2bin(sc->eps->BCD_revision)) - printf(", BCD Revision: %u.%u", - bcd2bin(sc->eps->BCD_revision >> 4), - bcd2bin(sc->eps->BCD_revision & 0x0f)); + sc->eps_64bit = smbios_eps_64bit(rman_get_virtual(sc->res)); + + if (sc->eps_64bit) { + sc->eps3 = RES2EPS3(sc->res); + device_printf(dev, "Version: %u.%u", + sc->eps3->major_version, sc->eps3->minor_version); + } else { + sc->eps = RES2EPS(sc->res); + device_printf(dev, "Version: %u.%u", + sc->eps->major_version, sc->eps->minor_version); + if (bcd2bin(sc->eps->BCD_revision)) + printf(", BCD Revision: %u.%u", + bcd2bin(sc->eps->BCD_revision >> 4), + bcd2bin(sc->eps->BCD_revision & 0x0f)); + } printf("\n"); return (0); @@ -244,16 +276,35 @@ DRIVER_MODULE(smbios, nexus, smbios_driver, smbios_devclass, smbios_modevent, 0); MODULE_VERSION(smbios, 1); +static bool +smbios_eps_64bit (void *v) +{ + struct smbios3_eps *e; + + e = (struct smbios3_eps *)v; + return (memcmp(e->anchor_string, SMBIOS3_SIG, SMBIOS3_LEN) == 0); +} + static int -smbios_cksum (struct smbios_eps *e) +smbios_cksum (void *v) { + struct smbios3_eps *eps3; + struct smbios_eps *eps; u_int8_t *ptr; u_int8_t cksum; + u_int8_t length; int i; - ptr = (u_int8_t *)e; + if (smbios_eps_64bit(v)) { + eps3 = (struct smbios3_eps *)v; + length = eps3->length; + } else { + eps = (struct smbios_eps *)v; + length = eps->length; + } + ptr = (u_int8_t *)v; cksum = 0; - for (i = 0; i < e->length; i++) { + for (i = 0; i < length; i++) { cksum += ptr[i]; }