内核代码阅读(1) - Intel CPU和段页式内存管理

Real Mode 8086

16位寄存器

20位地址

使用CS DS SS ED段寄存器

16位寄存器 << 4(基地址) + 16位地址

此乃实模式 Real Mode

Protect Mode 80386

保护模式实现思路

段式内存

GDTP (global descriptor table register)
 LDTR (local descriptor table
 每个段寄存器在CPU上都有一个扩展,
 当一个段寄存器被改变(MOV, POP)后,CPU会根据LDTP,GDTR+段寄存器的偏移,取出新的段描述符,放到这个寄存器的影子中。
 因为GDTR,LDTR的操作是特权指令,只能在内核态中执行,用户看不到段描述符表在哪里,所以部分实现了保护。
 最终的段值为 LDTR(GDTR) _+ 相应的段寄存器值的高13位

系统态和用户态(如何区分是系统态还是用户态呢?)

80386划分4个特权级别0是内核态,3是用户态
 16位的段寄存器后3位,用来描述权限
 typedef struct {
     unsigned short seg_idx:13;
 unsigned short ti:1;
 unsigned short tpl:2 /*Request Privilege Level 要求的优先级别*/
 } 段寄存器;

页式内存

与段式之间的关系

建立在段式基础之上。当前执行的权限就是存在相关的代码段描述项中
逻辑地址 (段式)-> 线性地址  (页式) -> 物理地址
所有的地址都要经过页式的转换,包括GDTR, LDTR等

线性地址

typedef struct {
     unsigned int dir:10;
 unsigned int page:10;
 unsigned int offset:12;
 } ;

为什么要2级映射,而不是像段式那样一步倒位?

如果像段式一步倒位,前面20位可以提供1M的页面数的寻址。
 那么,就必须开一个大小为1M的连续数组,用以定位页框下标。这个的设计,不需要页目录了大小是(4K),直接由1M大小的页表定位页面,然后,后面的12位的offset定位页内地址。
 而采用2层,就可以,在需要目录项,页面表目录的时候动态的申请,而不是一次行的申请1M的连续的页表目录大小。类似于STL的deque数据结构。巧妙的设计。

页面4k,为什么?

上面说了,在需要目录项,页面表目录的时候动态的申请。
 申请目录项:大小是1k,所占用的内存空间正好是4k,所以一个进程的页目录一个页面。
 申请页表:一个页表大小也是10位,大小1k,内存空间是4k。
 所以,申请目录项(一个进程一个),和页表项都是一个页面。
 alpha CPU 64位cpu的页面8K。

目录项,页表项

目录项和页表项都是高10位起作用,低22用不到。这22用来控制权限,虚存等。

PSE

页目录项中的ps为0: 页面大小4k,采用2层;
         ps为1: 页面大小4M, 采用1层。

CR0 寄存器最高PG位,是页式映射机制的踪开关。1是开启页式映射。

PAE 在Pentium Pro中作了地址扩充,增加了CR4寄存器,其中有一个PAE位。

上一篇:RabbitMQ DAG启动图解


下一篇:C1000K - Erlang (第一弹)