实模式与保护模式的地址形成关系

2019-04-14 22:11发布

参考 http://hi.baidu.com/sinbad_li/item/319be83e63fe455f80f1a728 来自《编程高手箴言》     我们知道,CPU上电后,从ROM 中的BIOS开始运行,而Intel 文档却说80x86 CPU上电总是从最高内存下16字节开始执行,那么,BIOS是处在内存的最顶端64KB(FFFF0000H),还是1MB之下的64KB(F0000H)处呢?事实上,BIOS在这两个地方都同时出现(可用后面存取4GB 内存的程序验证)。    为了弄清楚以上问题,首先要了解CPU 是如何处理物理地址的。真的是在实模式下用段寄存器左移4位与偏移量相加,还是在保护模式下用段描述符中的基地址加偏移量,难道两者是毫无关联的吗?      答案是两者其实是一样的。当Intel把80286推出时,其地址空间变成了24位,则从8086的20位到24位,十分自然地要加大段寄存器才行。实际上,段寄存器和指针都被加大了,只是由于保护的原因,加大的部分没有被程序看见,到了80386之后,地址又从24位加大到32位(80386 SX是24位)。     在8086中,CPU只有“看得见部分”,但在80286之后,在“看不见部分”中已经包含了地址值,看得见部分”就退化为只是一个标号,再也不用参与地址形成运算了。地址的形成总是从“不可看见部分”取出基址值与偏移相加形成地址。也就是说,在实模式下,当一个段寄存器被装入一个值时,“看不见部分”的界限被设成FFFFH,基址部分将装入值左移4位,属性部分设成16位0特权级。这个过程与保护模式时装入一个段寄存器是同理的,只是保护模式的“不可见部分”是从描述表中取值,而实模式是一套固定的过程。      对于CPU在形成地址时,是没有实模式与保护模式之分的,它只管用基址(“不可见部分”)去加上偏移量。实模式与保护模式的差别实际上只是保护处理部件是否工作得更精确而已,比如不允许代码段的写入。实模式下的段寄存装入有固定的形成办法,从而也就不需要保护模式的“描述符”了,因此,保持了与8086/8088的兼容性。而“描述符”也只是为了装入段寄存器的“不可见部分”而设的。       从上面的“整个段寄存器”可见,CPU的地址形成与“看得见部分”的当前值毫无关系。这也解释了为什么在刚进入保护模式时,后面的代码依然被正确地运行,而这时代码段寄存器CS的值却还是进入保护模式前的实模式值,或者从保护模式回到实模式时,代码段CS被改变之前程序是正常地工作,而不会“突变”到CS左移4位的地址上去。比如在保护模式时,CS是08H的选择子,到了实模式时,CS还是08H,但地址不会突然变成80H加上偏移量。因为地址的形成不理会段寄存器“看得见部分”的当前值,这一个值只是在被装入时对CPU有用。      地址的形成与CPU的工作模式无关,也就是说,实模式与0特权级保护模式不分页时是一模一样的。明白了这一机理后,在实模式下一样可以处理通常被认为只有在保护模式才能做的事,比如访问整个机器的内存。不必理会保护模式下的众多术语或许会更易于理解,如选择子就是“看得见部分”,描述符是为了装入“不可见部分”而设的。     有一些书籍也介绍有同样功能的汇编程序,但它们都错误地认为是利用80386芯片的设计疏漏。实际上,Intel本身就在使用这种办法,使得CPU上电时能从FFFFFFF0H处开始第一条指令,这种技术在286之后的每一台机器每一次冷启动时都使用,只是我们不知道罢了。   其中应该去理解的是:在386后段寄存器其实是32bit的。在实模式的时候,它是直接把给的段基地址左移4位然后装入的,而在保护模式下是在段描述表中取得段描述符后计算出基地址存入段寄存器中的。
参考 http://blog.csdn.net/ciahi/article/details/1556841
现在正在看于渊的《自己动手写操作系统》,里面的保护模式讲的算是比较详细的了,但是我还是有一些疑问。对实模式到保护模式之间的转换没有深入的理解。 今天看了梁大师的《编程高手箴言》,在第二章的最后,总结的几句话,让我如梦惊醒,对保护模式有了更深的理解 1.地址的形成与CPU的工作模式无关,实模式与0特权级保护模式不分页时是一样的 2.CS、DS等段寄存器的值只有在被装入时,才对CPU有用,其他时候CPU不会理会CS的值,所以,从实模式-》保护模式—》实模式,CS的值虽然不变,程序仍能正常执行。因为在实模式下当前指令的地址为:cs×16+offset,而在保护模式下,当前指令的地址为:cs所指向的描述符所指未的基址+offset  当在程序中执行: mov eax,cr0
or eax,01h
mov cr0,eax
进入保护模式,这中间并没有对CS进行改变。这里面的原因就是因为在程序执行的过程中,如果没有对CS进行重新装载,CPU并不管此时CS的值是多少,而执行下一条指令时,仅对 IP = IP + 1,指向下一条指令的地址 所以,根据以上的说明,你可能就会想到,如果在保护模式下,对FS进行了重新装载,然后回到实模式下,此时并不改变FS的值的话,此时仍可访问系统4G的地址空间(前提是A20地址线必须打开) 3. 如果把IDTR的界限设为0,则CPU自动关闭所有中断,包括NMI
以下是个人理解,欢迎指正
*********************************************************************************************************************** 在80386或者以后的CPU里面,其实段寄存器是被扩展成32位或者64位了,地址 = 段基地址 + 偏移 这个地址的公式没有改变,唯一改变的是我们所看到的cs,ds这些段寄存器不是直接正在参与到地址计算的寄存器, 我个人暂且把扩展后的32位或者64位段寄存器称之为高速缓存段寄存器,把我们看到的cs,ds这些还是称之为段寄存器。
上面的公式应该改写为 地址 = 高速缓存段寄存器(段基地址) + 偏移
高速缓存寄段存器只有当段寄存器被重新装载(段寄存器的值发生改变)时才会发生改变,也可以说是更新, 至于如何更新高速缓存段寄存器里面的基地址值呢,就要区分实模式与保护模式
在实模式下,高速缓存段寄存器(段基地址) = 段寄存器 * 16 保护模式下,高速缓存段寄存器(段基地址) = 段寄存器(选择子)所描述的段信息包含的基地址
这样的话就可以很好地兼容8086的程序了,在8086 CPU里面没有我们称之的高速缓存段寄存器, 地址是直接用段寄存器 + 偏移 的公式计算的,公式一直不变(地址计算机制不变),
因此可以把上面两篇文章所描述的内容都很好地解释了