Edited at

dmidecodeコマンドの実装

More than 1 year has passed since last update.


概要

コードリーディングの勉強も兼ねて、dmidecodeコマンドの実装をかなりざっくりと概要だけ追った時のメモです。使用した環境の構築メモは下記に記載しています。

誤りや過不足があればご指摘いただければ幸いです。


環境


  • CentOS 6.9

  • dmidecode-2.12


dmidecodeコマンド

DMI(いわゆるSMBIOS)テーブルからハードウェア情報をダンプするコマンドです。サーバ情報や物理CPU数などを確認する際に使用することが多いです。詳細はdmidecode(8)のmanページをご参照ください。


dmidecodeコマンドの実装をざっくりと



  • mmap(2)/dev/memをメモリマッピングしていました。これは、dmidecodeコマンドで使用するハードウェア情報はSMBIOSに格納されているのですが、Linuxでは/dev/memからSMBIOSを読み取れるためだそうです。


util.c

 127         mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset);



  • なので、/dev/memが存在しないDockerコンテナなどでdmidecodeコマンドを実行すると下記のようにエラーとなります。

# dmidecode 2.12

/dev/mem: No such file or directory



  • /dev/memのオフセットが0xF0000から0xFFFFFまでを順に読んでいき、_SM_という文字列が現れたら、そこを起点として読み取った内容をダンプする実装でした。なお、_DMI_という文字列が現れたら、SMBIOSとは異なるレガシーな方法でダンプします。


dmidecode.c

4672         if ((buf = mem_chunk(0xF0000, 0x10000, opt.devmem)) == NULL)

4673 {
4674 ret = 1;
4675 goto exit_free;
4676 }
4677
4678 for (fp = 0; fp <= 0xFFF0; fp += 16)
4679 {
4680 if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0)
4681 {
4682 if (smbios_decode(buf+fp, opt.devmem))
4683 {
4684 found++;
4685 fp += 16;
4686 }
4687 }
4688 else if (memcmp(buf + fp, "_DMI_", 5) == 0)
4689 {
4690 if (legacy_decode(buf + fp, opt.devmem))
4691 found++;
4692 }
4693 }


  • VirtualBoxの仮想環境で/dev/memをhexdumpコマンドで16進ダンプして見たところ、特定のオフセット間に確かに_SM_が存在することが見て取れます。


hexdump

# hexdump -C /dev/mem | grep _SM_

000fff60 5f 53 4d 5f 7d 1f 02 05 ff 00 00 00 00 00 00 00 |_SM_}...........|


  • 上記実装について、System Management BIOS 等に纏まっていたことを後々確認しました(汗)