2
* Trimmed from DMI Decode http://savannah.nongnu.org/projects/dmidecode
4
* (C) 2000-2002 Alan Cox <alan@redhat.com>
5
* (C) 2002-2007 Jean Delvare <khali@linux-fr.org>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
* For the avoidance of doubt the "preferred form" of this code is one which
22
* is in an open unpatent encumbered format. Where cryptographic key signing
23
* forms part of the process of creating an executable the information
24
* including keys needed to generate an equivalently functional executable
25
* are deemed to be part of the source code.
37
#include "dmidecode.h"
41
#include "../naming_policy.h"
43
static const char *bad_index = "<BAD INDEX>";
46
* Type-independant Stuff
49
const char *dmi_string(struct dmi_header *dm, u8 s)
51
char *bp=(char *)dm->data;
55
return "Not Specified";
71
if(bp[i]<32 || bp[i]==127)
81
#define MIN(a,b) (((a)<(b))?(a):(b))
83
static void strip_right(char *s)
85
int i, len = strlen(s);
86
for (i=len; i>=0; i--) {
94
static void fill_one_slot_function(struct pci_device *pdev, struct dmi_header *h)
97
pdev->physical_slot = WORD(data+0x09);
98
pdev->smbios_type = 0;
99
pdev->smbios_instance = 0;
100
pdev->uses_smbios |= HAS_SMBIOS_SLOT;
101
if (dmi_string(h, data[0x04])) {
102
pdev->smbios_label=strdup(dmi_string(h, data[0x04]));
103
pdev->uses_smbios |= HAS_SMBIOS_LABEL;
105
strip_right(pdev->smbios_label);
108
static void fill_all_slot_functions(const struct libbiosdevname_state *state, int domain, int bus, int device, struct dmi_header *h)
110
struct pci_device *pdev;
111
list_for_each_entry(pdev, &state->pci_devices, node) {
112
if (pdev->pci_dev->domain == domain &&
113
pdev->pci_dev->bus == bus &&
114
pdev->pci_dev->dev == device &&
115
! (pdev->uses_smbios & HAS_SMBIOS_EXACT_MATCH))
116
fill_one_slot_function(pdev, h);
120
static void dmi_decode(struct dmi_header *h, u16 ver, const struct libbiosdevname_state *state)
123
int domain, bus, device, function;
124
struct pci_device *pdev;
127
case 9: /* 3.3.10 System Slots */
128
if (h->length >= 0x0E && h->length >=0x11) {
129
domain = WORD(data+0x0D);
131
device = (data[0x10]>>3)&0x1F;
132
function = data[0x10] & 7;
133
if (! (domain == 0xFFFF && bus == 0xFF && data[0x10] == 0xFF)) {
134
device = (data[0x10]>>3)&0x1F;
135
function = data[0x10] & 7;
136
pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function);
138
fill_one_slot_function(pdev, h);
139
pdev->uses_smbios |= HAS_SMBIOS_EXACT_MATCH;
141
fill_all_slot_functions(state, domain, bus, device, h);
145
case 41: /* 3.3.xx Onboard Device Information */
146
domain = WORD(data+0x07);
148
device = (data[0xa]>>3) & 0x1F;
149
function = data[0xa] & 0x7;
150
pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function);
152
pdev->physical_slot = 0;
153
pdev->smbios_enabled = !!(data[0x05] & 0x80);
154
pdev->smbios_type = data[0x05] & 0x7F;
155
pdev->smbios_instance = data[0x06];
156
pdev->uses_smbios |= HAS_SMBIOS_INSTANCE | HAS_SMBIOS_SLOT;
157
if (dmi_string(h, data[0x04])) {
158
pdev->smbios_label=strdup(dmi_string(h, data[0x04]));
159
pdev->uses_smbios |= HAS_SMBIOS_LABEL;
161
strip_right(pdev->smbios_label);
166
if(dmi_decode_oem(h, state))
171
static void to_dmi_header(struct dmi_header *h, u8 *data)
175
h->handle=WORD(data+2);
179
static void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem, const struct libbiosdevname_state *state)
185
if((buf=mem_chunk(base, len, devmem))==NULL)
188
printf("Table is unreachable, sorry. Try compiling dmidecode with -DUSE_MMAP.\n");
194
while(i<num && data+4<=buf+len) /* 4 is the length of an SMBIOS structure header */
199
to_dmi_header(&h, data);
202
* If a short entry is found (less than 4 bytes), not only it
203
* is invalid, but we cannot reliably locate the next entry.
204
* Better stop at this point, and let the user know his/her
210
/* assign vendor for vendor-specific decodes later */
211
if(h.type==0 && h.length>=5)
212
dmi_set_vendor(dmi_string(&h, data[0x04]));
214
/* look for the next handle */
216
while(next-buf+1<len && (next[0]!=0 || next[1]!=0))
220
dmi_decode(&h, ver, state);
229
static int smbios_decode(u8 *buf, const char *devmem, const struct libbiosdevname_state *state)
231
if(checksum(buf, buf[0x05])
232
&& memcmp(buf+0x10, "_DMI_", 5)==0
233
&& checksum(buf+0x10, 0x0F))
235
dmi_table(DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C),
236
(buf[0x06]<<8)+buf[0x07], devmem, state);
243
static int legacy_decode(u8 *buf, const char *devmem, const struct libbiosdevname_state *state)
245
if(checksum(buf, 0x0F))
247
dmi_table(DWORD(buf+0x08), WORD(buf+0x06), WORD(buf+0x0C),
248
((buf[0x0E]&0xF0)<<4)+(buf[0x0E]&0x0F), devmem, state);
256
* Probe for EFI interface
258
#define EFI_NOT_FOUND (-1)
259
#define EFI_NO_SMBIOS (-2)
260
static int address_from_efi(size_t *address)
263
const char *filename;
267
*address=0; /* Prevent compiler warning */
270
* Linux up to 2.6.6: /proc/efi/systab
271
* Linux 2.6.7 and up: /sys/firmware/efi/systab
273
if((efi_systab=fopen(filename="/sys/firmware/efi/systab", "r"))==NULL
274
&& (efi_systab=fopen(filename="/proc/efi/systab", "r"))==NULL)
276
/* No EFI interface, fallback to memory scan */
277
return EFI_NOT_FOUND;
280
while((fgets(linebuf, sizeof(linebuf)-1, efi_systab))!=NULL)
282
char *addrp=strchr(linebuf, '=');
284
if(strcmp(linebuf, "SMBIOS")==0)
286
*address=strtoul(addrp, NULL, 0);
291
if(fclose(efi_systab)!=0)
294
if(ret==EFI_NO_SMBIOS)
295
fprintf(stderr, "%s: SMBIOS entry point missing\n", filename);
299
static const char *devmem = "/dev/mem";
301
int dmidecode_main(const struct libbiosdevname_state *state)
303
int ret=0; /* Returned value */
309
/* First try EFI (ia64, Intel-based Mac) */
310
efi=address_from_efi(&fp);
320
if((buf=mem_chunk(fp, 0x20, devmem))==NULL)
326
if(smbios_decode(buf, devmem, state))
331
/* Fallback to memory scan (x86, x86_64) */
332
if((buf=mem_chunk(0xF0000, 0x10000, devmem))==NULL)
338
for(fp=0; fp<=0xFFF0; fp+=16)
340
if(memcmp(buf+fp, "_SM_", 4)==0 && fp<=0xFFE0)
342
if(smbios_decode(buf+fp, devmem, state))
348
else if(memcmp(buf+fp, "_DMI_", 5)==0)
350
if (legacy_decode(buf+fp, devmem, state))