smbios.c revision 156519
1/*- 2 * Copyright (c) 2005, 2006 Jung-uk Kim <jkim@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/smbios.c 156519 2006-03-09 22:49:44Z jkim $"); 29 30#include <stand.h> 31#include <bootstrap.h> 32 33#include "btxv86.h" 34#include "libi386.h" 35 36/* 37 * Detect SMBIOS and export information about the SMBIOS into the 38 * environment. 39 * 40 * System Management BIOS Reference Specification, v2.4 Final 41 * http://www.dmtf.org/standards/published_documents/DSP0134.pdf 42 */ 43 44/* 45 * Spec. 2.1.1 SMBIOS Structure Table Entry Point 46 * 47 * 'The SMBIOS Entry Point structure, described below, can be located by 48 * application software by searching for the anchor-string on paragraph 49 * (16-byte) boundaries within the physical memory address range 50 * 000F0000h to 000FFFFFh.' 51 */ 52#define SMBIOS_START 0xf0000 53#define SMBIOS_LENGTH 0x10000 54#define SMBIOS_STEP 0x10 55#define SMBIOS_SIG "_SM_" 56#define SMBIOS_DMI_SIG "_DMI_" 57 58static uint8_t smbios_enabled_sockets = 0; 59static uint8_t smbios_populated_sockets = 0; 60 61static uint8_t *smbios_parse_table(const uint8_t *dmi); 62static void smbios_setenv(const char *name, const uint8_t *dmi, 63 const int offset); 64static uint8_t smbios_checksum(const caddr_t addr, const uint8_t len); 65static uint8_t *smbios_sigsearch(const caddr_t addr, const uint32_t len); 66 67#ifdef SHOW_SENSITIVE_INFO 68static void smbios_setuuid(const char *name, const uint8_t *dmi, 69 const int offset); 70#endif 71 72void 73smbios_detect(void) 74{ 75 uint8_t *smbios, *dmi, *addr; 76 uint16_t i, length, count; 77 uint32_t paddr; 78 char buf[4]; 79 80 /* locate and validate the SMBIOS */ 81 smbios = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH); 82 if (smbios == NULL) 83 return; 84 85 length = *(uint16_t *)(smbios + 0x16); /* Structure Table Length */ 86 paddr = *(uint32_t *)(smbios + 0x18); /* Structure Table Address */ 87 count = *(uint16_t *)(smbios + 0x1c); /* No of SMBIOS Structures */ 88 89 for (dmi = addr = PTOV(paddr), i = 0; 90 dmi - addr < length && i < count; i++) 91 dmi = smbios_parse_table(dmi); 92 sprintf(buf, "%d", smbios_enabled_sockets); 93 setenv("smbios.socket.enabled", buf, 1); 94 sprintf(buf, "%d", smbios_populated_sockets); 95 setenv("smbios.socket.populated", buf, 1); 96} 97 98static uint8_t * 99smbios_parse_table(const uint8_t *dmi) 100{ 101 uint8_t *dp; 102 103 switch(dmi[0]) { 104 case 0: /* Type 0: BIOS */ 105 smbios_setenv("smbios.bios.vendor", dmi, 0x04); 106 smbios_setenv("smbios.bios.version", dmi, 0x05); 107 smbios_setenv("smbios.bios.reldate", dmi, 0x08); 108 break; 109 110 case 1: /* Type 1: System */ 111 smbios_setenv("smbios.system.maker", dmi, 0x04); 112 smbios_setenv("smbios.system.product", dmi, 0x05); 113 smbios_setenv("smbios.system.version", dmi, 0x06); 114#ifdef SHOW_SENSITIVE_INFO 115 smbios_setenv("smbios.system.serial", dmi, 0x07); 116 smbios_setuuid("smbios.system.uuid", dmi, 0x08); 117#endif 118 break; 119 120 case 2: /* Type 2: Base Board (or Module) */ 121 smbios_setenv("smbios.planar.maker", dmi, 0x04); 122 smbios_setenv("smbios.planar.product", dmi, 0x05); 123 smbios_setenv("smbios.planar.version", dmi, 0x06); 124#ifdef SHOW_SENSITIVE_INFO 125 smbios_setenv("smbios.planar.serial", dmi, 0x07); 126#endif 127 break; 128 129 case 3: /* Type 3: System Enclosure or Chassis */ 130 smbios_setenv("smbios.chassis.maker", dmi, 0x04); 131 smbios_setenv("smbios.chassis.version", dmi, 0x06); 132#ifdef SHOW_SENSITIVE_INFO 133 smbios_setenv("smbios.chassis.serial", dmi, 0x07); 134 smbios_setenv("smbios.chassis.tag", dmi, 0x08); 135#endif 136 break; 137 138 case 4: /* Type 4: Processor Information */ 139 /* 140 * Offset 18h: Processor Status 141 * 142 * Bit 7 Reserved, must be 0 143 * Bit 6 CPU Socket Populated 144 * 1 - CPU Socket Populated 145 * 0 - CPU Socket Unpopulated 146 * Bit 5:3 Reserved, must be zero 147 * Bit 2:0 CPU Status 148 * 0h - Unknown 149 * 1h - CPU Enabled 150 * 2h - CPU Disabled by User via BIOS Setup 151 * 3h - CPU Disabled by BIOS (POST Error) 152 * 4h - CPU is Idle, waiting to be enabled 153 * 5-6h - Reserved 154 * 7h - Other 155 */ 156 if ((dmi[0x18] & 0x07) == 1) 157 smbios_enabled_sockets++; 158 if (dmi[0x18] & 0x40) 159 smbios_populated_sockets++; 160 break; 161 162 default: /* skip other types */ 163 break; 164 } 165 166 /* find structure terminator */ 167 dp = __DECONST(uint8_t *, dmi + dmi[1]); 168 while (dp[0] != 0 || dp[1] != 0) 169 dp++; 170 171 return(dp + 2); 172} 173 174static void 175smbios_setenv(const char *name, const uint8_t *dmi, const int offset) 176{ 177 char *cp = __DECONST(char *, dmi + dmi[1]); 178 int i; 179 180 /* skip undefined string */ 181 if (dmi[offset] == 0) 182 return; 183 184 for (i = 0; i < dmi[offset] - 1; i++) 185 cp += strlen(cp) + 1; 186 setenv(name, cp, 1); 187} 188 189static uint8_t 190smbios_checksum(const caddr_t addr, const uint8_t len) 191{ 192 const uint8_t *cp = addr; 193 uint8_t sum; 194 int i; 195 196 for (sum = 0, i = 0; i < len; i++) 197 sum += cp[i]; 198 199 return(sum); 200} 201 202static uint8_t * 203smbios_sigsearch(const caddr_t addr, const uint32_t len) 204{ 205 caddr_t cp; 206 207 /* search on 16-byte boundaries */ 208 for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) { 209 /* compare signature, validate checksum */ 210 if (!strncmp(cp, SMBIOS_SIG, 4)) { 211 if (smbios_checksum(cp, *(uint8_t *)(cp + 0x05))) 212 continue; 213 if (strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5)) 214 continue; 215 if (smbios_checksum(cp + 0x10, 0x0f)) 216 continue; 217 218 return(cp); 219 } 220 } 221 222 return(NULL); 223} 224 225#ifdef SHOW_SENSITIVE_INFO 226static void 227smbios_setuuid(const char *name, const uint8_t *dmi, const int offset) 228{ 229 const uint8_t *idp = dmi + offset; 230 int i, f = 0, z = 0; 231 char uuid[37]; 232 233 for (i = 0; i < 16; i++) { 234 if (idp[i] == 0xff) 235 f++; 236 if (idp[i] == 0x00) 237 z++; 238 } 239 if (f != 16 && z != 16) { 240 sprintf(uuid, "%02X%02X%02X%02X-" 241 "%02X%02X-%02X%02X-%02X%02X-" 242 "%02X%02X%02X%02X%02X%02X", 243 idp[0], idp[1], idp[2], idp[3], 244 idp[4], idp[5], idp[6], idp[7], idp[8], idp[9], 245 idp[10], idp[11], idp[12], idp[13], idp[14], idp[15]); 246 setenv(name, uuid, 1); 247 } 248} 249#endif 250