操作系統開發之——Loader程序編寫(2)


操作系統開發之——Loader程序編寫(2)


操作系統開發之——Loader程序編寫(2)

上一節我們已經掌握了進入保護模式的關鍵,這一節我們來具體實現他。


我們之前向屏幕輸出都是通過設置中斷實現,比較麻煩,這次我們換個方法,向顯存輸出信息,顯存地址(CGA)是0xB8000~0xBFFFF,我們只需要用其中一段就行,顯示功能不會用太多。使用方法很簡單,兩個顯存地址分別存儲字符和字符的前景,寫入後就可以看到效果了:

<code> 1[bits 16] 2;後面保護模式的代碼就是32位了,先寫著 3org 0x70000 4 5START: 6    ;這次一定要初始化,設置堆棧段和棧指針 7    mov ax,cs 8    mov ds,ax 9    mov es,ax10    mov ss,ax11    mov sp,01213point:14    ;清屏是個好習慣15    mov ax, 0x216    int 0x101718    mov ax, 0xb80019    mov es, ax20    mov di, 021    mov byte [es: di + 0], 'L'22    mov byte [es: di + 1], 0xcf23    mov byte [es: di + 2], 'o'24    mov byte [es: di + 3], 0xcf25    mov byte [es: di + 4], 'a'26    mov byte [es: di + 5], 0xcf27    mov byte [es: di + 6], 'd'28    mov byte [es: di + 7], 0xcf29    mov byte [es: di + 8], 'i'30    mov byte [es: di + 9], 0xcf31    mov byte [es: di + 10], 'n'32    mov byte [es: di + 11], 0xcf33    mov byte [es: di + 12], 'g'34    mov byte [es: di + 13], 0xcf/<code>

截圖太麻煩了,我拿我的人格擔保,一定可以顯示出Loading,效果和之前是一樣的。只是有人會發現,這樣打印字符串太不舒服了。是的,有更好的辦法,但是現在要先解決保護模式,保護模式進入也需要通過字符輸出來確認是否成功,但是進入保護模式後,我們就不能使用BIOS中斷來輸出字符了,所以這裡先簡單介紹操作顯存。

我們現在來初始化GDT並加載他,根據上一節初探保護模式,我們得知,我們需要填寫表相應位的值來初始化,填寫完後還要用GDTR加載:

<code> 1load_GDTR: 2    ;保存GDT地址到GDTR 3    lgdt[gdt]  4 5gdt_head: 6    dd 0x0000000 7    dd 0x0000000 8 9    dw 0x000ffff    ;段限制:0-15位10    dw 0x0000000    ;段基地址:0-15位11    db 0x0000000    ;段基地址:16-23位12    db 10011010b    ;段描述符的第6字節屬性(代碼段可讀寫)13    db 11001111b    ;段描述符的第7字節屬性:16-19位14    db 0x0000000    ;段描述符的最後一個字節是段基地址的第二部分:24-31位1516    dw 0x000ffff    ;段限制:0-15位17    dw 0x0000000    ;段基地址:0-15位18    db 0x0000000    ;段基地址:16-23位19    db 10010010b    ;段描述符的第6字節屬性(數據段可讀寫)20    db 11001111b    ;段描述符的第7字節屬性:limit(位16-19)21    db 0x0000000    ;段描述符的最後一個字節是段基地址的第二部分:24-31位2223gdt:24    dw gdt - gdt_head - 125    dd gdt_head/<code>

數字後綴b表示二進制。關於GDT的填寫,註釋已經寫得很詳細了,可以參考上一篇文章Intel的全局描述符示意圖來理解。此時已經完成了GDT的初始化,接下來打開A20地址線。

讀端口用in指令,寫端口用out指令。有個規定就是在92h端口,如果al的二進制第二位是1則打開,反之關閉:

<code> 1... 2    lgdt[gdt]  3 4enable_A20: 5    in al,0x92 6    or al,10b         ;一般直接寫2 7    out 0x92,al 8 9    cli1011gdt_head:12.../<code>

然後就是設置PE位,跳轉到保護模式:

<code> 1... 2    out 0x92,al 3 4    cli 5 6set_PE: 7    mov eax,cr0 8    or eax,1 9    mov cr0,eax1011entry_to_protection_mode:12    jmp dword 0x8:flush13...14    dd gdt_head1516[bits 32]17;這裡已經是32位模式了,nasm就會編譯成32位的代碼18flush:/<code>

此時我們要驗證保護模式是否真正開啟,需要向顯存寫入信息,但是這次我們不需要再偏移地址了,直接0xb8000就行:

<code>1flush:2    mov dword [0xb8000+160+0],'P'3    mov dword [0xb8000+160+1],0x2f45    jmp $    ;在這停止,cpu進入睡眠模式6    hlt78times 4096-($-$$) db 0    ;對齊內存/<code>

這回截個圖:

操作系統開發之——Loader程序編寫(2)

進入保護模式之後,很多事情就方便做了。今天先這樣。


分享到:


相關文章: