Chinaunix首页 | 论坛 | 博客
  • 博客访问: 469420
  • 博文数量: 164
  • 博客积分: 4024
  • 博客等级: 上校
  • 技术积分: 1580
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-10 16:27
文章分类

全部博文(164)

文章存档

2011年(1)

2010年(108)

2009年(55)

我的朋友

分类:

2010-08-13 13:19:18

参考于渊的《自己动手写操作系统》第三章中从实模式切换到保护模式

在由保护模式切换到实模式之前,用normal选择子对段寄存器进行填充。

原因:

在切换到实模式之前,把一个指向似乎没有用的数据段的描述符Normal的选择子装载到DSES。这是为什么呢?

实模
式下
段描
述符
高速
缓冲
寄存
器的
内容

段寄存器

段基地址

段界限(固定)

段属性(固定)

存在性

特权级

已存取

粒度

扩展方向

可读性

可写性

可执行

堆栈大小

一致特权

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,段属性的许多位也是固定的。所谓固定是指在实方式下不可设置这些属性值,只能继续沿用保护方式下所设置的值。因此,在准备结束保护模式回到实模式之前,要通过加载一个合适的描述符选择子(如实例代码中的Normal选择子)到有关段寄存器,以使得对应段描述符高速缓冲寄存器中含有合适的段界限和属性。

也就是说,在实模式下装载段寄存器并不会影响段告诉缓冲寄存器的值,比如段界限(其实在实模式也没有必要改变,应为段界限一直都是0ffffh),这也就是为甚麽所有讲保护模式的树在讲到有保护模式切换到实模式时都要加载一个normal选择子的原因了。

应为必须在保护模式下设置好段高速缓冲寄存器的值,因为一旦到了实模式下就不能在改变了。

经我试验,对于normal的描述符,其最重要是段界限一定要设置为0ffffh,如果不是这样,那莫在由保护模式跳转到实模式后会发生错误(对于上述代码如果把normal描述符的段界限改为别的的话,在跳转后会产生死循环的现象,具体是什么原因现在还不明确,哪位高人知道一定要告诉我啊~~)。其次就是属性的设置一定要设置为可读可写的,否则也会发生错误.

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

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


  
# re: 保护模式与实模式的切换 2009-02-21 15:34
在32位代码段中,当用jmp selector:offset意图从32位保护模式到16位的实模式,因jmp语句的作用是用将selector:offset当作CS:IP,因在保护模式情况下,当向一个段寄存器中装入新值时,同时会将这个新值对应的描述符装载到段寄存器对就的高速缓冲寄存器中,这样,当将selector装载到CS中时,同时也会查找这个selector对应的描述符,这个描述符根本没被定定义过。  回复  更多评论
  
# re: 保护模式与实模式的切换 2009-02-21 15:37
CS段寄存器中可不能胡乱载入一个值的,保护检测通不过  回复  更多评论
  
# re: 保护模式与实模式的切换 2009-02-21 22:56
我上面的回答是不对的,正确的理解应是这样:
关于为什么不能从32位的保护模式直接跳转到实模式,而要先跳转到16位的保护模式,再从16位的保护模式跳转到实模式的理解

;****************注意在此用normal选择子对段寄存器进行填充******************************
mov ax, SelectorNormal
317 mov ds, ax
318 mov es, ax
319 mov fs, ax
320 mov gs, ax
321 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,段属性:存在的只执行代码段
假设这个代码段的选择子为:select32,偏移地址为:offsetaddr
用一条转移指令向这段代码跳转:jmp select32:offsetaddr
因现在处于保护模式,所以jmp指令执行的结果是将select32对应的描述符装入cs对应的描述符高速缓冲寄存器中,这个描述符就是符合实模式要求的。这样,CS段寄存器对应的高速缓冲寄存器中的内容终于达到实模式的要求了,所以现在可以进行从保护模式到实模式跳转了,再用一条jmp语句就可以从保护模式跳转到实模式了。
阅读(5487) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~