Linux

dmidecodeコマンドの実装

概要

コードリーディングの勉強も兼ねて、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 等に纏まっていたことを後々確認しました(汗)