1 /* ----------------------------------------------------------------------- *
3 * Copyright 2006 Erwan Velu - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
19 void to_dmi_header(struct dmi_header
*h
, u8
*data
)
23 h
->handle
=WORD(data
+2);
27 void dmi_system_uuid(u8
*p
, s_dmi
*dmi
)
29 int only0xFF
=1, only0x00
=1;
32 for(i
=0; i
<16 && (only0x00
|| only0xFF
); i
++)
34 if(p
[i
]!=0x00) only0x00
=0;
35 if(p
[i
]!=0xFF) only0xFF
=0;
40 sprintf(dmi
->system
.uuid
,"Not Present");
45 sprintf(dmi
->system
.uuid
,"Not Settable");
49 sprintf(dmi
->system
.uuid
,"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
50 p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7],
51 p
[8], p
[9], p
[10], p
[11], p
[12], p
[13], p
[14], p
[15]);
54 static void dmi_base_board_features(u8 code
, s_dmi
*dmi
)
63 ((bool *)(& dmi
->base_board
.features
))[i
]=true;
67 static void dmi_processor_voltage(u8 code
, s_dmi
*dmi
)
70 static const float voltage
[]={
78 dmi
->processor
.voltage
=((float)(code
&0x7f)/10);
83 dmi
->processor
.voltage
=voltage
[i
];
87 static void dmi_processor_id(u8 type
, u8
*p
, const char *version
, s_dmi
*dmi
)
90 * Extra flags are now returned in the ECX register when one calls
91 * the CPUID instruction. Their meaning is explained in table 6, but
92 * DMI doesn't support this yet.
98 * This might help learn about new processors supporting the
99 * CPUID instruction or another form of identification.
101 sprintf(dmi
->processor
.id
,"ID: %02X %02X %02X %02X %02X %02X %02X %02X\n",
102 p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
104 if(type
==0x05) /* 80386 */
108 * 80386 have a different signature.
110 dmi
->processor
.signature
.type
=(dx
>>12);
111 dmi
->processor
.signature
.family
=((dx
>>8)&0xF);
112 dmi
->processor
.signature
.stepping
=(dx
>>4)&0xF;
113 dmi
->processor
.signature
.minor_stepping
=(dx
&0xF);
116 if(type
==0x06) /* 80486 */
120 * Not all 80486 CPU support the CPUID instruction, we have to find
121 * wether the one we have here does or not. Note that this trick
122 * works only because we know that 80486 must be little-endian.
124 if((dx
&0x0F00)==0x0400
125 && ((dx
&0x00F0)==0x0040 || (dx
&0x00F0)>=0x0070)
126 && ((dx
&0x000F)>=0x0003))
130 dmi
->processor
.signature
.type
=((dx
>>12)&0x3);
131 dmi
->processor
.signature
.family
=((dx
>>8)&0xF);
132 dmi
->processor
.signature
.model
=((dx
>>4)&0xF);
133 dmi
->processor
.signature
.stepping
=(dx
&0xF);
137 else if((type
>=0x0B && type
<=0x13) /* Intel, Cyrix */
138 || (type
>=0xB0 && type
<=0xB3) /* Intel */
139 || type
==0xB5 /* Intel */
140 || type
==0xB9) /* Intel */
142 else if((type
>=0x18 && type
<=0x1D) /* AMD */
143 || type
==0x1F /* AMD */
144 || (type
>=0xB6 && type
<=0xB7) /* AMD */
145 || (type
>=0x83 && type
<=0x85)) /* AMD */
147 else if(type
==0x01 || type
==0x02)
150 * Some X86-class CPU have family "Other" or "Unknown". In this case,
151 * we use the version string to determine if they are known to
152 * support the CPUID instruction.
154 if(strncmp(version
, "Pentium III MMX", 15)==0)
156 else if(strncmp(version
, "AMD Athlon(TM)", 14)==0
157 || strncmp(version
, "AMD Opteron(tm)", 15)==0)
162 else /* not X86-class */
170 dmi
->processor
.signature
.type
=((eax
>>12)&0x3);
171 dmi
->processor
.signature
.family
=(((eax
>>16)&0xFF0)+((eax
>>8)&0x00F));
172 dmi
->processor
.signature
.model
=(((eax
>>12)&0xF0)+((eax
>>4)&0x0F));
173 dmi
->processor
.signature
.stepping
=(eax
&0xF);
176 dmi
->processor
.signature
.family
=(((eax
>>8)&0xF)==0xF?(eax
>>20)&0xFF:(eax
>>8)&0xF);
177 dmi
->processor
.signature
.model
=(((eax
>>4)&0xF)==0xF?(eax
>>16)&0xF :(eax
>>4)&0xF);
178 dmi
->processor
.signature
.stepping
=(eax
&0xF);
183 if((edx
&0x3FF7FDFF)!=0)
187 if(cpu_flags_strings
[i
]!=NULL
&& edx
&(1<<i
))
188 ((bool *)(& dmi
->processor
.cpu_flags
))[i
]=true;
189 //printf("%s\t%s\n", prefix, flags[i]);
194 void dmi_system_wake_up_type(u8 code
, s_dmi
*dmi
)
197 static const char *type
[]={
198 "Reserved", /* 0x00 */
206 "AC Power Restored" /* 0x08 */
210 strcpy(dmi
->system
.wakeup_type
,type
[code
]);
212 strcpy(dmi
->system
.wakeup_type
,out_of_spec
);
217 void dmi_bios_runtime_size(u32 code
, s_dmi
*dmi
)
219 if(code
&0x000003FF) {
220 dmi
->bios
.runtime_size
=code
;
221 strcpy(dmi
->bios
.runtime_size_unit
,"bytes");
223 dmi
->bios
.runtime_size
=code
>>10;
224 strcpy(dmi
->bios
.runtime_size_unit
,"KB");
229 void dmi_bios_characteristics(u64 code
, s_dmi
*dmi
)
233 * This isn't very clear what this bit is supposed to mean
237 ((bool *)(& dmi
->bios
.characteristics
))[0]=true;
243 ((bool *)(& dmi
->bios
.characteristics
))[i
-3]=true;
246 void dmi_bios_characteristics_x1(u8 code
, s_dmi
*dmi
)
252 ((bool *)(& dmi
->bios
.characteristics_x1
))[i
]=true;
255 void dmi_bios_characteristics_x2(u8 code
, s_dmi
*dmi
)
261 ((bool *)(& dmi
->bios
.characteristics_x2
))[i
]=true;
264 const char *dmi_string(struct dmi_header
*dm
, u8 s
)
266 char *bp
=(char *)dm
->data
;
270 return "Not Specified";
283 /* ASCII filtering */
286 if(bp
[i
]<32 || bp
[i
]==127)
292 inline int dmi_checksum(u8
*buf
)
305 p
=(char *)0xF0000; /* The start address to look at the dmi table */
306 for (q
= p
; q
< p
+ 0x10000; q
+= 16) {
308 if(memcmp(buf
, "_DMI_", 5)==0 && dmi_checksum(buf
)) {
309 dmitable
.num
= buf
[13]<<8|buf
[12];
310 dmitable
.len
= buf
[7]<<8|buf
[6];
311 dmitable
.base
= buf
[11]<<24|buf
[10]<<16|buf
[9]<<8|buf
[8];
312 dmitable
.ver
= (buf
[0x06]<<8)+buf
[0x07];
315 * DMI version 0.0 means that the real version is taken from
316 * the SMBIOS version, which we don't know at this point.
319 printf("DMI %d.%d present.\n",buf
[14]>>4, buf
[14]&0x0F);
321 printf("DMI present.\n");
322 printf("%d structures occupying %d bytes.\n",dmitable
.num
, dmitable
.len
);
323 printf("DMI table at 0x%08X.\n",dmitable
.base
);
334 void dmi_decode(struct dmi_header
*h
, u16 ver
, s_dmi
*dmi
)
339 * Note: DMI types 37, 38 and 39 are untested
343 case 0: /* 3.3.1 BIOS Information */
344 // printf("BIOS Information\n");
345 if(h
->length
<0x12) break;
346 strcpy(dmi
->bios
.vendor
,dmi_string(h
,data
[0x04]));
347 strcpy(dmi
->bios
.version
,dmi_string(h
,data
[0x05]));
348 strcpy(dmi
->bios
.release_date
,dmi_string(h
,data
[0x08]));
349 dmi
->bios
.address
=WORD(data
+0x06);
350 dmi_bios_runtime_size((0x10000-WORD(data
+0x06))<<4,dmi
);
351 dmi
->bios
.rom_size
=(data
[0x09]+1)<<6;
352 strcpy(dmi
->bios
.rom_size_unit
,"kB");
353 dmi_bios_characteristics(QWORD(data
+0x0A),dmi
);
355 if(h
->length
<0x13) break;
356 dmi_bios_characteristics_x1(data
[0x12], dmi
);
357 if(h
->length
<0x14) break;
358 dmi_bios_characteristics_x2(data
[0x13], dmi
);
359 if(h
->length
<0x18) break;
360 if(data
[0x14]!=0xFF && data
[0x15]!=0xFF)
361 sprintf(dmi
->bios
.bios_revision
,"%u.%u",
362 data
[0x14], data
[0x15]);
363 if(data
[0x16]!=0xFF && data
[0x17]!=0xFF)
364 sprintf(dmi
->bios
.firmware_revision
,"%u.%u",
365 data
[0x16], data
[0x17]);
367 case 1: /* 3.3.2 System Information */
368 // printf("System Information\n");
369 if(h
->length
<0x08) break;
370 strcpy(dmi
->system
.manufacturer
,dmi_string(h
,data
[0x04]));
371 strcpy(dmi
->system
.product_name
,dmi_string(h
,data
[0x05]));
372 strcpy(dmi
->system
.version
,dmi_string(h
,data
[0x06]));
373 strcpy(dmi
->system
.serial
,dmi_string(h
,data
[0x07]));
374 if(h
->length
<0x19) break;
375 dmi_system_uuid(data
+0x08,dmi
);
376 dmi_system_wake_up_type(data
[0x18],dmi
);
377 if(h
->length
<0x1B) break;
378 strcpy(dmi
->system
.sku_number
,dmi_string(h
,data
[0x19]));
379 strcpy(dmi
->system
.family
,dmi_string(h
,data
[0x1A]));
382 case 2: /* 3.3.3 Base Board Information */
383 // printf("Base Board Information\n");
384 if(h
->length
<0x08) break;
385 strcpy(dmi
->base_board
.manufacturer
,dmi_string(h
,data
[0x04]));
386 strcpy(dmi
->base_board
.product_name
,dmi_string(h
,data
[0x05]));
387 strcpy(dmi
->base_board
.version
,dmi_string(h
,data
[0x06]));
388 strcpy(dmi
->base_board
.serial
,dmi_string(h
,data
[0x07]));
389 if(h
->length
<0x0F) break;
390 strcpy(dmi
->base_board
.asset_tag
,dmi_string(h
,data
[0x08]));
391 dmi_base_board_features(data
[0x09], dmi
);
392 strcpy(dmi
->base_board
.location
,dmi_string(h
,data
[0x0A]));
393 strcpy(dmi
->base_board
.type
,dmi_string(h
,data
[0x0D]));
394 if(h
->length
<0x0F+data
[0x0E]*sizeof(u16
)) break;
396 case 3: /* 3.3.4 Chassis Information */
397 // printf("Chassis Information\n");
398 if(h
->length
<0x09) break;
399 strcpy(dmi
->chassis
.manufacturer
,dmi_string(h
,data
[0x04]));
400 strcpy(dmi
->chassis
.type
,dmi_chassis_type(data
[0x05]&0x7F));
401 strcpy(dmi
->chassis
.lock
,dmi_chassis_lock(data
[0x05]>>7));
402 strcpy(dmi
->chassis
.version
,dmi_string(h
,data
[0x06]));
403 strcpy(dmi
->chassis
.serial
,dmi_string(h
,data
[0x07]));
404 strcpy(dmi
->chassis
.asset_tag
,dmi_string(h
,data
[0x08]));
405 if(h
->length
<0x0D) break;
406 strcpy(dmi
->chassis
.boot_up_state
,dmi_chassis_state(data
[0x09]));
407 strcpy(dmi
->chassis
.power_supply_state
,dmi_chassis_state(data
[0x0A]));
408 strcpy(dmi
->chassis
.thermal_state
,dmi_chassis_state(data
[0x0B]));
409 strcpy(dmi
->chassis
.security_status
,dmi_chassis_security_status(data
[0x0C]));
410 if(h
->length
<0x11) break;
411 sprintf(dmi
->chassis
.oem_information
,"0x%08X\n",DWORD(data
+0x0D));
412 if(h
->length
<0x15) break;
413 dmi
->chassis
.height
=data
[0x11];
414 dmi
->chassis
.nb_power_cords
=data
[0x12];
417 case 4: /* 3.3.5 Processor Information */
418 // printf("Processor Information\n");
419 if(h
->length
<0x1A) break;
420 strcpy(dmi
->processor
.socket_designation
,dmi_string(h
, data
[0x04]));
421 strcpy(dmi
->processor
.type
,dmi_processor_type(data
[0x05]));
422 strcpy(dmi
->processor
.family
,dmi_processor_family(data
[0x06]));
423 strcpy(dmi
->processor
.manufacturer
,dmi_string(h
, data
[0x07]));
424 dmi_processor_id(data
[0x06], data
+8, dmi_string(h
, data
[0x10]), dmi
);
425 strcpy(dmi
->processor
.version
,dmi_string(h
, data
[0x10]));
426 dmi_processor_voltage(data
[0x11],dmi
);
427 dmi
->processor
.external_clock
=WORD(data
+0x12);
428 dmi
->processor
.max_speed
=WORD(data
+0x14);
429 dmi
->processor
.current_speed
=WORD(data
+0x16);
430 if(data
[0x18]&(1<<6))
431 strcpy(dmi
->processor
.status
,dmi_processor_status(data
[0x18]&0x07));
433 sprintf(dmi
->processor
.status
,"Unpopulated");
434 sprintf(dmi
->processor
.upgrade
,dmi_processor_upgrade(data
[0x19]));
435 if(h
->length
<0x20) break;
436 dmi_processor_cache(WORD(data
+0x1A), "L1", ver
,dmi
->processor
.cache1
);
437 dmi_processor_cache(WORD(data
+0x1C), "L2", ver
,dmi
->processor
.cache2
);
438 dmi_processor_cache(WORD(data
+0x1E), "L3", ver
,dmi
->processor
.cache3
);
439 if(h
->length
<0x23) break;
440 strcpy(dmi
->processor
.serial
,dmi_string(h
, data
[0x20]));
441 strcpy(dmi
->processor
.asset_tag
,dmi_string(h
, data
[0x21]));
442 strcpy(dmi
->processor
.part_number
,dmi_string(h
, data
[0x22]));
447 void parse_dmitable(s_dmi
*dmi
) {
450 u8 buf
[dmitable
.len
];
452 memcpy(buf
,(int *)dmitable
.base
,sizeof(u8
) * dmitable
.len
);
454 while(i
<dmitable
.num
&& data
+4<=buf
+dmitable
.len
) /* 4 is the length of an SMBIOS structure header */ {
457 to_dmi_header(&h
, data
);
460 * If a short entry is found (less than 4 bytes), not only it
461 * is invalid, but we cannot reliably locate the next entry.
462 * Better stop at this point, and let the user know his/her
467 printf("Invalid entry length (%u). DMI table is broken! Stop.\n\n", (unsigned int)h
.length
);
471 // printf("Handle 0x%04X, DMI type %d, %d bytes\n", h.handle, h.type, h.length);
473 /* loo for the next handle */
475 while(next
-buf
+1<dmitable
.len
&& (next
[0]!=0 || next
[1]!=0))
478 if(next
-buf
<=dmitable
.len
)
480 dmi_decode(&h
, dmitable
.ver
,dmi
);
483 printf("\t<TRUNCATED>\n");