1a64f0b83SWarner Losh /*- 2a64f0b83SWarner Losh * Copyright (c) 2005-2009 Jung-uk Kim <jkim@FreeBSD.org> 3a64f0b83SWarner Losh * All rights reserved. 4a64f0b83SWarner Losh * 5a64f0b83SWarner Losh * Redistribution and use in source and binary forms, with or without 6a64f0b83SWarner Losh * modification, are permitted provided that the following conditions 7a64f0b83SWarner Losh * are met: 8a64f0b83SWarner Losh * 1. Redistributions of source code must retain the above copyright 9a64f0b83SWarner Losh * notice, this list of conditions and the following disclaimer. 10a64f0b83SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11a64f0b83SWarner Losh * notice, this list of conditions and the following disclaimer in the 12a64f0b83SWarner Losh * documentation and/or other materials provided with the distribution. 13a64f0b83SWarner Losh * 14a64f0b83SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a64f0b83SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a64f0b83SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a64f0b83SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a64f0b83SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a64f0b83SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a64f0b83SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a64f0b83SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a64f0b83SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a64f0b83SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a64f0b83SWarner Losh * SUCH DAMAGE. 25a64f0b83SWarner Losh */ 26a64f0b83SWarner Losh 27a64f0b83SWarner Losh #include <sys/cdefs.h> 28a64f0b83SWarner Losh __FBSDID("$FreeBSD$"); 29a64f0b83SWarner Losh 30a64f0b83SWarner Losh #include <stand.h> 31a64f0b83SWarner Losh #include <sys/endian.h> 32a64f0b83SWarner Losh 33a64f0b83SWarner Losh #define PTOV(x) ptov(x) 34a64f0b83SWarner Losh 35ee97f198SJohn-Mark Gurney /* Only enable 64-bit entry point if it makes sense */ 36ee97f198SJohn-Mark Gurney #if __SIZEOF_POINTER__ > 4 37ee97f198SJohn-Mark Gurney #define HAS_SMBV3 1 38ee97f198SJohn-Mark Gurney #endif 39ee97f198SJohn-Mark Gurney 40a64f0b83SWarner Losh /* 41a64f0b83SWarner Losh * Detect SMBIOS and export information about the SMBIOS into the 42a64f0b83SWarner Losh * environment. 43a64f0b83SWarner Losh * 44a64f0b83SWarner Losh * System Management BIOS Reference Specification, v2.6 Final 45a64f0b83SWarner Losh * http://www.dmtf.org/standards/published_documents/DSP0134_2.6.0.pdf 46a64f0b83SWarner Losh */ 47a64f0b83SWarner Losh 48a64f0b83SWarner Losh /* 49a64f0b83SWarner Losh * 2.1.1 SMBIOS Structure Table Entry Point 50a64f0b83SWarner Losh * 51a64f0b83SWarner Losh * "On non-EFI systems, the SMBIOS Entry Point structure, described below, can 52a64f0b83SWarner Losh * be located by application software by searching for the anchor-string on 53a64f0b83SWarner Losh * paragraph (16-byte) boundaries within the physical memory address range 54a64f0b83SWarner Losh * 000F0000h to 000FFFFFh. This entry point encapsulates an intermediate anchor 55a64f0b83SWarner Losh * string that is used by some existing DMI browsers." 56a64f0b83SWarner Losh */ 57a64f0b83SWarner Losh #define SMBIOS_START 0xf0000 58a64f0b83SWarner Losh #define SMBIOS_LENGTH 0x10000 59a64f0b83SWarner Losh #define SMBIOS_STEP 0x10 60a64f0b83SWarner Losh #define SMBIOS_SIG "_SM_" 61ee97f198SJohn-Mark Gurney #define SMBIOS3_SIG "_SM3_" 62a64f0b83SWarner Losh #define SMBIOS_DMI_SIG "_DMI_" 63a64f0b83SWarner Losh 64a64f0b83SWarner Losh #define SMBIOS_GET8(base, off) (*(uint8_t *)((base) + (off))) 65a64f0b83SWarner Losh #define SMBIOS_GET16(base, off) (*(uint16_t *)((base) + (off))) 66a64f0b83SWarner Losh #define SMBIOS_GET32(base, off) (*(uint32_t *)((base) + (off))) 67ee97f198SJohn-Mark Gurney #define SMBIOS_GET64(base, off) (*(uint64_t *)((base) + (off))) 68a64f0b83SWarner Losh 69a64f0b83SWarner Losh #define SMBIOS_GETLEN(base) SMBIOS_GET8(base, 0x01) 70a64f0b83SWarner Losh #define SMBIOS_GETSTR(base) ((base) + SMBIOS_GETLEN(base)) 71a64f0b83SWarner Losh 72a64f0b83SWarner Losh struct smbios_attr { 73a64f0b83SWarner Losh int probed; 74a64f0b83SWarner Losh caddr_t addr; 75a64f0b83SWarner Losh size_t length; 76a64f0b83SWarner Losh size_t count; 77a64f0b83SWarner Losh int major; 78a64f0b83SWarner Losh int minor; 79a64f0b83SWarner Losh int ver; 80a64f0b83SWarner Losh const char* bios_vendor; 81a64f0b83SWarner Losh const char* maker; 82a64f0b83SWarner Losh const char* product; 83a64f0b83SWarner Losh uint32_t enabled_memory; 84a64f0b83SWarner Losh uint32_t old_enabled_memory; 85a64f0b83SWarner Losh uint8_t enabled_sockets; 86a64f0b83SWarner Losh uint8_t populated_sockets; 87a64f0b83SWarner Losh }; 88a64f0b83SWarner Losh 89a64f0b83SWarner Losh static struct smbios_attr smbios; 90ee97f198SJohn-Mark Gurney #ifdef HAS_SMBV3 91ee97f198SJohn-Mark Gurney static int isv3; 92ee97f198SJohn-Mark Gurney #endif 93a64f0b83SWarner Losh 94a64f0b83SWarner Losh static uint8_t 95a64f0b83SWarner Losh smbios_checksum(const caddr_t addr, const uint8_t len) 96a64f0b83SWarner Losh { 97a64f0b83SWarner Losh uint8_t sum; 98a64f0b83SWarner Losh int i; 99a64f0b83SWarner Losh 100a64f0b83SWarner Losh for (sum = 0, i = 0; i < len; i++) 101a64f0b83SWarner Losh sum += SMBIOS_GET8(addr, i); 102a64f0b83SWarner Losh return (sum); 103a64f0b83SWarner Losh } 104a64f0b83SWarner Losh 105a64f0b83SWarner Losh static caddr_t 106a64f0b83SWarner Losh smbios_sigsearch(const caddr_t addr, const uint32_t len) 107a64f0b83SWarner Losh { 108a64f0b83SWarner Losh caddr_t cp; 109a64f0b83SWarner Losh 110a64f0b83SWarner Losh /* Search on 16-byte boundaries. */ 111ee97f198SJohn-Mark Gurney for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) { 112ee97f198SJohn-Mark Gurney /* v2.1, 32-bit Entry point */ 113ee97f198SJohn-Mark Gurney if (strncmp(cp, SMBIOS_SIG, sizeof(SMBIOS_SIG) - 1) == 0 && 114a64f0b83SWarner Losh smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 && 115a64f0b83SWarner Losh strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5) == 0 && 116a64f0b83SWarner Losh smbios_checksum(cp + 0x10, 0x0f) == 0) 117a64f0b83SWarner Losh return (cp); 118ee97f198SJohn-Mark Gurney 119ee97f198SJohn-Mark Gurney #ifdef HAS_SMBV3 120ee97f198SJohn-Mark Gurney /* v3.0, 64-bit Entry point */ 121ee97f198SJohn-Mark Gurney if (strncmp(cp, SMBIOS3_SIG, sizeof(SMBIOS3_SIG) - 1) == 0 && 122ee97f198SJohn-Mark Gurney smbios_checksum(cp, SMBIOS_GET8(cp, 0x06)) == 0) { 123ee97f198SJohn-Mark Gurney isv3 = 1; 124ee97f198SJohn-Mark Gurney return (cp); 125ee97f198SJohn-Mark Gurney } 126ee97f198SJohn-Mark Gurney #endif 127ee97f198SJohn-Mark Gurney } 128a64f0b83SWarner Losh return (NULL); 129a64f0b83SWarner Losh } 130a64f0b83SWarner Losh 131a64f0b83SWarner Losh static const char* 132a64f0b83SWarner Losh smbios_getstring(caddr_t addr, const int offset) 133a64f0b83SWarner Losh { 134a64f0b83SWarner Losh caddr_t cp; 135a64f0b83SWarner Losh int i, idx; 136a64f0b83SWarner Losh 137a64f0b83SWarner Losh idx = SMBIOS_GET8(addr, offset); 138a64f0b83SWarner Losh if (idx != 0) { 139a64f0b83SWarner Losh cp = SMBIOS_GETSTR(addr); 140a64f0b83SWarner Losh for (i = 1; i < idx; i++) 141a64f0b83SWarner Losh cp += strlen(cp) + 1; 142a64f0b83SWarner Losh return cp; 143a64f0b83SWarner Losh } 144a64f0b83SWarner Losh return (NULL); 145a64f0b83SWarner Losh } 146a64f0b83SWarner Losh 147a64f0b83SWarner Losh static void 148a64f0b83SWarner Losh smbios_setenv(const char *name, caddr_t addr, const int offset) 149a64f0b83SWarner Losh { 150a64f0b83SWarner Losh const char* val; 151a64f0b83SWarner Losh 152a64f0b83SWarner Losh val = smbios_getstring(addr, offset); 153a64f0b83SWarner Losh if (val != NULL) 154a64f0b83SWarner Losh setenv(name, val, 1); 155a64f0b83SWarner Losh } 156a64f0b83SWarner Losh 157a64f0b83SWarner Losh #ifdef SMBIOS_SERIAL_NUMBERS 158a64f0b83SWarner Losh 159a64f0b83SWarner Losh #define UUID_SIZE 16 160a64f0b83SWarner Losh #define UUID_TYPE uint32_t 161a64f0b83SWarner Losh #define UUID_STEP sizeof(UUID_TYPE) 162a64f0b83SWarner Losh #define UUID_ALL_BITS (UUID_SIZE / UUID_STEP) 163a64f0b83SWarner Losh #define UUID_GET(base, off) (*(UUID_TYPE *)((base) + (off))) 164a64f0b83SWarner Losh 165a64f0b83SWarner Losh static void 166a64f0b83SWarner Losh smbios_setuuid(const char *name, const caddr_t addr, const int ver) 167a64f0b83SWarner Losh { 168a64f0b83SWarner Losh char uuid[37]; 169a64f0b83SWarner Losh int byteorder, i, ones, zeros; 170a64f0b83SWarner Losh UUID_TYPE n; 171a64f0b83SWarner Losh uint32_t f1; 172a64f0b83SWarner Losh uint16_t f2, f3; 173a64f0b83SWarner Losh 174a64f0b83SWarner Losh for (i = 0, ones = 0, zeros = 0; i < UUID_SIZE; i += UUID_STEP) { 175a64f0b83SWarner Losh n = UUID_GET(addr, i) + 1; 176a64f0b83SWarner Losh if (zeros == 0 && n == 0) 177a64f0b83SWarner Losh ones++; 178a64f0b83SWarner Losh else if (ones == 0 && n == 1) 179a64f0b83SWarner Losh zeros++; 180a64f0b83SWarner Losh else 181a64f0b83SWarner Losh break; 182a64f0b83SWarner Losh } 183a64f0b83SWarner Losh 184a64f0b83SWarner Losh if (ones != UUID_ALL_BITS && zeros != UUID_ALL_BITS) { 185a64f0b83SWarner Losh /* 186a64f0b83SWarner Losh * 3.3.2.1 System UUID 187a64f0b83SWarner Losh * 188a64f0b83SWarner Losh * "Although RFC 4122 recommends network byte order for all 189a64f0b83SWarner Losh * fields, the PC industry (including the ACPI, UEFI, and 190a64f0b83SWarner Losh * Microsoft specifications) has consistently used 191a64f0b83SWarner Losh * little-endian byte encoding for the first three fields: 192a64f0b83SWarner Losh * time_low, time_mid, time_hi_and_version. The same encoding, 193a64f0b83SWarner Losh * also known as wire format, should also be used for the 194a64f0b83SWarner Losh * SMBIOS representation of the UUID." 195a64f0b83SWarner Losh * 196a64f0b83SWarner Losh * Note: We use network byte order for backward compatibility 197a64f0b83SWarner Losh * unless SMBIOS version is 2.6+ or little-endian is forced. 198a64f0b83SWarner Losh */ 199a64f0b83SWarner Losh #if defined(SMBIOS_LITTLE_ENDIAN_UUID) 200a64f0b83SWarner Losh byteorder = LITTLE_ENDIAN; 201a64f0b83SWarner Losh #elif defined(SMBIOS_NETWORK_ENDIAN_UUID) 202a64f0b83SWarner Losh byteorder = BIG_ENDIAN; 203a64f0b83SWarner Losh #else 204a64f0b83SWarner Losh byteorder = ver < 0x0206 ? BIG_ENDIAN : LITTLE_ENDIAN; 205a64f0b83SWarner Losh #endif 206a64f0b83SWarner Losh if (byteorder != LITTLE_ENDIAN) { 207a64f0b83SWarner Losh f1 = ntohl(SMBIOS_GET32(addr, 0)); 208a64f0b83SWarner Losh f2 = ntohs(SMBIOS_GET16(addr, 4)); 209a64f0b83SWarner Losh f3 = ntohs(SMBIOS_GET16(addr, 6)); 210a64f0b83SWarner Losh } else { 211a64f0b83SWarner Losh f1 = le32toh(SMBIOS_GET32(addr, 0)); 212a64f0b83SWarner Losh f2 = le16toh(SMBIOS_GET16(addr, 4)); 213a64f0b83SWarner Losh f3 = le16toh(SMBIOS_GET16(addr, 6)); 214a64f0b83SWarner Losh } 215a64f0b83SWarner Losh sprintf(uuid, 216a64f0b83SWarner Losh "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 217a64f0b83SWarner Losh f1, f2, f3, SMBIOS_GET8(addr, 8), SMBIOS_GET8(addr, 9), 218a64f0b83SWarner Losh SMBIOS_GET8(addr, 10), SMBIOS_GET8(addr, 11), 219a64f0b83SWarner Losh SMBIOS_GET8(addr, 12), SMBIOS_GET8(addr, 13), 220a64f0b83SWarner Losh SMBIOS_GET8(addr, 14), SMBIOS_GET8(addr, 15)); 221a64f0b83SWarner Losh setenv(name, uuid, 1); 222a64f0b83SWarner Losh } 223a64f0b83SWarner Losh } 224a64f0b83SWarner Losh 225a64f0b83SWarner Losh #undef UUID_SIZE 226a64f0b83SWarner Losh #undef UUID_TYPE 227a64f0b83SWarner Losh #undef UUID_STEP 228a64f0b83SWarner Losh #undef UUID_ALL_BITS 229a64f0b83SWarner Losh #undef UUID_GET 230a64f0b83SWarner Losh 231a64f0b83SWarner Losh #endif 232a64f0b83SWarner Losh 2339060f2c3SEmmanuel Vadot static const char * 2349060f2c3SEmmanuel Vadot smbios_parse_chassis_type(caddr_t addr) 2359060f2c3SEmmanuel Vadot { 2369060f2c3SEmmanuel Vadot int type; 2379060f2c3SEmmanuel Vadot 2389060f2c3SEmmanuel Vadot type = SMBIOS_GET8(addr, 0x5); 2399060f2c3SEmmanuel Vadot switch (type) { 2409060f2c3SEmmanuel Vadot case 0x1: 2419060f2c3SEmmanuel Vadot return ("Other"); 2429060f2c3SEmmanuel Vadot case 0x2: 2439060f2c3SEmmanuel Vadot return ("Unknown"); 2449060f2c3SEmmanuel Vadot case 0x3: 2459060f2c3SEmmanuel Vadot return ("Desktop"); 2469060f2c3SEmmanuel Vadot case 0x4: 2479060f2c3SEmmanuel Vadot return ("Low Profile Desktop"); 2489060f2c3SEmmanuel Vadot case 0x5: 2499060f2c3SEmmanuel Vadot return ("Pizza Box"); 2509060f2c3SEmmanuel Vadot case 0x6: 2519060f2c3SEmmanuel Vadot return ("Mini Tower"); 2529060f2c3SEmmanuel Vadot case 0x7: 2539060f2c3SEmmanuel Vadot return ("Tower"); 2549060f2c3SEmmanuel Vadot case 0x8: 2559060f2c3SEmmanuel Vadot return ("Portable"); 2569060f2c3SEmmanuel Vadot case 0x9: 2579060f2c3SEmmanuel Vadot return ("Laptop"); 2589060f2c3SEmmanuel Vadot case 0xA: 2599060f2c3SEmmanuel Vadot return ("Notebook"); 2609060f2c3SEmmanuel Vadot case 0xB: 2619060f2c3SEmmanuel Vadot return ("Hand Held"); 2629060f2c3SEmmanuel Vadot case 0xC: 2639060f2c3SEmmanuel Vadot return ("Docking Station"); 2649060f2c3SEmmanuel Vadot case 0xD: 2659060f2c3SEmmanuel Vadot return ("All in One"); 2669060f2c3SEmmanuel Vadot case 0xE: 2679060f2c3SEmmanuel Vadot return ("Sub Notebook"); 2689060f2c3SEmmanuel Vadot case 0xF: 2699060f2c3SEmmanuel Vadot return ("Lunch Box"); 2709060f2c3SEmmanuel Vadot case 0x10: 2719060f2c3SEmmanuel Vadot return ("Space-saving"); 2729060f2c3SEmmanuel Vadot case 0x11: 2739060f2c3SEmmanuel Vadot return ("Main Server Chassis"); 2749060f2c3SEmmanuel Vadot case 0x12: 2759060f2c3SEmmanuel Vadot return ("Expansion Chassis"); 2769060f2c3SEmmanuel Vadot case 0x13: 2779060f2c3SEmmanuel Vadot return ("SubChassis"); 2789060f2c3SEmmanuel Vadot case 0x14: 2799060f2c3SEmmanuel Vadot return ("Bus Expansion Chassis"); 2809060f2c3SEmmanuel Vadot case 0x15: 2819060f2c3SEmmanuel Vadot return ("Peripheral Chassis"); 2829060f2c3SEmmanuel Vadot case 0x16: 2839060f2c3SEmmanuel Vadot return ("RAID Chassis"); 2849060f2c3SEmmanuel Vadot case 0x17: 2859060f2c3SEmmanuel Vadot return ("Rack Mount Chassis"); 2869060f2c3SEmmanuel Vadot case 0x18: 2879060f2c3SEmmanuel Vadot return ("Sealed-case PC"); 2889060f2c3SEmmanuel Vadot case 0x19: 2899060f2c3SEmmanuel Vadot return ("Multi-system chassis"); 2909060f2c3SEmmanuel Vadot case 0x1A: 2919060f2c3SEmmanuel Vadot return ("Compact PCI"); 2929060f2c3SEmmanuel Vadot case 0x1B: 2939060f2c3SEmmanuel Vadot return ("Advanced TCA"); 2949060f2c3SEmmanuel Vadot case 0x1C: 2959060f2c3SEmmanuel Vadot return ("Blade"); 2969060f2c3SEmmanuel Vadot case 0x1D: 2979060f2c3SEmmanuel Vadot return ("Blade Enclosure"); 2989060f2c3SEmmanuel Vadot case 0x1E: 2999060f2c3SEmmanuel Vadot return ("Tablet"); 3009060f2c3SEmmanuel Vadot case 0x1F: 3019060f2c3SEmmanuel Vadot return ("Convertible"); 3029060f2c3SEmmanuel Vadot case 0x20: 3039060f2c3SEmmanuel Vadot return ("Detachable"); 3049060f2c3SEmmanuel Vadot case 0x21: 3059060f2c3SEmmanuel Vadot return ("IoT Gateway"); 3069060f2c3SEmmanuel Vadot case 0x22: 3079060f2c3SEmmanuel Vadot return ("Embedded PC"); 3089060f2c3SEmmanuel Vadot case 0x23: 3099060f2c3SEmmanuel Vadot return ("Mini PC"); 3109060f2c3SEmmanuel Vadot case 0x24: 3119060f2c3SEmmanuel Vadot return ("Stick PC"); 3129060f2c3SEmmanuel Vadot } 3139060f2c3SEmmanuel Vadot 3149060f2c3SEmmanuel Vadot return ("Undefined"); 3159060f2c3SEmmanuel Vadot } 3169060f2c3SEmmanuel Vadot 317a64f0b83SWarner Losh static caddr_t 318a64f0b83SWarner Losh smbios_parse_table(const caddr_t addr) 319a64f0b83SWarner Losh { 320a64f0b83SWarner Losh caddr_t cp; 321a64f0b83SWarner Losh int proc, size, osize, type; 32266c73af7SKornel Dulęba uint8_t bios_minor, bios_major; 32366c73af7SKornel Dulęba char buf[16]; 324a64f0b83SWarner Losh 325a64f0b83SWarner Losh type = SMBIOS_GET8(addr, 0); /* 3.1.2 Structure Header Format */ 326a64f0b83SWarner Losh switch(type) { 327a64f0b83SWarner Losh case 0: /* 3.3.1 BIOS Information (Type 0) */ 328a64f0b83SWarner Losh smbios_setenv("smbios.bios.vendor", addr, 0x04); 329a64f0b83SWarner Losh smbios_setenv("smbios.bios.version", addr, 0x05); 330a64f0b83SWarner Losh smbios_setenv("smbios.bios.reldate", addr, 0x08); 33166c73af7SKornel Dulęba bios_major = SMBIOS_GET8(addr, 0x14); 33266c73af7SKornel Dulęba bios_minor = SMBIOS_GET8(addr, 0x15); 33366c73af7SKornel Dulęba if (bios_minor != 0xFF && bios_major != 0xFF) { 33466c73af7SKornel Dulęba snprintf(buf, sizeof(buf), "%u.%u", 33566c73af7SKornel Dulęba bios_major, bios_minor); 33666c73af7SKornel Dulęba setenv("smbios.bios.revision", buf, 1); 33766c73af7SKornel Dulęba } 338a64f0b83SWarner Losh break; 339a64f0b83SWarner Losh 340a64f0b83SWarner Losh case 1: /* 3.3.2 System Information (Type 1) */ 341a64f0b83SWarner Losh smbios_setenv("smbios.system.maker", addr, 0x04); 342a64f0b83SWarner Losh smbios_setenv("smbios.system.product", addr, 0x05); 343a64f0b83SWarner Losh smbios_setenv("smbios.system.version", addr, 0x06); 344a64f0b83SWarner Losh #ifdef SMBIOS_SERIAL_NUMBERS 345a64f0b83SWarner Losh smbios_setenv("smbios.system.serial", addr, 0x07); 346a64f0b83SWarner Losh smbios_setuuid("smbios.system.uuid", addr + 0x08, smbios.ver); 347a64f0b83SWarner Losh #endif 348a64f0b83SWarner Losh if (smbios.major > 2 || 349a64f0b83SWarner Losh (smbios.major == 2 && smbios.minor >= 4)) { 350a64f0b83SWarner Losh smbios_setenv("smbios.system.sku", addr, 0x19); 351a64f0b83SWarner Losh smbios_setenv("smbios.system.family", addr, 0x1a); 352a64f0b83SWarner Losh } 353a64f0b83SWarner Losh break; 354a64f0b83SWarner Losh 355a64f0b83SWarner Losh case 2: /* 3.3.3 Base Board (or Module) Information (Type 2) */ 356a64f0b83SWarner Losh smbios_setenv("smbios.planar.maker", addr, 0x04); 357a64f0b83SWarner Losh smbios_setenv("smbios.planar.product", addr, 0x05); 358a64f0b83SWarner Losh smbios_setenv("smbios.planar.version", addr, 0x06); 359a64f0b83SWarner Losh #ifdef SMBIOS_SERIAL_NUMBERS 360a64f0b83SWarner Losh smbios_setenv("smbios.planar.serial", addr, 0x07); 361a64f0b83SWarner Losh smbios_setenv("smbios.planar.tag", addr, 0x08); 362a64f0b83SWarner Losh #endif 363a64f0b83SWarner Losh smbios_setenv("smbios.planar.location", addr, 0x0a); 364a64f0b83SWarner Losh break; 365a64f0b83SWarner Losh 366a64f0b83SWarner Losh case 3: /* 3.3.4 System Enclosure or Chassis (Type 3) */ 367a64f0b83SWarner Losh smbios_setenv("smbios.chassis.maker", addr, 0x04); 3689060f2c3SEmmanuel Vadot setenv("smbios.chassis.type", smbios_parse_chassis_type(addr), 1); 369a64f0b83SWarner Losh smbios_setenv("smbios.chassis.version", addr, 0x06); 370a64f0b83SWarner Losh #ifdef SMBIOS_SERIAL_NUMBERS 371a64f0b83SWarner Losh smbios_setenv("smbios.chassis.serial", addr, 0x07); 372a64f0b83SWarner Losh smbios_setenv("smbios.chassis.tag", addr, 0x08); 373a64f0b83SWarner Losh #endif 374a64f0b83SWarner Losh break; 375a64f0b83SWarner Losh 376a64f0b83SWarner Losh case 4: /* 3.3.5 Processor Information (Type 4) */ 377a64f0b83SWarner Losh /* 378a64f0b83SWarner Losh * Offset 18h: Processor Status 379a64f0b83SWarner Losh * 380a64f0b83SWarner Losh * Bit 7 Reserved, must be 0 381a64f0b83SWarner Losh * Bit 6 CPU Socket Populated 382a64f0b83SWarner Losh * 1 - CPU Socket Populated 383a64f0b83SWarner Losh * 0 - CPU Socket Unpopulated 384a64f0b83SWarner Losh * Bit 5:3 Reserved, must be zero 385a64f0b83SWarner Losh * Bit 2:0 CPU Status 386a64f0b83SWarner Losh * 0h - Unknown 387a64f0b83SWarner Losh * 1h - CPU Enabled 388a64f0b83SWarner Losh * 2h - CPU Disabled by User via BIOS Setup 389a64f0b83SWarner Losh * 3h - CPU Disabled by BIOS (POST Error) 390a64f0b83SWarner Losh * 4h - CPU is Idle, waiting to be enabled 391a64f0b83SWarner Losh * 5-6h - Reserved 392a64f0b83SWarner Losh * 7h - Other 393a64f0b83SWarner Losh */ 394a64f0b83SWarner Losh proc = SMBIOS_GET8(addr, 0x18); 395a64f0b83SWarner Losh if ((proc & 0x07) == 1) 396a64f0b83SWarner Losh smbios.enabled_sockets++; 397a64f0b83SWarner Losh if ((proc & 0x40) != 0) 398a64f0b83SWarner Losh smbios.populated_sockets++; 399a64f0b83SWarner Losh break; 400a64f0b83SWarner Losh 401a64f0b83SWarner Losh case 6: /* 3.3.7 Memory Module Information (Type 6, Obsolete) */ 402a64f0b83SWarner Losh /* 403a64f0b83SWarner Losh * Offset 0Ah: Enabled Size 404a64f0b83SWarner Losh * 405a64f0b83SWarner Losh * Bit 7 Bank connection 406a64f0b83SWarner Losh * 1 - Double-bank connection 407a64f0b83SWarner Losh * 0 - Single-bank connection 408a64f0b83SWarner Losh * Bit 6:0 Size (n), where 2**n is the size in MB 409a64f0b83SWarner Losh * 7Dh - Not determinable (Installed Size only) 410a64f0b83SWarner Losh * 7Eh - Module is installed, but no memory 411a64f0b83SWarner Losh * has been enabled 412a64f0b83SWarner Losh * 7Fh - Not installed 413a64f0b83SWarner Losh */ 414a64f0b83SWarner Losh osize = SMBIOS_GET8(addr, 0x0a) & 0x7f; 415a64f0b83SWarner Losh if (osize > 0 && osize < 22) 416a64f0b83SWarner Losh smbios.old_enabled_memory += 1 << (osize + 10); 417a64f0b83SWarner Losh break; 418a64f0b83SWarner Losh 419a64f0b83SWarner Losh case 17: /* 3.3.18 Memory Device (Type 17) */ 420a64f0b83SWarner Losh /* 421a64f0b83SWarner Losh * Offset 0Ch: Size 422a64f0b83SWarner Losh * 423a64f0b83SWarner Losh * Bit 15 Granularity 424a64f0b83SWarner Losh * 1 - Value is in kilobytes units 425a64f0b83SWarner Losh * 0 - Value is in megabytes units 426a64f0b83SWarner Losh * Bit 14:0 Size 427a64f0b83SWarner Losh */ 428a64f0b83SWarner Losh size = SMBIOS_GET16(addr, 0x0c); 429a64f0b83SWarner Losh if (size != 0 && size != 0xffff) 430a64f0b83SWarner Losh smbios.enabled_memory += (size & 0x8000) != 0 ? 431a64f0b83SWarner Losh (size & 0x7fff) : (size << 10); 432a64f0b83SWarner Losh break; 433a64f0b83SWarner Losh 434a64f0b83SWarner Losh default: /* skip other types */ 435a64f0b83SWarner Losh break; 436a64f0b83SWarner Losh } 437a64f0b83SWarner Losh 438a64f0b83SWarner Losh /* Find structure terminator. */ 439a64f0b83SWarner Losh cp = SMBIOS_GETSTR(addr); 440a64f0b83SWarner Losh while (SMBIOS_GET16(cp, 0) != 0) 441a64f0b83SWarner Losh cp++; 442a64f0b83SWarner Losh 443a64f0b83SWarner Losh return (cp + 2); 444a64f0b83SWarner Losh } 445a64f0b83SWarner Losh 446a64f0b83SWarner Losh static caddr_t 447a64f0b83SWarner Losh smbios_find_struct(int type) 448a64f0b83SWarner Losh { 449a64f0b83SWarner Losh caddr_t dmi; 450a64f0b83SWarner Losh size_t i; 451a64f0b83SWarner Losh 452a64f0b83SWarner Losh if (smbios.addr == NULL) 453a64f0b83SWarner Losh return (NULL); 454a64f0b83SWarner Losh 455a64f0b83SWarner Losh for (dmi = smbios.addr, i = 0; 456a64f0b83SWarner Losh dmi < smbios.addr + smbios.length && i < smbios.count; i++) { 457a64f0b83SWarner Losh if (SMBIOS_GET8(dmi, 0) == type) 458a64f0b83SWarner Losh return dmi; 459a64f0b83SWarner Losh /* Find structure terminator. */ 460a64f0b83SWarner Losh dmi = SMBIOS_GETSTR(dmi); 461a64f0b83SWarner Losh while (SMBIOS_GET16(dmi, 0) != 0) 462a64f0b83SWarner Losh dmi++; 463a64f0b83SWarner Losh dmi += 2; 464a64f0b83SWarner Losh } 465a64f0b83SWarner Losh 466a64f0b83SWarner Losh return (NULL); 467a64f0b83SWarner Losh } 468a64f0b83SWarner Losh 469a64f0b83SWarner Losh static void 470a64f0b83SWarner Losh smbios_probe(const caddr_t addr) 471a64f0b83SWarner Losh { 472a64f0b83SWarner Losh caddr_t saddr, info; 473a64f0b83SWarner Losh uintptr_t paddr; 474ee97f198SJohn-Mark Gurney int maj_off; 475ee97f198SJohn-Mark Gurney int min_off; 476a64f0b83SWarner Losh 477a64f0b83SWarner Losh if (smbios.probed) 478a64f0b83SWarner Losh return; 479a64f0b83SWarner Losh smbios.probed = 1; 480a64f0b83SWarner Losh 481a64f0b83SWarner Losh /* Search signatures and validate checksums. */ 482a64f0b83SWarner Losh saddr = smbios_sigsearch(addr ? addr : PTOV(SMBIOS_START), 483a64f0b83SWarner Losh SMBIOS_LENGTH); 484a64f0b83SWarner Losh if (saddr == NULL) 485a64f0b83SWarner Losh return; 486a64f0b83SWarner Losh 487ee97f198SJohn-Mark Gurney #ifdef HAS_SMBV3 488ee97f198SJohn-Mark Gurney if (isv3) { 489*13597be9SJohn-Mark Gurney smbios.length = SMBIOS_GET32(saddr, 0x0c); /* Structure Table Length */ 490ee97f198SJohn-Mark Gurney paddr = SMBIOS_GET64(saddr, 0x10); /* Structure Table Address */ 491ee97f198SJohn-Mark Gurney smbios.count = -1; /* not present in V3 */ 492ee97f198SJohn-Mark Gurney smbios.ver = 0; /* not present in V3 */ 493ee97f198SJohn-Mark Gurney maj_off = 0x07; 494ee97f198SJohn-Mark Gurney min_off = 0x08; 495ee97f198SJohn-Mark Gurney } else 496ee97f198SJohn-Mark Gurney #endif 497ee97f198SJohn-Mark Gurney { 498a64f0b83SWarner Losh smbios.length = SMBIOS_GET16(saddr, 0x16); /* Structure Table Length */ 499a64f0b83SWarner Losh paddr = SMBIOS_GET32(saddr, 0x18); /* Structure Table Address */ 500a64f0b83SWarner Losh smbios.count = SMBIOS_GET16(saddr, 0x1c); /* No of SMBIOS Structures */ 501a64f0b83SWarner Losh smbios.ver = SMBIOS_GET8(saddr, 0x1e); /* SMBIOS BCD Revision */ 502ee97f198SJohn-Mark Gurney maj_off = 0x06; 503ee97f198SJohn-Mark Gurney min_off = 0x07; 504ee97f198SJohn-Mark Gurney } 505ee97f198SJohn-Mark Gurney 506a64f0b83SWarner Losh 507a64f0b83SWarner Losh if (smbios.ver != 0) { 508a64f0b83SWarner Losh smbios.major = smbios.ver >> 4; 509a64f0b83SWarner Losh smbios.minor = smbios.ver & 0x0f; 510a64f0b83SWarner Losh if (smbios.major > 9 || smbios.minor > 9) 511a64f0b83SWarner Losh smbios.ver = 0; 512a64f0b83SWarner Losh } 513a64f0b83SWarner Losh if (smbios.ver == 0) { 514ee97f198SJohn-Mark Gurney smbios.major = SMBIOS_GET8(saddr, maj_off);/* SMBIOS Major Version */ 515ee97f198SJohn-Mark Gurney smbios.minor = SMBIOS_GET8(saddr, min_off);/* SMBIOS Minor Version */ 516a64f0b83SWarner Losh } 517a64f0b83SWarner Losh smbios.ver = (smbios.major << 8) | smbios.minor; 518a64f0b83SWarner Losh smbios.addr = PTOV(paddr); 519a64f0b83SWarner Losh 520a64f0b83SWarner Losh /* Get system information from SMBIOS */ 521a64f0b83SWarner Losh info = smbios_find_struct(0x00); 522a64f0b83SWarner Losh if (info != NULL) { 523a64f0b83SWarner Losh smbios.bios_vendor = smbios_getstring(info, 0x04); 524a64f0b83SWarner Losh } 525a64f0b83SWarner Losh info = smbios_find_struct(0x01); 526a64f0b83SWarner Losh if (info != NULL) { 527a64f0b83SWarner Losh smbios.maker = smbios_getstring(info, 0x04); 528a64f0b83SWarner Losh smbios.product = smbios_getstring(info, 0x05); 529a64f0b83SWarner Losh } 530a64f0b83SWarner Losh } 531a64f0b83SWarner Losh 532a64f0b83SWarner Losh void 533a64f0b83SWarner Losh smbios_detect(const caddr_t addr) 534a64f0b83SWarner Losh { 535a64f0b83SWarner Losh char buf[16]; 536a64f0b83SWarner Losh caddr_t dmi; 537a64f0b83SWarner Losh size_t i; 538a64f0b83SWarner Losh 539a64f0b83SWarner Losh smbios_probe(addr); 540a64f0b83SWarner Losh if (smbios.addr == NULL) 541a64f0b83SWarner Losh return; 542a64f0b83SWarner Losh 543a64f0b83SWarner Losh for (dmi = smbios.addr, i = 0; 544a64f0b83SWarner Losh dmi < smbios.addr + smbios.length && i < smbios.count; i++) 545a64f0b83SWarner Losh dmi = smbios_parse_table(dmi); 546a64f0b83SWarner Losh 547a64f0b83SWarner Losh sprintf(buf, "%d.%d", smbios.major, smbios.minor); 548a64f0b83SWarner Losh setenv("smbios.version", buf, 1); 549a64f0b83SWarner Losh if (smbios.enabled_memory > 0 || smbios.old_enabled_memory > 0) { 550a64f0b83SWarner Losh sprintf(buf, "%u", smbios.enabled_memory > 0 ? 551a64f0b83SWarner Losh smbios.enabled_memory : smbios.old_enabled_memory); 552a64f0b83SWarner Losh setenv("smbios.memory.enabled", buf, 1); 553a64f0b83SWarner Losh } 554a64f0b83SWarner Losh if (smbios.enabled_sockets > 0) { 555a64f0b83SWarner Losh sprintf(buf, "%u", smbios.enabled_sockets); 556a64f0b83SWarner Losh setenv("smbios.socket.enabled", buf, 1); 557a64f0b83SWarner Losh } 558a64f0b83SWarner Losh if (smbios.populated_sockets > 0) { 559a64f0b83SWarner Losh sprintf(buf, "%u", smbios.populated_sockets); 560a64f0b83SWarner Losh setenv("smbios.socket.populated", buf, 1); 561a64f0b83SWarner Losh } 562a64f0b83SWarner Losh } 563a64f0b83SWarner Losh 564a64f0b83SWarner Losh static int 565a64f0b83SWarner Losh smbios_match_str(const char* s1, const char* s2) 566a64f0b83SWarner Losh { 567a64f0b83SWarner Losh return (s1 == NULL || (s2 != NULL && !strcmp(s1, s2))); 568a64f0b83SWarner Losh } 569a64f0b83SWarner Losh 570a64f0b83SWarner Losh int 571a64f0b83SWarner Losh smbios_match(const char* bios_vendor, const char* maker, 572a64f0b83SWarner Losh const char* product) 573a64f0b83SWarner Losh { 574a64f0b83SWarner Losh /* XXXRP currently, only called from non-EFI. */ 575a64f0b83SWarner Losh smbios_probe(NULL); 576a64f0b83SWarner Losh return (smbios_match_str(bios_vendor, smbios.bios_vendor) && 577a64f0b83SWarner Losh smbios_match_str(maker, smbios.maker) && 578a64f0b83SWarner Losh smbios_match_str(product, smbios.product)); 579a64f0b83SWarner Losh } 580