您的位置:首页 > 其它

一个操作系统的实现(4):分页机制

2016-09-01 18:53 309 查看
分页与分段最大的不同之处在于分页是用来固定长度的页面(一般为4KB)。如果仅适用分段地址转换,那么存储在物理内存中的一个数据结构将包含器所有部分。但如果适用了分页,那么一个数据结构就可以一部分存储在物理内存中,而另一部分保存在磁盘中。这也就是分页机制在现代内存管理中存在的重要性。

那么首先我们还是熟悉一下分页机制的基本概念。



如上图所示,分页是在分段的基础上将线性地址转化为物理地址。转换时使用了两级页表,第一级是页目录,大小为4KB,存储在一个物理页上,每个表项4字节长,共有1024个表项。每个表项对应第二级的一个页表,第二级的每个页表也有1024个表项,每个表项对应一个物理页。页目录表的表项简称PDE(Page Directory Entry),页表的表项简称PTE(Page
Table Entry)。

整个转换过程:

1)先是从寄存器cr3指定的页目录中根据线性地址的高10位得到页表。

2)在页表中,根据线性地址的第12—21位得到物理页首地址。

3)将这个首地址,加上线性地址的低12位便得到了物理地址。

PDE的结构图如下:



PTE的结构图如下:



cr3的结构图如下:



下面我们还是通过分析代码来理解分页:

[cpp]
view plain
copy

PageDirBase equ 200000h ; 页目录开始地址:2M
PageTblBase equ 201000h ; 页表开始地址: 2M+4K

; 启动分页机制 --------------------------------------------------------------
SetupPaging:
; 为简化处理, 所有线性地址对应相等的物理地址.

; 首先初始化页目录
mov ax, SelectorPageDir ; 此段首地址为 PageDirBase 200000h(2M)
mov es, ax ; es:[edi]指向PageDirBase,页目录表基地址
mov ecx, 1024 ; 共 1K 个表项,循环1024次
xor edi, edi
xor eax, eax
mov eax, PageTblBase | PG_P | PG_USU | PG_RWW ; eax里是PageTblBase(201000h)加上属性PG_P | PG_USU | PG_RWW后的结果,也就是第一个页表的地址和属性

.1:
stosd ; es:[edi] ← eax ; 把第一个页表地址、属性填入页目录基地址,也就是第一个页目录表项里

add eax, 4096 ; 为了简化, 所有页表在内存中是连续的. ;eax里存的其实就是页目录表项的内容,这里在第一个表项内容基础上加上4096,相当与第二个表项指向的页

表基地址是PageTblBase+4096,下面是循环以此类推...
loop .1 ;循环1024次,完成页目录里1024个表项的初始化

; 再初始化所有页表 (1K 个, 4M 内存空间)
mov ax, SelectorPageTbl ; 此段首地址为 PageTblBase
mov es, ax ; es:[edi]指向PageTblBase,页表基地址
mov ecx, 1024 * 1024 ; 1024个页表,每个页表有1024个表项, 也就是有 1M 个页
xor edi, edi
xor eax, eax
mov eax, PG_P | PG_USU | PG_RWW ; 这里属性前没有地址,其实地址是0,也就是将线性地址0开始的4K空间映射到物理地址上
.2:
stosd ; es:[edi] ← eax ; 把第一个页表地址、属性填入页表基地址,也就是第一个页表里
add eax, 4096 ; 下一页表里存放的基地址在前一个的基地址基础上+4049,实际就是表明一个页的大小为4K
loop .2 ; 循环1M次,每次映射1页(4K大小的空间),所以总共映射了4G空间

mov eax, PageDirBase
mov cr3, eax ;cr3寄存器里存入PageDirBase基地址
mov eax, cr0
or eax, 80000000h
mov cr0, eax ;将控制寄存器cr0的PE标志(位31)置为1,开启分页机制
jmp short .3
.3:
nop

ret
; 分页机制启动完毕 ----------------------------------------------------------

上述程序大致做了这样的事:构建页目录表和页表,为了构建简单,表项都在内存中连续存放,将页目录表基地址存入cr3中,然后开启分页机制。

关键的地方是在页目录表和页表结构里的基地址内容:

PDE里页表基址:依次为201000,202000......600000。总共1024个,每两个页表基地址相差4K,这是由于一个页表基址指向的是1024个页表的基地址,而每个页表4个字节。

PTE里页基址:依次为0000 0000,0000 01000......FFFF FFFF。总共1024*1024个,没两个页基址相差4K,这是由于一个页面占4K。这样就将4G的地址空间全都映射到了。

分页的图示:



书中还提到一句话 "切换任务时通过改变cr3的值来切换页目录,从而改变地址映射关系”,这应该是切换进程时要做的事吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: