2009年6月24日水曜日

detect_memory

main関数で呼び出しているお次は「detect_memory」。
その名のとおり、メモリを検出しているに違いありません。

arch/x86/boot/memory.c
======
int detect_memory(void)
{
int err = -1;

if (detect_memory_e820() > 0)
err = 0;

if (!detect_memory_e801())
err = 0;

if (!detect_memory_88())
err = 0;

return err;
}

======

それでは各サブ関数を見ていきましょう。
すべて同じファイル内にあります。

======
static int detect_memory_e820(void)
{
/* ~変数宣言~ */

do {
size = sizeof(struct e820entry);

/* システムのアドレスマップをBIOSに問い合わせる。 */
asm("int $0x15; setc %0"
: "=d" (err), "+b" (next), "=a" (id), "+c" (size),
"=m" (*desc)
: "D" (desc), "d" (SMAP), "a" (0xe820));

/* 失敗してたらループを抜ける*/
if (err)
break;

/* BIOSによってはこのループ中にSMAPを返すのをやめてしまいます。
こちらとしてはここまで成功してんだか失敗してんだか
          ゴミまざってんだか分からないのでエントリ数0で
          ループ抜けちゃいます */
if (id != SMAP) {
count = 0;
break;
}

/* アドレスマップのエントリ数を加算 */
count++;
desc++;

/* アドレスマップエントリの配列サイズ(=128)を越えてないか? */
} while (next && count < e820_entries =" count;">

======
SMAPとか出てきますがこれは「System Memoy mAP」の略です。
BIOSからもらえるメモリマップの情報です。
要約してしまうとこの関数はBIOSの機能を使ってシステムのメモリマップを取得しているのです。
次に「detect_memory_e801」を見てみます。

======
static int detect_memory_e801(void)
{
/* ~変数宣言~ */

/* BIOSから拡張メモリ領域サイズ(64MBを超える部分)を取得する */
bx = cx = dx = 0;
ax = 0xe801;
asm("stc; int $0x15; setc %0"
: "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));

if (err)
return -1;

/* これ必要?(※原文まま)*/
if (cx || dx) {
ax = cx;
bx = dx;
}

/* とれてくる値が16MB超過していたらおかしい */
if (ax > 15*1024)
return -1; /* Bogus! */

/* とってきた64MBを超える分の拡張メモリサイズを格納しておく */
boot_params.alt_mem_k = (ax == 15*1024) ? (dx <<>


======
さっきから出てくる「int 0x15」というのはBIOSの機能を呼び出している部分で、
ファンクション表は英語のWikipediaが便利です。
あんまり難しい英語でもないのでなんとかいけます。

http://en.wikipedia.org/wiki/BIOS_call


他に親切な解説としては下記が詳しくて参考になります。
ブートローダー(その3) -ありえるえりあ


最後の方はコメントを無理やり訳してみましたが、正直よく理解できてません。
めげずに次へ

======
static int detect_memory_88(void)
{
u16 ax;
u8 err;

/* 拡張メモリサイズをとってくる */
ax = 0x8800;
asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax));

/* とってきたメモリサイズを格納しておく */
boot_params.screen_info.ext_mem_k = ax;
/* エラーの結果を返す */
return -err;
}

=======

というわけで「detect_memory」の内容をまとめると
1)「detect_memory_e820」でシステムメモリのアドレスマップエントリ数を取得
2)「detect_memory_e801」で64MBを超えた部分の拡張メモリサイズを取得
3)「detect_memory_88」で拡張メモリサイズを取得
ということをしているのです。

0 件のコメント:

コメントを投稿