(第三章 14)克勤克俭用内存——初始化页目录表、页表,开启分页机制
在启动分页机制SetupPaging之前,先调用了DispMemSize函数,在函数中计算出了[dwMemSize]——最大内存地址值。
?
; 启动分页机制 --------------------------
SetupPaging:
;1、计算出最大地址为[dwMemSize]对应的内存共有多少个页表(也即PDE个数,不是页面个数),将个数(ecx,32bit)压栈
xoredx, edx
moveax, [dwMemSize]
movebx, 400000h; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小(一个页面是4k,一个页表有1024个页面)
divebx ? ? ? ? ? ? ; edx:eax / ebx ==> eax ...... edx
movecx, eax; 此时 ecx 为页表的个数,也即 PDE 应该的个数
testedx, edx
jz.no_remainder
incecx; 如果余数不为 0 就需增加一个页表
.no_remainder:
pushecx; 暂存页表个数
?
; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.
?
;2、首先初始化“页目录表”(即初始化每个PDE)
movax, SelectorPageDir; 此段首地址为 PageDirBase
moves, ax
xoredi, edi
xoreax, eax
moveax, PageTblBase | PG_P ?| PG_USU | PG_RWW
.1:
stosd ? ? ? ? ? ? ? ? ? ? ? ? ? ; eax中的4个字节 -> es:edi ,每循环一次是一个PDE
addeax, 4096; 为了简化, 所有页表在内存中是连续的.
loop.1 ? ? ? ? ? ? ? ? ? ? ?; 循环次数为ecx=PDE个数
?
;3、再初始化所有“页表”,即初始化每个PTE
movax, SelectorPageTbl; 此段首地址为 PageTblBase
moves, ax
popeax; 页表个数,也是PDE个数
movebx, 1024; 每个页表 1024 个 PTE
mulebx ? ? ? ? ? ? ? ? ? ? ; eax*ebx==>积edx:eax
movecx, eax; PTE个数 = 页表个数 * 1024
xoredi, edi
xoreax, eax
moveax, PG_P ?| PG_USU | PG_RWW
.2:
stosd ? ? ? ? ? ? ? ? ? ? ? ? ? ; eax==>es:edi
addeax, 4096; 每一页指向 4K 的空间
loop.2 ? ? ? ? ? ? ? ? ? ? ?; 循环次数为ecx=PTE个数
?
;4、开启页表机制
moveax, PageDirBase
movcr3, eax
?
moveax, cr0
oreax, 80000000h
movcr0, eax
?
jmpshort .3
.3:
nop
?
ret
; 分页机制启动完毕 ----------------------