smbios.c revision 156712
1250199Sgrehan/*- 2298446Ssephe * Copyright (c) 2005, 2006 Jung-uk Kim <jkim@FreeBSD.org> 3250199Sgrehan * All rights reserved. 4250199Sgrehan * 5250199Sgrehan * Redistribution and use in source and binary forms, with or without 6250199Sgrehan * modification, are permitted provided that the following conditions 7250199Sgrehan * are met: 8250199Sgrehan * 1. Redistributions of source code must retain the above copyright 9250199Sgrehan * notice, this list of conditions and the following disclaimer. 10250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11250199Sgrehan * notice, this list of conditions and the following disclaimer in the 12250199Sgrehan * documentation and/or other materials provided with the distribution. 13250199Sgrehan * 14250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15250199Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16250199Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17250199Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18250199Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19250199Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20250199Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21250199Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22250199Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23250199Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24250199Sgrehan * SUCH DAMAGE. 25250199Sgrehan */ 26250199Sgrehan 27250199Sgrehan#include <sys/cdefs.h> 28250199Sgrehan__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/smbios.c 156712 2006-03-14 19:02:00Z jkim $"); 29250199Sgrehan 30296028Ssephe#include <stand.h> 31250199Sgrehan#include <bootstrap.h> 32250199Sgrehan 33250199Sgrehan#include "btxv86.h" 34250199Sgrehan#include "libi386.h" 35250199Sgrehan 36299927Ssephe/* 37250199Sgrehan * Detect SMBIOS and export information about the SMBIOS into the 38250199Sgrehan * environment. 39250199Sgrehan * 40250199Sgrehan * System Management BIOS Reference Specification, v2.4 Final 41300102Ssephe * http://www.dmtf.org/standards/published_documents/DSP0134.pdf 42300102Ssephe */ 43250199Sgrehan 44250199Sgrehan/* 45250199Sgrehan * Spec. 2.1.1 SMBIOS Structure Table Entry Point 46250199Sgrehan * 47250199Sgrehan * 'The SMBIOS Entry Point structure, described below, can be located by 48250199Sgrehan * application software by searching for the anchor-string on paragraph 49250199Sgrehan * (16-byte) boundaries within the physical memory address range 50250199Sgrehan * 000F0000h to 000FFFFFh.' 51282212Swhu */ 52282212Swhu#define SMBIOS_START 0xf0000 53282212Swhu#define SMBIOS_LENGTH 0x10000 54282212Swhu#define SMBIOS_STEP 0x10 55282212Swhu#define SMBIOS_SIG "_SM_" 56282212Swhu#define SMBIOS_DMI_SIG "_DMI_" 57282212Swhu 58282212Swhustatic uint8_t smbios_enabled_sockets = 0; 59282212Swhustatic uint8_t smbios_populated_sockets = 0; 60282212Swhu 61282212Swhustatic uint8_t *smbios_parse_table(const uint8_t *dmi); 62282212Swhustatic void smbios_setenv(const char *name, const uint8_t *dmi, 63282212Swhu const int offset); 64282212Swhustatic uint8_t smbios_checksum(const caddr_t addr, const uint8_t len); 65282212Swhustatic uint8_t *smbios_sigsearch(const caddr_t addr, const uint32_t len); 66282212Swhu 67282212Swhu#ifdef SMBIOS_SERIAL_NUMBERS 68282212Swhustatic void smbios_setuuid(const char *name, const uint8_t *dmi, 69282212Swhu const int offset); 70282212Swhu#endif 71282212Swhu 72250199Sgrehanvoid 73282212Swhusmbios_detect(void) 74282212Swhu{ 75282212Swhu uint8_t *smbios, *dmi, *addr; 76282212Swhu uint16_t i, length, count; 77282212Swhu uint32_t paddr; 78282212Swhu char buf[4]; 79282212Swhu 80282212Swhu /* locate and validate the SMBIOS */ 81282212Swhu smbios = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH); 82282212Swhu if (smbios == NULL) 83282212Swhu return; 84282212Swhu 85282212Swhu length = *(uint16_t *)(smbios + 0x16); /* Structure Table Length */ 86282212Swhu paddr = *(uint32_t *)(smbios + 0x18); /* Structure Table Address */ 87282212Swhu count = *(uint16_t *)(smbios + 0x1c); /* No of SMBIOS Structures */ 88282212Swhu 89282212Swhu for (dmi = addr = PTOV(paddr), i = 0; 90282212Swhu dmi - addr < length && i < count; i++) 91282212Swhu dmi = smbios_parse_table(dmi); 92295309Ssephe sprintf(buf, "%d", smbios_enabled_sockets); 93282212Swhu setenv("smbios.socket.enabled", buf, 1); 94295308Ssephe sprintf(buf, "%d", smbios_populated_sockets); 95295309Ssephe setenv("smbios.socket.populated", buf, 1); 96282212Swhu} 97282212Swhu 98282212Swhustatic uint8_t * 99282212Swhusmbios_parse_table(const uint8_t *dmi) 100282212Swhu{ 101297635Ssephe uint8_t *dp; 102282212Swhu 103282212Swhu switch(dmi[0]) { 104282212Swhu case 0: /* Type 0: BIOS */ 105282212Swhu smbios_setenv("smbios.bios.vendor", dmi, 0x04); 106282212Swhu smbios_setenv("smbios.bios.version", dmi, 0x05); 107282212Swhu smbios_setenv("smbios.bios.reldate", dmi, 0x08); 108297635Ssephe break; 109282212Swhu 110282212Swhu case 1: /* Type 1: System */ 111282212Swhu smbios_setenv("smbios.system.maker", dmi, 0x04); 112282212Swhu smbios_setenv("smbios.system.product", dmi, 0x05); 113282212Swhu smbios_setenv("smbios.system.version", dmi, 0x06); 114282212Swhu#ifdef SMBIOS_SERIAL_NUMBERS 115297635Ssephe smbios_setenv("smbios.system.serial", dmi, 0x07); 116282212Swhu smbios_setuuid("smbios.system.uuid", dmi, 0x08); 117282212Swhu#endif 118282212Swhu break; 119282212Swhu 120297635Ssephe case 2: /* Type 2: Base Board (or Module) */ 121282212Swhu smbios_setenv("smbios.planar.maker", dmi, 0x04); 122282212Swhu smbios_setenv("smbios.planar.product", dmi, 0x05); 123282212Swhu smbios_setenv("smbios.planar.version", dmi, 0x06); 124282212Swhu#ifdef SMBIOS_SERIAL_NUMBERS 125282212Swhu smbios_setenv("smbios.planar.serial", dmi, 0x07); 126282212Swhu#endif 127296028Ssephe break; 128282212Swhu 129297635Ssephe case 3: /* Type 3: System Enclosure or Chassis */ 130282212Swhu smbios_setenv("smbios.chassis.maker", dmi, 0x04); 131282212Swhu smbios_setenv("smbios.chassis.version", dmi, 0x06); 132282212Swhu#ifdef SMBIOS_SERIAL_NUMBERS 133282212Swhu smbios_setenv("smbios.chassis.serial", dmi, 0x07); 134297635Ssephe smbios_setenv("smbios.chassis.tag", dmi, 0x08); 135282212Swhu#endif 136282212Swhu break; 137282212Swhu 138282212Swhu case 4: /* Type 4: Processor Information */ 139282212Swhu /* 140282212Swhu * Offset 18h: Processor Status 141282212Swhu * 142282212Swhu * Bit 7 Reserved, must be 0 143282212Swhu * Bit 6 CPU Socket Populated 144282212Swhu * 1 - CPU Socket Populated 145282212Swhu * 0 - CPU Socket Unpopulated 146282212Swhu * Bit 5:3 Reserved, must be zero 147282212Swhu * Bit 2:0 CPU Status 148282212Swhu * 0h - Unknown 149250199Sgrehan * 1h - CPU Enabled 150250199Sgrehan * 2h - CPU Disabled by User via BIOS Setup 151250199Sgrehan * 3h - CPU Disabled by BIOS (POST Error) 152250199Sgrehan * 4h - CPU is Idle, waiting to be enabled 153250199Sgrehan * 5-6h - Reserved 154282212Swhu * 7h - Other 155250199Sgrehan */ 156250199Sgrehan if ((dmi[0x18] & 0x07) == 1) 157250199Sgrehan smbios_enabled_sockets++; 158250199Sgrehan if (dmi[0x18] & 0x40) 159250199Sgrehan smbios_populated_sockets++; 160250199Sgrehan break; 161250199Sgrehan 162250199Sgrehan default: /* skip other types */ 163250199Sgrehan break; 164250199Sgrehan } 165250199Sgrehan 166250199Sgrehan /* find structure terminator */ 167250199Sgrehan dp = __DECONST(uint8_t *, dmi + dmi[1]); 168250199Sgrehan while (dp[0] != 0 || dp[1] != 0) 169250199Sgrehan dp++; 170250199Sgrehan 171297635Ssephe return(dp + 2); 172250199Sgrehan} 173250199Sgrehan 174250199Sgrehanstatic void 175282212Swhusmbios_setenv(const char *name, const uint8_t *dmi, const int offset) 176250199Sgrehan{ 177250199Sgrehan char *cp = __DECONST(char *, dmi + dmi[1]); 178250199Sgrehan int i; 179250199Sgrehan 180250199Sgrehan /* skip undefined string */ 181295309Ssephe if (dmi[offset] == 0) 182250199Sgrehan return; 183295309Ssephe 184250199Sgrehan for (i = 0; i < dmi[offset] - 1; i++) 185250199Sgrehan cp += strlen(cp) + 1; 186250199Sgrehan setenv(name, cp, 1); 187250199Sgrehan} 188250199Sgrehan 189250199Sgrehanstatic uint8_t 190250199Sgrehansmbios_checksum(const caddr_t addr, const uint8_t len) 191250199Sgrehan{ 192250199Sgrehan const uint8_t *cp = addr; 193250199Sgrehan uint8_t sum; 194250199Sgrehan int i; 195250199Sgrehan 196295309Ssephe for (sum = 0, i = 0; i < len; i++) 197295309Ssephe sum += cp[i]; 198250199Sgrehan 199295309Ssephe return(sum); 200295309Ssephe} 201250199Sgrehan 202295309Ssephestatic uint8_t * 203295309Ssephesmbios_sigsearch(const caddr_t addr, const uint32_t len) 204250199Sgrehan{ 205250199Sgrehan caddr_t cp; 206250199Sgrehan 207250199Sgrehan /* search on 16-byte boundaries */ 208295308Ssephe for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) { 209250199Sgrehan /* compare signature, validate checksum */ 210294553Ssephe if (!strncmp(cp, SMBIOS_SIG, 4)) { 211294553Ssephe if (smbios_checksum(cp, *(uint8_t *)(cp + 0x05))) 212294553Ssephe continue; 213282212Swhu if (strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5)) 214282212Swhu continue; 215250199Sgrehan if (smbios_checksum(cp + 0x10, 0x0f)) 216282212Swhu continue; 217250199Sgrehan 218282212Swhu return(cp); 219282212Swhu } 220282212Swhu } 221282212Swhu 222282212Swhu return(NULL); 223282212Swhu} 224282212Swhu 225282212Swhu#ifdef SMBIOS_SERIAL_NUMBERS 226250199Sgrehanstatic void 227282212Swhusmbios_setuuid(const char *name, const uint8_t *dmi, const int offset) 228282212Swhu{ 229250199Sgrehan const uint8_t *idp = dmi + offset; 230282212Swhu int i, f = 0, z = 0; 231282212Swhu char uuid[37]; 232250199Sgrehan 233282212Swhu for (i = 0; i < 16; i++) { 234282212Swhu if (idp[i] == 0xff) 235293870Ssephe f++; 236282212Swhu else if (idp[i] == 0x00) 237250199Sgrehan z++; 238250199Sgrehan else 239250199Sgrehan break; 240250199Sgrehan } 241250199Sgrehan if (f != 16 && z != 16) { 242250199Sgrehan sprintf(uuid, "%02X%02X%02X%02X-" 243250199Sgrehan "%02X%02X-%02X%02X-%02X%02X-" 244250199Sgrehan "%02X%02X%02X%02X%02X%02X", 245250199Sgrehan idp[0], idp[1], idp[2], idp[3], 246250199Sgrehan idp[4], idp[5], idp[6], idp[7], idp[8], idp[9], 247250199Sgrehan idp[10], idp[11], idp[12], idp[13], idp[14], idp[15]); 248250199Sgrehan setenv(name, uuid, 1); 249250199Sgrehan } 250250199Sgrehan} 251250199Sgrehan#endif 252250199Sgrehan