上次完成了啓動盤,我們已經成功把啓動區加載到了內存中,當然了,這512字節的空間肯定是不可能夠我們寫一個完整的操作系統的,所以,我們操作系統的其他部分肯定得在別的地方寫,那麼,ipl的任務就應該是把軟盤這1440KB的內容全部加載到內存中,不過這裏有一個相當嚴重的問題,就是我們在實模式下,只有20位尋址空間,換句話說,我們只能訪問1MB的內存,所以暫時還沒辦法把所有的數據都放到內存中,暫時我們先只放10個柱面的內容到內存中。交給操作系統的內存部分是0x8000到0x9fbff,不過,雖然ipl的部分事先被加載到了0x7c00的位置,但是,它仍然作爲軟盤數據的一部分,這部分的數據在以後是有可能會用到的,因此,我們還是把0x8000到0x81ff的內存空間留給它,把剩下的內容從0x8200開始儲存。
我們按照扇區-磁頭-柱面的順序變更來讀取軟盤(也就是C0-H0-S1, C0-H0-S2, ……C0-H0-S18, C0-H1-S1, …… C0-H1-S18, C1-H0-S1, ……這樣的順序)一直讀到C9-H1-S18。下面是改過後的ipl。
org 0x7c00
jmp entry
db 0x90
db "HELLOIPL"
dw 512
db 1
dw 1
db 2
dw 224
dw 2880
db 0xf0
dw 9
dw 18
dw 2
dd 0
dd 2880
db 0, 0, 0x29
db 0xffffffff
db "HELLO-OS "
db "FAT12 "
resb 18
entry:
mov ax, 0
mov ss, ax
mov sp, 0x7c00
mov ds, ax
mov ax, 0x0820
mov es, ax ;緩衝地址段地址
mov ch, 0 ; 柱面號
mov dh, 0 ; 磁頭號
mov cl, 2 ; 扇區號
readloop:
mov si, 0
retry:
mov ah, 0x02
mov al, 1 ; 處理1個扇區
mov bx, 0 ; 緩衝地址基址
mov dl, 0 ; 驅動器號
int 0x13 ; 0x13號中斷,ah=0x2時讀盤,內容讀取到es:bx中
jnc succeed ; 如果進位符是1表示讀取錯誤,jnc表示進位符爲0
add si, 1
cmp si, 5
jae error
mov ah, 0
mov dl, 0
int 0x13 ; 0x13號中斷 ah=0, dl=0時系統復位
jmp retry
next:
mov ax, es
add ax, 0x20
mov es, ax
add cl, 1
cmp cl, 18
jbe readloop
mov cl, 1
add dh, 1
cmp dh, 2
jb readloop
mov dh, 0
add ch, 1
cmp ch, 10
jb readloop
mov [0xff0], ch
jmp 0xc200
succeed:
mov si, msg_succeed
jmp putloop
error:
mov si,msg_error
putloop:
mov al, [si]
add si, 1
cmp al, 0
je next
mov ah, 0x0e
mov bx, 15
int 0x10
jmp putloop
msg_error:
db 0x0d, 0x0a
db "load error"
db 0x0a, 0
msg_succeed:
db 0x0d, 0x0a
db "load success "
db 0x0a, 0
resb 0x7dfe-$
db 0x55, 0xaa
24-27行是寄存器的初始化,ss和sp這兩個寄存器在本程序裏還用不到,只不過寫上合適的值方便以後添加程序。29-30行初始化了緩衝地址寄存器es,這是因爲我們要設置數據的起點,由於我們要把數據加載到0x8200位置,所以數據的起點就是這裏,段寄存器就指向這裏。13號BIOS中斷時有關軟盤操作的,當al爲1時進行讀盤操作,將會把dl表示的驅動器中的內容存放到[es:bx]中;當al爲0時進行重新讀盤操作。36-49行嘗試讀盤,si寄存器存放的是嘗試讀盤的次數,所以在35行初始化爲0,當嘗試5次都失敗時將放棄讀取,輸出錯誤信息,而讀取成功後,就會跳轉到next標籤下。50-64行通過不斷循環36-49行的指令,把10個扇區的數據全部載入內存中。65行向內存0xff0處保存了一個數據,這個數據是目前讀取的扇區數,這也是爲了以後拓展這個程序用的,可以方便地知道之前加載了多少數據。執行到66行時,程序應當將10個扇區都加載完畢了,跳轉到0xc200處,沒錯,0xc200已經超出ipl的範圍了,這就是給操作系統的一個引子,我們就應當把操作系統加載到這個位置,由於ipl之前已經把這些內容都加載到內存中了,所以,接下來就可以直接執行操作系統的內容了,接下來我們來寫操作系統,很簡單的,輸出一行文字就好。
org 0xc200
osEntry:
mov ax, 0
mov ds, ax
mov si, msg
putloop:
mov al, [si]
add si, 1
cmp al, 0
je fin
mov ah, 0xe
mov bx, 15
int 0x10
jmp putloop
fin:
hlt
jmp fin
msg:
db 0x0d, 0x0a
db "Hello World!"
db 0x0d, 0x0a, 0
在輸出了一系列的加載成功以後,又輸出了Hello World!,這就表示,我們的操作系統已經加載出來了。
所以,ipl的使命基本就是這樣,但是現在還不是很完善,這個以後再去修改,在較長的一段時間就會保持這樣,接下來的任務就要轉向我們的操作系統內核了。下次將介紹在操作系統加載後如何進入保護模式,以便利用32位尋址空間,訪問4GB的內存。