smbios.c revision 151452
1/*- 2 * Copyright (c) 2005 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 151452 2005-10-18 20:03:31Z jkim $"); 29 30#include <stand.h> 31#include <bootstrap.h> 32 33#include "btxv86.h" 34 35/* 36 * Detect SMBIOS and export information about the SMBIOS into the 37 * environment. 38 * 39 * System Management BIOS Reference Specification, v2.4 Final 40 * http://www.dmtf.org/standards/published_documents/DSP0134.pdf 41 */ 42 43/* 44 * Spec. 2.1.1 SMBIOS Structure Table Entry Point 45 * 46 * 'The SMBIOS Entry Point structure, described below, can be located by 47 * application software by searching for the anchor-string on paragraph 48 * (16-byte) boundaries within the physical memory address range 49 * 000F0000h to 000FFFFFh.' 50 */ 51#define SMBIOS_START 0xf0000 52#define SMBIOS_LENGTH 0x10000 53#define SMBIOS_STEP 0x10 54#define SMBIOS_SIG "_SM_" 55#define SMBIOS_DMI_SIG "_DMI_" 56 57static u_int8_t smbios_enabled_sockets = 0; 58static u_int8_t smbios_populated_sockets = 0; 59 60static u_int8_t *smbios_parse_table(const u_int8_t *dmi); 61static void smbios_setenv(const char *env, const u_int8_t *dmi, 62 const int offset); 63static u_int8_t smbios_checksum(const u_int8_t *addr, const u_int8_t len); 64static u_int8_t *smbios_sigsearch(const caddr_t addr, const u_int32_t len); 65 66void 67smbios_detect(void) 68{ 69 u_int8_t *smbios, *dmi, *addr; 70 u_int16_t i, length, count; 71 u_int32_t paddr; 72 char buf[4]; 73 74 /* locate and validate the SMBIOS */ 75 smbios = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH); 76 if (smbios == NULL) 77 return; 78 79 length = *(u_int16_t *)(smbios + 0x16); /* Structure Table Length */ 80 paddr = *(u_int32_t *)(smbios + 0x18); /* Structure Table Address */ 81 count = *(u_int16_t *)(smbios + 0x1c); /* No of SMBIOS Structures */ 82 83 for (dmi = addr = PTOV(paddr), i = 0; 84 dmi - addr < length && i < count; i++) 85 dmi = smbios_parse_table(dmi); 86 sprintf(buf, "%d", smbios_enabled_sockets); 87 setenv("smbios.socket.enabled", buf, 1); 88 sprintf(buf, "%d", smbios_populated_sockets); 89 setenv("smbios.socket.populated", buf, 1); 90} 91 92static u_int8_t * 93smbios_parse_table(const u_int8_t *dmi) 94{ 95 u_int8_t *dp; 96 97 switch(dmi[0]) { 98 case 0: /* Type 0: BIOS */ 99 smbios_setenv("smbios.bios.vendor", dmi, 0x04); 100 smbios_setenv("smbios.bios.version", dmi, 0x05); 101 smbios_setenv("smbios.bios.reldate", dmi, 0x08); 102 break; 103 104 case 1: /* Type 1: System */ 105 smbios_setenv("smbios.system.maker", dmi, 0x04); 106 smbios_setenv("smbios.system.product", dmi, 0x05); 107 smbios_setenv("smbios.system.version", dmi, 0x06); 108 break; 109 110 case 2: /* Type 2: Base Board (or Module) */ 111 smbios_setenv("smbios.planar.maker", dmi, 0x04); 112 smbios_setenv("smbios.planar.product", dmi, 0x05); 113 smbios_setenv("smbios.planar.version", dmi, 0x06); 114 break; 115 116 case 3: /* Type 3: System Enclosure or Chassis */ 117 smbios_setenv("smbios.chassis.maker", dmi, 0x04); 118 smbios_setenv("smbios.chassis.version", dmi, 0x06); 119 break; 120 121 case 4: /* Type 4: Processor Information */ 122 /* 123 * Offset 18h: Processor Status 124 * 125 * Bit 7 Reserved, must be 0 126 * Bit 6 CPU Socket Populated 127 * 1 - CPU Socket Populated 128 * 0 - CPU Socket Unpopulated 129 * Bit 5:3 Reserved, must be zero 130 * Bit 2:0 CPU Status 131 * 0h - Unknown 132 * 1h - CPU Enabled 133 * 2h - CPU Disabled by User via BIOS Setup 134 * 3h - CPU Disabled by BIOS (POST Error) 135 * 4h - CPU is Idle, waiting to be enabled 136 * 5-6h - Reserved 137 * 7h - Other 138 */ 139 if ((dmi[0x18] & 0x07) == 1) 140 smbios_enabled_sockets++; 141 if (dmi[0x18] & 0x40) 142 smbios_populated_sockets++; 143 break; 144 145 default: /* skip other types */ 146 break; 147 } 148 149 /* find structure terminator */ 150 dp = (u_int8_t *)(dmi + dmi[1]); 151 while (dp[0] != 0 || dp[1] != 0) 152 dp++; 153 154 return(dp + 2); 155} 156 157static void 158smbios_setenv(const char *str, const u_int8_t *dmi, const int offset) 159{ 160 char *cp; 161 int i; 162 163 /* skip undefined string */ 164 if (dmi[offset] == 0) 165 return; 166 167 for (cp = (char *)(dmi + dmi[1]), i = 0; i < dmi[offset] - 1; i++) 168 cp += strlen(cp) + 1; 169 setenv(str, cp, 1); 170} 171 172static u_int8_t 173smbios_checksum(const u_int8_t *addr, const u_int8_t len) 174{ 175 u_int8_t sum; 176 int i; 177 178 for (sum = 0, i = 0; i < len; i++) 179 sum += addr[i]; 180 181 return(sum); 182} 183 184static u_int8_t * 185smbios_sigsearch(const caddr_t addr, const u_int32_t len) 186{ 187 caddr_t cp; 188 189 /* search on 16-byte boundaries */ 190 for (cp = addr; cp - addr < len; cp += SMBIOS_STEP) { 191 /* compare signature, validate checksum */ 192 if (!strncmp(cp, SMBIOS_SIG, 4)) { 193 if (smbios_checksum(cp, *(cp + 0x05))) 194 continue; 195 if (strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5)) 196 continue; 197 if (smbios_checksum(cp + 0x10, 0x0f)) 198 continue; 199 200 return(cp); 201 } 202 } 203 204 return(NULL); 205} 206