1.前言
还是先来分析下保护模式的代码pmtest1.asm,要硬这头皮看这段代码,而且的搞明白了,后面的代码都是在此基础上扩展的,此代码是大致轮廓
2.代码分析
; ========================================== ; pmtest1.asm ; 编译方法:nasm pmtest1.asm -o pmtest1.bin ; ========================================== %include "pm.inc" ; 常量, 宏, 以及一些说明 org 07c00h ; 加载07c00h处cs=0000h,ip=07c00h(别人规定的)
jmp LABEL_BEGIN ; 跳转到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 ;32位代码段选择子 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 ;以上代码将当前的ds,es,ss全部指向cs代码段 mov sp, 0100h ;sp设置为0100h ; 初始化 32 位代码段描述符 xor eax, eax ;eax清0 mov ax, cs ;存入cs shl eax, 4 ;左移4位,扩展为20位地址 add eax, LABEL_SEG_CODE32 ;在cs的基础上加上LABEL_SEG_CODE32的地址偏移(相对于0)
mov word [LABEL_DESC_CODE32 + 2], ax ;将ax中的16位段地址移入描述符LABEL_DESC_CODE32对应的2~3字节 shr eax, 16 ;将eax的高16位移入低16位中 mov byte [LABEL_DESC_CODE32 + 4], al ;将al中的8位段地址移入描述符LABEL_DESC_CODE32对应的4字节中 mov byte [LABEL_DESC_CODE32 + 7], ah ;将ah中的8位段地址移入描述符LABEL_DESC_CODE32对应的7字节中 ; 为加载 GDTR 作准备 xor eax, eax ;eax清0 mov ax, ds ;ds移入ax shl eax, 4 ;扩展为20位 add eax, LABEL_GDT ; eax <- gdt 基地址 ds+gdt基地址 mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址 将gdt基地址移入GdtPtr中 ; 加载 GDTR lgdt [GdtPtr];将GdtPtr中的GDT界限和GDT基地址加载到寄存器gdtr中 ; 关中断 cli ; 打开地址线A20-----前面的段地址已经扩展位20位 in al, 92h or al, 00000010b out 92h, al ; 准备切换到保护模式 mov eax, cr0 ;加载cr0到eax or eax, 1 ;将cr0的PE置位1,打开保护模式 mov cr0, eax ;更改cr0 ; 真正进入保护模式 jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, ; 并跳转到 Code32Selector:0 处 SelectorCode32中段基址指向LABEL_SEG_CODE32偏移为0 ; END of [SECTION .s16] [SECTION .s32]; 32 位代码段. 由实模式跳入. [BITS 32] LABEL_SEG_CODE32: mov ax, SelectorVideo mov gs, ax ; 视频段选择子(目的) mov edi, (80 * 11 + 79) * 2 ; 屏幕第 11 行, 第 79 列。 mov ah, 0Ch ; 0000: 黑底 1100: 红字 mov al, 'P' mov [gs:edi], ax ; 到此停止 jmp $ SegCode32Len equ $ - LABEL_SEG_CODE32 ; END of [SECTION .s32]
3.编译
nasm pmtest1.asm –o pmtest1.bin
4.写入软盘
dd if=pmtest1.bin of=a.img bs=512 count=1 conv=notrunc
5. jmp dword SelectorCode32:0
保护模式下SelectorCode选择子对应的描述符为LABEL_DESC_CODE32,而我们之前已经将描述符的段基址初始化为指向LABEL_SEG_CODE32,
偏移为0,所以会跳转到LABEL_SEG_CODE32处执行.
6.进入保护模式的主要步骤
a.准备GDT
b.用lgdt加载gdtr
c.打开A20
d.置cr0的PE位
e.跳转,进入保护模式