Normal
0
7.8 磅
0
2
false
false
false
MicrosoftInternetExplorer4
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
在2.6内核中,所有进程的内核空间(3G-4G)都是共享的。
LINUX内核在初始化过程中,内核页表的初始化在保护模式下,但是此时尚未开启分页机制。内核填充PGD表(静态数组),使得(3G-4G)的虚拟地址映射到物理地址(0-1G),确切的讲,是(3G -3G+896M)的虚拟地址映射到物理地址(0-896M),因为剩下的(3G+896M--4G)虚拟空间可以用来映射物理存储器的高端地址(大于896M)。然后内核将PGD基地址加载到CR3中,将CR0的PG位置1,正式开启分页机制。此时,(3G-3G+896M)的虚拟地址正式映射到物理地址(0-896M)。
内核页表PGD将作为进程SWAPPER(PID=0)的页表,SWAPPER是系统中的第一个进程,除了SWAPPER,内核还创建INIT进程。
INIT进程的页表跟内核页表是一致的,系统中的其它所有用户进程都是INIT进程的儿子或后代。
而在LINUX中,用户进程的创建都是父进程通过FORK()函数实现,创建的子进程有两种情形:1)子进程与父进程完全共享地址空间,此时它们共享PGD以及PTE;2)子进程不与父进程共享地址空间,此时它们有各自的PGD与PTE,但是(在创建之初)子进程的PGD与PTE是父进程的拷贝。
在各个进程的运行过程中,他们的页表可能会发生变化,比如发生缺页异常,或者执行EXEC()系列函数,但是所有这些页表项的变化都属于用户空间(0--3G)。内核空间的页表几乎不变,确切的讲,(3G-3G+896M)之间的页表项不变(也就是说,所有进程的3G--3G+896M的虚拟地址都映射到物理地址0--896M)。相反,(3G+896M--4G)之间的页表可能会变,比如内核执行VMALLOC()函数,可能就会修改(3G+896M--4G)之间的页表,为了使所有进程的内核空间(3G--4G)都保持一致,原则上必须修改每个进程的(3G+896M--4G)之间的页表,这样做的效率比较低下。LINUX内核通过PAGE FAULT机制保持所有进程的(3G+896M--4G)之间的页表一致。
比如在vmalloc分配了一块内存,如何通知所有的进程修改其页表呢?遍历修改?vmalloc先在kernel virtual space找出一段空间,分配出物理页,然后更新到init_mm.pgd所指的page table中。但是当前进程的page table中kernel virtual space那段还是要通过page fault来更新。当发生page fault时,内核通过读取cr2来判断异常的类型,异常发生时cpu会将3位的error_code压入到栈中。如果发生了由于内核访问不存在的页框引起的异常,就跳转去执行vmalloc_fault标记处的代码。这部分代码负责从主内核页表中取出相应信息并更新当前进程的页表。
阅读(1128) | 评论(0) | 转发(1) |