/* * Trimmed from DMI Decode http://savannah.nongnu.org/projects/dmidecode * * (C) 2000-2002 Alan Cox * (C) 2002-2007 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For the avoidance of doubt the "preferred form" of this code is one which * is in an open unpatent encumbered format. Where cryptographic key signing * forms part of the process of creating an executable the information * including keys needed to generate an equivalently functional executable * are deemed to be part of the source code. */ #include #include #include #include #include #include "config.h" #include "types.h" #include "util.h" #include "dmidecode.h" #include "dmioem.h" #include "../state.h" #include "../pci.h" #include "../naming_policy.h" extern int smver_mjr, smver_mnr; static const char *bad_index = ""; /* * Type-independant Stuff */ const char *dmi_string(struct dmi_header *dm, u8 s) { char *bp=(char *)dm->data; size_t i, len; if(s==0) return "Not Specified"; bp+=dm->length; while(s>1 && *bp) { bp+=strlen(bp); bp++; s--; } if(!*bp) return bad_index; /* ASCII filtering */ len=strlen(bp); for(i=0; i=0; i--) { if (isspace(s[i-1])) s[i-1] = '\0'; else break; } } static void fill_one_slot_function(struct pci_device *pdev, struct dmi_header *h) { u8 *data = h->data; pdev->physical_slot = WORD(data+0x09); pdev->smbios_type = 0; pdev->smbios_instance = 0; pdev->uses_smbios |= HAS_SMBIOS_SLOT; if (dmi_string(h, data[0x04])) { pdev->smbios_label=strdup(dmi_string(h, data[0x04])); pdev->uses_smbios |= HAS_SMBIOS_LABEL; } strip_right(pdev->smbios_label); } static void fill_all_slot_functions(const struct libbiosdevname_state *state, int domain, int bus, int device, struct dmi_header *h) { struct pci_device *pdev; list_for_each_entry(pdev, &state->pci_devices, node) { if (pdev->pci_dev->domain == domain && pdev->pci_dev->bus == bus && pdev->pci_dev->dev == device && ! (pdev->uses_smbios & HAS_SMBIOS_EXACT_MATCH)) fill_one_slot_function(pdev, h); } } static void dmi_decode(struct dmi_header *h, u16 ver, const struct libbiosdevname_state *state) { u8 *data=h->data; int domain, bus, device, function; struct pci_device *pdev; switch(h->type) { case 9: /* 3.3.10 System Slots */ if (h->length >= 0x0E && h->length >=0x11) { domain = WORD(data+0x0D); bus = data[0x0F]; device = (data[0x10]>>3)&0x1F; function = data[0x10] & 7; if (! (domain == 0xFFFF && bus == 0xFF && data[0x10] == 0xFF)) { device = (data[0x10]>>3)&0x1F; function = data[0x10] & 7; pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function); if (pdev) { fill_one_slot_function(pdev, h); pdev->uses_smbios |= HAS_SMBIOS_EXACT_MATCH; } fill_all_slot_functions(state, domain, bus, device, h); } } break; case 41: /* 3.3.xx Onboard Device Information */ domain = WORD(data+0x07); bus = data[0x09]; device = (data[0xa]>>3) & 0x1F; function = data[0xa] & 0x7; pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function); if (pdev) { pdev->physical_slot = 0; pdev->smbios_enabled = !!(data[0x05] & 0x80); pdev->smbios_type = data[0x05] & 0x7F; pdev->smbios_instance = data[0x06]; pdev->uses_smbios |= HAS_SMBIOS_INSTANCE | HAS_SMBIOS_SLOT; if (dmi_string(h, data[0x04])) { pdev->smbios_label=strdup(dmi_string(h, data[0x04])); pdev->uses_smbios |= HAS_SMBIOS_LABEL; } strip_right(pdev->smbios_label); } break; default: if(dmi_decode_oem(h, state)) break; } } static void to_dmi_header(struct dmi_header *h, u8 *data) { h->type=data[0]; h->length=data[1]; h->handle=WORD(data+2); h->data=data; } static int isvalidsmbios(int mjr, int mnr) { if (!smver_mjr && !smver_mnr) return 1; if (mjr > smver_mjr) return 1; if ((mjr == smver_mjr) && (mnr >= smver_mnr)) return 1; return 0; } static void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem, const struct libbiosdevname_state *state) { u8 *buf; u8 *data; int i=0; /* Verify SMBIOS version */ if (!isvalidsmbios(ver >> 8, ver & 0xFF)) { return; } if((buf=mem_chunk(base, len, devmem))==NULL) { #ifndef USE_MMAP printf("Table is unreachable, sorry. Try compiling dmidecode with -DUSE_MMAP.\n"); #endif return; } data=buf; while(i=5) dmi_set_vendor(dmi_string(&h, data[0x04])); /* look for the next handle */ next=data+h.length; while(next-buf+1