smbios.c revision 127135
1112553Smdodd/*- 2112553Smdodd * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net> 3112553Smdodd * All rights reserved. 4112553Smdodd * 5112553Smdodd * Redistribution and use in source and binary forms, with or without 6112553Smdodd * modification, are permitted provided that the following conditions 7112553Smdodd * are met: 8112553Smdodd * 1. Redistributions of source code must retain the above copyright 9112553Smdodd * notice, this list of conditions and the following disclaimer. 10112553Smdodd * 2. Redistributions in binary form must reproduce the above copyright 11112553Smdodd * notice, this list of conditions and the following disclaimer in the 12112553Smdodd * documentation and/or other materials provided with the distribution. 13112553Smdodd * 14112553Smdodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15112553Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16112553Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17112553Smdodd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18112553Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19112553Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20112553Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21112553Smdodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22112553Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23112553Smdodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24112553Smdodd * SUCH DAMAGE. 25112553Smdodd */ 26112553Smdodd 27115679Sobrien#include <sys/cdefs.h> 28115679Sobrien__FBSDID("$FreeBSD: head/sys/i386/bios/smbios.c 127135 2004-03-17 17:50:55Z njl $"); 29115679Sobrien 30112553Smdodd#include <sys/param.h> 31112553Smdodd#include <sys/systm.h> 32112553Smdodd#include <sys/kernel.h> 33112553Smdodd#include <sys/socket.h> 34112553Smdodd 35112553Smdodd#include <sys/module.h> 36112553Smdodd#include <sys/bus.h> 37112553Smdodd 38112553Smdodd#include <machine/bus.h> 39112553Smdodd#include <machine/resource.h> 40112553Smdodd#include <sys/rman.h> 41112553Smdodd 42112553Smdodd#include <vm/vm.h> 43112553Smdodd#include <vm/pmap.h> 44112553Smdodd#include <machine/md_var.h> 45112553Smdodd#include <machine/pc/bios.h> 46112553Smdodd 47112553Smdodd/* 48112553Smdodd * SMBIOS Entry Point Structure 49112553Smdodd */ 50112553Smdoddstruct smbios_eps { 51112553Smdodd u_int8_t Anchor[4]; /* '_SM_' */ 52112553Smdodd u_int8_t Checksum; 53112553Smdodd u_int8_t Length; 54112553Smdodd 55112553Smdodd u_int8_t SMBIOS_Major; 56112553Smdodd u_int8_t SMBIOS_Minor; 57112553Smdodd u_int8_t Max_Size; 58112553Smdodd u_int8_t Revision; 59112553Smdodd u_int8_t Formatted_Area; 60112553Smdodd 61112553Smdodd u_int8_t Intermediate_Anchor[5]; /* '_DMI_' */ 62112553Smdodd u_int8_t Intermediate_Checksum; 63112553Smdodd 64112553Smdodd u_int16_t Structure_Table_Length; 65112553Smdodd u_int32_t Structure_Table_Address; 66112553Smdodd u_int16_t Structure_Count; 67112553Smdodd 68112553Smdodd u_int8_t SMBIOS_BCD_Revision; 69112553Smdodd} __packed; 70112553Smdodd 71112553Smdoddstruct smbios_softc { 72112553Smdodd device_t dev; 73112553Smdodd struct resource * res; 74112553Smdodd int rid; 75112553Smdodd 76112553Smdodd struct smbios_eps * eps; 77112553Smdodd}; 78112553Smdodd 79112553Smdodd#define SMBIOS_START 0xf0000 80112553Smdodd#define SMBIOS_STEP 0x10 81112553Smdodd#define SMBIOS_OFF 0 82112553Smdodd#define SMBIOS_LEN 4 83112553Smdodd#define SMBIOS_SIG "_SM_" 84112553Smdodd 85112553Smdodd#define RES2EPS(res) ((struct smbios_eps *)rman_get_virtual(res)) 86112553Smdodd#define ADDR2EPS(addr) ((struct smbios_eps *)BIOS_PADDRTOVADDR(addr)) 87112553Smdodd 88112553Smdoddstatic devclass_t smbios_devclass; 89112553Smdodd 90112553Smdoddstatic void smbios_identify (driver_t *, device_t); 91112553Smdoddstatic int smbios_probe (device_t); 92112553Smdoddstatic int smbios_attach (device_t); 93112553Smdoddstatic int smbios_detach (device_t); 94112553Smdoddstatic int smbios_modevent (module_t, int, void *); 95112553Smdodd 96112553Smdoddstatic int smbios_cksum (struct smbios_eps *); 97112553Smdodd 98112553Smdoddstatic void 99112553Smdoddsmbios_identify (driver_t *driver, device_t parent) 100112553Smdodd{ 101112553Smdodd device_t child; 102112553Smdodd u_int32_t addr; 103112553Smdodd int length; 104112553Smdodd int rid; 105112553Smdodd 106112553Smdodd if (!device_is_alive(parent)) 107112553Smdodd return; 108112553Smdodd 109112553Smdodd addr = bios_sigsearch(SMBIOS_START, SMBIOS_SIG, SMBIOS_LEN, 110112553Smdodd SMBIOS_STEP, SMBIOS_OFF); 111112553Smdodd if (addr != 0) { 112112553Smdodd rid = 0; 113112553Smdodd length = ADDR2EPS(addr)->Length; 114112553Smdodd 115112553Smdodd child = BUS_ADD_CHILD(parent, 0, "smbios", -1); 116112553Smdodd device_set_driver(child, driver); 117112553Smdodd bus_set_resource(child, SYS_RES_MEMORY, rid, addr, length); 118112553Smdodd device_set_desc(child, "System Management BIOS"); 119112553Smdodd } 120112553Smdodd 121112553Smdodd return; 122112553Smdodd} 123112553Smdodd 124112553Smdoddstatic int 125112553Smdoddsmbios_probe (device_t dev) 126112553Smdodd{ 127112553Smdodd struct resource *res; 128112553Smdodd int rid; 129112553Smdodd int error; 130112553Smdodd 131112553Smdodd error = 0; 132112553Smdodd rid = 0; 133127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 134112553Smdodd if (res == NULL) { 135112553Smdodd device_printf(dev, "Unable to allocate memory resource.\n"); 136112553Smdodd error = ENOMEM; 137112553Smdodd goto bad; 138112553Smdodd } 139112553Smdodd 140112553Smdodd if (smbios_cksum(RES2EPS(res))) { 141112553Smdodd device_printf(dev, "SMBIOS checksum failed.\n"); 142112553Smdodd error = ENXIO; 143112553Smdodd goto bad; 144112553Smdodd } 145112553Smdodd 146112553Smdoddbad: 147112553Smdodd if (res) 148112553Smdodd bus_release_resource(dev, SYS_RES_MEMORY, rid, res); 149112553Smdodd return (error); 150112553Smdodd} 151112553Smdodd 152112553Smdoddstatic int 153112553Smdoddsmbios_attach (device_t dev) 154112553Smdodd{ 155112553Smdodd struct smbios_softc *sc; 156112553Smdodd int error; 157112553Smdodd 158112553Smdodd sc = device_get_softc(dev); 159112553Smdodd error = 0; 160112553Smdodd 161112553Smdodd sc->dev = dev; 162112553Smdodd sc->rid = 0; 163127135Snjl sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, 164127135Snjl RF_ACTIVE); 165112553Smdodd if (sc->res == NULL) { 166112553Smdodd device_printf(dev, "Unable to allocate memory resource.\n"); 167112553Smdodd error = ENOMEM; 168112553Smdodd goto bad; 169112553Smdodd } 170112553Smdodd sc->eps = RES2EPS(sc->res); 171112553Smdodd 172112553Smdodd device_printf(dev, "Version: %d.%02d", 173112553Smdodd sc->eps->SMBIOS_Major, sc->eps->SMBIOS_Minor); 174112553Smdodd if (bcd2bin(sc->eps->SMBIOS_BCD_Revision)) 175112553Smdodd printf(", Revision: %d.%02d", 176112553Smdodd bcd2bin(sc->eps->SMBIOS_BCD_Revision >> 4), 177112553Smdodd bcd2bin(sc->eps->SMBIOS_BCD_Revision & 0x0f)); 178112553Smdodd printf("\n"); 179112553Smdodd 180112553Smdodd return (0); 181112553Smdoddbad: 182112553Smdodd if (sc->res) 183112553Smdodd bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); 184112553Smdodd return (error); 185112553Smdodd} 186112553Smdodd 187112553Smdoddstatic int 188112553Smdoddsmbios_detach (device_t dev) 189112553Smdodd{ 190112553Smdodd struct smbios_softc *sc; 191112553Smdodd 192112553Smdodd sc = device_get_softc(dev); 193112553Smdodd 194112553Smdodd if (sc->res) 195112553Smdodd bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); 196112553Smdodd 197112553Smdodd return (0); 198112553Smdodd} 199112553Smdodd 200112553Smdoddstatic int 201112553Smdoddsmbios_modevent (mod, what, arg) 202112553Smdodd module_t mod; 203112553Smdodd int what; 204112553Smdodd void * arg; 205112553Smdodd{ 206112553Smdodd device_t * devs; 207112553Smdodd int count; 208112553Smdodd int i; 209112553Smdodd 210112553Smdodd switch (what) { 211112553Smdodd case MOD_LOAD: 212112553Smdodd break; 213112553Smdodd case MOD_UNLOAD: 214112553Smdodd devclass_get_devices(smbios_devclass, &devs, &count); 215112553Smdodd for (i = 0; i < count; i++) { 216112553Smdodd device_delete_child(device_get_parent(devs[i]), devs[i]); 217112553Smdodd } 218112553Smdodd break; 219112553Smdodd default: 220112553Smdodd break; 221112553Smdodd } 222112553Smdodd 223112553Smdodd return (0); 224112553Smdodd} 225112553Smdodd 226112553Smdoddstatic device_method_t smbios_methods[] = { 227112553Smdodd /* Device interface */ 228112553Smdodd DEVMETHOD(device_identify, smbios_identify), 229112553Smdodd DEVMETHOD(device_probe, smbios_probe), 230112553Smdodd DEVMETHOD(device_attach, smbios_attach), 231112553Smdodd DEVMETHOD(device_detach, smbios_detach), 232112553Smdodd { 0, 0 } 233112553Smdodd}; 234112553Smdodd 235112553Smdoddstatic driver_t smbios_driver = { 236112553Smdodd "smbios", 237112553Smdodd smbios_methods, 238112553Smdodd sizeof(struct smbios_softc), 239112553Smdodd}; 240112553Smdodd 241112553SmdoddDRIVER_MODULE(smbios, nexus, smbios_driver, smbios_devclass, smbios_modevent, 0); 242112553SmdoddMODULE_VERSION(smbios, 1); 243112553Smdodd 244112553Smdoddstatic int 245112553Smdoddsmbios_cksum (struct smbios_eps *e) 246112553Smdodd{ 247112553Smdodd u_int8_t *ptr; 248112553Smdodd u_int8_t cksum; 249112553Smdodd int i; 250112553Smdodd 251112553Smdodd ptr = (u_int8_t *)e; 252112553Smdodd cksum = 0; 253112553Smdodd for (i = 0; i < e->Length; i++) { 254112553Smdodd cksum += ptr[i]; 255112553Smdodd } 256112553Smdodd 257112553Smdodd return (cksum); 258112553Smdodd} 259