实地址模式与保护模式之间的切换

9.1  实地址模式与保护模式之间的切换

 

我们知道,IA-32计算机在加电或者Reset信号有效之后,首先进入实地址模式,执行BIOS程序,然后再进入保护模式,执行Windows环境下的程序。因此,IA-32 CPU在工作的时候,需要从实地址模式切换到保护模式。从实地址模式切换到保护模式,通常需要建立描述符表(descriptor table),设置控制寄存器CR0的PE位,如例9.1所示。

 

例9.1  IA-32 CPU从实地址模式切换到保护模式,然后又切换回实地址模式。

;

;IA-32 CPU enters into protected mode from real address mode,

;a string is displayed on the screen, IA-32 CPU returns into real

;address mode from protected mode.

;

.386p

.model   small,c

.stack   100h

;

Descriptor      STRUCT

  limit         word     0

  basel         word     0

  basem         byte     0

  attrib        word     0

  baseh         byte     0

Descriptor      ENDS

;

Data            Segment  use16

;

gdt0          Descriptor <>

;

DataSel       equ      $-gdt0

DataDes       Descriptor <0ffffh,,,92h,>

;

CodeSel       equ      $-gdt0

CodeDes       Descriptor <0ffffh,,,98h,>

;

VideoSel      equ      $-gdt0

VideoDes      Descriptor <0ffffh,8000h,0Bh,92h,>

;

GdtLen        equ      $-gdt0

;

GdtPtr        word     GdtLen

dword    0

;

Mess          byte     ‘IA-32 CPU is in Protected Mode.’,0

;

JmpTable      dword    0

;

Data            ends

;

Code            Segment  use16

    assume cs:Code,ds:Data

;

Start:          xor      eax,eax          ;Clear eax.

;

mov      ax,Data          ;Initialize DS.

mov      ds,ax            ;

;

;Prepare for entering into protected mode.

;

shl      eax,4          ;create base address for data segment

;

mov      dword ptr [GdtPtr+2],eax ;Base address for load GDTR

;

mov      DataDes.basel,ax ;Fill base address for data segment

shr      eax,16           ;into data segment descriptor.

mov      DataDes.basem,al ;

mov      DataDes.baseh,ah ;

;

xor      eax,eax              ;Fill base address for code segment

mov      ax,Code          ;into code segment descriptor.

shl      eax,4            ;

mov      CodeDes.basel,ax ;

shr      eax,16           ;

mov      CodeDes.basem,al ;

mov      CodeDes.baseh,ah ;

;

lgdt     fword ptr GdtPtr ;Load GDTR

;

cli                      ;Disable interrupt.

mov      eax,cr0            ;SetPE of CR0 into 1.

or       eax,1

mov      cr0,eax

;

mov      dx,CodeSel     ;Use “jmp far ptr [esi]” to flush

shl      edx,16         ;instruction prefetch queue.

mov      dx,offset Code16

mov      JmpTable,edx

lea      esi,JmpTable

jmp      far ptr [esi]

;

;Enter into protected mode.

;

Code16:         mov      ax,DataSel   ;The string is displayed on the screen.

mov      ds,ax

mov      ax,VideoSel

mov      es,ax

mov      si,offset Mess

mov      di,80*46+48

mov      ah,47h

Load:           mov      al,[si]

inc      si

cmp      al,0

jz       ReadyToRmode

mov      es:[di],ax

add      di,2

jmp      Load

;

;Prepare for returning to real address mode.

;

ReadyToRmode:   mov      eax,cr0        ;Clear PE of CR0.

and      eax,0fffffffeh

mov      cr0,eax

;

mov      dx,seg Rmode   ;Use “jmp far ptr [esi]” to flush

shl      edx,16         ;instruction prefetch queue.

mov      dx,offset Rmode

mov      JmpTable,edx

lea      esi,JmpTable

jmp      far ptr [esi]

;

;Return to real address mode.

;

Rmode:          sti                     ;Set IF.

;

mov      ax,Data        ;Initialize DS and ES.

mov      ds,ax

mov      es,ax

;

mov      ax,4c00h       ;Retire.

int      21h

;

Code            ends                    ;Code segment is over.

;

                end      Start          ;The source program is over.

课堂练习:对于例9.1中所示的程序,我们可以在MASM 6.11环境下进行汇编和链接,然后运行并观察其结果:

A.  启动PWB。

B.  更改设置:点Options,在弹出的选单上选中Build Options,在弹出的Build Options窗口中选中Use Release Options,点OK。

C.  打开源程序文件sam9-1.asm,建立可执行程序sam9-1.exe。注意,请不要进入CodeView环境去运行sam9-1.exe。

D.  重启计算机,根据计算机的不同,进行适当操作,使其进入MS-DOS方式。

E.  在MS-DOS方式下,运行sam9-1.exe,即可看到在屏幕上显示出的字符串。

现在对例9.1中所示程序的工作原理进行分析:

1.  声明结构类型Descriptor

保护模式下的段寄存器:其内容不再是段的基地址,而是称之为选择符(selector),其功能在于从全局段描述符表(Global Descriptor Table,GDT)或者局部段描述符表(Local Descriptor Table,LDT)中选出一个段描述符。选择符的字段结构如表9.1所示。

表9.1  选择符的字段结构

b15~b3

b2

b1~b0

Index

TI

RPL

选择符的位b1~b0称之为请求特权级(Requested Privilege Level,RPL)。RPL的数字必须小于当前特权级(Current privilege level,CPL)的数字,才可以访问某个段的数据。CPL是当前正在执行的任务所具有的特权级,也就是段寄存器CS和SS中b1~b0所具有的数字。另外,段描述符的访问权限字节(字节5)的b6~b5称之为段描述符特权级(Descriptor privilege level,DPL)。DPL、CPL、RPL是Windows操作系统中保护机制的重要基础。

TI位:为0时,说明段描述符在GDT中,应该访问GDT;为1时,说明段描述符在LDT中,应该访问LDT。

Index:利用它可以从GDT或者LDT中选出一个段描述符。具体作法是,由CPU硬件首先把Index的值乘以8,然后把乘积加到段描述符表的基地址上。段描述符表的基地址和限长分别存在全局段描述符表寄存器(Global Descriptor Table Register,GDTR)和局部段描述符表寄存器(Local Descriptor Table Register,LDTR)中。

GDT和LDT都放在内存中,由Windows操作系统维护。通常,系统任务的段描述符存放在GDT中,用户任务的段描述符存放在LDT中。每个段描述符表包含8192( )个段描述符。

GDT和LDT中的段描述符可以认为是一种数据结构,每个段描述符具有8个字节的长度,其结构如表9.2所示。

表9.2  段描述符的结构

字节7

字节6

字节5

字节4~2

字节1~0

基址b31~b24

控制位

段限b19~b16

访问权限

基址b23~b0

段限b15~b0

           

在例9.1中,所声明的结构类型Descriptor与表9.2所示的段描述符结构是完全一致的。

2.  关于完全段

本例中的数据段和代码段都使用了完全段来定义。原因在于只有使用完全段才可以实现在保护模式下,定义16位段的功能。

3.  数据段

定义结构变量必须在数据段中,而声明结构类型则可不必在数据段中。

gdt0:NULL段描述符,Windows操作系统要求第一个段描述符必须定义为NULL。

DataSel:定义数据段选择符。

DataDes:定义数据段描述符,基地址需用指令填充。

CodeSel:定义代码段选择符。

CodeDes:定义代码段描述符,基地址需用指令填充。

VideoSel:定义视频缓冲区段选择符。

VideoDes:定义视频缓冲区段描述符。

GdtLen:全局段描述符表限长。

GdtPtr:指向全局段描述符表限长和基地址的指针。

Mess:进入保护模式后显示在屏幕上的字符串。

JmpTable:在jump指令的间接寻址方式下,用来存放转移目标地址。

4.  代码段:初始化DS,建立数据段基地址,建立用来装入GDTR的基地址,把数据段基地址填入数据段描述符,把代码段基地址填入代码段描述符。

5.  代码段:装全局描述符表寄存器指令

该指令助记符用“LGDT”表示,其功能是把内存数据段中的GDT的限长和基地址装入GDTR。

GDTR的字段结构如表9.3所示。

表9.3  GDTR的字段结构

b47~b16

b15~b0

GDT的基地址

GDT的限长

LGDT指令只需要一个操作数。由表9.3知道GDTR的长度具有6个字节,所以其操作数的类型也应该是6个字节。LGDT指令的形式和操作列在表9.4中。

表9.4  LGDT指令的形式和操作

汇编语句格式

编码示例

寻址方式与操作

LGDT m16&32

LGDT     fword ptr GdtPtr

直接寻址

注:在表9.4中,m代表memory,ptr代表pointer,以下同。

LGDT指令只能由操作系统使用,用户程序不能使用。通常,LGDT指令运行在实地址模式下,以便于CPU在切换到保护模式以前能够执行初始化操作。

6.  代码段:关中断,设置CR0的PE位,清除指令预取队列

用cli指令关中断。

控制寄存器(Control Register,CR)CR0具有32位的长度,其b0为保护模式允许位(Protection Enable,PE)。当该位为1时,允许CPU工作在保护模式下;当该位为0时,禁止CPU工作在保护模式下。系统加电启动时,该位被置0。

用“jmp far ptr [esi]”指令,执行一个无条件转移,以便于清除指令预取队列,保证顺利地进入保护模式。此处jmp指令使用了间接寻址方式,方法是:首先把转移目标地址存入内存数据段变量JmpTable中,然后把JmpTable的偏移量传送到esi中,最后执行一个以esi内容为指针的far转移。

7.  代码段:进入保护模式

在屏幕上显示字符串“IA-32 CPU is i.n Protected Mode.”。此处采用直接写显示缓冲区的方法。

显示缓冲区的基地址:实地址模式下为B8000H(以物理地址形式表示),保护模式下为000B8000H(以物理地址形式表示)。

指定屏幕上的显示坐标:mov      di,80*46+48。屏幕上可显示字符的容量为24行×80字符。在显示缓冲区中,每个字符用两个字节来表示,高字节表示颜色与属性,低字节存储字符的ASCII代码。

指定屏幕上的显示属性:mov      ah,47h,请参考MASM 6.11的联机帮助。

8.  代码段:准备返回到实地址模式

清除CR0的PE位,以便于CPU能够工作在实地址模式下。

用“jmp far ptr [esi]”指令,执行一个无条件转移,以便于清除指令预取队列,保证顺利地返回到实地址模式。

9.  代码段:返回到实地址模式

设置ds和es,返回到系统。

课堂练习:调节屏幕显示坐标和颜色与属性。

原文地址:https://www.cnblogs.com/wanghj-dz/p/3975107.html