arch/i386/stand/libsa/memprobe.c

checkA20関数

絶対アドレスの000000h番地と100000h番地を比較して、同じ値だったら0(GateA20 off)を、違う値であったら1(GateA20 on)を返します。

なぜ000000h番地と100000h番地を比較するのかは、この辺に書いておきました。

bios_E820関数

システムメモリマップを取得

BIOSのINT 15H callを使い、システムメモリマップを取得します。

入力
レジスタ 内容
AX E820h
EBX 取得するメモリマップのオフセット?
ECX メモリマップ情報を返すエリアのレングス (20byte以上)
EDX 534D4150h ('SMAP')
ES:DI メモリマップ情報を返すエリアのアドレス
出力
レジスタ 内容
CF 正常:CF clear 異常:CF set(AHにエラーコードが入る)
EAX 534D4150h ('SMAP')
EBX 次に取得するメモリマップのオフセット(00000000hならば取得完了)
ECX 実際のメモリマップ情報のレングス
ES:DI メモリマップ情報を返すエリアのアドレス
INT 15H(AX=E820h)のパラメータ
ES:DIで指定したエリアに入るマップ情報
offset 内容
00h base address
08h レングス(byte)
10h メモリマップタイプ
タイプ  内容
01h	memory, available to OS
02h	reserved, not available (system ROM, memory-mapped等)
03h	ACPI Reclaim Memory
04h	ACPI NVS Memory
		

メモリマップ情報の取得はEBXレジスタが0になるまで、複数回に分けて取得する必要があります。取得した情報は変数mpに複数個セットされます。

マップの取得が出来なかった場合は、NULLが返ります。

bios_8800関数

Extended Memoryサイズを取得

BIOSのINT 15H callを使い、Extended Memoryサイズを取得します。

入力
レジスタ 内容
AX 8800h
INT 15H(AX=8800h)のパラメータ
出力
レジスタ 内容
CF 正常:CF clear 異常:CF set(AHにエラーコードが入る)
AX 絶対アドレス100000Hから連続したメモリのKbyte数

検出した容量は、Mbyteに丸められて変数mpにセットされます。検出出来なかった場合はNULLを返します。

bios_int12関数

Conventional Memoryサイズを取得

BIOSのINT 12H callを使い、Conventional Memoryサイズを取得します。

入力
入力パラメータは無
INT 12Hのパラメータ
出力
レジスタ 内容
AX 絶対アドレス0000Hから連続したメモリのKbyte数

addrprobe関数

Memoryを走査

  1. 最初に引数の値を1024倍して走査するメモリのアドレスを変数locにセットします。
  2. 次に走査するアドレスの内容を変数saveに保存ます。
  3. 走査するアドレスに幾つかのパターンを書き込み、その値が読み出せるかチェックします。読み出せない場合は変数retをインクリメントします。
  4. 走査が完了したら、保存しておいた元の値に戻します。

さらに詳しくMemoryを走査

上記で走査したアドレスがR/W可ならば(ret=0)、その下位バイトも走査します。やっていることは、上記の処理と一緒なので割愛。

結果を返す

メモリが有効ならばzero、無効ならばnon zeroを返します。

badprobe関数

Extended Memoryサイズを取得

Extended Memoryを絶対アドレスの1Mbyte目から512*1024Mbyte目までを4Mbyte単位でaddrprobe関数をcallして走査します。

走査して有効なExtended Memoryがあった場合は、変数mpにその容量をセットします。

memprobe関数

画面に表示

memprobeのメッセージを画面に表示します。

Using drive 0 , partition 4 .
Loading........
probing:pc0 com1 com2 apm pci mem[
      

memoryのProbe処理

  1. 最初にbios_E820関数をcallしシステムメモリマップを取得します。
  2. bios_E820関数で取得出来た場合は、IF文を抜けます。
  3. bios_E820関数で取得出来なかった場合は、bios_int12をcallしConventional Memoryサイズを取得し、bios_memmap[0]にセットします。
  4. さらにbios_8800関数をcallしてExtended Memoryサイズを取得し、bios_memmap[1]にセットします。
  5. bios_8800関数でも検出出来ない場合は、badprobe関数をcallして検出を試みます。

分かりにくいのでロジックを書いておこうかな。

if(システムメモリマップ情報(bios_E820)を取得失敗){
  Conventional Memory情報(bios_int12)を取得
  if(Extended Memory情報(bios_8800)を取得失敗){
     Extended Memoryを走査(badprobe)して情報を取得
  }
}	

検出された、各メモリの情報は配列bios_memmapに格納されます。メモリ情報の終端には識別子としてpm->type = BIOS_MAP_ENDがセットされます。

apmfixmem

有効メモリの計算と表示

配列bios_memmapに格納された、メモリ情報を元にメモリ量を表示します。

reading boot ....
Probing:pc0 com1 com2 apm pci mem[639K 253M
      

そして、I/O Memory holeの領域を除いた、Conventional Memoryサイズを変数cnvmemに、Extended Memoryサイズを変数extmemにセットします。

gateA20のチェック

gateA20on関数で、有効にしたgateA20が正しく動作しているかをcheckA20関数をcallしてチェックします。

そしてチェックの結果を画面に表示します。

reading boot ....
Probing:pc0 com1 com2 apm pci mem[639K 253M a20=on]
      
Last modified: Tue Apr 29 19:42:43 2008 JST