现在的位置: 首页 > 技术文章 > 操作系统 > 正文

为什么不能从32位的保护模式直接跳转到实模式

2014年02月28日 操作系统 ⁄ 共 1456字 ⁄ 字号 为什么不能从32位的保护模式直接跳转到实模式已关闭评论 ⁄ 阅读 2,133 次

为什么不能从32位的保护模式直接跳转到实模式,而要先跳转到16位的保护模式,再从16位的保护模式跳转到实模式的理解

呼呼

呼呼

不能从32位代码段返回实模式,而只能从16位代码段返回。

原因:(书中说的)因为无法实现从32位代码段返回时CS高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)

下面具体的来进行分析:

;****************注意在此用normal选择子对段寄存器进行填充******************************

mov ax, SelectorNormal

mov ds, ax

mov es, ax

mov fs, ax

mov gs, ax

mov ss, ax

从上述代码可以看出:ds,es,fs,gs,ss这些段寄存器对应的段描述符高速缓冲寄存器(关于什么是段描述符高速缓冲寄存器,请看这篇文章段描述符高速缓冲寄存器介绍中的内容可以通过加载normal选择子而得到更新,当向这几个段寄存器中装入normal选择子时,会自动地将normal对应的描述符装载到描述符高速缓冲寄存器中,因normal选择子所对应的描述符的属性符合实模式下的要求,即:段界限为ffffh,段属性也是固定的。 

但是:CS寄存器是不可以通过装载normal来更新CS对应的高速缓冲寄存器的为什么?你能写出这样的指令吗:MOV CS,SelectorNormal,汇编中没有这样的指令

即然这样,那怎么可以让CS对应的高速缓冲寄存器中的内容符合实模式的要求呢?

方法是这样的:因为CS的值只能通过jmp,call这样的指令去改变,所以,定义一个16位的代码段,这个代码段的描述符定义为:段界限0ffffh,段属性:存在的只执行代码段 DA_C

假设这个代码段的选择子为:SelectorCode16,偏移地址为:offsetaddr

用一条转移指令向这段代码跳转:jmp SelectorCode16:offsetaddr

因现在处于保护模式,所以jmp指令执行的结果是将SelectorCode16对应的描述符装入cs对应的描述符高速缓冲寄存器中,这个描述符就是符合实模式要求的。这样,CS段寄存器对应的高速缓冲寄存器中的内容终于达到实模式的要求了,所以现在可以进行从保护模式到实模式跳转了,再用一条jmp语句就可以从保模式跳转到实模式了,下边的代码是所定义的一个16位的代码段:

;16位代码段,由32位代码段跳入,跳出后到实模式

[SECTION .s16code]

ALIGN 32

[BITS 16]

LABEL_SEG_CODE16:

;跳回实模式:

mov ax, SelectorNormal

mov ds, ax

mov es, ax

mov fs, ax

mov gs, ax

mov ss, ax

mov eax, cr0

and al, 11111110b

mov cr0, eax

LABEL_GO_BACK_TO_REAL:

jmp 0:LABEL_REAL_ENTRY      ;段地址会在程序开始处被设置成正确的值 ,(看下边的代码)

开始处的代码如下:


LABEL_BEGIN:

mov ax, cs

mov ds, ax

mov es, ax

mov ss, ax

mov sp, 0100h

mov [LABEL_GO_BACK_TO_REAL+3], ax   ;设置正确的返回实模式时的段寄存器值

×