システム奮闘記:その86

memtest86+でメモリの検査



Tweet

(2010年8月25日に掲載)

はじめに

 パソコンが不安定になったり、立ち上がらなくなったりする事があります。
 色々なソフトを入れすぎてOSが不安定になっていたり、
ハードディスクの障害は思いつきやすいですが、メモリは忘れがちです。

 そこで今回はメモリ障害の実話を紹介する事にしました。

パソコンの異常発生!!  2010年のある日、同僚のWindowsXPのパソコンのメモリを交換した。  しばらくは問題なく動いていたのだが、ある日の事、同僚が  菅さん、画面の解像度が悪くなりました  と言ってきた。  再起動して動かす。  でも・・・  640×480の16色しか出へんやん (TT) もしかしてドライバが悪さをしているのではないかと思い モニターを交換してみた。  すると、うまくいったので、ドライバが原因だと思った。  だが、数日後・・・  菅さん、またおかしくなりました  だった。  原因がわからない。  とりあえず、この数日の間で何かOS関係で問題が発生したかもしれない。  そこでWindowsXPの機能の「システムの復元」を使う事にした。
WindowsXPのシステムの復元機能
システムの復元の開始画面
システムの復元する日の指定

 そのおかげで、しばらく何事もなかったかのように、システムが安定した。

 これで安心かと思っていたら同僚から

 菅さん、またおかしくなりました!

 と言ってきた。

 それ以来、定期的に、システムの復元を行なうようにしてみた。

 だが、別の所で問題が発生するようになった。

 いきなりソフトが落ちました

 エクセルが落ちたり、AS400のエミュレーターが落ちたりなど
Windowsパソコンが呪われたかの如く、OSが不安定になっていた。

 そして、ついにはWindows起動時に、以下の画面が出るようになった。

Windows起動時に出たエラー画面
Windows起動時に出たエラー画面

 エラーの内容は以下の通りだ。

エラーの内容
画面に表示されている内容
Check to make sure any new hardware or software is properly installed.
If this is a new installation, ask your hardware or software manufacturer
for any windows updates you might need .

Run the driver verifier against any new (or suspect) drivers.
If that doesn't reveal the corrupting driver, try enabling special pool.
Both of these features are intended to catch the corruption at an earlier
point where the offending driver can be identified.

If you need to use safe mode to remove or disable components,
restart your computer , press F8 to select advanced startup options,
and then select Safe Mode.

If this is the first time you've seen this stop error screen,
restart computer.If this screen appears again , follow
these step:

Check to make sure any new hardware or software is properly installed.
If this is a installation, ask your hardware or software manufacturer
for any windows updates you might need.

If problems continue, disable or remove any newly installed hardware
or software.Disables BIOS memory options such as caching or shadowing.
If you need to use Safe Mode to remove or disable components, restart
your computer, press F8 to select Advanced Startup options, and then
select Safe Mode.

Thchnical information:

*** STOP: 0x000000C5 (0x00540138,0x00000002,0x00000000,0x80536CDC)
何やらエラーの対処方法が書いている。
新しいソフトやハードウェアを追加したのなら、メーカに聞いてくれとか
Windowsアップデートや、ドライバの検査の必要が書いている。

セーフモードで立ち上げて、ドライバーを無効(取り除いて)がある。

 だが、冷静に英文なんて読める私ではない。
 こんな時Windowsが関係すると、瞬間湯沸かし気になって・・・

 おどれMS、ナメとんのか!

 となる (^^)

 だが、悪名高きWindowsVistaと違い、安定しているはずのWindowsXPで
ここまで不安定になるのから、Windowsではなく、何か別の所に
原因があるのではないかと思った。

 そこでハードディスクを調べてみたが、問題がない。


 ふと思った。

 もしかして、メモリちゃうか!

 メモリを交換してから、パソコンの動きがおかしくなったため
メモリに原因があるのではないかと思った。

 そこでメモリ検査のソフトのmemtest86+をダウンロードする事にした。
 memset86+のサイト

 オ−プンソースなので、メモリ関連の技術的な事に興味のある方は
ソースの解読が可能です (^^)


 早速、CDに焼いて動かしてみる。

 すると・・・

 エラーだらけやん (--;;

memtest86+でのメモリ検査結果
memtest86+でのメモリの検査結果
赤い部分がエラー表示。
エラーだらけなので、メモリに障害がある事がわかる。

 メモリ交換せねば!!

 早速、メモリ交換を行なう事にした。

パソコンのメモリ差し込み口
メモリの差し込み口
個々の部品ごとに取り外しが簡単なのだが
実際にはハードウェアの知識などになると奥が深い。
いまだにマザーボードの知識やチップの知識は
あまり大した事がない私 (^^;;

 エラーを吐きまくったメモリを取り出す。

問題があったメモリ
問題があったメモリ
台湾製のメモリだ。
台湾製のメモリは安い分、博打的な要素がある事を後で知った。

個人的には台湾は好きな国なのだが、博打的なメモリを売っていたら
少しガッカリする。

メモリの相性や価格について メモリは難しい?


 メモリを交換して以来、WindowsXPが不安定になったり、
ソフトが突然落ちたりする事がなくなった。

 これで平和になったと思った。


今度は私のパソコンが・・・  それから数ヶ月経った。  なんだか私のパソコンが不安定になってきた。
不安定のために発生したエラー
発生したエラー
この手のエラーは、メモリ上で領域違反が発生したため
OSの安全機能が働いて、ソフトが落ちたのだ。

メモリの領域違反の話については「システム奮闘記:その46」の
OSが固まる理由をご覧ください。

 そしてFireFoxが落ちるようになった。

Firefoxがエラーを吐いて落ちた様子
Firefoxが落ちた様子

 私のパソコンには色々なソフトが入っているため
コンポーネントの依存性の問題で不安定になっていると思った。

 そこでWindowsXPの入れ替えを考えた。


 でも、ここでふと思い出す。

 これもメモリが原因かもしれへん!

 そこでメモリチェックを行なう事にした。
 すると・・・

 エラー出まくりやん (--;;

 そこでメモリを買い替えて入れ直す事にした。

 買い替えたメモリだと異常なしだった。

新しいメモリでmemtest86+で検査した結果
検査結果の画面
memtest86+の検査の結果、正常だった
拡大画面
memtest86+の検査の結果、異常が0だった場合
2回、検査したが、異常なしの結果だった (^^)

 それ以来、Windowsが安定して動くようになったので
やはりメモリが悪さをしていたのだった。


memtest86+で仮想化OSのメモリチェック実験

 メモリの異常。  ふと思った。メモリ異常がある場合・・・  仮想化OS上でもメモリ異常が発生するのか?  仮想化を導入しているため、気になる所。
不安定のために発生したエラー
発生したエラー
もし、物理メモリに異常があれば、仮想OS上にある仮想メモリにも
異常が発生しても不思議ではない。

 そこで以下の実験を行なう事にした。

仮想メモリに異常が検知できるかの実験
仮想メモリに異常が検知できるかどうかの実験内容
仮想OSを起動時に、memtest86+を使って仮想メモリに
異常が検知できるかどうかを実験してみる事にした。

 まずは、仮想化ソフトのVMwareServerを起動させる。

VMware Serverを起動
VMwareServerを起動させる

 そして仮想OSを立ち上げる。
 この際、memtest86+のCDをいれて、CDから起動(ブート)できるようにしておく。

 その結果・・・

 メモリの異常が検知できた!!

仮想メモリ異常を検知した様子
仮想メモリの異常を検知した様子
エラー吐きまくりの結果が出てきた。
仮想メモリでの異常が検知されたという事は
物理メモリに異常があれば、その影響を受ける事というのだ。

 ちなみに、物理メモリに異常がない場合は
仮想メモリでは異常は検知されない。

物理メモリが正常な場合
物理メモリが正常の場合、仮想メモリも正常な結果が出る
物理メモリが正常のため、仮想メモリも異常なしの結果が出てくる。

 もし、仮想化サーバーで、サーバーを止めずにメモリ検査を行なう場合
仮想OSを作って、仮想OS上でメモリ検査を行なえば、間接的だが
サーバーのメモリ検査ができる事がわかった。

 ただ、ここで行なったのは、VMwareServerであって
VMwareESXi(VMware vSphere)や、Xenなどでは試していませんので。


実は恐いメモリ異常

 メモリの異常。  システムの不安定をもたらすだけに厄介だ。  でも、それだけでは済まない事がわかった。  データがオシャカになる危険がある  折角作ったワード、エクセル、OpenOfficeなどの書類ファイルが 開けなくなる問題なのだ。  どういう事なのか。  少しメモリに関して復習してみます。  物理メモリと論理メモリについてです。
物理メモリと論理メモリ
物理メモリと論理メモリについて
物理メモリは実際のメモリの事だ。
論理メモリとは、個々のプロセスがメモリを使用する際に
使用するメモリ領域の事を指す。

論理メモリを使う事によって、プロセスは自由にメモリの
アドレスを自由に指定できるのだ。

 わざわざ論理メモリを設ける理由は以下の通りです。

論理メモリがある理由
論理メモリがある理由
プロセスが1つしか動かさない場合なら、物理メモリアドレスを
そのまま使って、自由にアドレス指定やメモリ操作を
行なえるのだが、OSを始め、複数のプロセスが稼働している場合
他のプロセスとの関係で、自由にメモリのアドレス指定ができなくなる。

そこで物理メモリと論理メモリのアドレス変換機能を使って
あたかも個々のプロセスが自由にメモリのアドレス指定する事で
プロセスのプログラム作成時にメモリ部分の処理が簡単になる。

アドレス変換の話などは、x86CPUの場合、CPUのMMU機構などが
出てきます。でも、ここでは割愛します。

 ところで物理メモリ(メモリ本体)に異常があると
プロセス側から見えるメモリにも異常が見える。

論理メモリへの影響
論理メモリへの影響
物理メモリの異常があると、異常領域に該当する論理メモリに
影響が出てくる。

 論理メモリの部分。
 x86CPUの場合、論理メモリは、以下のような使い方をしている。

x86CPUでの論理メモリの使い方
x86CPUでの論理メモリの使い方
プロセスの実行ファイルを格納するコード領域。
各種データを格納するヒープ領域とスタック領域がある。

 もし、メモリ本体に障害があり、その影響が論理メモリに
及んでいたら、次のようになる。

メモリ障害の影響
メモリ障害の影響
メモリ本体の障害が、あるプロセスの論理メモリ領域に該当する場合
プロセス稼働に重要なコード領域、ヒープ領域などで
データに異常値が発生し、それが原因でプロセスが不安定になる。

 ところで、メモリ障害が起こっている状態で、ワード、エクセル、
OpenOfficeなどを使っていると、プロセスの不安定以外に
別の厄介な問題も発生する。

プロセスの不安定以外に生じる問題
プロセスの不安定以外に生じる問題
ワード、エクセルなどの文章を作成している際
メモリのヒープ領域に作成された文章が記録される。
ファイル保存をして初めてハードディスクに保管される。

ヒープ領域で障害が起こっている場合、折角、作成した
文書ファイルに異常が発生し、内容が破壊されたり
ファイルが破壊されたりする危険性がある。

 他にも恐ろしい事がある。
 OSが使用しているメモリ領域で異常が起こっている場合だ。

OSが使用しているメモリ領域で
異常が発生している場合
OSが使用しているメモリ領域で異常が起こっている場合
OSが使用しているメモリ領域で異常が発生すると
OSが不安定になったりする。

OSが誤作動を起こして悪さをする危険性もある。
ファイル管理システムに悪影響を及ぼしたら
ファイルシステムの破壊によるデータの消失も考えられる。

 そう考えると、メモリの障害は

 恐ろしい結果を招きかねないのだ!

 サーバー用途の場合、データの重要性が高くなるだけに
ECC付メモリが推奨されているのも、納得ができる。


ちょっとだけソースを見てみる  memtest86+はオ−プンソースなのだ。  そこで、ちょっとソースを見てみる事にした。  ちなみに、ガンガン、ソースを読むだけの力量はないので ソースの内容は解説できませーん (^^)
(注意)
ここで出ていますmemtest86+のバージョンは4.0です。

 早速、ダウンロードして圧縮されたファイルを展開する。

lsコマンドでファイルを見てみる
[suga@linux memtest86+-4.00]$ ls
FAQ                   dmi.h               makeiso.sh          reloc.c
Makefile              elf.h               memsize.c           screen_buffer.c
README                error.c             memtest.bin.lds     screen_buffer.h
README.build-process  extra.c             memtest.exe         serial.h
bootsect.S            extra.h             memtest.lds         setup.S
changelog             head.S              memtest_shared.lds  smp.c
config.c              init.c              msr.h               smp.h
config.h              io.h                mt86+_loader        spd.c
controller.c          jedec_id.h          mt86+_loader.asm    spd.h
controller.h          lib.c               patn.c              stdint.h
cpuid.c               linuxbios.c         pci.c               test.c
cpuid.h               linuxbios_tables.h  pci.h               test.h
defs.h                main.c              precomp.bin
dmi.c                 makedos.sh          random.c
[suga@linux memtest86+-4.00]$ 

 上の赤い部分の「elf」の文字を見た。
 確か、実行ファイル形式の種類なのだ。

 Executable and Linking Format

 の略なのだ。よくわからん・・・ (--;;

 Linuxディストリビューションの多くに採用されている
標準バイナリ形式の種類なのだ。

 elf形式ファイルの情報を見るのにreadelfコマンドがある事を知る。

readelfコマンドのオプション
-h ヘッダーだけ表示
-a 全ての情報を表示

 適当な実行ファイルのELF情報を見てみる事にした。

実行ファイル「ls」のELF情報(ヘッダーのみ)
[suga@linux]$ readelf -h /bin/ls
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8049a30
  Start of program headers:          52 (bytes into file)
  Start of section headers:          92320 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         8
  Size of section headers:           40 (bytes)
  Number of section headers:         31
  Section header string table index: 30
[suga@linux]$ 
何やらELFファイルの情報のようだ。
相当な知識がないと意味が理解できそうにない。

 見てもわからへん (TT)

 でも、事務員の私なので、わからなくても良いのだ (^^)
 図太く開きなおった所で、次に進む。

 elf.hの中身をのぞいてみる。

elf.hの中身(一部抜粋)

(途中、省略)

/*
* Program header.
*/
typedef struct {
        Elf32_Word      p_type;         /* Entry type. */
        Elf32_Off       p_offset;       /* File offset of contents. */
        Elf32_Addr      p_vaddr;        /* Virtual address (not used). */
        Elf32_Addr      p_paddr;        /* Physical address. */
        Elf32_Size      p_filesz;       /* Size of contents in file. */
        Elf32_Size      p_memsz;        /* Size of contents in memory. */
        Elf32_Word      p_flags;        /* Access permission flags. */
        Elf32_Size      p_align;        /* Alignment in memory and file. */
} Elf32_Phdr;

(途中、省略)
プログラムヘッダーの構造体の定義だ。
物理アドレスなどの記述などを見ると、プログラムに関する
基本情報が格納されるようだ。

今は、ELF形式の知識はないが、興味はそそられる。
ELFに関するウンチクが話せたら、格好良いかも (^^)

 ELF形式について、少し調べると、共有ライブラリの利用が
可能になったりするという。(参考URL:日本語です)
 Executable and Linkable Format
 ELF format

 この分野に詳しくなれば面白そうだ (^^)

 しかし、現時点では踏み込んでいけるだけの知識がないため
何年先になるか、わかりませんが、いずれ取り上げたいと思います。



lib.cについて  さて、lsコマンドを使ってみる。
lsコマンドでファイルを見てみる
[suga@linux memtest86+-4.00]$ ls
FAQ                   dmi.h               makeiso.sh          reloc.c
Makefile              elf.h               memsize.c           screen_buffer.c
README                error.c             memtest.bin.lds     screen_buffer.h
README.build-process  extra.c             memtest.exe         serial.h
bootsect.S            extra.h             memtest.lds         setup.S
changelog             head.S              memtest_shared.lds  smp.c
config.c              init.c              msr.h               smp.h
config.h              io.h                mt86+_loader        spd.c
controller.c          jedec_id.h          mt86+_loader.asm    spd.h
controller.h          lib.c               patn.c              stdint.h
cpuid.c               linuxbios.c         pci.c               test.c
cpuid.h               linuxbios_tables.h  pci.h               test.h
defs.h                main.c              precomp.bin
dmi.c                 makedos.sh          random.c
[suga@linux memtest86+-4.00]$ 
lib.cファイルに注目する。

 「lib.c」という名前なので、ライブラリ用のソースだと思う。
 そこで、ソースを見てみる事にした。

lib.cの中身(一部抜粋)

(途中、省略)

void memcpy (void *dst, void *src, int len)
{
        char *s = (char*)src;
        char *d = (char*)dst;
        int i;

        if (len <= 0) {
                return;
        }
        for (i = 0 ; i < len; i++) {
                *d++ = *s++;
        } 
}

int strncmp(const char *s1, const char *s2, ulong n) {
        signed char res = 0;
        while (n) {
                res = *s1 - *s2;
                if (res != 0)
                        return res;
                if (*s1 == '\0')
                        return 0;
                ++s1, ++s2;
                --n;
        }
        return res;
}


(途中、省略)


/*
 * Print characters on screen
 */
void cprint(int y, int x, const char *text)
{
        register int i;
        char *dptr;

        dptr = (char *)(SCREEN_ADR + (160*y) + (2*x));
        for (i=0; text[i]; i++) {
                *dptr = text[i];
                dptr += 2;
        }
        tty_print_line(y, x, text);
}



(途中、省略)

lib.cファイルの内容を見ると、各種関数の定義が多い上
C言語の標準ライブラリの関数に似ている物ばかりなので
glibcのソースみたいに思えたりする。

 ここで見えてきたのは、memtest86+の場合
glibcのライブラリを使っていないように思える。

 memtest86+の場合、Linux上で動くのではなく
パソコンを起動させてから、独自で動くソフトのため
共有ライブラリを使わない。

 だからといって、glibcを静的ライブラリで取り込むと

 強烈にファイルが大きくなる!

 という問題が起こる。

 そのため独自で関数を定義しているのだろうと思われる。

 静的ライブラリを取り込むとファイルが大きくなる話については
詳しくは「システム奮闘記:その53」(ライブラリって何)を
ご覧ください。



controller.cについて  別のソースを見てみる事にする。
lsコマンドでファイルを見てみる
[suga@linux memtest86+-4.00]$ ls
FAQ                   dmi.h               makeiso.sh          reloc.c
Makefile              elf.h               memsize.c           screen_buffer.c
README                error.c             memtest.bin.lds     screen_buffer.h
README.build-process  extra.c             memtest.exe         serial.h
bootsect.S            extra.h             memtest.lds         setup.S
changelog             head.S              memtest_shared.lds  smp.c
config.c              init.c              msr.h               smp.h
config.h              io.h                mt86+_loader        spd.c
controller.c          jedec_id.h          mt86+_loader.asm    spd.h
controller.h          lib.c               patn.c              stdint.h
cpuid.c               linuxbios.c         pci.c               test.c
cpuid.h               linuxbios_tables.h  pci.h               test.h
defs.h                main.c              precomp.bin
dmi.c                 makedos.sh          random.c
[suga@linux memtest86+-4.00]$ 
controller.cファイルに注目する。
なにやらコントロールバスに関する関数のようだ。

 controller.cファイルを眺めてみる。

controller.cの中身(一部抜粋)

static void setup_i850(void)
{
        static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED };
        unsigned long mchcfg;

        /* Fill in the correct memory capabilites */
        pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x50, 2, &mchcfg);
        ctrl.cap = ECC_CORRECT;
        ctrl.mode = ddim[(mchcfg >> 7)&3];
}


「i850」を見て、マザーボードに関する事かなぁと思ったら
チップセットの事だった。

一時期、チップセットの本を読んで、マザボードの話を勉強しただけに
サウスブリッジ、ノースブリッジなど懐かしい用語が出てくる。

思い出すために以下のサイトで勉強した。
チップセット ぐうたら感謝の日

 ソースコードを眺めても

 ハードウェアの知識がないと理解できへん (TT)

 ハードウェアの知識のなさを痛感してしまった。


mt86+_loader.asmを見る  別のソースを見てみる事にする。
lsコマンドでファイルを見てみる
[suga@linux memtest86+-4.00]$ ls
FAQ                   dmi.h               makeiso.sh          reloc.c
Makefile              elf.h               memsize.c           screen_buffer.c
README                error.c             memtest.bin.lds     screen_buffer.h
README.build-process  extra.c             memtest.exe         serial.h
bootsect.S            extra.h             memtest.lds         setup.S
changelog             head.S              memtest_shared.lds  smp.c
config.c              init.c              msr.h               smp.h
config.h              io.h                mt86+_loader        spd.c
controller.c          jedec_id.h          mt86+_loader.asm    spd.h
controller.h          lib.c               patn.c              stdint.h
cpuid.c               linuxbios.c         pci.c               test.c
cpuid.h               linuxbios_tables.h  pci.h               test.h
defs.h                main.c              precomp.bin
dmi.c                 makedos.sh          random.c
[suga@linux memtest86+-4.00]$ 
mt86+_loader.asmファイルに注目する。
拡張子を見るとアセンブラだとわかる。
ハードウェアに直結した部分を記述している感じがする。

ファイル名を見ると「loader」になっているので、memtest86+を
メモリ上に読み込むプログラムなのではないかと推測する。

 Linuxのブートローダーの役目と同じ感じがする。
 でも、アセンブラなので

 全然、わからへん (TT)

 なのだ。


 でも、わかる所だけでも解読しようと、悪あがきをする私。
 最初のコメント文を見る事にした。

mt86+_loader.asmの先頭部分の抜粋
; A loader for www.memtest.org images, by Eric Auer 2003.
; This assumes that the image starts with the boot sector,
; which has the size of setup.S in sectors in a byte at offset
; 1f1h (497). Further, I assume setup.S directly after the boot
; sector and the actual memtest head.S after setup.S ...

; This version is derived from memtestL loader, which loads
; memtest.bin from a separate file. This version is meant to
; be used like (DOS / Unix variants):
; copy /b memteste.bin + memtest.bin memtest.exe
; cat memteste.bin memtest.bin > memtest.exe
; The good thing is that you get a single file which can be
; compressed, for example with http://upx.sf.net/ (UPX).

以下、省略

 でも・・・

 イマイチ、よくわからへん (TT)

 なのだ。

 おぼろげながら、ブートセクターを読み込むためのプログラムの
感じがするのだが、自信を持って「そうです!」とは言い切れない。

 自信を持って言い切れるまで、まだまだ先の話なのだ (^^;;


SMBIOSとDMIとは  ソース一覧を眺めてみる。
lsコマンドでファイルを見てみる
[suga@linux memtest86+-4.00]$ ls
FAQ                   dmi.h               makeiso.sh          reloc.c
Makefile              elf.h               memsize.c           screen_buffer.c
README                error.c             memtest.bin.lds     screen_buffer.h
README.build-process  extra.c             memtest.exe         serial.h
bootsect.S            extra.h             memtest.lds         setup.S
changelog             head.S              memtest_shared.lds  smp.c
config.c              init.c              msr.h               smp.h
config.h              io.h                mt86+_loader        spd.c
controller.c          jedec_id.h          mt86+_loader.asm    spd.h
controller.h          lib.c               patn.c              stdint.h
cpuid.c               linuxbios.c         pci.c               test.c
cpuid.h               linuxbios_tables.h  pci.h               test.h
defs.h                main.c              precomp.bin
dmi.c                 makedos.sh          random.c
[suga@linux memtest86+-4.00]$ 
何気なくdmi.cファイルに注目する。

 何気なくdmi.cファイルに注目する。
 そしてファイルの中身を見てみる。
dmi.cファイルを見てみる(一部抜粋)
/* dmi.c  using the DMI from SMBIOS to read information about the hardware's
 * memory devices capabilities and where they are mapped into the address space
 *
 * Copyright (c) Joachim Deguara, AMD 2006
 *
 * Release under the GPL version 2
 * ----------------------------------------------------
 * Memtest86+ V4.00 - Added compliance with SMBIOS Spec V2.6.1
 */

(以下、省略)
最初のコメント分の青い部分「SMBIOS」に目がいった。

 SMBIOSとは、SMがつくだけに・・・

 女王様とお呼びよ!

 と叫ぶ音声機能付BIOSなのだ。
 どうも「SM」なので、変な方向に考えてしまう (--;;


 さて、本当の意味を調べてみると、以下の通りだった。

 System Management BIOS

 なのだ。
 しかし横文字だけど・・・

 だから何やねん!

 なのだ。

 そこで調べてみた。
 すると以下の事だった。

SMBIOSとは何か?
BIOS内のデータ構造(及び、そのアクセス方法)の配置に関する仕様
SMBIOSがある事による利点
SMBIOSがある事で、PC固有の情報をユーザーやアプリが格納したり
使用したりする事ができる。

 要するに

 パソコン固有の情報を格納するデータ構造の仕様

 なのだ。

 SMBIOSという業界の統一仕様(?)があるから、システム管理ソフトが
BIOSから、そのパソコンのハードウェアの情報を引き出す事が容易にできる。


 dmi.cのソースの最初の部分を見て次の事も思った。

dmi.cファイルを見てみる(一部抜粋)
/* dmi.c  using the DMI from SMBIOS to read information about the hardware's
 * memory devices capabilities and where they are mapped into the address space
 *
 * Copyright (c) Joachim Deguara, AMD 2006
 *
 * Release under the GPL version 2
 * ----------------------------------------------------
 * Memtest86+ V4.00 - Added compliance with SMBIOS Spec V2.6.1
 */

(以下、省略)
赤い部分の「DMI」に目がいった。

 DMIって何やろ?

 調べてみると以下の略語だった

 Desktop Management Interface
 
 日本語にすると「デスクトップ管理インターフェイス」なのだ。
 でも、日本語にしても

 何かわからへんやん・・・ (--;;

 そこでDMIがどういう物か見てみる事にした。

 調べていくと、わかってきた。
 DMTF (Distributed Management Task Force) が策定している
コンピュータ管理を行うためのインターフェースだという。

 OSに依存しない、MIF形式のデータベースを使っているなど
業界の統一規格でのインターフェイスだという。

 (参考URL)
 http://mcn.oops.jp/dev/pcat/dmi.htm
 @ITのDMIの説明

 でも、SMBIOSにしてもDMIにしても、イマイチ、よくわからない。
 つまり、私自身、全然、わかっていない証拠だ。

 ハードウェアの知識の必要性を感じてしまった (--

init.c  ファイル名から初期化のためのプログラムだと推測できる。  ソースを眺めてみる。
init.cの中身(一部抜粋)

(途中、省略)

/*
 * Initialize test, setup screen and find out how much memory there is.
 */
void init(void)
{
        int i;

        outb(0x8, 0x3f2);  /* Kill Floppy Motor */

        /* Turn on cache */
        set_cache(1);


(以下、省略)
青い部分に目がいった。
フロッピーのモーターを切るという部分だ。

 ところで「outb()」命令は、どこで定義されているのかを
調べてみると、ヘッダーファイル「io.h」で定義されていた。

io.hの中身(一部抜粋)

#define outb(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
        __outbc((val),(port)) : \
        __outb((val),(port)))


__outb()や__outbc()が出てきた。
これはどこで定義されているのか調べてみたが
見つからなかった

 outb()の意味合いがわからない。
 アセンブラが読めない私。そこで調べてみる事した。

 すると似たような命令(?)で、アセンブラのOUT命令があった。
 出力装置に指示を送るための命令だという。

 アセンブラのout命令のついて参考URL
 http://www5c.biglobe.ne.jp/~ecb/assembler/8_3.html

アセンブラのout()命令の意味
英語で「out」には色々な意味があるが、それぞれの言葉の共通点として
「外側」の意味がある。この場合は「出力」(外に出す)だ。

何かを出力する、そのために出力装置に命令を送る。
そこから由来して「out()」になっていると思われる。

 ただ、memtest86+のソースで出てきている「outb()」は
どういう仕様で使っているのか、詳しい部分まで踏み込めるだけの
知識がないので残念だ (--;;


 私の目に入ったソースの部分を、もう一度見てみる。

init.cの中身(一部抜粋)

(途中、省略)

/*
 * Initialize test, setup screen and find out how much memory there is.
 */
void init(void)
{
        int i;

        outb(0x8, 0x3f2);  /* Kill Floppy Motor */

        /* Turn on cache */
        set_cache(1);


(以下、省略)
青い部分のoutb()命令だ。
outb()で代入している第1引数の値は「0x8」だ。
といっても、意味合いがよくわからない。

第2引数の値は「0x3f2」で、フロッピーディスクのI/Oポートの
番号になっている。



 どうやらプログラムが起動した際の初期設定の際に
フロッピーの機能停止をさせるための処理だというのは、わかった。


 ソースの他の部分を見ていく。
 メモリの初期化に関する部分がある。

 思わず・・・

 「はじめて読む486」の世界やん!!

 と思った。

init.cの一部抜粋

int map_page(unsigned long page)
{
        unsigned long i;
        struct pde {
                unsigned long addr_lo;
                unsigned long addr_hi;
        };
        extern unsigned char pdp[];
        extern struct pde pd2[];
        unsigned long window = page >> 19;
        if (FLAT || (window == mapped_window)) {
                return 0;
        }
        if (window == 0) {
                return 0;
        }
        if (!v->pae || (window >= 32)) {
                /* Fail either we don't have pae support
                 * or we want an address that is out of bounds
                 * even for pae.
                 */
                return -1;
        }
        /* Compute the page table entries... */
        for(i = 0; i < 1024; i++) {
                /*-----------------10/30/2004 12:37PM---------------
                 * 0xE3 --
                 * Bit 0 = Present bit.      1 = PDE is present
                 * Bit 1 = Read/Write.       1 = memory is writable
                 * Bit 2 = Supervisor/User.  0 = Supervisor only (CPL 0-2)
                 * Bit 3 = Writethrough.     0 = writeback cache policy
                 * Bit 4 = Cache Disable.    0 = page level cache enabled
                 * Bit 5 = Accessed.         1 = memory has been accessed.
                 * Bit 6 = Dirty.            1 = memory has been written to.
                 * Bit 7 = Page Size.        1 = page size is 2 MBytes
                 * --------------------------------------------------*/
                pd2[i].addr_lo = ((window & 1) << 31) + ((i & 0x3ff) << 21) + 0xE3;
                pd2[i].addr_hi = (window >> 1);
        }
        paging_off();
        if (window > 1) {
                paging_on(pdp);
        }
        mapped_window = window;
        return 0;
}


仮想アドレスから物理アドレスへの変換方法の1つにページング方式がある。
ページング方式で、メモリ管理を行なう際、青い部分で示している
ページテーブルエントリ(PTE:Page Table Entry)が重要になる。

for文で1024回のループがある。PTEは1024個ある事がわかる。

 久々に「はじめて読む486」(蒲地輝尚:アスキー出版局)の
本を取り出し、PTEの部分を見てみる。

PTEの構造
PTEの構造
PTE(Page Table Entry)の構造だ。
32ビット(4バイト)の大きさで、x86系CPUの場合の
ページング方式でのメモリ管理を行なう上で重要な働きをする。

ちなみにページ(Page)とはメモリを4バイトに区切った単位の事です。

 でも、PTEだけ見ても、ページング方式の仕組みを
知らない人にとってはピンとこない。

 PTEに入る前に、仮想アドレス(プロセスが見ているメモリアドレス)から
物理アドレス(実際のメモリのアドレス)への変換の仕組みを見た方が
わかりやすい。

ページング方式でのメモリ変換の仕組み
(仮想アドレスから物理アドレスへの変換)
仮想アドレス(プロセスから見えるメモリアドレス)は、32ビットCPUの場合
4Gのメモリ空間を扱う事ができる。

仮想アドレスは上のように、10ビット、10ビット、12ビットで区切られている。
CPUのCR3レジスタには、Page Directory Tableの先頭アドレスを
格納している。

(1)CR3レジスタでPage Directory Tableに先頭アドレスが格納されている。

(2) (1)の値に、仮想アドレスの上位10ビットの値×PTEの大きさを加えると
  該当のPTEの物理アドレスの先頭の値が出てくる。

(3) PTEに格納されているアドレスにはPage Tableの先頭の物理アドレスが
  格納されている。

(4) (3)の値に、仮想アドレスの上位11〜20の値×PTEの大きさを加えると
  物理メモリ上の該当のデータが入ったページの先頭のアドレスが出てくる。

(5) (4)の値に、仮想アドレスのOffset部分を加えると、物理アドレスが
   算出される。

 PTEにはアドレス変換の役目がある事がわかった。
 でも、それだけではないので、もう一度、PTEの構造を見てみる。

PTEの構造について
PTEの構造
bit0
Present bit.

「1」の場合、仮想アドレスに対応する物理アドレスが存在するので
アドレス変換が行なわれる。「0」の場合は、物理メモリ上には
存在しないので、Pege Fault(ページフォールト)が発生する。
ページフォールトとは、ページ(メモリの単位)の閲覧の失敗だ。

ところで、メモリ上のデータがハードディスクに退避(スワップ)している場合
物理メモリ上には存在しないため、この部分は「0」になる。
そのためページフォールトが発生して、ハードディスクへ
見にいく仕組みにしている。
bit1
Read/Write.
ここが「0」の場合、CPUの特権レベル3の命令は
この領域には書き込みができなくなる。特権レベル0のみ書き込み可能。
bit2
Supervisor/User.
ここが「0」の場合、CPUの特権レベル3の命令は
アクセスできない。特権レベル0の場合のみになる。
bit5
Accessビット
アクセスがあると「1」になる。
アクセスがないと「0」で、長時間「0」の場合、メモリの節約のため
退避(スワップ)の対象になるようだ。
bit6
Dirtyビット

書き込みがあると「1」になる。
「Dirty bit」を直訳すると「汚れビット」なのだ。
でも、名前の付け方が、イマイチ良くない。

 メモリ不足の際の退避(スワップ)や、CPUの特権レベル「0」で
動いているプロセスが使うメモリの保護など、メモリ管理に
重要な役割を果たしている事がわかる。

メモリとバッファオーバーフロー攻撃について
PTEにアクセスや書き込みの許可のビットがあるが
実行の許可のビットがない。そのためバッファオーバーフロー攻撃で
メモリ上に送り込まれた不正な実行データを、無効化する事が
メモリのPTEでは不可能だ。

AMD64ビットCPUでは、メモリ管理において、C実行の許可・不許可の
NXビットを設けている。

(ITPro)
CPUが用意してOSが使う 不正コードの実行を禁止する「NX」ビット

 以前、バッファオーバーフロー攻撃を調べた時、AMDの64ビットCPUから
CPUで防止機能がついたという記憶があった。

 その時は、64ビットCPUからでないと、NXビットは働かないのかと思った。
 でも、今回、調べてみたら、AMD64ビットでNXビットのCPUが出た後、
インテルではx86CPUでもNXビットを設けたりした。

 知らへんかった (^^;;

 ちなみにインテルではXDビットと呼んでいる。

 NXビットを使った物が、実は身近にあった。
 WindowsXP SP2からは、NXビットを使って不正実行を防ぐ機能がある。

Windows XP SP2から可能になった
データ実行防止(DEP)機能
WindowsXP SP2からあるデータ実行防止機能(DEP)
この機能は、CPUのNXビット(XDビット)を使った機能で
バッファオーバーフロー攻撃によって不正に送り込まれた
実行ファイルを無効化する役目がある。

 自分が使っているパソコンのCPUに、NXビット機能があるかどうかの
確認だが、Linuxでは次の方法がある。

/proc/cpuinfoファイルの中身
[suga@linux]$ more /proc/cpuinfo 
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 15
model name      : Intel(R) Core(TM)2 Duo CPU     E4600  @ 2.40GHz
stepping        : 8
cpu MHz         : 2393.480
cache size      : 2048 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 10
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca 
                  cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss 
                  nx constant_tsc up pni ds_cpl
bogomips        : 4738.69

[suga@linux]$ 
/procディレクトリは、メモリ上にあるカーネルの情報を
人間の見える形(ファイル形式)にしているのだ。

cpuinfoは、文字通りCPUの情報が入っている。
赤い色の部分がNXビット機能が付いている事を意味している。

 知らない事がどんどん出てくる。

 色々、ボロが出てくるやん (^^;;

 なのだ。
 でも、知らないのを放置するより、遥かに良いので
どんどんボロを出していこうと思う今日この頃 (^^)V


 ところでLinuxの場合、ページング方式を採用しているのだが
3段階ページングだ。上で書いたページングは2段階なので
ページングの仕組みが違ってくる。

 Linuxの3段階ページングの利点は、4G以上のメモリ空間が扱える事だ。

 64ビットLinuxでは、3段階ページング方式を使う事で、
4G以上のメモリ空間を認識できる。

 そして、32ビットLinuxだったとしてもCPUのPAE機構
(Physical Address Extension:物理アドレス拡張)があると
PAEの助けと、3段階ページングが働いて、4G以上のメモリ空間が扱えるのだ。

 ちなみに、CPUにPAE機構の有無を確かめるには
NXビットと同様の事をすれば良いのだ。

/proc/cpuinfoファイルの中身
[suga@linux]$ more /proc/cpuinfo 
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 15
model name      : Intel(R) Core(TM)2 Duo CPU     E4600  @ 2.40GHz
stepping        : 8
cpu MHz         : 2393.480
cache size      : 2048 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 10
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca 
                  cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss nx 
                  constant_tsc up pni ds_cpl
bogomips        : 4738.69

[suga@linux]$ 
/procディレクトリは、メモリ上にあるカーネルの情報を
人間の見える形(ファイル形式)にしているのだ。

cpuinfoは、文字通りCPUの情報が入っている。
赤い色の部分がPAE機能が付いている事を意味している。


 ページング方式だが、他にも興味深い内容があるのだが
今回は、踏み込んで調べるには割愛します。
 だって・・・

 調べるのが大変だもーん (^^;;

 なので、サイトだけ紹介します。
 メモリー上のデータを見えなくする(ITpro)



 memtest86+のソースでメモリ管理のページングの部分があった。
 でも、ページング方式の処理があるのか、イマイチよくわからない。

 memtest86+だと、単一プロセスで稼働していると思われるので
複数のプロセスのメモリ管理を行なう必要がないのではないか?

 もしかしたら、ページング方式が正しく稼働するかどうかの
検査を行なっているのかもしれない。

 ソースコードをガンガン読める実力があれば、わかるのだが
そこまで実力はないし、メモリ関連の知識も、ほんの触り程度しか
知らないので、踏み込んで調べる事ができない。
 いずれは謎解きを行ないたいと思います。


bootsect.S  ファイル名から、memtest86+を起動する際の ブートプログラムだというのは推測できる。  ソースを眺めてみる事にしたが、アセンブラの知識がないので  見てもわからへん (--;;  なのだ。  でも、最後の部分に反応した。
bootsect.Sの中身(一部抜粋)
(途中、省略)

syssize:
        .word _syssize
.org 508
root_dev:
        .word ROOT_DEV
boot_flag:
        .word 0xAA55
_eboot:
「0xAA55」に反応した。
どこかで見た値だと思ったら、マスターブートレコードで
ブートシグネチャーという所に格納される値で
この値でないと、マスターブートレコードが無効になり
起動しなくなるのだ。

「システム奮闘記:その71」をご覧ください。
(ブートローダー、GRUBの仕組み)

 ブートシグネチャの値「0xAA55」のお蔭で、ブートプログラム
だというのがわかった。


 ところでアセンブラの書式がわからない。

bootsect.Sの中身(一部抜粋)
(途中、省略)

syssize:
        .word _syssize
.org 508
root_dev:
        .word ROOT_DEV
boot_flag:
        .word 0xAA55
_eboot:
アセンブラの学習経験がないため
赤い部分の意味合いがわからない。

 アセンブラを調べてみるとC言語との対比を発見した。

C言語との対比
C言語
short boot_flag 0xAA55 ;
アセンブラ
boot_flag:
        .word 0xAA55

 C言語と対比させると、わかりやすい。

 「.word」だが、2バイト整数の意味だ。


 アセンブラ。
 勉強する余裕がないだけに、覚える機会がないのだが
アセンブラとハードウェアの知識を持てば、色々な事がわかって
面白いと思ったりする。


最後に  memtest86+を使ったメモリ検査の話を取り上げました。  今までメモリ障害の経験がなかっただけに、メモリの事は 全然、考えずにいましたが、2回も障害発生を体験して 大事なサーバーにはECC付が必要な事などを知りましたし、 OSが不安定になったら、メモリの検査も必要だというのも知りました。  最後にソース読みに挑戦したが、見事に挫折しました (^^;;  ソースで理解できた部分が、あまりにも少ないため 今回は、つまみ食い的な紹介にとどめました。  今の状態をパズルの例えると、像のパズルの一部分だけ埋めた後、 完成すればサイやカバになるとか、恐竜になるかの想像になりそうなので、 わからないまま、一旦、置いていく事にしました。

次章「scalixの導入とインストール」を読む
前章「BPMN:ビジネスプロセスモデリング表記入門」を読む
目次:Linux、オープンソースで「システム奮闘記」に戻る
トップ:オ−プンソース(OSS)で中小企業のIT化

Tweet