本文主要涉及方面:实模式/保护模式,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)作为真实地址偏移量(后面的叙述中将使用“页目索引”、“页表索引”和“真实地址偏移量”指代这三部分,并用斜体表示)。
具体寻址方式如下:
- CR3寄存器内容+页目索引*4 = 页目条目
- 从该页目条目中取出高20位,得到页表首地址(20位左移12位变成32位地址)
- 页表首地址 + 页表索引*4 = 页表条目
- 从页表条目中取出高20位,得到真实地址首地址(20位左移12位变成32位地址)
- 真实地址首地址 + 真实地址偏移量 = 真实地址
索引*4是因为每个条目有4字节。由于真实地址偏移量只有12位,所以一页最大能寻址4KiB。图示如下(来自维基百科):
4MiB分页寻址:
4MiB分页寻址同样使用一个32位寄存器保存索引(也叫线性地址),但在这里,线性地址只分为两部分:高10位(31~22)为页目索引,剩余22位为真实地址偏移量(后面的叙述中将使用“页目索引”和“真实地址偏移量”指代这两部分,为了与4KiB寻址区分,这两个名称用下划线标示)。4MiB寻址不使用页表,页目所存即物理地址首地址。
具体寻址方式方式如下:
- CR3寄存器内容+页目索引*4 = 页目条目
- 从该页目条目中取出高20位,得到真实地址首地址(20位左移12位变成32位地址)
- 真实地址首地址 + 真实地址偏移量 = 真实地址
由于真实地址偏移量为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