深入理解Linux虚拟内存管理,《深入理解LINUX内存管理》学习笔记 (三)

PMD_SHIFT是线性地址中第三级页表的所占的位数,PMD_SIZE和PMD_MARK是由这个宏计算得到的。

PUD_SHIFT是线性地址中第二级页表的所占的位数,PUD_SIZE和PUD_MARK是由这个宏计算得到的。

PGD_SHIFT是线性地址中第一级页表的所占的位数,PGD_SIZE和PGD_MARK是由这个宏计算得到的。

k.JPG

最后介绍4个重要的宏:PTRS_PER_PGD,PTRS_PER_PUD, PTRS_PER_PMD,PTRS_PER_PTE。它们用于确定每级页表有多少条目。

不使能PAE特性的x86体系结构这几个宏定义如下:

#define PTRS_PER_PGD  1024

#define PTRS_PER_PUD    1  //这种情况下PUD事实不起作用,为了代码的硬件无关性,设置为1。

//在include/asm-generic/pgtable-nopud.h中定义

#define PTRS_PER_PMD  1  //这种情况下PMD事实不起作用,为了代码的硬件无关性,设置为1。

//在include/asm-generic/pgtable-nopmd.h中定义

#define PTRS_PER_PTE  1024 页表条目(Page table entry)

页表的每个条目都是一个声明为数据结构的对象:pgd_t,pud_t,pmd_t和pte_t分别对应PGD,PUD,PMD和PTE。

虽然这些数据结构常常只有一个无符号整数,它们被定义成数据结构有2个原因:第一,类型保护,防止被不合适的方式使用。第二,容易扩展每个条目所占字节的数量,如x86使能PAE,则需要另外加入4位(原书是说4位,但是我觉得应该是错误的,应该是加入了4个字节),以使得能够访问多余4GB的物理内存。

为了保持一些保护位,定义了pgprot_t数据结构,它保存相关的标志,通常会保持在页表条目的低位区域。

为了类型的计算,在文件asm/page_32.h或者asm/page_64.h中定义了5个宏。传入上述的类型,返回相应的数据结构中的部分数值:pte_val(),pmd_val(),pud_val()和pgprot_val(). 相反的操作的计算的宏:__pte(),__pmd(),__pud(),__pgd()和__pgprot()。

条目中的状态位,完全是和体系结构相关的。下面解释一下不使能PAE的x86体系结构下,各个状态位的含义。

没有使能PAE的x86,pte_t数据结构中只有一个32位的整数。每个PTE中的类型为pte_t的指针指向一个页面的首地址,也就是说指向的地址总是页面对齐的。因此,在这个整数中PAGE_SHIFT指定数目的位数,也就是12位,是给页表条目中的状态位。列表如下:

l.JPG

比较费解的是_PAGE_PROTNONE这个状态位,x86的体系结构上并不存在这个状态位,LINUX内核借用了PAT位作为这个来使用。这里还有一个问题如果有PSE位被设置,则PAT位的位置就会使用另外一个位置,幸运的是,LINUX内核不会在用户页面中使用PSE特性。LINUX内核挪用这个位的目的是:确定一个虚拟内存的页面在物理内存中是存在的,但是用户空间的进程不能访问它,如同对一段内存区域调用mprotect() API函数并传入PROT_NONE标志一样。当一段内存区域被要求保护,_PAGE_PRESENT为被清除,_PAGE_PROTNONE位被置一。pte_present()宏会同时检测这2位的设置情况,让kernel能够自己知道对应的PTE是否可用:

#define pte_present(x)  ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))

如果正好是用户空间不能访问的页面,这就相当巧妙了,但是也相当的重要考量。因为硬件状态为_PAGE_PRESENT已经被清除,当试图访问这个页面的时候,会产生一个page fault的异常,LINUX内核强制的保护了页面访问,但是内核还是知道页面是存在的,如果需要交换到磁盘或者进程退出释放页面,能够做出正确的动作。

页表条目的操作

X86体系结构的情况下,在include/asm-x86/pgtable.h文件中,定义了“析出”或者“检查”页表条目中的值的几个宏(在2.6.24版本的内核中,由于体系结构的关系,这几个宏可能分布在几个相关的头文件中)。

通过 4 个宏,把一个线性地址从第一级页目录表 (Page directories) 追巡最后一级页目录表。

pgd_offset:通过线性地址 ( 其中的一部分指出了需要访问的内存地址在的 PGD 中的索引 ) 和进程的 mm_struct 数据结构对象,返回一个指向 PGD 条目的地址,内容是某个 PUD 页面的首地址。

pud_offset:通过线性地址(也是索引)和指向 PGD 条目的地址,返回一个指向 PUD 条目的地址,内容是某个 PMD 页面的首地址。如果硬件系统并不支持 PUD , 则直接返回指向 PGD 条目的地址。也就是通过巧妙的直接返回 PGD 的方式,使得不同体系结构下,统一的软件架构。

pmd_offset:通过线性地址(也是索引)和指向 PUD 条目的地址,返回一个指向 PMD 条目的地址,内容是某个 PTE 页面的首地址。如果硬件系统并不支持 PMD , 则直接返回指向 PUD 条目的地址。也就是通过巧妙的直接返回 PUD 的方式,使得不同体系结构下,统一的软件架构。

pte_offset:通过线性地址(也是索引)和指向 PMD 条目的地址(内容是 PMD 页面的首地址),返回一个指向 PTE 条目的地址,内容是某个需要访问的数据内存页面的首地址(物理地址),这个地址和线性地址的低位部分的数据在内存页面中的偏移相加,就获得了数据真正所在的物理地址了。

第二组宏,用于检测页表条目是否存在或者是否可用的信息。pte_none(), pmd_none(), pud_none(),pgd_none() ,如果对应的条目不存在,则返回 1 。宏的定义只是检测条目的内容是否全 0.pte_present(), pmd_present(), pud_present(),pgd_present(),如果条目中的 PRESENT 位被设置,则返回 1.pte_clear(), pmd_clear(), pud_clean(),pgd_clear(),对相应条目清零。pmd_bad(), pud_bad(),pgd_bad(),

====

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值