认真阅读章节资料,掌握什么是分页机制
调试代码,掌握分页机制基本方法与思路
- 代码pmtest6.asm中,212行~237行,设置断点调试这几个循环,分析究竟在这里做了什么
掌握PDE,PTE的计算方法
- 动手画一画这个映射图
- 为什么代码3.22里面,PDE初始化添加了一个PageTblBase(Line 212),而PTE初始化时候没有类似的基地址呢(Line224)?
熟悉如何获取当前系统内存布局的方法
掌握内存地址映射关系的切换
- 画出流程图
基础题:依据实验的代码,
- 自定义一个函数,给定一个虚拟地址,能够返回该地址从虚拟地址到物理地址的计算过程,如果该地址不存在,则返回一个错误提示。
- 完善分页管理功能,补充alloc_pages, free_pages两个函数功能,试试你能一次分配的最大空间有多大,如果超出了有什么办法解决呢?
进阶题(选做)
- 设计一个内存管理器,选择其一实现:首次适应算法、最佳适应算法、伙伴算法,要求实现内存的分配与回收。(提示,均按照页为最小单位进行分配、对于空闲空间管理可采用位图法或者双向链表法管理)
什么是分页机制
分页机制就是通过页目录和页表将物理地址与线性地址进行映射
页就是指一块内存,一般来说大小在4 KB。
分页机制使进程运行在线性地址上,不必关注物理地址的情况,提供了虚拟内存和隔离机制,是内存的调度完全由操作系统负责。
分页机制实现的基本方法
分页机制使用二级页表实现
第一级叫页目录:大小4 KB,共1024表项(PDE),表项对应一个二级页表
第二级页表:1024个表项(PTE),每个表项对应一个物理页
线性地址转换时,
- 寄存器cr3指定页目录
- 线性地址高十位为页目录索引
- 线性地址第二个十位为二级页表索引
注:PDE,PTE,cr3寄存器都由高二十位进行寻址,这是因为页表地址都是4 KB对齐的。
分页机制的标志
cr0寄存器 的 最高位 PG位,PG位为1表示分页机制生效
调试 pmtest6.asm
212行----237行
分析:
.1 部分是在初始化目录页,大小为4096,将目录页首地址存在目录页的第一个表项中
.2部分实在初始化其他页表,一共1024个页表,需要1024 x 1024。
.3预备阶段将目录页基地址赋给cr3,将cr0的PG位置1,启动分页机制。
magic break断点调试
PDE和PTE的计算方法
映射图
为什么PDE添加了基地址,PTE不添加基地址
???不清楚,可能PDE是指向页表的映射,而页目录本身也是一个页表。PTE是指向物理页的映射,所以不存自己页表的地址。
也可能cr3不存页目录基地址,只能页目录自己来存,而PTE所在页表的基地址在页目录中存放,不需要自己额外存。
如何获取当前系统内存布局
使用中断15 h
参数:
eax:获取内存信息,ax赋值0E820h
ebx:放置着“后续值continuation value”第一次调用时ebx必须为0。
es : di :指向一个地址范围描述符结构ARDS (Address Range Descriptor Structure), BIOS将会填充此结构。
ecx : es : di所指向的地址范围描述符结构的大小以字节为单位。无论es: di所指向的结构如何设置BIOS最多将会填充ecx个字节。不过通常情况下无论ecx为多大BIOS只填充20字节有些BIOS忽略ecx的值总是填充20字节。
edx :0534D4150h('SMAP')──BIOS将会使用此标志对调用者将要请求的系统映像信息进行校验这些信息会被BIOS放置到es :di所指向的结构中。
结果:
CF :CF = 0表示没有错误
eax :0534D4150h('SMAP')
es: di :返回的地址范围描述符结构指针,与输入值相同
ecx :BIOS填充在地址范围描述符中的字节数量,一般是20字节
ebx : 下次迭代时原封不动放入ebx,就可以通过它获取下一个地址范围描述符,如果ebx值为0,且CF没有进位,表示是最后一个地址描述符
地址描述符结构(ARDS)20个字节
注:调用int 15 h时返回的地址描述符需要存放在一个缓冲区中,我们要事先定义一个缓冲区
pmtest7.asm分析
定义256字节的缓冲区,es: di指向缓冲区
CF被置位或ebx为0,循环结束。
di每次增20字节,存一个描述符
内存地址映射关系的切换
6.1 线性地址到物理地址
代码如下:
; 显示地址计算过程并进行检查 -----------------------------------------
AddressCheck:
mov ax, SelectorFlatRW
mov ss, ax
mov eax, LinearAddrDemo
shr eax, 22
mov ecx, eax
shl ecx, 2
add ecx, PageDirBase1
mov eax, ss:[ecx]
mov ebx, eax
push ecx
call DispInt
pop ecx
shr ebx, 12
shl ebx, 12
push ebx
call DispInt
pop ebx
mov eax, LinearAddrDemo
shl eax, 10
shr eax, 22
mov ecx, eax
shl ecx, 2
add ebx, ecx
mov eax, ss:[ebx]
shr eax, 12
shl eax, 12
push eax
call DispInt
push ProcBar
call DispInt
ret
效果展示:
6.2 分页管理功能完善
alloc_pages的实现
alloc_pages用于连续物理内存的分配: struct page *alloc_pages(gft_t gfp, unsigned int order) alloc_pages函数用于分配2^order个 连续 的物理页。分配失败返回NULL。
free_pages的实现
void free_pages(unsigned long addr, unsigned int order) 功能:释放逻辑地址addr开始的页面2^order次方个
addr: 页面开始的逻辑地址
order: 释放页面的个数2^order个
实验结果总结
- 分页和分段有何区别?在本次实验中,段页机制是怎么搭配工作 的?
- PDE、PTE是什么?例程中如何进行初始化?CPU是怎样访问 到PDE、PTE,从而计算出物理地址的?
- 开启分页机制之后,在GDT表中、在PDE、PTE中存的地址是物理地址、线性地址,还是逻辑地址,为什么?
- 为什么PageTblBase初始值为2M+4K?能不能比这个值小?
- 怎么读取本机的实际物理内存信息?
- 如何进行地址映射与切换?
- 如何实现alloc_pages, free_pages
1.分页和分段有何区别?在本次实验中,段页机制是怎么搭配工作的?
区别在于:1、从功能上看,页是信息的物理单位,分页是为实现离散分配方式,以消减内存的外碎片,提高内存的利用率,即满足系统管理的需要,而不是用户的需要;而段是信息的逻辑单位,它含有一组其意义相对完整的信息,目的是为了能更好地满足用户的需要。2、页的大小固定且由系统确定,而段的长度却不固定,决定于用户所编写的程序。3、分页的作业地址空间是一维的,而分段的作业地址空间是二维的。
在本次实验中,未打开分页机制时,线性地址等同于物理地址,即逻辑地址通过分段机制直接转化为物理地址(由SEG找到对应Descriptor定义的段+OFFSET);启动了分页机制后,要先通过分段机制将逻辑地址转化为线性地址,在通过分页机制将线性地址转化为物理地址。首先,将页目录的段首地址设置为PageDirBase,再将页表的段首地址设置为PageTblBase,在页目录中每个表项都指向一个页表,而每个页表的表项都指向一个物理地址,从而实现了从线性地址到物理地址的映射以及离散分配。
2. PDE、PTE,是什么?例程中如何进行初始化?CPU是怎样访问到PDE、PTE,从而计算出物理地址的?
PDE(Page Directory Entry)是页目录表的表项,PTE(Page Table Entry)是页表的表项。例程中初始化的方式是通过循环将每一个PDE初始化成存在的可读可写可执行的用户级别页表,其中第一个PDE对应的页表首地址是PageDirBase。类似的,页表中每个PTE都被初始化为可读可写可执行的用户级别页表,其中第一个页表的首地址是PageTblBase。CPU首先根据分段机制,找到描述符所对应的段并加上偏移得到线性地址,得到线性地址之后,CPU会借助cr3在指定的目录页中根据线性地址的高十位得到页表地址,然后再根据线性地址的第二十一位到第十二位在页表中得到物理页首地址,最后加上第十二位偏移,从而计算出物理地址。
3. 开启分页机制之后,在GDT表中、在PDE、PTE中存的地址是物理地址、线性地址,还是逻辑地址,为什么?
在查询GDT表后得到线性地址,首先通过选择子确定对应描述符是GDT表中的第几项,然后取出段首地址加上逻辑地址的偏移,最终得到线性地址。PDE和PTE存放的都是物理地址,分别指向页表和真实地址。
4. 为什么PageTblBase初始值为2M+4K?能不能比这个值小?
因为设置页目录表起始位置为2M,而页目录表占4K,且页目录表与页表在内存中相邻,所以是2M+4K。在保证寻址大小为4G不变的情况下减小初始值,可以选择前移页目录表的起始位置。
5. 怎么读取本机的实际物理内存信息
利用中断15h,后循环读取ARDS结构。先填充如下寄存器:eax int 15h可完成许多工作,主要由ax的值决定,要获取内存信息,需要将ax赋值为0E820h,ebx寄存器放置着后续值,第一次调用时ebx必须为0。es: di 指向一个地址范围描述符结构ARDS,而BIOS将会填充此结构。ecx,es:di所指向的地址范围描述符结构的大小,以字节为单位。无论es:di所指向的结构如何设置,BIOS最多将会填充ecx个字节。edx 0534D4150h('SMAP')──BIOS将会使用此标志,对调用者将要请求的系统映像信息进行校验,这些信息会被 BIOS放置到es:di所指向的结构中。
中断调用之后,结果存放于下列寄存器之中。CF CF=0表示没有错误,否则存在错误。eax 0534D4150h('SMAP')。es: di 返回的地址范围描述符结构指针,和输入值相同。ecx BIOS填充在地址范围描述符中的字节数量,被BIOS所返回的最小值是20字节。ebx 这里放置着为等到下一个地址描述符所需要的后续值,如果 它的值为0,并且CF没有进位,表示它是最后一个地址范围描述符。
6. 如何进行地址映射与切换
通过改变cr3来转换地址映射。改变cr3从而切换页目录表,从而切换页表,从而使得同一个线性地址映射到不同的物理地址。
7. 如何实现alloc_pages,free_pages
alloc_pages的实现
alloc_pages用于连续物理内存的分配: struct page *alloc_pages(gft_t gfp, unsigned int order) alloc_pages函数用于分配2^order个 连续 的物理页。分配失败返回NULL。
free_pages的实现
void free_pages(unsigned long addr, unsigned int order) 功能:释放逻辑地址addr开始的页面2^order次方个
addr: 页面开始的逻辑地址
order: 释放页面的个数2^order个