今回は「query_apm_bios」関数を見てみます。
例によってBIOSにAPMの情報を問い合わせて、ブートパラメータ構造体に格納している関数に違いありません。
arch/x86/boot/apm.c
======
int query_apm_bios(void)
{
/* ~省略(変数宣言)~ */
/* APM対応かチェックする */
ax = 0x5300;
bx = cx = 0;
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
: "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
: : "esi", "edi");
/* ~省略(エラーチェック)~*/
/* いったんAPMから切断する */
ax = 0x5304;
bx = 0;
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
: "+a" (ax), "+b" (bx)
: : "ecx", "edx", "esi", "edi");
/* Paranoia */
ebx = esi = 0;
cx = dx = di = 0;
/* 改めてAPM接続 */
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6"
: "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx),
"+S" (esi), "+D" (di), "=m" (err)
: "a" (0x5303));
/* ブートパラメータ構造体にセット */
boot_params.apm_bios_info.cseg = ax;
boot_params.apm_bios_info.offset = ebx;
boot_params.apm_bios_info.cseg_16 = cx;
boot_params.apm_bios_info.dseg = dx;
boot_params.apm_bios_info.cseg_len = (u16)esi;
boot_params.apm_bios_info.cseg_16_len = esi >> 16;
boot_params.apm_bios_info.dseg_len = di;
/* ~省略~ */
/* もう一度APM情報を取得してくる */
ax = 0x5300;
bx = cx = 0;
asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
: "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
: : "esi", "edi");
/*~省略(エラーチェック)~*/
/* バージョンとフラグ情報をセット */
boot_params.apm_bios_info.version = ax;
boot_params.apm_bios_info.flags = cx;
return 0;
}
======
なんだか似たようなコードばかり読んでいますが、こういった地道な作業の積み重ねなのです。
2009年6月30日火曜日
2009年6月29日月曜日
query_ist
main関数で「query_mca」の次にあるのは「query_voyager」ですが、NUMAシステム用なのでパスします。
その次の「query_ist」を見ていきます。
ISTとは「Intel Speedstep Technology」の略で、省電力機能です。
BIOSを使ってその辺の情報を拾ってくるんだろうな、と。。
同関数はmain.cの中にあります。
======
======
徐々にパターンが見えてきた気がしませんか。
問い合わせたい情報をレジスタにセットして0x15でソフトウェア割り込み。
とれた値を構造体に格納。
でもネットで調べてみてもISTを取得するためのBIOS機能なんて見つからず。
きっとここではそうやって取っているんだろうな、という解釈で進めますか、、、
その次の「query_ist」を見ていきます。
ISTとは「Intel Speedstep Technology」の略で、省電力機能です。
BIOSを使ってその辺の情報を拾ってくるんだろうな、と。。
同関数はmain.cの中にあります。
======
static void query_ist(void)
{
/* 古いBIOSでこの問い合わせするとクラッシュする */
if (cpu.level < 6)
return;
asm("int $0x15"
: "=a" (boot_params.ist_info.signature),
"=b" (boot_params.ist_info.command),
"=c" (boot_params.ist_info.event),
"=d" (boot_params.ist_info.perf_level)
: "a" (0x0000e980), /* IST Support */
"d" (0x47534943)); /* Request value */
}
======
徐々にパターンが見えてきた気がしませんか。
問い合わせたい情報をレジスタにセットして0x15でソフトウェア割り込み。
とれた値を構造体に格納。
でもネットで調べてみてもISTを取得するためのBIOS機能なんて見つからず。
きっとここではそうやって取っているんだろうな、という解釈で進めますか、、、
2009年6月28日日曜日
query_mca
main関数もようやく中盤に差し掛かってきました。
今回見るのは「query_mca」。
arch/x86/boot/mca.c
======
======
int 0x15(AH:0xc0)でブートパラメータをとってきてboot_params_sysにコピーしている、というのがquery_mcaでやっていること。
で、これでとれてくるブートパラメータって何?というところは色々調べてみたのだけど分からずじまい。。。
この関数で呼んでいる「set_fs」「rdfs16」「copy_from_fs」といった関数はコメント以上のことは
やっていない単純なものなので見ないおきます。
今回見るのは「query_mca」。
arch/x86/boot/mca.c
======
int query_mca(void)
{
u8 err;
u16 es, bx, len;
/* BIOSを使ってROMテーブルを取得する */
asm("pushw %%es ; "
"int $0x15 ; "
"setc %0 ; "
"movw %%es, %1 ; "
"popw %%es"
: "=acd" (err), "=acdSD" (es), "=b" (bx)
: "a" (0xc000));
if (err)
return -1; /* No MCA present */
/* thread_info->addr_limitにesの値を格納する */
set_fs(es);
/* テーブルサイズを取得 */
len = rdfs16(bx);
if (len > sizeof(boot_params.sys_desc_table))
len = sizeof(boot_params.sys_desc_table);
/* ROMテーブルの内容をboot_params.sys_desc_tableにコピーする */
copy_from_fs(&boot_params.sys_desc_table, bx, len);
return 0;
}
======
int 0x15(AH:0xc0)でブートパラメータをとってきてboot_params_sysにコピーしている、というのがquery_mcaでやっていること。
で、これでとれてくるブートパラメータって何?というところは色々調べてみたのだけど分からずじまい。。。
この関数で呼んでいる「set_fs」「rdfs16」「copy_from_fs」といった関数はコメント以上のことは
やっていない単純なものなので見ないおきます。
2009年6月25日木曜日
keyboard_set_repeat
main関数で呼び出しているお次は「keyboard_set_repeat」。
コメントにもなぜここでやるのか分からん、と書いてあるような関数なので
モチベーションあがりませんが、短いので見ておきましょう。
======
======
キーボードのリピートレートをMAXに設定しています。
この部分はBIOSの機能としてはかなりマニアックなようでネット探しても
なかなか詳細な解説には出会えません。
linux-usersメーリングリストの過去ログから拾ってきました
http://search.luky.org/linux-users.3/msg02165.html
追記)
こちらも参考になります。
ブートローダー(その4)ーありえるえりあ
コメントにもなぜここでやるのか分からん、と書いてあるような関数なので
モチベーションあがりませんが、短いので見ておきましょう。
======
static void keyboard_set_repeat(void)
{
u16 ax = 0x0305;
u16 bx = 0;
asm volatile("int $0x16"
: "+a" (ax), "+b" (bx)
: : "ecx", "edx", "esi", "edi");
}
======
キーボードのリピートレートをMAXに設定しています。
この部分はBIOSの機能としてはかなりマニアックなようでネット探しても
なかなか詳細な解説には出会えません。
linux-usersメーリングリストの過去ログから拾ってきました
http://search.luky.org/linux-users.3/msg02165.html
追記)
こちらも参考になります。
ブートローダー(その4)ーありえるえりあ
2009年6月24日水曜日
detect_memory
main関数で呼び出しているお次は「detect_memory」。
その名のとおり、メモリを検出しているに違いありません。
arch/x86/boot/memory.c
======
======
それでは各サブ関数を見ていきましょう。
すべて同じファイル内にあります。
======
======
SMAPとか出てきますがこれは「System Memoy mAP」の略です。
BIOSからもらえるメモリマップの情報です。
要約してしまうとこの関数はBIOSの機能を使ってシステムのメモリマップを取得しているのです。
次に「detect_memory_e801」を見てみます。
======
======
さっきから出てくる「int 0x15」というのはBIOSの機能を呼び出している部分で、
ファンクション表は英語のWikipediaが便利です。
あんまり難しい英語でもないのでなんとかいけます。
http://en.wikipedia.org/wiki/BIOS_call
他に親切な解説としては下記が詳しくて参考になります。
ブートローダー(その3) -ありえるえりあ
最後の方はコメントを無理やり訳してみましたが、正直よく理解できてません。
めげずに次へ
======
=======
というわけで「detect_memory」の内容をまとめると
1)「detect_memory_e820」でシステムメモリのアドレスマップエントリ数を取得
2)「detect_memory_e801」で64MBを超えた部分の拡張メモリサイズを取得
3)「detect_memory_88」で拡張メモリサイズを取得
ということをしているのです。
その名のとおり、メモリを検出しているに違いありません。
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」で拡張メモリサイズを取得
ということをしているのです。
2009年6月23日火曜日
set_bios_mode
main関数でvalidate_cpuの次に呼び出しているのは「set_bios_mode」、今回はこちらを見ていきます。
=====================
=====================
、、、64bit CPUでないと何もしないようなのでおしまい。
CPUモードをBIOSに設定しているようです。
=====================
static void set_bios_mode(void)
{
#ifdef CONFIG_X86_64
u32 eax, ebx;
eax = 0xec00;
ebx = 2;
asm volatile("int $0x15"
: "+a" (eax), "+b" (ebx)
: : "ecx", "edx", "esi", "edi");
#endif
}
=====================
、、、64bit CPUでないと何もしないようなのでおしまい。
CPUモードをBIOSに設定しているようです。
2009年6月22日月曜日
validate_cpu
main関数から呼び出している関数のうち、前回までにcopy_boot_params、init_heapの2つを
見てきました。今回は3つめ「validate_cpu」を見てみましょう。
arch/x86/boot/cpu.c
======
=======
check_cpuという関数を呼び出して、関数内で設定された値をチェックして必要に応じてエラーメッセージを表示しているのみ。なので、実機能はcheck_cpuにあります。
arch/x86/boot/cpucheck.c
=======
=======
どんなCPUを使っているの?という情報をとってきてパラメータに格納しています。
見てきました。今回は3つめ「validate_cpu」を見てみましょう。
arch/x86/boot/cpu.c
======
int validate_cpu(void)
{
/*変数宣言(省略) */
/* CPUのチェック */
check_cpu(&cpu_level, &req_level, &err_flags);
/* CPUレベルと要求レベルの比較 */
if (cpu_level < req_level) {
/* エラー処理(省略) */
}
/* エラーフラグが立っているか?*/
if (err_flags) {
/* エラー処理(省略)*/
} else {
return 0;
}
}
=======
check_cpuという関数を呼び出して、関数内で設定された値をチェックして必要に応じてエラーメッセージを表示しているのみ。なので、実機能はcheck_cpuにあります。
arch/x86/boot/cpucheck.c
=======
int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)
{
int err;
/* とりあえずCPUレベル3をセット */
memset(&cpu.flags, 0, sizeof cpu.flags);
cpu.level = 3;
/* アライメントチェックフラグがあればレベル4 */
if (has_eflag(X86_EFLAGS_AC))
cpu.level = 4;
/* CPUID命令でプロセッサを識別する。必要ならレベルも更新 */
get_flags();
/* エラーがないかチェックする */
err = check_flags();
/* 64bitかどうか */
if (test_bit(X86_FEATURE_LM, cpu.flags))
cpu.level = 64;
if (/*AMDの場合*/) {
~省略~
} else if (/* VIA C3の場合 */) {
~省略~
} else if (/* Transmetaの場合 */) {
~省略~
}
if (err_flags_ptr)
*err_flags_ptr = err ? err_flags : NULL;
if (cpu_level_ptr)
*cpu_level_ptr = cpu.level;
if (req_level_ptr)
*req_level_ptr = req_level;
return (cpu.level < req_level || err) ? -1 : 0;
}
=======
どんなCPUを使っているの?という情報をとってきてパラメータに格納しています。
登録:
投稿 (Atom)