透过BIOS获取Linux/Unix的设备信息

Time: 三月 8, 2012
Category: Programming practices
目录索引

c 的标准里并没有提供读取硬件基本信息方面的API,但是有时候我们需要知道一些系统方面的信息,比如内存的规格,缓存,CPU以及磁盘等等。目前比较常见的方法就是通过读取BIOS信息。下文所述的方法理论上在各种Linux/Unix发行版里是适用的,但是没有仔细代码测试过,而且BIOS信息因各厂商不同而异,难有统一的标准,另一方面,BIOS信息量巨大,我仅作简单的描述

  1. Linux i386, x86-64, ia64
  2. FreeBSD i386, amd64
  3. NetBSD i386, amd64
  4. OpenBSD i386, amd64
  5. BeOS i386
  6. Cygwin i386
  7. Solaris x86
  8. Haiku i586

BIOS表

BIOS信息会在系统刚刚启动的时候加载到内存的0xF0000地址处,以表的形式组成,长度不会超过65536个字节。将那块内存区域的数据拷贝出来就可以看到,首先最前面的是_SM_和_DMI_两个信息头,如下,所有数据都是ASCII码

0x80613f8: "_SM_30370205d"
0x8061402: ""
0x8061403: ""
0x8061404: ""
0x8061405: ""
0x8061406: ""
0x8061407: ""
0x8061408: "_DMI_&3630520"
0x8061412: "16"
0x8061414: ","

还有别忘了上面每个字符串后面其实有一个'',编译器给省略了显示。首先分析_SM_头,挑重要的说。0205 表示SMBIOS信息的版本是2.5,37是_SM_头的长度,单位为字节。还有一个很重要的特性,是为了防止BIOS数据块损坏而起校验作用的,就是_SM_头内所有字节值的和是256的倍数,下面_DMI_的校验和这个也是一样的。_SM_头后紧接着就是_DMI_头,长度固定,15字节,_DMI_头里记录着后面记录的起始地址和长度,36305 两个字节表示长度,20001600 四个字节表示内存中的地址,而 ',' 表示记录的数量,这里 ',' 的值是44

BIOS记录

BIOS记录数据的首地址长度等信息在前面已经提到,这块区域储存了各种计算机设备的基本信息,包括CPU,缓存,内存,磁盘,鼠标,等等。

每条记录主要有两部分内容,一个是记录头,一个是记录备注,记录头里记录了记录头信息的长度,而记录备注则是连串的字符串,但是没有长度。那么如何确定下一条记录的位置呢,也不难,除了第一条记录之外,此后的每条记录前面必有两个连续的 00 字节。如下

0x806a04c: "013301"
0x806a050: "0102030420345y01J~21˥O355 370-21531206"
0x806a066: "03LENOVO"
0x806a06e: "28747GC"
0x806a076: "ThinkPad SL410"
0x806a085: "LRHVT48"
0x806a08d: ""
0x806a08e: "021702"    /* 0x806a08e - 0x806a04c == 33 */
0x806a092: "01020304"
0x806a097: ""

第一个01是Handle标志,33表示记录头的长度,后面的 01是DMI标志。如果DMI的值是127,表示记录到此结束。Handle标志表示该设备属于哪类设备,有43个值,参考如下:

"BIOS", /* 0 */
"System",
"Base Board",
"Chassis",
"Processor",
"Memory Controller",
"Memory Module",
"Cache",
"Port Connector",
"System Slots",
"On Board Devices",
"OEM Strings",
"System Configuration Options",
"BIOS Language",
"Group Associations",
"System Event Log",
"Physical Memory Array",
"Memory Device",
"32-bit Memory Error",
"Memory Array Mapped Address",
"Memory Device Mapped Address",
"Built-in Pointing Device",
"Portable Battery",
"System Reset",
"Hardware Security",
"System Power Controls",
"Voltage Probe",
"Cooling Device",
"Temperature Probe",
"Electrical Current Probe",
"Out-of-band Remote Access",
"Boot Integrity Services",
"System Boot",
"64-bit Memory Error",
"Management Device",
"Management Device Component",
"Management Device Threshold Data",
"Memory Channel",
"IPMI Device",
"Power Supply",
"Additional Information",
"Onboard Device",
"Management Controller Host Interface", /* 42 */

上面所说的3个字位是记录头里最重要的信息,然后接着是一个00位,00之后的数据,记录了该设备的详细参数,比如缓存的大小,设备厂商,序列号,等等。而且每个设备的记录头组织完全不一样,但是都是固定的,大多类似

0x806a050: "0102030420345y01J~21˥O355 370-21531206"
0x806a066: "03LENOVO"
0x806a06e: "28747GC"
0x806a076: "ThinkPad SL410"
0x806a085: "LRHVT48"

01说明它的值是记录备注的第一条字符串,02表示第二条,03表示第三条,04表示第四条,但是注意:

  1. 并不是每条记录的头部都是这么组织的,有可能01并不表示第一条字段,而是说明其他信息
  2. 每两条字段之间都有一个 00 隔开
  3. 重要的是,记录头里每个固定的位,都是有意义的,可能表示第几条记录,也有可能表示某种其他的意义。

如果想了解得透彻,可以读读dmidecode的代码。

Leave a Comment