~ubuntu-branches/ubuntu/saucy/biosdevname/saucy-proposed

« back to all changes in this revision

Viewing changes to src/dmidecode/dmidecode.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2011-02-23 17:58:36 UTC
  • Revision ID: james.westby@ubuntu.com-20110223175836-4f0cbcno9zm0lmdu
Tags: upstream-0.3.7
ImportĀ upstreamĀ versionĀ 0.3.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Trimmed from DMI Decode http://savannah.nongnu.org/projects/dmidecode
 
3
 *
 
4
 *   (C) 2000-2002 Alan Cox <alan@redhat.com>
 
5
 *   (C) 2002-2007 Jean Delvare <khali@linux-fr.org>
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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
 
20
 *
 
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.
 
26
 */
 
27
 
 
28
#include <stdio.h>
 
29
#include <string.h>
 
30
#include <stdlib.h>
 
31
#include <unistd.h>
 
32
#include <ctype.h>
 
33
 
 
34
#include "config.h"
 
35
#include "types.h"
 
36
#include "util.h"
 
37
#include "dmidecode.h"
 
38
#include "dmioem.h"
 
39
#include "../state.h"
 
40
#include "../pci.h"
 
41
#include "../naming_policy.h"
 
42
 
 
43
static const char *bad_index = "<BAD INDEX>";
 
44
 
 
45
/*
 
46
 * Type-independant Stuff
 
47
 */
 
48
 
 
49
const char *dmi_string(struct dmi_header *dm, u8 s)
 
50
{
 
51
        char *bp=(char *)dm->data;
 
52
        size_t i, len;
 
53
 
 
54
        if(s==0)
 
55
                return "Not Specified";
 
56
 
 
57
        bp+=dm->length;
 
58
        while(s>1 && *bp)
 
59
        {
 
60
                bp+=strlen(bp);
 
61
                bp++;
 
62
                s--;
 
63
        }
 
64
 
 
65
        if(!*bp)
 
66
                return bad_index;
 
67
 
 
68
        /* ASCII filtering */
 
69
        len=strlen(bp);
 
70
        for(i=0; i<len; i++)
 
71
                if(bp[i]<32 || bp[i]==127)
 
72
                        bp[i]='.';
 
73
 
 
74
        return bp;
 
75
}
 
76
 
 
77
/*
 
78
 * Main
 
79
 */
 
80
 
 
81
#define        MIN(a,b) (((a)<(b))?(a):(b))
 
82
 
 
83
static void strip_right(char *s)
 
84
{
 
85
        int i, len = strlen(s);
 
86
        for (i=len; i>=0; i--) {
 
87
                if (isspace(s[i-1]))
 
88
                        s[i-1] = '\0';
 
89
                else
 
90
                        break;
 
91
        }
 
92
}
 
93
 
 
94
static void fill_one_slot_function(struct pci_device *pdev, struct dmi_header *h)
 
95
{
 
96
        u8 *data = h->data;
 
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;
 
104
        }
 
105
        strip_right(pdev->smbios_label);
 
106
}
 
107
 
 
108
static void fill_all_slot_functions(const struct libbiosdevname_state *state, int domain, int bus, int device, struct dmi_header *h)
 
109
{
 
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);
 
117
        }
 
118
}
 
119
 
 
120
static void dmi_decode(struct dmi_header *h, u16 ver, const struct libbiosdevname_state *state)
 
121
{
 
122
        u8 *data=h->data;
 
123
        int domain, bus, device, function;
 
124
        struct pci_device *pdev;
 
125
        switch(h->type)
 
126
        {
 
127
                case 9: /* 3.3.10 System Slots */
 
128
                        if (h->length >= 0x0E && h->length >=0x11) {
 
129
                                domain = WORD(data+0x0D);
 
130
                                bus = data[0x0F];
 
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);
 
137
                                        if (pdev) {
 
138
                                                fill_one_slot_function(pdev, h);
 
139
                                                pdev->uses_smbios |= HAS_SMBIOS_EXACT_MATCH;
 
140
                                        }
 
141
                                        fill_all_slot_functions(state, domain, bus, device, h);
 
142
                                }
 
143
                        }
 
144
                        break;
 
145
                case 41: /* 3.3.xx Onboard Device Information */
 
146
                        domain = WORD(data+0x07);
 
147
                        bus    = data[0x09];
 
148
                        device = (data[0xa]>>3) & 0x1F;
 
149
                        function = data[0xa] & 0x7;
 
150
                        pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function);
 
151
                        if (pdev) {
 
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;
 
160
                                }
 
161
                                strip_right(pdev->smbios_label);
 
162
                        }
 
163
                        break;
 
164
 
 
165
                default:
 
166
                        if(dmi_decode_oem(h, state))
 
167
                                break;
 
168
        }
 
169
}
 
170
 
 
171
static void to_dmi_header(struct dmi_header *h, u8 *data)
 
172
{
 
173
        h->type=data[0];
 
174
        h->length=data[1];
 
175
        h->handle=WORD(data+2);
 
176
        h->data=data;
 
177
}
 
178
 
 
179
static void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem, const struct libbiosdevname_state *state)
 
180
{
 
181
        u8 *buf;
 
182
        u8 *data;
 
183
        int i=0;
 
184
 
 
185
        if((buf=mem_chunk(base, len, devmem))==NULL)
 
186
        {
 
187
#ifndef USE_MMAP
 
188
                printf("Table is unreachable, sorry. Try compiling dmidecode with -DUSE_MMAP.\n");
 
189
#endif
 
190
                return;
 
191
        }
 
192
 
 
193
        data=buf;
 
194
        while(i<num && data+4<=buf+len) /* 4 is the length of an SMBIOS structure header */
 
195
        {
 
196
                u8 *next;
 
197
                struct dmi_header h;
 
198
 
 
199
                to_dmi_header(&h, data);
 
200
 
 
201
                /*
 
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
 
205
                 * table is broken.
 
206
                 */
 
207
                if(h.length<4)
 
208
                        break;
 
209
 
 
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]));
 
213
 
 
214
                /* look for the next handle */
 
215
                next=data+h.length;
 
216
                while(next-buf+1<len && (next[0]!=0 || next[1]!=0))
 
217
                        next++;
 
218
                next+=2;
 
219
                if(next-buf<=len)
 
220
                        dmi_decode(&h, ver, state);
 
221
 
 
222
                data=next;
 
223
                i++;
 
224
        }
 
225
        free(buf);
 
226
}
 
227
 
 
228
 
 
229
static int smbios_decode(u8 *buf, const char *devmem, const struct libbiosdevname_state *state)
 
230
{
 
231
        if(checksum(buf, buf[0x05])
 
232
         && memcmp(buf+0x10, "_DMI_", 5)==0
 
233
         && checksum(buf+0x10, 0x0F))
 
234
        {
 
235
                dmi_table(DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C),
 
236
                          (buf[0x06]<<8)+buf[0x07], devmem, state);
 
237
                return 1;
 
238
        }
 
239
 
 
240
        return 0;
 
241
}
 
242
 
 
243
static int legacy_decode(u8 *buf, const char *devmem, const struct libbiosdevname_state *state)
 
244
{
 
245
        if(checksum(buf, 0x0F))
 
246
        {
 
247
                dmi_table(DWORD(buf+0x08), WORD(buf+0x06), WORD(buf+0x0C),
 
248
                          ((buf[0x0E]&0xF0)<<4)+(buf[0x0E]&0x0F), devmem, state);
 
249
                return 1;
 
250
        }
 
251
 
 
252
        return 0;
 
253
}
 
254
 
 
255
/*
 
256
 * Probe for EFI interface
 
257
 */
 
258
#define EFI_NOT_FOUND   (-1)
 
259
#define EFI_NO_SMBIOS   (-2)
 
260
static int address_from_efi(size_t *address)
 
261
{
 
262
        FILE *efi_systab;
 
263
        const char *filename;
 
264
        char linebuf[64];
 
265
        int ret;
 
266
 
 
267
        *address=0; /* Prevent compiler warning */
 
268
 
 
269
        /*
 
270
         * Linux up to 2.6.6: /proc/efi/systab
 
271
         * Linux 2.6.7 and up: /sys/firmware/efi/systab
 
272
         */
 
273
        if((efi_systab=fopen(filename="/sys/firmware/efi/systab", "r"))==NULL
 
274
        && (efi_systab=fopen(filename="/proc/efi/systab", "r"))==NULL)
 
275
        {
 
276
                /* No EFI interface, fallback to memory scan */
 
277
                return EFI_NOT_FOUND;
 
278
        }
 
279
        ret=EFI_NO_SMBIOS;
 
280
        while((fgets(linebuf, sizeof(linebuf)-1, efi_systab))!=NULL)
 
281
        {
 
282
                char *addrp=strchr(linebuf, '=');
 
283
                *(addrp++)='\0';
 
284
                if(strcmp(linebuf, "SMBIOS")==0)
 
285
                {
 
286
                        *address=strtoul(addrp, NULL, 0);
 
287
                        ret=0;
 
288
                        break;
 
289
                }
 
290
        }
 
291
        if(fclose(efi_systab)!=0)
 
292
                perror(filename);
 
293
 
 
294
        if(ret==EFI_NO_SMBIOS)
 
295
                fprintf(stderr, "%s: SMBIOS entry point missing\n", filename);
 
296
        return ret;
 
297
}
 
298
 
 
299
static const char *devmem = "/dev/mem";
 
300
 
 
301
int dmidecode_main(const struct libbiosdevname_state *state)
 
302
{
 
303
        int ret=0;                  /* Returned value */
 
304
        int found=0;
 
305
        size_t fp;
 
306
        int efi;
 
307
        u8 *buf;
 
308
 
 
309
        /* First try EFI (ia64, Intel-based Mac) */
 
310
        efi=address_from_efi(&fp);
 
311
        switch(efi)
 
312
        {
 
313
                case EFI_NOT_FOUND:
 
314
                        goto memory_scan;
 
315
                case EFI_NO_SMBIOS:
 
316
                        ret=1;
 
317
                        goto exit_free;
 
318
        }
 
319
 
 
320
        if((buf=mem_chunk(fp, 0x20, devmem))==NULL)
 
321
        {
 
322
                ret=1;
 
323
                goto exit_free;
 
324
        }
 
325
 
 
326
        if(smbios_decode(buf, devmem, state))
 
327
                found++;
 
328
        goto done;
 
329
 
 
330
memory_scan:
 
331
        /* Fallback to memory scan (x86, x86_64) */
 
332
        if((buf=mem_chunk(0xF0000, 0x10000, devmem))==NULL)
 
333
        {
 
334
                ret=1;
 
335
                goto exit_free;
 
336
        }
 
337
 
 
338
        for(fp=0; fp<=0xFFF0; fp+=16)
 
339
        {
 
340
                if(memcmp(buf+fp, "_SM_", 4)==0 && fp<=0xFFE0)
 
341
                {
 
342
                        if(smbios_decode(buf+fp, devmem, state))
 
343
                        {
 
344
                                found++;
 
345
                                fp+=16;
 
346
                        }
 
347
                }
 
348
                else if(memcmp(buf+fp, "_DMI_", 5)==0)
 
349
                {
 
350
                        if (legacy_decode(buf+fp, devmem, state))
 
351
                                found++;
 
352
                }
 
353
        }
 
354
 
 
355
done:
 
356
        free(buf);
 
357
 
 
358
 
 
359
exit_free:
 
360
        return ret;
 
361
}