LAB_1_Part2_The Boot Loader
4485 ワード
1. LAB_1_Booting a PC
1.1. Part 2: The Boot Loader
6.828では、従来のHDD起動メカニズムを使用します.これは、
boot loaderは、1つのアセンブリ言語ソースファイル
1.1.1. boot.S
BIOSは、
ソース読解、知識点:1.
df:方向フラグビット.シリアル処理命令では,操作毎にsi,diの増減を制御する.(df=0で、操作毎にsi、diが増加し、df=1で、操作毎にsi、diが減少する).
以前のPC機との互換性のため、
CR 0には6つの事前定義フラグが含まれており、0ビットは保護許可ビットPE(Protedted Enable)であり、保護モードを起動するために使用され、PE位置1の場合、保護モードが起動し、PE=0の場合、実モードで動作する.
PROT_MODE_CSEG=8、この値はこだわりがあるようで、『自分でオペレーティングシステムを書く』という本で見たことがあります.この時点で既に32ビット実モードに入っているため、このときの
1.1.2. デバッグS
BIOSはboot loaderを0 x 7 c 00の位置にロードするので、ブレークポイント
この記事には、詳細なデバッグプロセスMIT 6.828 JOS学習ノートがあります.Exercise 1.3ですが、しばらくは細かく分析する必要はないと思います.
1.1.3. カーネルのロード
次に、
まず以下のCポインタを熟知しています.コンパイル運転
ELFフォーマットは非常に強力で複雑ですが、ほとんどの複雑な部分は共有ライブラリの動的ロードをサポートするために使用され、6.828コースでは使用されません.このコースでは、ELF実行可能ファイルを簡単にロード情報付きヘッダーと見なすことができます.その後、いくつかのプログラムセクションに続き、各プログラムセクションは連続したコードブロックまたはデータであり、指定したメモリにロードされます.
私たちが関心を持つProgram Sectionは次のとおりです. .text:実行可能命令 .rodata:文字列定数などの読取り専用データセグメント.(ただし、書き込みを禁止するためにハードウェアを設定するのに苦労しません.) .data:初期化されたデータを格納する .bss:初期化されていない変数を格納が、ELFには記録のみが必要である.bssの開始アドレスと長さ.
各プログラムヘッダの
BIOSはブートセクタの内容を0 x 7 c 00の位置にロードし、ブートプログラムも0 x 7 C 00の位置から実行します.
一部の情報に加えて、ELFヘッダには
0 x 7 d 6 bのブレークポイント後、
実際に実行した
1.1.4. Exercise 6
BIOSがBoot loaderに入ったときにメモリの8文字が0 x 0100000であることを確認し、ブートローダがカーネルに入ったときに再度チェックします.彼らはどうして違うのですか.2番目のブレークポイントは何ですか?△あなたは本当にQEMUでこの質問に答える必要はありません.考えてみてください.
答えは明らかであるべきで、BIOSがBoot loaderに入る時、0 x 10000000メモリの後の8文字はすべてゼロで、この時カーネルプログラムはまだメモリにロードしていないためです.カーネルのロードは
gdbでデバッグする必要がある場合は、
1.1. Part 2: The Boot Loader
6.828では、従来のHDD起動メカニズムを使用します.これは、
boot loader
512バイトを満たす必要があることを意味します.boot loaderは、1つのアセンブリ言語ソースファイル
boot / boot.S
と1つのCソースファイルboot / main.c
からなる.1.1.1. boot.S
BIOSは、
boot.S
このコードをハードディスクの最初のセクタloadから物理アドレス0x7c00
までの位置で、CPUはreal mode
で動作する.boot.S
CPUの動作モードを実モードから32ビットの保護モードに変換し、jumpからC言語プログラムに移行する必要がある.ソース読解、知識点:1.
cli (clear interrupt)
2. cld (clear direction flag)
df:方向フラグビット.シリアル処理命令では,操作毎にsi,diの増減を制御する.(df=0で、操作毎にsi、diが増加し、df=1で、操作毎にsi、diが減少する).
以前のPC機との互換性のため、
A20
アドレス線が接地されているため、アドレスが1 M範囲より大きい場合はデフォルトで0にロールバックされる.従って32ビットモードに移行する前に、イネーブルA20
が必要となる.3.test論理演算命令は、2つのオペランドに対してAND
操作を行い、かつ修正PSW
test
AND
命令と唯一異なる点は、TEST
命令が目標オペランドを修正しないことである.test al, 00001001b ; 0 3
lgdt gdtdesc
グローバル記述子テーブルをロードし、グローバル記述テーブルがどのように生成されたかにかかわらず一時的に関係なくロードする.cr0
,control register,制御レジスタ.CR 0には6つの事前定義フラグが含まれており、0ビットは保護許可ビットPE(Protedted Enable)であり、保護モードを起動するために使用され、PE位置1の場合、保護モードが起動し、PE=0の場合、実モードで動作する.
ljmp $PROT_MODE_CSEG, $protcseg
, PROT_MODE_CSEG=8、この値はこだわりがあるようで、『自分でオペレーティングシステムを書く』という本で見たことがあります.この時点で既に32ビット実モードに入っているため、このときの
8
実モードでは簡単ではないcs
となっており、GDTに関係しているようで、当時はGDTの初期化が複雑だと思っていたが、ここではまず深く考えない.1.1.2. デバッグS
terminal
中cdからlab
ディレクトリの下で、make qemu-gdb
を実行します.もう一つterminal
実行make gdb
.BIOSはboot loaderを0 x 7 c 00の位置にロードするので、ブレークポイント
b *0x7c00
を設定します.再実行c
、QUMU端末に表示されるBooting from hard disk
.x/30i 0x7c00
を実行するとboot.S
と似たようなアセンブリコードが表示されます.この記事には、詳細なデバッグプロセスMIT 6.828 JOS学習ノートがあります.Exercise 1.3ですが、しばらくは細かく分析する必要はないと思います.
1.1.3. カーネルのロード
次に、
boot loader
のC言語部分を分析します.まず以下のCポインタを熟知しています.コンパイル運転
pointer.c
結果.a[]
・b
のアドレスの違いは、両者が格納されているセグメントが異なるため、かなり異なることがわかります.1: a = 0xbfa8bdbc, b = 0x9e3a160, c = (nil)
2: a[0] = 200, a[1] = 101, a[2] = 102, a[3] = 103
3: a[0] = 200, a[1] = 300, a[2] = 301, a[3] = 302
4: a[0] = 200, a[1] = 400, a[2] = 301, a[3] = 302
5: a[0] = 200, a[1] = 128144, a[2] = 256, a[3] = 302
// b = a + 4
6: a = 0xbfa8bdbc, b = 0xbfa8bdc0, c = 0xbfa8bdbd
ELFフォーマットは非常に強力で複雑ですが、ほとんどの複雑な部分は共有ライブラリの動的ロードをサポートするために使用され、6.828コースでは使用されません.このコースでは、ELF実行可能ファイルを簡単にロード情報付きヘッダーと見なすことができます.その後、いくつかのプログラムセクションに続き、各プログラムセクションは連続したコードブロックまたはデータであり、指定したメモリにロードされます.
私たちが関心を持つProgram Sectionは次のとおりです.
Loader
andprogram
自分でやらなければならない.bssセグメントクリア.各プログラムヘッダの
ph-> p_pa
フィールドにはセグメントのターゲット物理アドレスが含まれている(この場合、ELF仕様はフィールドの実際の意味が曖昧であるにもかかわらず、実際には物理アドレスである)BIOSはブートセクタの内容を0 x 7 c 00の位置にロードし、ブートプログラムも0 x 7 C 00の位置から実行します.
-Ttext 0x7C00
・・boot / Makefrag
のリンクにリンクアドレスを渡すことで、リンクは生成したコードに正しいメモリアドレスを生成します.一部の情報に加えて、ELFヘッダには
e_entry
という私たちにとって重要なフィールドがあります.このフィールドは、プログラム内のエントリポイントのリンクアドレスを保存します.プログラムが実行を開始すべきコードセグメントの記憶アドレスです.逆アセンブリコードでは、最後のcallが0 x 10018アドレスであることがわかります.((void (*)(void)) (ELFHDR->e_entry))();
7d6b: ff 15 18 00 01 00 call *0x10018
0 x 7 d 6 bのブレークポイント後、
c
再si
一度、実際のジャンプアドレスビット0 x 10000 cを発見(gdb) b *0x7d6b
Breakpoint 3 at 0x7d6b
(gdb) c
Continuing.
=> 0x7d6b: call *0x10018
Breakpoint 3, 0x00007d6b in ?? ()
(gdb) si
=> 0x10000c: movw $0x1234,0x472
実際に実行した
objdump -f kernel
の結果と一致する.../kern/kernel: file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0010000c
1.1.4. Exercise 6
BIOSがBoot loaderに入ったときにメモリの8文字が0 x 0100000であることを確認し、ブートローダがカーネルに入ったときに再度チェックします.彼らはどうして違うのですか.2番目のブレークポイントは何ですか?△あなたは本当にQEMUでこの質問に答える必要はありません.考えてみてください.
答えは明らかであるべきで、BIOSがBoot loaderに入る時、0 x 10000000メモリの後の8文字はすべてゼロで、この時カーネルプログラムはまだメモリにロードしていないためです.カーネルのロードは
bootmain
関数で完了します.gdbでデバッグする必要がある場合は、
x/8x 0x100000
メモリの内容を表示します.