zoukankan      html  css  js  c++  java
  • 第十课 实模式到保护模式 上

      远古时期的程序开发是直接操作物理内存的,CPU指令的操作数直接使用实地址(实际内存地址),程序员拥有绝对的权利,可以随意访问内存的任意一个地址,可以说是指哪打哪。

      使用绝对的物理地址会带来很多问题,例如:

    1、难以重定位,程序每次都需要同样地址的内存来运行,所以从一台机器移植到另一台内存大小不同的机器上需要修改源码中的地址。

    2、给多道程序设计带来了障碍,也就是说,不管内存多大,但凡一个字节被其他程序占用都无法执行。

      为了解决以上的问题,英特尔开发出了8086 CPU处理器,其引入了如下特性:

    1、地址线宽度为20位,可访问1M内存空间

    2、引入[段地址:偏移地址] 的内存访问方式

      8086的段寄存器和通用寄存器为16位

      单个寄存器寻址最多访问64K的内存空间

      需要两个寄存器配合,完成所有内存空间的访问

    下面我们来研究一下  段地址:偏移地址  的访问方式,其中硬件会做如下工作:

      段地址左移4位,构成20位的基地址,也就是起始地址,这正好和20根地址线对应上

      基地址 + 偏移地址 = 实地址

    段地址 :偏移地址的访问方式对开发者具有很大的意义:

      更有效的划分内存的功能(数据段、代码段等)

      当出现程序地址冲突时,通过修改段地址解决冲突,给重定位带来了方便

    段地址:偏移地址的示例如下:

      默认情况下,数据访问的段地址存在ds寄存器中,我们也可以显式的给出,例如把段地址放到es寄存器中。

       段地址:偏移地址的访问方式会产生一点小问题,例如,[段地址:偏移地址]能访问的最大地址为0xFFFF:0xFFFF,按照求实地址的方法得到最终的地址为10FFEF,这已经超过了1MB的空间,那么CPU如何进行处理呢?

    看下面的推导:

      0xFFFF:0xFFFF

        ->0xFFFF0 + 0xFFFF

          ->0xFFFF0 + (0xF + 0xFFF0)

            ->(0xFFFF0 + 0xF) + 0xFFF0

    上面的0xFFFF0 + 0xF已经是1MB内存的最大地址了,再加上0xFFF0已经超出了物理内存大小,这超出的部分在8086中称为高端地址区(HMA)。

       上面的地址已经超过了20位,8086怎么处理呢?由于8086只有20位地址线,因此最高位被丢弃(溢出),如下所示:

      8086是一款非常成功的产品,因此,拥有一大批的开发者和应用程序,各种基于8086程序设计的技术得到了发展,同时,各种奇淫技巧也应运而生,虽然8086解决了程序重定位的问题,但还是存在很多其他的问题:

    1、1MB的内存完全不够用,内存太小了不够用

    2、开发者在程序中大量使用内存回卷技术(HMA地址被使用),没有内存保护机制,即使超出内存最大地址也不会报错,而是回卷。

    3、应用程序之间没有界限,相互之间随意干扰,没有内存保护机制

      A程序可以随意访问B程序中的数据

      C程序可以修改系统调度程序的指令

     为了解决以上问题,英特尔的第二代CPU被开发出来,也即80286,8086已经有很多程序在运行了,因此,80286必须兼容8086,而且80286地址线的数量增加到了24位,[段地址:偏移地址]的访问方式也得到了强化:

      1、为每一个段提供了更多的属性(如范围、特权级等),也就是提供了内存保护机制,内存地址超出最大偏移后会产生异常

      2、为每个段的定义提供固定方式

    默认情况下80286是完全兼容8086的运行方式(实模式),例如,默认可以访问1MB的内存空间、通过特殊的方式可以访问1MB+的内存空间,80286开始上电时默认处于实模式。通过特殊指令可以使它进入保护模式。

    进入保护模式后可以访问更大的地址,而且保护模式下会有内存保护机制,防止内存越界,实模式和保护模式有如下不同:

    保护模式:

      1、每一段内存拥有一个属性定义(描述符Descriptor)

      2、所有段的属性定义构成一张表(描述符表Descriptor Table)

      3、段寄存器保存的是段属性定义在表中的索引(选择子Selector),实模式下段寄存器存储的是基地址,而保护模式下存储的是段选择子。

    描述符的内存结构如下:

    描述符表如下:

    选择子的结构如下:

    80286进入保护模式的方式如下:

    1、定义描述符表

    2、打开A20地址线,使CPU支持24位地址

    3、加载描述符表,定义一个结构体用来存储描述符表的起始物理地址和大小,加载描述符表就是将这个结构体加载到CPU寄存器中。

    4、通知CPU进入保护模式(通过设置CPU中的某个寄存器实现),描述符中一般把段定义为32位保护模式的段,因此,进入保护模式就是进入了32位访问方式的保护模式。

     

      在多道程序设计中,A、B两个程序访问的地址有冲突,这时就需要修改其中的一个程序进行重定位,如果修改的话就需要将程序中的所有地址都进行修改,这就是使用绝对地址带来的弊端,8086引入了基地址:偏移地址访问方式,这时的地址是相对地址,重定位一个程序时只需要修改基地址即可,为重定位带来了方便,但是8086只是解决了程序重定位的问题,没有解决段与段之间越界访问的问题,80286的引入真正解决了段与段之间的访问保护,这是真正的保护模式。

    参考狄泰软件学院操作系统开发教程

  • 相关阅读:
    剑指Offer_#7_重建二叉树
    剑指Offer_#6_从尾到头打印链表
    剑指Offer_#5_替换空格
    剑指Offer_#4_二维数组中的查找
    Redis详解(十三)- Redis布隆过滤器
    Redis详解(十二)- 缓存穿透、缓存击穿、缓存雪崩
    Redis详解(十一)- 过期删除策略和内存淘汰策略
    Redis详解(十)- 集群模式详解
    Redis详解(九)- 哨兵(Sentinel)模式详解
    Redis详解(八)- 主从复制
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9331088.html
Copyright © 2011-2022 走看看