80x86保护模式系列教程(4)实模式与保护模式切换实例

原创 2003年03月10日 10:24:00

四.实模式与保护模式切换实例

本文介绍两个实现实模式与保护模式切换的实例,通过他们说明如何实现实模式与保护模式的切换, 也说明保护模式下的80386及其编程。

<一>演示实模式和保护模式切换的实例(实例一)

实例一的逻辑功能是,以十六进制数的形式显示从内存地址110000H开始的256个字节的值。本实例指定该内存区域的目的仅仅是想说明切换到保护模式的必要性,因为在实模式下不能访问该指定内存区域,只有在保护模式下才能访问到该指定区域。
本实例的具体实现步骤是:(1)作切换到保护方式的准备;(2)切换到保护方式;(3)把指定内存区域的内容传送到位于常规内存的缓冲区中;(4)切换回实模式;(5)显示缓冲区内容。

1.包含文件

386保护模式汇编语言程序用到的包含文件如下所示,该包含文件在后面的程序中还要用到。









       
                    
                      
                      
                     
                     
                



      
                    
                      
                     
                     
                     
                



             Selector
                           
                         
                      Selector 
                





             Selector
                           
                      
                      
                      Selector 
                



             Selector
                            
                         
                      Selector 
                





             Selector
                            
                      
                      
                      Selector 
                



Desc            
LimitL                 
BaseL                  
BaseM                  
Attributes             
LimitH                 
BaseH                  
Desc            



Gate            
OffsetL                
Selector               
DCount                 
GType                  
OffsetH                
Gate            



PDesc           
Limit                  
Base                   
PDesc           



TSS             
TRLink                      
                            
TRESP0                      
TRSS0                       
                            
TRESP1                      
TRSS1                       
                            
TRESP2                      
TRSS2                       
                            
TRCR3                       
TREIP                       
TREFlag                     
TREAX                       
TRECX                       
TREDX                       
TREBX                       
TRESP                       
TREBP                       
TRESI                       
TREDI                       
TRES                        
                            
TRCS                        
                            
TRSS                        
                            
TRDS                        
                            
TRFS                        
                            
TRGS                        
                            
TRLDTR                      
                            
TRTrip                      
TRIOMap                   
TSS             



ATDR                  
ATDW                  
ATDWA                 
ATCE                  
ATCER                 
ATCCO                 
ATCCOR                



ATLDT                 
ATTaskGate            
AT386TSS              
AT386CGate            
AT386IGate            
AT386TGate            



DPL0                  
DPL1                  
DPL2                  
DPL3                  



RPL0                  
RPL1                  
RPL2                  
RPL3                  



IOPL0                 
IOPL1                 
IOPL2                 
IOPL3                 



D32                         
GL                          
TIL                         
VMFL                  
VMFLW                
IFL                   
RFL                   
RFLW                 
NTL                   



PL                        
RWR                       
RWW                       
USS                       
USU                       


2.实例源程序

实例一的源程序如下所示:


         SCD



EchoCh             ascii
                     
                     ascii
                     
                

DSEG                              

GDT                                  
DUMMY           Desc                        
            Desc    ATCE     
DataS           Desc    ATDW 
DataD           Desc    ATDW     

GDTLen                 GDT                 
VGDTR           PDesc   GDTLen           

Code_Sel               GDT              
DataS_Sel              DatasGDT             
DataD_Sel              DataDGDT             

BufLen                                    
Buffer                BufLen          

DSEG                                      

CSEG                              
                  :CSEG:DSEG

Start           
                     DSEG
                     
                
                     
                     
                      GDT          
                                        
                       VGDTRBase
                       VGDTRBase
                
                     
                     
                       BaseL 
                       BaseM 
                       BaseH
                
                     
                                          
                      Buffer
                     
                       DataDBaseL
                       DataDBaseM
                       DataDBaseH
                
                      VGDTR
                                            
                                      
                
                     
                      
                     
                
                  Code_Sel Virtual
        
                     DataS_Sel
                                       
                     DataD_Sel
                                       
                
                     
                                       
                     BufLen            
                    movsd                  
                
                     
                     
                     
                
                   Real Real
           
                
                
                     DSEG
                     
                      Buffer
                
                     BufLen
            
         
                    
                     
                    ToASCII
                EchoCh  
                     
                    ToASCII
                EchoCh  
                EchoCh  
                    NextCh
                EchoCh  
                EchoCh  
                     
                     NextLine
                     
                     
Start           

ToASCII         
                     
                     
                
                     
                
                
ToASCII         

CSEG                                       

                     Start

3.关于实例步骤的注释

在源程序的开头首先包含了文件“386SCD.INC”,在此包含文件中定义了保护模式程序设计要用到的一些结构、宏及常量。下面对各实现步骤作些说明。

(1)切换到保护方式的准备工作

在从实模式切换到保护模式之前,必须作必要的准备。准备工作的内容根据实际而定。最起码的准备工作是建立合适的全局描述符表,并使用GDTR指向该GDT。因为在切换到保护方式时,至少要把代码段的选择子装载到CS,所以GDT中至少含有代码段的描述符。
从本实例源程序可见,全局描述符表GDT仅有四个描述符:第一个是空描述符;第二个是代码段描述符;第三个和第四个分别为源数据段及目标数据段描述符。本实例各描述符中的段界限是在定义时设置的,并且除伪描述符VGDTR中的界限按GDT的实际长度设置外,各使用的存储段描述符的界限都规定为0FFFFH。另外,描述符中的段属性也根据所描述段的类型被预置,各属性的定义在包含文件386SCD.INC中均有说明。从属性值可知,这三个段都是16位段。
由于在切换到保护方式后就要引用GDT,所以在切换到保护方式前必须装载GDTR。实例中使用如下指令装载GDTR:
       VGDTR
该指令的功能是把存储器中的伪描述符VGDTR装入到全局描述符表寄存器GDTR中。伪描述符VGDTR的结构如前所述结构类型PDESC所示,低字是以字节位单位的全局描述符表段的界限,高双字为描述符表段的线性基地址(本实例不启用分页机制,所以线性地址等同于物理地址)。本实例中未涉及到局部描述符表及中断描述符表,后面的文章将作详细说明。

(2)由实模式切换到保护模式

在做好准备后,从实模式切换到保护模式并不难。原则上只要把控制寄存器CR0中的PE位置1即可。本实例采用如下三条指令设置PE位:
         
          
         
实际情况要比这复杂些。执行上面的三条指令后,处理器转入保护模式,但CS中的内容还是实模式下代码段的段值,而不是保护模式下代码段的选择子,所以在取指令之前得把代码段的选择子装入CS。为此,紧接着这三条指令,安排一条如下所示的段间转移指令:
    JUMP16  Code_Sel Virtual
这条段间转移指令在实模式下被预取并在保护方式下被执行。利用这条段间转移指令可把保护模式下代码段的选择子装入CS,同时也刷新指令预取队列。从此真正进入保护模式。

(3)由保护模式切换到实模式

在80386上,从保护模式切换到实模式的过程类似于从实模式切换到保护模式。原则上只要把控制寄存器CR0中的PE位清0即可。实际上,在此之后也要安排一条段间转移指令,一方面清指令预取队列,另一方面把实模式下代码段的段值送CS。这条段间转移指令在保护方式下被预取并在实模式下被执行

(4)保护模式下的数据传送

首先,把源数据段和目标数据段的选择子装入DS和ES寄存器,这两个描述符已在实模式下设置好,把选择子装入段寄存器就意味着把包括基地址在内的段信息装入到了段描述符高速缓冲寄存器。然后设置指针寄存器SI和DI的初值,也设置计数器CX的初值。根据预置的段属性,在保护方式下,代码段也仅是16位段,串操作指令只使用16位的SI、DI和CX等寄存器。最后利用串操作指令实施传送。

(5)显示缓冲区中的内容

由于缓冲区在常规内存中,所以在实模式下根据要求按十六进制显示其内容是很容易理解的,这里就不再多说。

4.内存映象

在源程序中没有把GDT作为一个单独的段对待,但在进入保护方式后,它是一个独立的段。从对代码段和源数据段描述符所赋的基地址和段界限值可见,代码段和数据段有部分覆盖。尽管这样做不利于代码和数据的安全,但如果需要,这样做是可行的。本实例运行时的内存映象如下图所示。

5.特别说明

作为第一个实模式和保护模式切换的例子,本实例作了大量的简化处理。
通常,由实模式切换到保护模式的准备工作还应包含建立中断描述符表。但本实例没有建立中断描述符表。为此,要求整个过程在关中断的情况下进行;要求不使用软中断指令;假设不发生任何异常。否则会导致系统崩溃。
本实例未使用局部描述符表,所以在进入保护模式后没有设置局部描述符表寄存器LDTR。为此,在保护模式下使用的段选择子都指定GDT中的描述符。
本实例未定义保护模式下的堆栈段,GDT中没有堆栈段描述符,在保护模式下没有设置SS,所以在保护方式下没有涉及堆栈操作的指令。
本实例各描述符特权级DPL和各选择子的请求特权级RPL均为0,在保护方式下运行时的当前特权级CPL也是0。
本实例没有采用分页管理机制,也即CR0中的PG位为0,线性地址就是存储单元的物理地址。

6.打开和关闭地址线A20

PC及其兼容机的第21根地址线(A20)较特殊,计算机系统中一般安排一个 “门”控制该地址线是否有效。为了访问地址在1M以上的存储单元,应先打开控制地址线A20的“门”。这种设置与实模式下只使用最低端的1M字节存储空间有关,与处理器是否工作在实模式或保护方式无关,即使在关闭地址线A20时,也可进入保护模式。
如何打开和关闭地址线A20与计算机系统的具体设置有关。在本文中介绍的包含文件386SCD.INC中定义了两个宏,打开地址线A20的宏EnableA20和关闭地址线A20的宏DisableA20,此两个宏指令在一般的PC兼容机上都是可行的。

<二>演示32位代码段和16位代码段切换的实例(实例二)

实例二的逻辑功能是,以十六进制数和ASCII字符两种形式显示从内存地址100000H开始的16个字节的内容。
从功能上看,本实例类似于实例一,但在实现方法上却有了改变,它更能反映出实模式和保护模式切换的情况。具体实现步骤是:(1)作切换到保护方式的准备;(2)切换到保护方式的一个32位代码段;(3)把指定内存区域的内容以字节为单位,转换成对应的十六进制数的ASCII码,并直接填入显示缓冲区实现显示;(4)再变换到保护方式下的一个16位代码段;(5)把指定内存区域的内容直接作为ASCII码填入显示缓冲区中实现显示;(6)切换回实模式。

1.实例二源程序

实例二的源程序如下所示:


         SCD

DSEG                                  

GDT                                      
DUMMY           Desc                            
Normal          Desc    ATDW         
Code32          Desc    C32LenATCED32    
Code16          Desc    ATCE         
DataS           Desc    DataLenATDR  
DataD           Desc    ATDW   
Stacks          Desc    StackLenATDW     

GDTLen                 GDT                     
VGDTR           PDesc   GDTLen               

SaveSP                                         
SaveSS                                         

Normal_Sel             NormalGDT                
Code32_Sel             Code32GDT                
Code16_Sel             Code16GDT                
DataS_Sel              DatasGDT                 
DataD_Sel              DataDGDT                 
Stacks_Sel             StacksGDT                

DataLen                

DSEG                                          

StackSeg           
StackLen               
                      StackLen 
StackSeg        

CSEG1                           
                  :CSEG1:DSEG

Start           
                     DSEG
                     
                
                     
                     
                      GDT             
                                           
                       VGDTRBase
                       VGDTRBase
                
                     CSEG2
                     
                       Code32BaseL
                       Code32BaseM
                       Code32BaseH
                
                     CSEG3
                     
                       Code16BaseL  
                       Code16BaseM  
                       Code16BaseH
                
                     
                       SaveSS
                       SaveSP
                     StackSeg
                     
                       StacksBaseL
                       StacksBaseM
                       StacksBaseH
                
                      VGDTR
                                               
                                         
                
                     
                      
                     
                
                  Code32_Sel SPM32
         
                     DSEG
                     
                     SaveSP
                     SaveSS
                
                
                     
                     
Start           

CSEG1                                         

CSEG2             
                  :CSEG2

SPM32           
                     Stacks_Sel
                     
                     StackLen
                     DataS_Sel
                     
                     DataD_Sel
                     
                     
                     
                     DataLen
                
           
                    
                    ToASCII
                     
                     
                     
                     
                    ToASCII
                     
                
                     
                
                    Next
                   Code16_Sel SPM16
SPM32           

ToASCII         
                     
                     
                     
                     Isdig
                     
          
ToASCII         

C32Len                 

CSEG2           

CSEG3             
                  :CSEG3

SPM16           
                     
                     DataLen
                     
                     DataLen
          
                
                    AGain
                     Normal_sel
                     
                     
                     
                     
                     
                     
                       ToReal
SPM16           

CSEG3           

                     Start

2.关于实现步骤的注释

(1)切换到保护模式的准备工作

建立全局描述符表,这里的全局描述符表含有两个16位数据段的描述符、一个16位代码段的描述符和一个16位的堆栈段描述符。此外,GDT中还有一个32位的代码段描述符,描述32位代码段,该描述符的属性字段中的D位为1。

(2)由实模式切换到保护模式

由实模式切换到保护模式32位代码段的方法与切换到16位代码段的方法相同。由保护模式16位代码段切换回实模式的方法与实例一相似。
在保护模式下,通过如下直接段间转移指令从32位代码段切换到16位代码段:
    JUMP32   Code16_Sel SPM16
从该宏指令的定义可知,该转移指令含48位指针,其高16位是16位代码段的选择子,低32位是16位代码段的入口偏移。该指令在32位方式下预取并执行。由于在32位方式下执行,所以要使用48位指针。

(3)显示指定内存区域的内容

在本实例中,采用直接写显示缓冲区的方法实现显示。假设显示缓冲区的开始物理地址是0B8000H, 3号文本显示模式,在屏幕的第一行进行显示。

3.特别说明

本实例在保护方式下使用了涉及堆栈操作的指令,因此建立了一个16位的保护模式下的堆栈段。
本实例仍作了大量的简化处理。如:没有建立IDT和LDT等,各特权级均是0。也没有采用分页管理机制。
从本实例的GDT中可见,两个数据段的界限都是根据实际大小而设置的。从源程序代码段CSEG3可见,在切换到实模式之前,把一个指向似乎没有用的数据段的描述符Normal的选择子装载到DS和ES。这是为什么呢?


 

实模
式下
段描
述符
高速
缓冲
寄存
器的
内容
段寄存器 段基地址 段界限(固定) 段属性(固定)
存在性 特权级 已存取 粒度 扩展方向 可读性 可写性 可执行 堆栈大小 一致特权
CS 当前CS*16 0000FFFFH Y 0 Y B U Y Y Y - N
SS 当前SS*16 0000FFFFH Y 0 Y B U Y Y N W -
DS 当前DS*16 0000FFFFH Y 0 Y B U Y Y N - -
ES 当前ES*16 0000FFFFH Y 0 Y B U Y Y N - -
FS 当前FS*16 0000FFFFH Y 0 Y B U Y Y N - -
GS 当前GS*16 0000FFFFH Y 0 Y B U Y Y N - -


 

在分段管理机制一文中已介绍过,每个段寄存器都配有段描述符高速缓冲寄存器,这些高速缓冲寄存器在实方式下仍发挥作用,只是内容上与保护模式下有所不同。如上表所示,其中“Y”表示“是”; “N”表示“否”;“B”表示字节;“U”表示向上扩展,“W”表示以字方式操作堆栈。段基地址仍是 32位,其值是相应段寄存器值(段值)乘以16,在把段值装载到段寄存器时刷新。由于其值是16位段值乘上16,所以在实模式下基地址实际上有效位只有20位。每个段的32位段界限都固定为0FFFFH,段属性的许多位也是固定的。所谓固定是指在实方式下不可设置这些属性值,只能继续沿用保护方式下所设置的值。因此,在准备结束保护模式回到实模式之前,要通过加载一个合适的描述符选择子到有关段寄存器,以使得对应段描述符高速缓冲寄存器中含有合适的段界限和属性。本实例GDT中的描述符Normal就是这样一个描述符,在返回实模式之前把对应选择子Normal_Sel加载到DS和ES就是此目的。由于SS段描述符中的内容已符合实模式的需要,所以尽管也改变了SS,但不需要重新加载SS(本实例中重新加载了SS,这除了稍增加运行时间外,并没有什么坏处)。16位代码段描述符中的内容也符合实模式的需要,所以在通过16位代码段返回实模式时,CS段描述符中的内容也符合实模式的要求。需要注意的是,不能从32位代码段返回实模式,这是因为无法实现从32位代码段返回时CS高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)。顺便说以下,实例一中的描述符都是符合实模式要求的。段描述符高速缓冲寄存器中含有合适的段界限

4.关于32位代码段程序设计的说明

在32位代码段中,缺省的操作数大小是32位,缺省的存储单元地址大小是32位。由于串操作指令使用的指针寄存器是ESI和EDI,LOOP指令使用的计数器是ECX,所以,在代码段CSEG2中,为了使用串操作指令,对ESI和EDI等寄存器赋初值。请比较代码段CSEG3中的相关片段和实例一中的相关片段,它们是16位代码段。


 

参考资料 书        名 出  版  社 作    者
《保护方式下的80386及其编程》 清华大学出版社 周明德主编
《80X86汇编语言程序设计教程》 清华大学出版社 扬季文主编




 

80x86寻址方式 -- 实模式和保护模式

首先实模式和保护模式是CPU的两种工作模式。一开始PC启动时CPU是工作在实模式下的,经过某种机制后,CPU跳转到保护模式。         Intel 8086是16位CPU,它只有16位寄存器、...
  • u012243115
  • u012243115
  • 2015年06月03日 21:26
  • 827

linux内核 80x86保护模式及其编程

这一章涉及intel8086系列cpu的保护模式编程,应该是学习内核编程,驱动编程及嵌入式编程一些基础知识。不过对于没接触过底层编程的我来说,感觉还是好复杂。   不过里面也有许多以前汇编学过的东西...
  • yishuige
  • yishuige
  • 2015年12月30日 15:06
  • 868

80x86处理器保护模式下的分段机制

(本文为《深入理解Linux内核》笔记) 对于80x86处理器,我们要区分以下三种地址: 逻辑地址:由段地址和段内偏移两部分组成。 线性地址(虚拟地址):将逻辑地址进行解释得到的地址形式,...
  • imred
  • imred
  • 2016年02月13日 16:37
  • 834

80x86保护模式系列教程(4)实模式与保护模式切换实例

转自:http://www.chinaitpower.com/A/2001-12-10/7366.html本文介绍两个实现实模式与保护模式切换的实例,通过他们说明如何实现实模式与保护模式的切换, 也说...
  • redchairman
  • redchairman
  • 2011年04月23日 21:17
  • 633

(实模式+保护模式)模式切换的过程步骤(代码+文字解析)

【0】写在前面文末的个人总结是干货,前面代码仅供参考的,且source code from orange’s implemention of a os. ; ================...
  • PacosonSWJTU
  • PacosonSWJTU
  • 2015年08月26日 20:03
  • 1584

CPU的实模式与保护模式(简介)

16位微处理器 8086寄存器组成 8086/8088包括:4个16位的数据寄存器,2个16位的指针寄存器,2个16位变址寄存器,分成四组。 通用寄存器中,这些寄存器除完成规定的专门用途外,...
  • yang_yulei
  • yang_yulei
  • 2014年03月30日 23:35
  • 8128

80X86的物理地址形成(实模式+保护模式)——段式寻址

1.实模式 80X86系列CPU中,最早的是8086,它有20根地址线,可以寻址1MB(2^20)内存空间。 很自然地,如果CPU要跟主存交换信息,它也必须有20位的物理地址,但是,8086CPU...
  • rongwenbin
  • rongwenbin
  • 2014年02月08日 18:03
  • 757

实模式和保护模式中断机制的简单对比与一点硬件细节

和实模式相比,保护模式下的中断处理有两点最大的区别。首先,中断向量表可以在内存中自由浮动。其次,中断的功能获得了拓展。     在实模式下,中断向量表占据内存最低的1KB,共256个表项。每个表项4...
  • zhd19910223
  • zhd19910223
  • 2014年12月21日 10:55
  • 938

保护模式和实模式的区别

   实模式:寻址采用和8086相同的16位段和偏移量,最大寻址空间1MB,最大分段64KB。可以使用32位指令。32位的x86 CPU用做高速的8086。  保护模式:寻址采用32位段和偏移量,最大...
  • bichenggui
  • bichenggui
  • 2009年06月01日 15:16
  • 7270

x86 实模式与保护模式

0386开始,CPU有三种工作方式:实模式,保护模式和虚拟8086模式。只有在刚刚启动的时候是real-mode,等到操作系统运行起来以后就切换到protected-mode。实模式只能访问地址在1M...
  • wrx1721267632
  • wrx1721267632
  • 2016年07月26日 16:25
  • 1703
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:80x86保护模式系列教程(4)实模式与保护模式切换实例
举报原因:
原因补充:

(最多只允许输入30个字)