全局描述符表GDT和局部描述符表GDT
一个任务会涉及多个段,每个任务需要一个描述符来描述,为了便于组织管理,80386把描述符组织成线性表。由描述符组成的线性表称为描述符表。在80386中有三种类型的描述符表:全局描述符表GDT(Global Descriptor Table)、局部描述符表LDT(Local Descriptor Table)和中断描述符表IDT(Interrupt Descriptor Table)。
在整个系统中,全局描述符表GDT和中断描述符表IDT只有一张,局部描述符表可以有若干张,每个任务可以有一张。
每个描述符表本身形成一个特殊的数据段。这样的特殊数据段最多可包含有8K(8192)个描述符.
每个任务的局部描述符表LDT含有该任务自己的代码段、数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调用门描述符等。随着任务的切换,系统当前的局部描述符表LDT也随之切换。
全局描述符表GDT含有每一个任务都可能或可以访问的段的描述符,通常包含描述操作系统所使用的代码段、数据段和堆栈段的描述符,也包含多种特殊数据段描述符,如各个用于描述任务LDT的特殊数据段等。
在任务切换时,切换LDT,并不切换GDT
通过LDT可以使各个任务私有的各个段与其它任务相隔离,从而达到受保护的目的。通过GDT可以使各任务都需要使用的段能够被共享。
一个任务可使用的整个虚拟地址空间分为相等的两半,一半空间的描述符在全局描述符表中,另一半空间的描述符在局部描述符表中。由于全局和局部描述符表都可以包含多达8192个描述符,而每个描述符所描述的段的最大值可达4G字节,因此最大的虚拟地址空间可为:
4GB81922=64MMB=64TB
段选择子
在实模式下,逻辑地址空间中存储单元的地址由段值和段内偏移两部分组成。
在保护方式下,虚拟地址空间(相当于逻辑地址空间)中存储单元的地址由段选择子和段内偏移两部分组成。
与实模式相比,段选择子代替了段值。
段选择子的高13位是描述符索引(Index)。所谓描述符索引是指描述符在描述符表中的序号
段选择子的第2位是引用描述符表指示位,标记为TI(Table Indicator),TI=0指示从全局描述符表GDT中读取描述符;TI=1指示从局部描述符表LDT中读取描述符。
选择子–>描述符---->段基地址----+偏移->线性地址
选择子的最低两位是请求特权级RPL(Requested Privilege Level),用于特权检查。每当程序试图访问一个段时,要把当前特权级与所访问段的特权级进行比较,以确定是否允许程序对该段的访问
虚拟地址转换为线性地址
为了将虚拟地址转换为线性地址,分段单元执行如下操作。
- 先检查段选择子的T1字段,已决定段描述符号,存储在全局段描述符表GDL还是局部段描述符表中。如果在全局段描述符表GDL中,则分段单元则从GDTR中得到GDT的线性基地址,相反如果局部段描述符表中则从LDTR中获取到LDT的线性基地址。
- 从段选择子的index索引字段,计算段描述符的地址,index字段的值乘以8(一个段描述符的大小是8个字节),然后这个值(偏移)与GDTR或者LDTR的寄存器的值(全局/局部段描述符表的基地址)相加,全局/局部段描述符表中偏移为index*8的这个地址就存储着我们当前段的段描述符。
- 把得到的段描述符的base字段与逻辑地址额偏移offset值相加就得到了线性地址
分段管理机制结束
接下来是页式管理
如果没有采用存储器分页管理机制,那么我们得到的线性地址就直接对应与物理地址,否则,则需要将线性地址转换为物理地址。
page = frame = block
-
页 :线性地址被分为以固定长度为单位的组,成为页。页内部连续的线性地址空间被映射到连续的物理地址中。
-
页框:把所有的 RAM 分成固定长度的页框(page frame)(有时叫做物理页)。每一个页框包含一个页(page),也就是说一个页框的长度与一个页的长度一致。页框是主存的一部分,因此也是一个存储区域。区分一页和一个页框是很重要的,前者只是一个数据块,可以存放在任何页框或磁盘中。
-
页表: 把线性地址映射到物理地址的数据结构称为页表(page table)。页表存放在主存中
32位线性地址被分成三个区域
目录偏移 | 页表偏移 | Offset |
---|---|---|
最高10位 | 中间10位 | 最低12位 |
CR3 指向页目录指针表(PDPT)的基地址
Directory字段和Table字段都是10位长,因此页目录和页表都可以多达1024项。那么一个页目录可以寻址到高达 1024 * 1024 * 4096=2^32个存储单元,这和32位地址所期望的一样。
https://blog.csdn.net/bfboys/article/details/52431345 段式管理
https://blog.csdn.net/bfboys/article/details/52431370 页式管理
哈工大实验开始
在bochs 中运行这个程序,并且找到i的物理地址然后修改他的值,修改成0让他跳出死循环
#include <stdio.h>
int i = 0x12345678;
int main(void)
{
printf("The logical/virtual address of i is 0x%08x", &i);
fflush(stdout);
while (i)
;
return 0;
}
基本的思想:
- ds段是选择子 index(描述表内偏移) ti rpl
根据T1是0(GDT)是1(LDT) - LDTR:是局部描述符表寄存器 index TI RPL
- GDTR:全局描述符表寄存器,他的值+LDTR的INDEX *8 就找到 LDT
- 找到LDT 之后 根据组合出base,就是LDT的入口
- base + ds的index *8 就是 段基址+偏移量 在根据上图得出的线性地址的基址
- &i 就是得出来的偏移
- 基址+偏移就是线性地址
分段结束
得出线性地址0X1000 3004
换算成 二进制就是
0001000000 0000000011 000000000100
也就是
director = 64 table = 3 offset = 4
- CR+dir*4得到页目录
- 页目录最高20位 + table*4 得到页
- 页最高20位+offset得到物理地址
(这时候查看该地址的内容,可以看到是I =12345678)
修改为0则完成修改I值,可以跳出循环
总结一下过程
- 找段号跟段偏移量(选择子index就是描述表偏移)
- 找LDT跟GDT
- 根据GDT的段描述符找到LDT入口(GDT+LDTR*8)再后查看内容,根据描述表结构组合出LDT的地址
- 根据LDT地址查看内容,组合出线性地址的基址(段基址)
- 段基址+偏移量(ip内容 (通过&得出来))得出线性地址
- 线性地址换算成二进制分别对应DIR TABLE OFFSET
- CR3+DIR(十进制)*4得出页目录地址,查看内容最高20位是有效位
- 页目录有效位+TABLE(十进制)*4得出页表地址,查看内容,最高20位是有效位
- 页表 + OFFSET 得出实际物理地址
https://blog.csdn.net/ccshijtgc/article/details/60605573 代码修改参考