diff --git a/sys/dev/smbios/smbios.h b/sys/dev/smbios/smbios.h --- a/sys/dev/smbios/smbios.h +++ b/sys/dev/smbios/smbios.h @@ -64,6 +64,54 @@ uint16_t handle; } __packed; +struct smbios_bios_information { + struct smbios_structure_header header; + uint8_t vendor_str; + uint8_t version_str; + uint16_t starting_addr_segment; + uint8_t release_date_str; + uint8_t rom_size; + uint64_t characteristics; +} __packed; + +struct smbios_system_information { + struct smbios_structure_header header; + uint8_t manufacturer_str; + uint8_t product_str; + uint8_t version_str; + uint8_t serial_str; + /* SMBIOS 2.1+ */ + uint8_t uuid[16]; + uint8_t wakeup_type; + /* SMBIOS 2.4+ */ + uint8_t sku_str; + uint8_t family_str; +} __packed; + +struct smbios_board_information { + struct smbios_structure_header header; + uint8_t manufacturer_str; + uint8_t product_str; + uint8_t version_str; + uint8_t serial_str; + uint8_t asset_tag_str; + uint8_t features; + uint8_t location_in_chassis_str; + uint16_t chassis_handle; + uint8_t board_type; + uint8_t num_handles; + uint16_t handles[]; +} __packed; + +struct smbios_chassis_information { + struct smbios_structure_header header; + uint8_t manufacturer_str; + uint8_t chassis_type; + uint8_t version_str; + uint8_t serial_str; + uint8_t asset_tag_str; +} __packed; + typedef void (*smbios_callback_t)(struct smbios_structure_header *, void *); static inline void @@ -91,4 +139,21 @@ } } +static inline const char * +smbios_nth_string(uint8_t *strings, size_t n) +{ + const char *res = (const char*)strings; + int i, len; + + /* Find a string by its 1-based (!) index */ + for (i = 0; i < n - 1; i++) { + len = strlen(res); + if (len == 0) + return (NULL); + res += len + 1; + } + + return (res); +} + #endif /* _SMBIOS_H_ */ diff --git a/sys/dev/smbios/smbios.c b/sys/dev/smbios/smbios.c --- a/sys/dev/smbios/smbios.c +++ b/sys/dev/smbios/smbios.c @@ -3,6 +3,7 @@ * * Copyright (c) 2003 Matthew N. Dodd * All rights reserved. + * Copyright (c) 2021 Greg V * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +35,7 @@ #include #include #include +#include #if defined(__amd64__) || defined(__aarch64__) #include #endif @@ -59,6 +61,36 @@ * http://www.dmtf.org/standards/published_documents/DSP0134.pdf */ +static SYSCTL_NODE(_hw, OID_AUTO, dmi, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, + "SMBIOS DMI system information"); + +#define DMI_SYSCTL(name, desc) \ + static char name[128] = { 0 }; \ + SYSCTL_STRING(_hw_dmi, OID_AUTO, name, CTLFLAG_RD, name, 0, desc) + +#define DMI_SYSCTL_INT(name, desc) \ + static int name = 0; \ + SYSCTL_INT(_hw_dmi, OID_AUTO, name, CTLFLAG_RD, &name, 0, desc) + +#define STRLCPY(dst, src) strlcpy((dst), (src), sizeof(dst)) + +/* The names match Linux sysfs */ +DMI_SYSCTL(bios_vendor, "Firmware vendor name"); +DMI_SYSCTL(bios_version, "Firmware version"); +DMI_SYSCTL(bios_date, "Firmware release date"); +DMI_SYSCTL(sys_vendor, "System vendor name"); +DMI_SYSCTL(product_name, "System product name"); +DMI_SYSCTL(product_version, "System product version"); +DMI_SYSCTL(product_family, "System product family"); +DMI_SYSCTL(board_asset_tag, "Board asset tag"); +DMI_SYSCTL(board_vendor, "Baseboard/module vendor name"); +DMI_SYSCTL(board_name, "Baseboard/module product name"); +DMI_SYSCTL(board_version, "Baseboard/module version"); +DMI_SYSCTL(chassis_asset_tag, "Chassis asset tag"); +DMI_SYSCTL(chassis_vendor, "Chassis vendor name"); +DMI_SYSCTL(chassis_version, "Chassis version"); +DMI_SYSCTL_INT(chassis_type, "Chassis type"); + struct smbios_softc { device_t dev; struct resource * res; @@ -162,11 +194,96 @@ return (error); } +static void +smbios_bios_info(struct smbios_bios_information *tbl, struct smbios_softc *sc) +{ + uint8_t *strings = (uint8_t*)tbl + tbl->header.length; + + if (tbl->vendor_str) + STRLCPY(bios_vendor, smbios_nth_string(strings, tbl->vendor_str)); + if (tbl->version_str) + STRLCPY(bios_version, smbios_nth_string(strings, tbl->version_str)); + if (tbl->release_date_str) + STRLCPY(bios_date, smbios_nth_string(strings, tbl->release_date_str)); + + device_printf(sc->dev, "Firmware: %s (%s) %s\n", bios_version, bios_date, bios_vendor); +} + +static void +smbios_system_info(struct smbios_system_information *tbl, struct smbios_softc *sc) +{ + uint8_t *strings = (uint8_t*)tbl + tbl->header.length; + + if (tbl->manufacturer_str) + STRLCPY(sys_vendor, smbios_nth_string(strings, tbl->manufacturer_str)); + if (tbl->product_str) + STRLCPY(product_name, smbios_nth_string(strings, tbl->product_str)); + if (tbl->version_str) + STRLCPY(product_version, smbios_nth_string(strings, tbl->version_str)); + if (tbl->header.length >= 0x1b && tbl->family_str) + STRLCPY(product_family, smbios_nth_string(strings, tbl->family_str)); +} + +static void +smbios_board_info(struct smbios_board_information *tbl, struct smbios_softc *sc) +{ + uint8_t *strings = (uint8_t*)tbl + tbl->header.length; + + if (tbl->manufacturer_str) + STRLCPY(board_vendor, smbios_nth_string(strings, tbl->manufacturer_str)); + if (tbl->product_str) + STRLCPY(board_name, smbios_nth_string(strings, tbl->product_str)); + if (tbl->version_str) + STRLCPY(board_version, smbios_nth_string(strings, tbl->version_str)); + if (tbl->asset_tag_str) + STRLCPY(board_asset_tag, smbios_nth_string(strings, tbl->asset_tag_str)); + + device_printf(sc->dev, "Board: %s %s %s\n", board_vendor, board_name, board_version); +} + +static void +smbios_chassis_info(struct smbios_chassis_information *tbl, struct smbios_softc *sc) +{ + uint8_t *strings = (uint8_t*)tbl + tbl->header.length; + + chassis_type = tbl->chassis_type; + if (tbl->asset_tag_str) + STRLCPY(chassis_asset_tag, smbios_nth_string(strings, tbl->asset_tag_str)); + if (tbl->manufacturer_str) + STRLCPY(chassis_vendor, smbios_nth_string(strings, tbl->manufacturer_str)); + if (tbl->version_str) + STRLCPY(chassis_version, smbios_nth_string(strings, tbl->version_str)); +} + +static void +smbios_dmi_info(struct smbios_structure_header *h, void *arg) +{ + struct smbios_softc *sc = arg; + + switch (h->type) { + case 0: + smbios_bios_info((struct smbios_bios_information *)h, sc); + break; + case 1: + smbios_system_info((struct smbios_system_information *)h, sc); + break; + case 2: + smbios_board_info((struct smbios_board_information *)h, sc); + break; + case 3: + smbios_chassis_info((struct smbios_chassis_information *)h, sc); + break; + default: + break; + } +} + static int smbios_attach (device_t dev) { struct smbios_softc *sc; int error; + void *table; sc = device_get_softc(dev); error = 0; @@ -190,6 +307,11 @@ bcd2bin(sc->eps->BCD_revision & 0x0f)); printf("\n"); + table = pmap_mapbios(sc->eps->structure_table_address, + sc->eps->structure_table_length); + smbios_walk_table(table, sc->eps->number_structures, smbios_dmi_info, sc); + pmap_unmapbios((vm_offset_t)table, sc->eps->structure_table_length); + return (0); bad: if (sc->res)