可能有错,更新中。。。
用2级页表将用户空间的0-3G线性地址映射到256MBSDRAM的物理地址3000 0000-3FFF FFFF中
2^10=1024=0x400 2^12=4096=0x1000 2^14=16384=0x4000
1个页目录-->覆盖3GB物理内存范围(可以4GB)
1个页目录项-->1个页表-->覆盖4MB物理内存范围
1个页表项-->1个物理页框-->覆盖4KB物理内存范围
1个页目录占1个页框,4KB
一个页表占1个页框,4KB
**********************************************************************************************************************
1每个进程对应一个页目录(花费4KB内存)--页目录应该放在了内核空间的起始地址即0xc000 0000(如果内核空间起始地址映射到了物理空间起始地址处,则上面的例子有些不妥,页目录起始地址应该是0x3000 0000才好)
--页目录中,每个进程的0-767项不怎么相同,但所有进程的768-1023项和内核页目录的768-1023项相同,见ulk3 ch2 进程页表那节
2.如果进程0将其768个页目录项都用完,意味这对应有768个页表(需花费3MB内存)
所以如果一个内核要完全映射一个大小为3GB的进程(代码段数据段等的总大小),需要额外用3MB+4KB的内存来保存相关寻址信息
不过现阶段貌似不会发生这种情况,最常见的每个进程只使用几百kB(linux操作系统原理与应用 陈莉君 p95),一个页目录+1个页表(共计8KB)足够用了
3.两个相邻的页目录项可以指向不相邻的物理页
4.两个相邻的页表项可以指向不相邻的物理页
5.页目录的内容随着页表的增加减少更改而更新,页表的内容随着物理页框的增加减少更改而更新
实际中,刚开始时这些页表项的内容为空,而在真正要对某个线性地址读写数据的时候才会分配物理单元。如下
当访问一个线性地址如0xBFC0 4FFE时,mmu根据线性地址的信息找到了页表767的4号页表项,发现其内容为空,于是发出缺页中断,内核控制路径用get_zerod_page(lkd2 p148)在适当的内存区找到一个物理页,将该物理页的page结构体count+1(表明此物理页已名花有主),然后将此物理页的首地址塞进4号页表项里,然后mmu就可以执行上面的第3步了
(现阶段是这样理解的外加一点猜测可能有误更新中),一个疑问,get_zerod_page返回的是什么样的线性地址???
当下一次再去访问这个地址时,由于线性地址已经映射过物理页框,便可直接访问
**********************************************************************************************************************
比如要访问线性地址0xBFC0 4FFE(1byte),
2进制形式
假设linux是按照上图所示安排进程0的页目录和页表
假设进程0在运行,进程0的页目录起始物理地址保存在cr3寄存器中cr3=0x3800 0000
1.mmu先取线性地址高10位(31-22)=767,x4=3068=0xBFC,+cr3=0x3800 0bfc,即页目录项在内存的地址,此地址的内容0x392f f000即页表首地址(页对齐最后12位清0)
2.mmu取线性地址下面10位数(21-12)=4,x4=16=0x10,+0x392f f000=0x392f f010,即页表项在内存的地址,此地址的内容0x3080 4000即物理页面的首地址(页对齐最后12位清0)
3.mmu取线性地址最后12位数(11-0)=4094=0xffe作为低12位,0x3080 4000的前20位作为高20位,组成一个新的32位数0x3080 4ffe即线性地址0xBFC0 4FFE对应的物理地址
内核中涉及的不都是线性地址吗?而要从线性地址得到物理地址要经过mmu转换,现在mmu还没开始呢,那么内核从哪里搞来这个物理地址的呢?下面回答了这个问题,不是所有的线性地址都经过mmu才能找到物理地址的,_pa也可以,他给mmu的上场表演开了一个头
(
进程的页目录PGD(属于内核数据结构)就处于内核空间中。在进程切换时,要将寄存器CR3设置成指向新进程的页目录PGD,而该目录的起始地址在内核空间中是虚地址,但CR3所需要的是物理地址,这时候就要用__pa()进行地址转换。在mm_context.h中就有这么一行语句:
asm volatile(“movl %0,%%cr3”: :”r” (__pa(next->pgd));
这是一行嵌入式汇编代码,其含义是将下一个进程的页目录起始地址next_pgd,通过__pa()转换成物理地址,存放在某个寄存器中,然后用mov指令将其写入CR3寄存器中。经过这行语句的处理,CR3就指向新进程next的页目录表PGD了。
refer to http://oss.org.cn/kernel-book/ch06/6.1.2.htm
)
一个进程的线性地址范围是0-3GB,即线性地址在c000 0000以内,即前12位是1100 0000 00以内,即768以内,即最多有768个页目录项,项索引为0-767(其余的768-1023项内容见上所述),所以可以寻址3GB的物理内存,但范围可以不限于0-3GB,即映射到哪个物理页由页表项的内容决定,比如一个页表项内容是CFFF 1000,则访问此物理页,即物理地址不会局限在c000 0000以内
*****************************************************************************************************************************************
页表项的内容代表了实际的物理地址,所以如果一个系统仅有256MB的内存,则共需64个页表,64x1024个页表项,且物理地址从0x3000 0000开始,那么页表项的内容应该在0x3000 0000---0x3FFF FFFF之间的数字即
0x3000 0000
0x3000 1000...
0x303F F000
0x3040 0000
0x3040 1000...
0x307F F000
0x3080 0000
0x3080 1000...
0x30BF F000
0x30C0 0000
0x30C0 1000...
0x30FF F000
0x3100 0000
0x3100 1000...
0x313F F000
0x3140 0000
0x3140 1000...
0x317F F000
...
...
0x3FC0 0000
0x3FC0 1000...
0x3FFF F000
具有256MB内存的mini2440的页表内容的应该此范围内----可惜linux2.6.32.2用4级页表,所以不成立
内核负责维护页表项的内容,因为内核知道哪个物理页面可以用,但手动帮内核修改一下页表项的内容便可实现操作特定的物理页面的效果
*****************************************************************************************************************************************
页目录项或页表项的最后12位是其属性,具体格式如下(上面为了表达简洁,将最后12位全设0,实际不是)
(点击查看大图)图4-18 页目录和页表的表项格式
P--位0是存在(Present)标志,用于指明表项对地址转换是否有效。P=1表示有效;P=0表示无效。在页转换过程中,如果说涉及的页目录或页表的表项无效,则会导致一个异常。如果P=0,那么除表示表项无效外,其余位可供程序自由使用,如图4-18b所示。例如,操作系统可以使用这些位来保存已存储在磁盘上的页面的序号。
R/W--位1是读/写(Read/Write)标志。如果等于1,表示页面可以被读、写或执行。如果为0,表示页面只读或可执行。当处理器运行在超级用户特权级(级别0、1或2)时,则R/W位不起作用。页目录项中的R/W位对其所映射的所有页面起作用。
U/S--位2是用户/超级用户(User/Supervisor)标志。如果为1,那么运行在任何特权级上的程序都可以访问该页面。如果为0,那么页面只能被运行在超级用户特权级(0、1或2)上的程序访问。页目录项中的U/S位对其所映射的所有页面起作用。
A--位5是已访问(Accessed)标志。当处理器访问页表项映射的页面时,页表表项的这个标志就会被置为1。当处理器访问页目录表项映射的任何页面时,页目录表项的这个标志就会被置为1。处理器只负责设置该标志,操作系统可通过定期地复位该标志来统计页面的使用情况。
D--位6是页面已被修改(Dirty)标志。当处理器对一个页面执行写操作时,就会设置对应页表表项的D标志。处理器并不会修改页目录项中的D标志。
AVL--该字段保留专供程序使用。处理器不会修改这几位,以后的升级处理器也不会。
原文链接:https://blog.csdn.net/opencpu/article/details/6784344