操作系统开发系列—2.进入32位保护模式
源碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | ; ========================================== ; pm.asm ; 編譯方法:nasm pm.asm -o pm.bin ; ========================================== %include??? "pm.inc"??? ; 常量, 宏, 以及一些說明 org 07c00h ????jmp LABEL_BEGIN [SECTION .gdt] ; GDT ;???????????????????????????????????????????????????????????????????????? 段基址,??????? 段界限???? ,????????????????????????????? 屬性 LABEL_GDT:??????????????????????? Descriptor????????? 0,??????????????? 0,???????????????????????????????????????? 0????????????????? ; 空描述符 LABEL_DESC_CODE32: Descriptor?????????? 0,???????????? SegCode32Len - 1,??? DA_C + DA_32?? ; 非一致代碼段 LABEL_DESC_VIDEO:??? Descriptor??? 0B8000h,???? 0ffffh,????????????????????????????? DA_DRW??????? ; 顯存首地址 ; GDT 結束 GdtLen????? equ $ - LABEL_GDT?? ; GDT長度 GdtPtr????? dw? GdtLen - 1? ; GDT界限 ????????????????????dd? 0?????? ; GDT基地址 ; GDT 選擇子 SelectorCode32????? equ LABEL_DESC_CODE32?? - LABEL_GDT SelectorVideo?????? equ LABEL_DESC_VIDEO??? - LABEL_GDT ; END of [SECTION .gdt] [SECTION .s16] [BITS?? 16] LABEL_BEGIN: ????mov ax, cs ????mov ds, ax ????mov es, ax ????mov ss, ax ????mov sp, 0100h ????; 初始化 32 位代碼段描述符 ????xor eax, eax ????mov ax, cs ????shl eax, 4 ????add eax, LABEL_SEG_CODE32 ????mov word [LABEL_DESC_CODE32 + 2], ax ????shr eax, 16 ????mov byte [LABEL_DESC_CODE32 + 4], al ????mov byte [LABEL_DESC_CODE32 + 7], ah ????; 為加載 GDTR 作準備 ????xor eax, eax ????mov ax, ds ????shl eax, 4 ????add eax, LABEL_GDT????? ; eax <- gdt 基地址 ????mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址 ????; 加載 GDTR ????lgdt??? [GdtPtr] ????; 關中斷 ????cli ????; 打開地址線A20 ????in? al, 92h ????or? al, 00000010b ????out 92h, al ????; 準備切換到保護模式 ????mov eax, cr0 ????or? eax, 1 ????mov cr0, eax ????; 真正進入保護模式 ????jmp dword SelectorCode32:0? ; 執行這一句會把 SelectorCode32 裝入 cs, ????????????????????; 并跳轉到 SelectorCode32:0? 處 ; END of [SECTION .s16] [SECTION .s32]; 32 位代碼段. 由實模式跳入. [BITS?? 32] LABEL_SEG_CODE32: ????mov ax, SelectorVideo ????mov gs, ax????????? ; 視頻段選擇子(目的) ????mov ecx, 28 ????mov edi, 0 ????mov bx, BootMessage .show: ????mov ah, 0Ch???????? ; 0000: 黑底??? 1100: 紅字 ????mov al, [bx] ????mov [gs:edi], ax ????inc edi ????inc edi ????inc bx ????loop .show ????; 到此停止 ????jmp $ BootMessage:??????? db? "Joey, I'm in protected mode!" SegCode32Len??? equ $ - LABEL_SEG_CODE32 ; END of [SECTION .s32] |
運行結果如下:
源碼解析:
1.首先程序跳轉至LABEL_BEGIN處,jmp LABEL_BEGIN。將ds、es、ss段寄存器全部初始化為當前代碼段。
2.初始化32位代碼段描述符
在實模式下,也就是8086的16位的CPU的尋址方式是段x16+偏移,而在保護模式下,段寄存器值變成了一個索引,這個索引指向段描述符,也就是GDT中對應的那個描述符,描述符中包含了最終的基地址。
?38-41行表示將當前程序代碼段左移4位也就是x16,再加上LABEL_SEG_CODE32的偏移地址,最終形成LABEL_SEG_CODE32的物理地址,42-45表示把此物理地址加載到段描述符對應的段基址位置,段描述符格式如下圖所示
段基地址0-15位也就是LABEL_DESC_CODE32 + 2地址處,將16位的ax傳入,第43行向右移動16位表示已經傳入的16位消除,然后將剩余的兩個8位高低寄存器值傳入對應的段基地址處。
Descriptor是在pm.inc中定義的宏,如下圖所示,表示的就是段描述符的格式:
3.加載GDTR,GDRT的結構圖如下所示
GDTR是唯一的一個指向段描述符表的寄存器,48-55行就是把段描述符表的基地址加載到GDTR寄存器當中。48行清除eax值,49-52是把LABEL_GDT的物理地址加載到20行的GdtPtr的雙字處,也就是GDT基地址。55行把GdtPtr地址的內容加載到GDTR,雙字節dw對應的是16位界限,雙字dd對應的是32位基地址。
4.關中斷和打開A20
保護模式下中斷處理機制和實模式不同,所以先關閉中斷,指令為cli。打開A20為歷史原因防止偏移超出最大值時回滾。58-63行
5.切換到保護模式
只要把寄存器cr0的第0位置為1就行了。66-68行
6.真正進入保護模式的代碼段
jmp dword SelectorCode32:0,這一行是真正進入保護模式的代碼,SelectorCode32是個段選擇子,段選擇子的作用是找到對應的段描述符從而找到對應的段基地址。段選擇子的格式如下圖所示
從位3開始表示為段描述符表的索引,這句代碼執行完之后就會把描述符LABEL_DESC_CODE32中的段基址也就是LABEL_SEG_CODE32加載到cs。
dword的作用是因為當前還是16位的代碼,如果沒有dword,SelectorCode32:0的偏移地址如果超出16位那么只會截取16位。
到此已經完全進入32位保護模式的代碼了。
7.顯示字符
接下來就會跳轉到LABEL_SEG_CODE32處運行指令了,80-81行把段選擇子SelectorVideo傳入段寄存器gs中,也就是描述符LABEL_DESC_VIDEO的段基地址0B8000h,這就是顯存的基地址。84行edi是顯存的偏移地址,87-88行是字符及字符屬性,89行為最終顯示字符。
8.描述符屬性
代碼段的屬性是DA_C + DA_32,根據pm.inc中的定義,DA_C是98h
對應的二進制為10011000。根據第2條的格式,DA_C其實是上面的第8-15位,第15位P是1表明這個段在內存中存在,S位是1表明這個段是代碼段或數據段,TYPE為1000也就是8表明這個段是只執行的代碼段,TYPE格式如下圖所示
DA_32是4000h,
4000h為100000000000000,表明是從上面的位8開始計算的后面15位也就是D/B位為1,表明這個段是32位的代碼段。
總結
以上是生活随笔為你收集整理的操作系统开发系列—2.进入32位保护模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NASM汇编程序中的宏定义
- 下一篇: 段选择符和段寄存器