ディスク読み込みの方法がわかりましたので、
マスタブートローダの改良にうつります。
本格的なローダの作成は後で行うことにして、
今回はファイルシステムのことは考えずに、
2番目のセクタ、つまり論理セクタ1(C,H,S=0,0,2)を
07E00h-07FFFh に読み込むことにします。
まずは、セクタ読み込み関数を書くことにします。
ディスクのセクタ指定方法ですが、CHS ではプログラミング上面倒ですので、
0 からはじまる論理セクタで指定することにします。
指定された論理セクタを 1 セクタ分だけ読みこむ関数は次の通りです。
read_single_sector: pusha mov si, 18 div si ; ax = track number ; dl = residual sector number / dh = 0 inc dx ; dl = sector index / dh = 0 shr ax, 1 ; ax = cylinder number rcl dh, 1 ; dh = head index mov ch, al ; ch = cylinder index mov cl, dl ; cl = sector index mov dl, 00h ; drive = FDD #0 mov ax, 0201h int 13h jnc readsector_end ; recalibrate and retry xor ax, ax mov dl, 00h ; drive = FDD #0 int 13h jc fatal_error popa jmp read_single_sector readsector_end: popa ret fatal_error: ; エラー処理 ; 今回は無限ループ sti hlt jmp fatal_error
次のコードは、
hello, world を論理セクタ 1 におき、
それを実行するマスタブートローダです。
この例では hello,world を表示するだけですが、ここで
OS のブートコードを読み込めば、OS が起動できることになります。
org 7C00h ; sector #1 xor ax, ax mov ds, ax mov es, ax cli mov ss, ax mov sp, 7C00h ; SS:SP = 0000h:7C00h sti mov ax, 1 mov bx, 7E00h call read_single_sector jmp 7E00h (先の read_single_sector やエラー処理) times 01FEh-($-$$) db 0 db 55h,0AAh ; sector #2 mov si, msg_hello put_next: mov ax, cs mov ds, ax lodsb cmp al, '$' jz put_end mov ah, 0Eh mov bl, 07h int 10h jmp put_next put_end: self: jmp self msg_hello: db 'Hello, world! (ver 2)',0dh,0ah,'$'
今回は読み込み先としてアドレス 07E00h-07FFFh に読み込みました。
マスタブートローダが起動した段階で、
リアルモードで扱える 1M バイトのメモリアドレスに
アクセスすることができます。
このとき、ほとんどのメモリは使われておらず
自由に使うことができます。
機種によってメモリの内容は違いますが、その典型的な例を次の表の通りです。
| アドレス | 内容 |
| 00000h - 003FFh | INT 00h〜INT FFhの割り込みハンドラ |
| 00400h - 005FFh | BIOS のワークエリア 1 |
| 00600h - 9FBFFh | 通常は空きメモリ(メモリサイズはINT 12hで取得) |
| 9FC00h - 9FFFFh | BIOS のワークエリア 2 |
| A0000h - BFFFFh | ビデオメモリ |
| C0000h - CFFFFh | ビデオカードの BIOS |
| D0000h - EFFFFh | BIOS など |
| F0000h - FFFFFh | マザーボードの BIOS |