ディスクからの読み込み方法、FAT の構造がわかりましたので、
FAT のルートディレクトリからファイルを読み込んで実行する
マスタブートローダの作成に移ります。
セクタを読み込む関数は
ディスク読み込みの方法で
作りましたので、今回はそれ以外の部分を作ります。
今回は複雑な処理を省くためにカーネルファイルのサイズを
50K 以下に制限することにしました。
以下のソースで使う定数は次のとおりです。
FAT12 は最大でも 6K を超えることはありませんので、
管理テーブルを保存するバッファは6Kとします。
ブートセクタは 0000h:7C00h に読み込まれますが、
この位置では都合が悪いため起動直後に 0000h:F000h にコピーし、
F000h 以降のコードを実行することにします。
%define kernelseg 0060h %define bootfatbuf 0D800h %define top_of_mbr 0F000h %define work_fatcur 0F200h %define work_rootdirsec 0F202h %define work_seccountrootdir 0F204h %define bootdmabuf 0F400h %define top_of_stack 0FFFEh
org top_of_mbr jmp short bootentry nop db 'HOVERDOS' ;+03 byte[8] OEM name bytespersec: dw 512 ;+0B word bytes/sector secpercl: db 1 ;+0D byte sectors/cluster firstsec: dw 1 ;+0E word the first sector fatcount: db 2 ;+10 byte =2(2 FATs) rootentries: dw 14*16 ;+11 word entries in root dir. dw 1440*2 ;+13 word total sectors. db 0F0h ;+15 byte media descriptor secperfat: dw 9 ;+16 word sectors/FAT secpertrack: dw 18 ;+18 word sectors/track heads: dw 2 ;+1A word heads dd 0 ;+1C dword hidden sectors dd 0 ;+20 dword total sectors(>=32MB) db 0 ;+24 byte drive number db 0 ;+25 byte reserved db 29h ;+26 byte signature = 29h dd 0 ;+27 dword volume serial number db 'HOVERDOS ' ;+2B byte[11] volume label db 'FAT12 ' ;+36 byte[8] file system
bootentry: call bootentry_2 bootentry_2: pop si sub si, bootentry_2-top_of_mbr xor ax, ax mov ds, ax mov es, ax mov ss, ax ; DS = ES = SS = 0000h mov sp, top_of_stack cld sti mov di, top_of_mbr mov cx, 200h >> 1 rep cs movsw mov dx, cs jmp 0000h:bootentry_3 bootentry_3:
; set work_rootdirsec. mov ax, word [secperfat] xor dx, dx mov dl, byte [fatcount] mul dx add ax, word [firstsec] mov word [work_rootdirsec], ax ; set work_seccountrootdir. xor dx, dx mov ax, word [rootentries] mov cx, word [bytespersec] shr cx, 5 ; 32-byte/dir div cx mov word [work_seccountrootdir], ax ; load FAT12. mov ax, word [firstsec] mov cx, word [secperfat] mov bx, bootfatbuf loadfat12_next: call read_single_sector inc ax add bx, word [bytespersec] loop loadfat12_next mov di, str_sysldr call find_file mov bp, kernelseg call read_file push kernelseg push 0 retf ; search a entry in root directory and ; set ds:[work_fatcur] to the first sector. ; es:di = filename find_file: pusha mov ax, word [work_rootdirsec] mov dx, word [work_seccountrootdir] searchdisk_next: mov bx, bootdmabuf mov si, bx call read_single_sector inc ax mov bp, word [bytespersec] shr bp, 5 ; 512/32=16 searchmem_next: mov cx, 8+3 push si push di repe cmpsb pop di pop si je search_found add si, 32 dec bp jnz searchmem_next dec dx jnz searchdisk_next ; not found. jmp fatal_error search_found: mov ax, word [si+1Ah] mov word [work_fatcur], ax popa ret ; read the active file. ; bp = segment of the buffer. ; ds:[work_fatcur] shall be set before calling. read_file: pusha push es xor ax, ax mov al, byte [secpercl] mov si, ax mov di, word [bytespersec] shr di, 4 ; DI = bytespersec / 16 xor bx, bx readnextcluster: mov ax, word [work_fatcur] cmp ax, 0FF8h jae short endoffile sub ax, 2 jb short endoffile mul si ; AX = [work_fatcur] * [secpercl] add ax, word [work_rootdirsec] add ax, word [work_seccountrootdir] mov cx, si ; [secpercl] readnextsector: mov es, bp call read_single_sector inc ax add bp, di loop readnextsector call fat_next jmp short readnextcluster endoffile: pop es popa ret ; seek to the next cluster. ; [work_fatcur] is updated fat_next: pusha mov si, word [work_fatcur] mov bx, si shr bx, 1 mov ax, word [bootfatbuf+si+bx] jnc fat12_next_even shr ax, 4 fat12_next_even: and ah, 0Fh mov word [work_fatcur], ax popa ret str_sysldr: db 'HOVERDOSBIN' ; bootable times 01FEh-($-$$) db 0 db 55h,0AAh