zoukankan      html  css  js  c++  java
  • 实模式/保护模式

    本文主要涉及方面:实模式/保护模式,8086/80286/80386下的寻址方式

    细小知识点:段地址+偏移地址寻址方式,近指针,远指针,GDT,LDT等

    实模式与8086

      现在所说的实模式可以认为是为了和保护模式区分而产生的说法,用来指8088/8086工作的模式,是80286以后为了兼容以前的CPU而产生的概念。

      上古时期(雾),8088/8086(还有80186)处理器只有20位地址总线(即存储空间最大为1MiB),而寄存器位数为16位。为了可以寻址20位,芯片的设计者想出了一种段地址+偏移地址的寻址方式(通常写作  段地址:偏移地址)。8086内置4个段寄存器(代码段CS,数据段DS,堆栈段SS,附加段ES),每个段寄存器可以存放一个16位的段地址,在寻址时,处理器首先将段地址左移4位,然后再加上偏移地址,由此得到20位的物理地址(如 1234H:5678H所对应的物理地址为12340H+5678H=179B8H,其中, 1234H:5678H称作逻辑地址或虚地址)。当地址有溢出时(FFFFH:FFFFH 对应的物理地址是FFFF0H+FFFFH=10FFEFH,大于FFFFFH),会发生回卷(10FFEFH = FFF0H)。

      近指针与远指针:定址时段寄存器与偏移量都指定为远指针寻址,只指定偏移量为近指针寻址(系统默认DS作为段指针)

      如此寻址会产生很多问题。一个段大小最大为2^16=64KiB,并且,所有的段都是可读写的。这意味着不同的段存在着重叠部分(即不同的逻辑地址可以映射到相同的物理地址),无法保证程序的安全性(程序段可被修改),也不具有权限分级(大家都有读写权限,另,那时真的有权限这个概念么)。

    实模式/保护模式与80286

      80286使用了24位的地址线,寄存器位数依然是16位。80286拥有两种寻址方式:实模式(兼容8086)和保护模式。80286启动时工作在实模式,而后可以切换到保护模式(后面讲)

      80286的实模式:

      在系统开机时,80286默认工作在实模式下,80286的实模式是为了兼容8086的寻址方式而存在的。

      在实模式工作的80286可以看做是一个比较快的8086,在由实模式切换到保护模式时需要打开A20总线。

      关于A20:在24位地址线的80286中使用实模式时会出现一个问题,当地址溢出时,由于80286真的有那么多的存储空间,会使得寻址得到高位的存储空间,而不是像8086中一样产生回卷。于是乎,IBM的设计师们采用了一种在总线外部增加逻辑的方式(将第21根地址线即A20与键盘的一个输出做AND),使得A20地址线恒为0。如此,当发生溢出时,由于A20被屏蔽,得到的地址便是回卷后的低位地址了(什么?你溢出了1M?)。

      注意:286是在实模式还是保护模式是由控制寄存器的PE位决定的,A20只是为了解决回卷问题而存在的。当然,在保护模式下如果不打开A20,则处理器只能访问一半的存储空间。

      80286的保护模式:

      一般来说,80286是工作在保护模式下的。保护模式下的寻址也是采用了段地址加偏移量的方法啊,但这里的寻址方式和实模式有所不同。

      在保护模式中,处理器将段信息存放于描述符表中。一张描述符表有213个条目(描述符),每条目8字节长,其中包括24位长的段起始物理地址、16位长的段长(因此段的长度范围从1 B到216 B,即不超过64 KiB),其余为属性信息。每一段的地址范围为 段首~段首+段长,每一个段的大小不一定相同(由段长确定)。描述符表有两个,一个是全局描述符表(GDT),一个是局部描述符表(LDT),也就是说,总共可以有 2 * 213  个段。

      在实模式中,段寄存器保存的是段首地址(左移4位以后),而在保护模式,其中保存的内容称作选择器(selector),其本质是索引(13位,即在表中的偏移量)加TI位(1位,表示是使用GDT还是LDT)和优先级信息(2位,0~3值越小优先级越高)。

      在寻址时,首先拿出选择器(段寄存器)的高13位作为偏移量(索引),结合TI位找到描述符。取出其中24位长的段首地址信息,再加上偏移量(这个偏移量是段地址:偏移量 中的偏移量,前面提到的描述符表的偏移量是段地址的高13位),得到实际物理地址。

      简单来说,286保护模式下的寻址步骤是:拿到段寄存器高14位(13+1),查描述符表,得到24位段地址,加上偏移量,得到物理地址。当然,其中还有保护机制,这里没有说明。

      下图来自维基百科

          

    分页/分段寻址与80386

      80386使用了8个32位通用寄存器(均为8086通用寄存器扩展而来),数据总线与地址总线均为32位(为了与16位寄存器区分,32位寄存器名称前均加了一个E,如AX变为EAX,SP变为ESP)。另外,80386使用了6个段寄存器(均为16位),与之匹配的,有6个段描述符寄存器(32位,用来存放从段描述符表中取出的数据)。

      英特尔32位架构常被称为IA-32或i386或x86-32。80386具有三种工作模式:实模式、保护模式、虚拟86模式。其中,实模式与286相似,不再介绍,虚拟86模式允许在保护模式操作系统的控制下执行实模式的程序。在386的保护模式下,有两种寻址方式:分页寻址与分段寻址

      分页寻址:

      分页寻址模式中,cpu维护一张页目(page directory)与多张页表(page table),其中,页目首地址由CR3寄存器给出,而页表的首地址存放在页目中。页目与页表中的条目每条均为4字节,而每个页目页表最多能容纳1024个条目(即每张页目页表最大空间占用4kiB,4096位)。页目与页表存放信息的方式相似,在每条目的32位中,最高20位(31~12)存放地址信息,剩余12位存放属性信息(页表与页目存放的属性信息不同,具体如下)。

      11 10 9 8 7 6 5 4 3 2 1 0
    页目 操作系统预留 0 PS 0 A PCD PWT U/S R/W P
    页表 操作系统预留 0 0 D A PCD PWT U/S R/W P
      • PS(Page Size)位仅存在于页目中,该位为1时,表明这是一个4M的页面
      • D位仅存在与页表中,D为1时表示正在对该页表进行读写;
      • A位为访问位,正在访问该表时A=1;
      • PCD(Page Cache Disable)表示是否使用高速缓存,PCD=1为启用;
      • PWT(Page Write-Through)表示是否采用写透方式(内存和缓存都写),PWT=1 表示采用写透方式;
      • U/S为用户/管理员位,R/W为读/写位,这两位为页目录项提供硬件保护。当特权级为3 的进程要想访问页面时,需要通过页保护检查,而特权级为0 的进程就可以绕过页保护;
      • P位表示页表是否在物理内存中,P=1为存在

      由于PS位的不同,分页寻址可分为4KiB分页寻址4MiB分页寻址两种

      4KiB分页寻址:

      4KiB分页寻址只使用一个32位的寄存器内容作为索引(称为线性地址)。线性地址的内容分为三部分,高10位(31~22)作为页目索引,中间10位(21~12)作为页表索引,低12位(11~0)作为真实地址偏移量(后面的叙述中将使用“页目索引”、“页表索引”和“真实地址偏移量”指代这三部分,并用斜体表示)。

      具体寻址方式如下:

    1. CR3寄存器内容+页目索引*4 = 页目条目
    2. 从该页目条目中取出高20位,得到页表首地址(20位左移12位变成32位地址)
    3. 页表首地址 + 页表索引*4 = 页表条目
    4. 从页表条目中取出高20位,得到真实地址首地址(20位左移12位变成32位地址)
    5. 真实地址首地址 + 真实地址偏移量 = 真实地址

      索引*4是因为每个条目有4字节。由于真实地址偏移量只有12位,所以一页最大能寻址4KiB。图示如下(来自维基百科):

        

      4MiB分页寻址:

      4MiB分页寻址同样使用一个32位寄存器保存索引(也叫线性地址),但在这里,线性地址只分为两部分:高10位(31~22)为页目索引,剩余22位为真实地址偏移量(后面的叙述中将使用“页目索引”和“真实地址偏移量”指代这两部分,为了与4KiB寻址区分,这两个名称用下划线标示)。4MiB寻址不使用页表,页目所存即物理地址首地址。

      具体寻址方式方式如下:

    1. CR3寄存器内容+页目索引*4 = 页目条目
    2. 从该页目条目中取出高20位,得到真实地址首地址(20位左移12位变成32位地址)
    3. 真实地址首地址 + 真实地址偏移量 = 真实地址

      由于真实地址偏移量为22位,所以一页最大能寻址4MiB。图示如下(来自维基百科):

            

      分段寻址:

      80386保护模式另一种寻址方式是分段寻址。386下的分段寻址模式可参考286的分段寻址:逻辑地址为 段地址(16位):偏移量(32位)。寻址时,由段地址高13位配合TI位作为索引,找到段描述符表,然后取出段描述符,获得段描述符中的32位段基地址,然后基地址+偏移地址,得到真实地址。

      80386的段描述符为64位(8字节),其中包含了32位的段基地址,20位的段界限,以及12位的属性信息。具体存储方式如下(一行为一字节):

      7 6 5 4 3 2 1 0
    0 段界限7~0
    1 段界限15~8
    2 段基地址7~0
    3 段基地址15~8
    4 段基地址23~16
    5 P DPL S TYPE A
    6 G D 0 AVL 段基地址19~16
    7 段基地址31~24
      • G:粒度位,G=0时段长以字节为单位,G=0时段长以页为单位(4 KiB)
      • D:指示操作数和有效地址默认长度,D=1使用32位操作数和32位寻址方式,D=0使用16位;
      • AVL:AVL=1表示操作系统可任意使用
      • P:表示段描述符描述的这个段是否在内存中,P=1为在内存中;
      • DPL(Descriptor Privilege Level):描述符特权级,值为0~3,用来确定这个段的特权级,越小级别越高;
      • S:表示这个段是系统段还是用户段。如果S=0,为系统段,如果S=1,则为用户程序的代码段、数据段或堆栈段。
      • TYPE:用于区别不同类型的描述符。可表示所描述的段是代码段还是数据段,所描述的段是否可读/写/执行,段的扩展方向等。
      • A:访问位,被访问时A=1

      由于段界限为20位,根据G位的不同,当G=0时,段长最大为220 * 1B = 1MiB;当G=1时,段长最大为220 * 4KiB = 4GiB

    参考链接:

    http://blog.csdn.net/jnu_simba/article/details/11712747

    https://objectkuan.gitbooks.io/ucore-docs/lab1/lab1_3_2_1_protection_mode.html

    http://blog.csdn.net/jnu_simba/article/details/11712747

    http://www.macode.net/80386-protected-mode-essential/

    https://zh.wikipedia.org/wiki/%E4%BF%9D%E8%AD%B7%E6%A8%A1%E5%BC%8F

    https://github.com/chyyuu/simple_os_book/blob/master/zh/chapter-1/protect_mode.md

    本文作者:Dumblidor

    转载请注明出处:http://www.cnblogs.com/Dumblidor/p/6725602.html

    2017.4.19

  • 相关阅读:
    Cocos开发中Visual Studio下libcurl库开发环境设置
    Cocos2d-x数据持久化-修改数据
    Cocos2d-x数据持久化-查询数据
    Cocos2d-x中SQLite数据库管理工具
    Cocos2d-x中创建SQLite数据库
    Visual Studio下SQLite数据库开发环境设置
    spring01
    String类的常用方法
    基本数据类型的包装类和随机数
    枚举类的使用
  • 原文地址:https://www.cnblogs.com/Dumblidor/p/6725602.html
Copyright © 2011-2022 走看看