005-完成ipl

       上次完成了啓動盤,我們已經成功把啓動區加載到了內存中,當然了,這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的內存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章