保护模式
从80286开始,X86系列的CPU提供了保护模式。所谓保护模式,是指CPU提供各种机制对内存进行保护。为照顾专门为8086编写的程序的兼容性,又提供了实模式,当计算机启动时即进入这种模式。要进入保护模式,必须先经过软件的切换,在后面讲述切换入保护模式的步骤。
1. 保护模式特点
在保护模式下,段寄存器CS、DS、ES、FS、GS、SS的意义不同于实模式,它里面放的不再是段基地址,而是指向一个表中的某项的指针,叫选择子。这个表可以是全局描述符表(GDT)或局部描述符表(LDT)。另处还有一个中断描述符表(IDT)。GDT或LDT由寄存器GDTR或GDTR指出,它们已在前面讲过,这里不再重述。GDT或LDT中的内容可以是描述符或门。
保护模式是80386最常用的模式,该模式提供了多任务环境中的各种复杂功能以及对复杂存储器组织的管理机制。只有在保护模式下,80386才能发挥其强大的功能和本性。保护模式有以下特点:
1)存储器用虚拟地址空间、线性地址空间和物理地址空间三种方式来描述,虚拟地址也就是逻辑地址。
2)程序员可以使用的存储空间称为逻辑地址空间,CPU借助于存储器管理部件的功能,将磁盘等存储设备有效地影射到内存,使逻辑地址空间大大超过实际的物理地址空间,这样使主存储器容量似乎非常大,其逻辑存储空间为64兆兆字节。
3)在保护模式下可以使用4级保护功能,由此实现程序与程序之间、用户与操作系统之间的隔离和保护,为多任务操作系统提供优化支持。
2. 进入保护模式
进入保护模式首先要做的是建立系统表格,至少必须建立全局描述符表GDT。这是因为分段的信息放在GDT中,而系统寻址必须通过分段的方式。即使是使用局部描述符表LDT,LDT的地址和界限等信息也放在GDT中。
建立起GDT及其它一些系统表格(如果有必要的话)后,就可以用LGDTR等指令来把GDT的地址及界限装入GDTR中,然后把CR0的PE(保护模式功能)位置1。这时需要用一个远程转指令JMP XXXX:XXXX来摆脱指令预取队列。这样,系统就进入保护模式,可以用保护模式下的段寻址方式进行寻址了。
下面的程序演示了进入保护模式的过程。
程序开始时建立GDT表。注意GDT表的第一项是不能使用的,即选择子的索引值为0且第2位也为0时,若用它来寻址则会引起异常。这种选择子称为空选择子。
例5.4 编写一程序,进入保护模式,并且显示字符串“Now Is In Protect Mode.”。
进入保护模式后,实模式下的中断就不能用了,不能通过调用DOS或BIOS中断来显示。本程序用直接写入显存地址的方法,把上面的字串写入地址B80000H,因此,在GDT中建立了一个以B8000H为基地址的段。
程序欲要回到实模式,与进入保护模式的过程差不多,首先把CR0的PE位置0,然后用一个长跳转摆脱指令预取队列。程序的具体代码如下:
.386p
;-----------------------------------------------------
JUMP16 MACRO selector,offsetv ;无条件转移宏指令
DB 0EAH ;0EAH为JMP指令代码
DW offsetv ;段偏移
DW selector ;段选择子
ENDM
;-----------------------------------------------------
Descriptor STRUC ;描述符结构体
limitl dw 0
basel dw 0
basem db 0
attrib dw 0
baseh db 0
Descriptor ENDS
;===============================
Data Segment use16
gdt0 Descriptor <> ;第0个全局描述符
DataSel = $-gdt0 ;数据段选择子
DataDes Descriptor <0ffffh,,,92H,> ;数据段描述符
CodeSel = $-gdt0 ;代码段选择子
CodeDes Descriptor <0ffffh,,,98H,> ;代码段描述符
VideoSel = $-gdt0 ;视频段选择子
VideoDes Descriptor <0ffffh,8000H,0BH,92H,> ;视频段描述符
GdtLen = $-gdt0
GdtPtr dw GdtLen ;全局描述符表寄存器值
dd 0
Mess db 'Now Is In Protect Mode.',0 ;显示信息
Data ends
;================================
Code Segment use16
assume cs:Code,ds:Data
Start:
xor eax,eax
mov ax,Data
mov ds,ax
shl eax,4
mov dword ptr [GdtPtr 2],eax
mov DataDes.basel,ax ;初始化数据段描述符
shr eax,16
mov DataDes.basem,al
mov DataDes.baseh,ah
xor eax,eax ;初始化代码段描述符
mov ax,Code
shl eax,4
mov CodeDes.basel,ax
shr eax,16
mov CodeDes.basem,al
mov CodeDes.baseh,ah
lgdt qword ptr GdtPtr ;Load GDTR
cli
mov eax,cr0 ;转到保护模式模式
or eax,1
mov cr0,eax
JUMP16 CodeSEL,<offset Code16>
Code16:
mov ax,DataSel ;设置数据段选择子
mov ds,ax
mov ax,VideoSel ;设置视频段选择子
mov es,ax
mov si,offset Mess
mov di,80*10
cld
mov ah,1eh
Load:
lodsb
cmp al,0
jz ReadyToReal
stosb
jmp Load
ReadyToReal: ;返回实模式
mov eax,cr0
and eax,0fffffffeh
mov cr0,eax
JUMP16 <seg Real>,<offset Real>
Real:
sti
mov ax,Data
mov ds,ax
mov es,ax
mov ax,4c00h
int 21h
Code ends
end Start