win32 007

这是不是说,在保护模式下,段寄存器就不再有用了呢?

答案是否定的!实际上段寄存器更有用了,虽然在寻址上不再有分段的限制问题,但在保护模式下,一个地址空间是否可以被写入,可以被多少优先级的代码写入,是不是允许执行等涉及保护的问题就出来了。

要解决这些问题,必须对一个地址空间定义一些安全上的属性。段寄存器这时就派上了用途,不妨将这些属性存放在段寄存器中!

但是问题来了,涉及属性和保护模式下段的其他参数,要表示的信息太多了,要用64位长的数据才能表示。我们把这64位的属性数据叫做段描述符(Segment Descriptor)。

 

80386的段寄存器仍然是16位的,无法放下保护模式下64位的段描述符。如何解决这个新的问题呢?

解决办法是把所有段的段描述符顺序放在内存中的指定位置,组成一个段描述符表(Descriptor Table)

而段寄存器中的16位用来做索引信息,指定这个段的属性用段描述符表中的第几个描述符来表示。

这时,段寄存器中的信息不再是段地址了,而是段选择器(Segment Selector)。可以通过它在段描述符表中“选择”一个项目以得到段的全部信息。

 

既然这样,段描述符表放在哪里呢?

80386中引入了两个新的寄存器来管理段描述符表。一个是48位的全局描述符表寄存器GDTR,一个是16位的局部描述符表寄存器LDTR。

 

那么,为什么有两个描述符表寄存器呢?

GDTR指向的描述符表为全局描述符表GDT(Global Descriptor Table)。

它包含系统中所有任务都可用的段描述符,通常包含描述操作系统所使用的代码段、数据段和堆栈段的描述符及各任务的LDT段等;全局描述符表只有一个。

 

LDTR则指向局部描述符表LDT(Local Descriptor Table)。

80386处理器设计成每个任务都有一个独立的LDT。

它包含有每个任务私有的代码段、数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调用门描述符等。

不同任务的局部描述符表分别组成不同的内存段,描述这些内存段的描述符当做系统描述符放在全局描述符表中。

 

和GDTR直接指向内存地址不同,LDTR和CS,DS等段选择器一样只存放索引值,指向局部描述符表内存段对应的描述符在全局描述符表中的位置。

随着任务的切换,只要改变LDTR的值,系统当前的局部描述符表LDT也随之切换,这样便于各任务之间数据的隔离。但GDT并不随着任务的切换而切换。

 

看到这里,读者可能会提出一个问题,既然有全局描述符表和局部描述符表两个表,那么段选择器中的索引值对应哪个表中的描述符呢?

实际上,16位的段选择器中只有高13位表示索引值。

剩下的3个数据位中,第0,1位表示程序的当前优先级RPL;第2位TI位用来表示在段描述符的位置;TI=0表示在GDT中,TI=1表示在LDT中。

 

图说寻址路线:

在保护模式下,同样以xxxx:yyyyyyyy格式表示一个虚拟地址。

注意,xxxx(16位,相当于8086时代的段地址) 保存在段寄存器,yyyyyyyy(32位,相当于8086时代的偏移地址)保存在通用寄存器。

下边,小甲鱼从图片来给大家做演示!

图说寻址路线

 

 

Win32基础知识4

 

让编程改变世界

Change the world by program


 

 

80386的内存分页机制

 

在实模式下寻址的时候,“段寄存器+偏移地址”经过转换计算以后得到的地址是“物理地址”,也就是在物理内存中的实际地址。

而保护模式下,“段选择器+偏移地址”转换后的地址被称为“线性地址”而不是“物理地址”。那么,线性地址就是物理地址吗?

答案可能是“是”,也可能是“不是”,这取决于80386的内存分页机制是否被使用。

 

为什么会有内存分页机制?!

我们来回顾一下:在单任务的DOS系统中,一个应用程序可以使用所有的空闲内存。

程序退出后,操作系统回收所有的碎片内存并且合并成一个大块内存继续供下一个程序使用。

 

内存合并过程中的一个极端情况是当系统中有多个TSR程序时,早装入内存的TSR被卸载后,后装入的TSR会留在内存的中间部位,把空闲内存隔成两个区域。

这时应用程序使用的最大内存块只能是这两块内存中较大的一块,无法将它们合并使用。

 

对于一个多任务的操作系统,内存的碎片化是不能容忍的。否则,经过一段时间后,即使空闲内存的总和很大,也可能出现任何一片内存都小到无法装入执行程序的地步。

所以多任务操作系统中碎片内存的合并是个很重要的问题。

 

80386处理器的分页机制可以很好地解决这个问题。

80386处理器把4 KB大小的一块内存当做一“页”内存,每页物理内存可以根据“页目录”和“页表”,随意映射到不同的线性地址上。

 

这样,就可以将物理地址不连续的内存的映射连到一起,在线性地址上视为连续。

在80386处理器中,除了和CR3寄存器(指定当前页目录的地址)相关的指令使用的是物理地址外,其他所有指令都是用线性地址寻址的。

 

名词扫盲:

CR3 用于保存页目录表页面的物理地址,因此被称为PDBR。

由于目录是页对齐的,所以仅高20位有效,低12 位保留供更加高级的处理器使用。

向CR3中装入一个新值时,低12位必须为0,从 CR3中取值时,低12位被忽略。

 

还有,是否启用内存分页机制是由80386处理器新增的CR0寄存器中的位31(PG位)决定的。

如果PG=0,则分页机制不启用,这时所有指令寻址的地址(线性地址)就是系统中实际的物理地址;

当PG=1的时候,80386处理器进入内存分页管理模式,所有的线性地址要经过页表的映射才得到最后的物理地址。废话不多说,先上美图!!

 

 

 

一个xxxx:yyyyyyyy格式的虚拟地址,经过上节课所示的段地址转换步骤后得到32位的线性地址zzzzzzzz(步骤①)。

当禁用分页机制时,线性地址就是物理地址,处理器直接从物理内存存取数据(步骤②);

当启用分页机制时,得到线性地址的方法还是一样(步骤1′),但是还要根据页目录和页表指定的映射关系把地址映射到物理内存的真正位置上(步骤3′)。

 

然后,CPU以映射后的物理地址在物理内存中存取数据。这个过程对于指令来说是透明的。

内存分页管理只能在保护模式下才可以实现,实模式不支持分页机制。

 

但不管在哪种模式下,所有寻址指令使用的都是线性地址,程序不用关心数据最后究竟存放在物理内存的哪个地方。

页表规定的不仅是地址的映射,同时还规定了页的访问属性,如是否可写、可读和可执行等。

 

比如把代码所在的内存页设置为可读与可执行,那么权限不够的代码向它写数据就会引发保护异常。利用这个机制可以在硬件层次上支持虚拟内存的实现。

页表可以指定一个页面并不真正映射到物理内存中。这样,访问这个页的指令会引发页异常错误。这时,处理器会自动转移到页异常处理程序中去。

 

操作系统可以在异常处理程序中将硬盘上的虚拟内存读到内存中并修改页表重新映射,然后重新执行引发异常的指令。

这样指令可以正常执行下去。请看图!

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值