smbios.c revision 148006
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 148006 2005-07-14 19:52:22Z 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_parse_table(const u_int8_t *dmi); 58static void smbios_setenv(const char *env, const u_int8_t *dmi, 59 const int offset); 60static u_int8_t smbios_checksum(const u_int8_t *addr, const u_int8_t len); 61static u_int8_t *smbios_sigsearch(const caddr_t addr, const u_int32_t len); 62 63void 64smbios_detect(void) 65{ 66 u_int8_t *smbios, *dmi, *addr; 67 u_int16_t i, length, count; 68 u_int32_t paddr; 69 70 /* locate and validate the SMBIOS */ 71 smbios = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH); 72 if (smbios == NULL) 73 return; 74 75 /* export values from the SMBIOS */ 76 setenv("hint.smbios.0.enabled", "YES", 1); 77 78 length = *(u_int16_t *)(smbios + 0x16); /* Structure Table Length */ 79 paddr = *(u_int32_t *)(smbios + 0x18); /* Structure Table Address */ 80 count = *(u_int16_t *)(smbios + 0x1c); /* No of SMBIOS Structures */ 81 82 for (dmi = addr = PTOV(paddr), i = 0; 83 dmi - addr < length && i < count; i++) 84 dmi = smbios_parse_table(dmi); 85} 86 87static u_int8_t * 88smbios_parse_table(const u_int8_t *dmi) 89{ 90 u_int8_t *dp; 91 92 switch(dmi[0]) { 93 case 0: /* Type 0: BIOS */ 94 smbios_setenv("hint.smbios.0.bios.vendor", dmi, 0x04); 95 smbios_setenv("hint.smbios.0.bios.version", dmi, 0x05); 96 smbios_setenv("hint.smbios.0.bios.reldate", dmi, 0x08); 97 break; 98 99 case 1: /* Type 1: System */ 100 smbios_setenv("hint.smbios.0.system.maker", dmi, 0x04); 101 smbios_setenv("hint.smbios.0.system.product", dmi, 0x05); 102 smbios_setenv("hint.smbios.0.system.version", dmi, 0x06); 103 break; 104 105 case 2: /* Type 2: Base Board (or Module) */ 106 smbios_setenv("hint.smbios.0.planar.maker", dmi, 0x04); 107 smbios_setenv("hint.smbios.0.planar.product", dmi, 0x05); 108 smbios_setenv("hint.smbios.0.planar.version", dmi, 0x06); 109 break; 110 111 case 3: /* Type 3: System Enclosure or Chassis */ 112 smbios_setenv("hint.smbios.0.chassis.maker", dmi, 0x04); 113 smbios_setenv("hint.smbios.0.chassis.version", dmi, 0x06); 114 break; 115 116 default: /* skip other types */ 117 break; 118 } 119 120 /* find structure terminator */ 121 dp = (u_int8_t *)(dmi + dmi[1]); 122 while (dp[0] != 0 || dp[1] != 0) 123 dp++; 124 125 return(dp + 2); 126} 127 128static void 129smbios_setenv(const char *str, const u_int8_t *dmi, const int offset) 130{ 131 char *cp; 132 int i; 133 134 /* skip undefined string */ 135 if (dmi[offset] == 0) 136 return; 137 138 for (cp = (char *)(dmi + dmi[1]), i = 0; i < dmi[offset] - 1; i++) 139 cp += strlen(cp) + 1; 140 setenv(str, cp, 1); 141} 142 143static u_int8_t 144smbios_checksum(const u_int8_t *addr, const u_int8_t len) 145{ 146 u_int8_t sum; 147 int i; 148 149 for (sum = 0, i = 0; i < len; i++) 150 sum += addr[i]; 151 152 return(sum); 153} 154 155static u_int8_t * 156smbios_sigsearch(const caddr_t addr, const u_int32_t len) 157{ 158 caddr_t cp; 159 160 /* search on 16-byte boundaries */ 161 for (cp = addr; cp - addr < len; cp += SMBIOS_STEP) { 162 /* compare signature, validate checksum */ 163 if (!strncmp(cp, SMBIOS_SIG, 4)) { 164 if (smbios_checksum(cp, *(cp + 0x05))) 165 continue; 166 if (strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5)) 167 continue; 168 if (smbios_checksum(cp + 0x10, 0x0f)) 169 continue; 170 171 return(cp); 172 } 173 } 174 175 return(NULL); 176} 177