代码是从于渊的书上抄过来的,不过书的注释简单得实在不行,加上汇编都差不多给回学校了,看了好几遍才把这些代码看透。看到虚拟机的屏幕上输出个”P”感觉不错 :) 。
从实模式到保护模式一般的过程为:
- 建立起合适的全局描述符表。
- 用lgdt加载GDTR,使GDTR指向GDT。
- 打开A20地址线。PC及其兼容机的第20根地址线较特殊,计算机系统中一般安排一个“门”控制该地址线是否有效。为了访问地址在1M以上的存储单元,应先打开控制地址线A20的“门”。这种设置与实方式下只使用最的1M字节存储空间有关,与处理器是否工作在实方式和保护方式无关,即使在关闭地址线A20时,也可进行保护方式。
- 置cr0的PE位。PE位为1表示运行在保护模式,为0表示运行在实方式。
- 跳转,进入保护模式。
简单的切换代码如下(这个asm的着色是自己加上去的,着色得有点丑陋:)):
%macro Descriptor 3
dw %2 & 0FFFFh ;; segment limit 1
dw %1 & 0FFFFh ;; segment base 1
db (%1 >> 16) & 0FFh ;; segment base 2
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ;; properties1 + segment limit 2 + properties2
db (%1 >> 24) & 0FFh ;; segment base 3
%endmacro
;; descriptor type
DA_32 equ 4000h ;; 32 bits segment,D位设为1
;; descriptor type of data segment
DA_DRW equ 92h ;; accessed & readable
DA_C equ 98h ;; accessed & code segment
org 07c00h ;;将这段程序加载到内存偏移地址0x7c00处 ,即引导代码的开始处
jmp LABEL_BEGIN
[SECTION .gdt]
;; GDT 全局描述符表
;; base limit attr
LABEL_GDT: Descriptor 0, 0, 0 ;; void descriptor, gdt表第一个元素需为0
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ;; unconforming code segment
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0FFFFh, DA_DRW ;; addr of video memory,文本显示模式下显储地址空间的段值是B800h
;; end GDT
GdtLen equ $ - LABEL_GDT ;; GDT length
GdtPtr dw GdtLen - 1 ;; GDT limit
dd 0 ;; GDT base addr
;; GDT selector,selector是一个索引
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
;; initialize descriptor of 32bits code segment
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32 ;;实模式下求得LABEL_SEG_CODE32的地址值
mov word [LABEL_DESC_CODE32 + 2], ax ;;将实模式下求得的LABEL_SEG_CODE32地址赋给LABEL_DESC_CODE32描述符
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah
;; prepare for loading gdtr
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT ;; eax < - gdt base addr
mov dword [GdtPtr + 2], eax ;; [GdtPtr + 2] <- gdt base addr
;; load GDTR
lgdt [GdtPtr]
;; close interupt
cli
;; open addr bus A20
in al, 92h
or al, 00000010b
out 92h, al
;; prepare for swithing to pmode,cr0的PE位设为1,表示在保护模式下运行
mov eax, cr0
or eax, 1
mov cr0, eax
;; jmp into pmode,32位的跳转
jmp dword SelectorCode32:0
;; END of [SECTION .s16]
[SECTION .s32]
[BITS 32]
LABEL_SEG_CODE32:
mov ax, SelectorVideo
mov gs, ax
mov edi, (80 * 11 + 79) * 2 ;; row 11, col 79
mov ah, 0Ch
mov al, 'P'
mov [gs:edi], ax
;; stop here
jmp $
SegCode32Len equ $ - LABEL_SEG_CODE32
;; END of [SECTION .s32]
怎么没有解释啊