Chinaunix首页 | 论坛 | 博客
  • 博客访问: 621752
  • 博文数量: 69
  • 博客积分: 1891
  • 博客等级: 上尉
  • 技术积分: 1359
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-20 23:38
文章分类

全部博文(69)

文章存档

2012年(46)

2011年(23)

分类: LINUX

2012-03-21 23:14:16

接着上节讲解页表项操作函数
  1. pgd_index,pud_index,pmd_index,pte_index用于从内存指针和页表项取得下一级页表的地址

    点击(此处)折叠或打开

    1. #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))

    点击(此处)折叠或打开

    1. static inline unsigned long pud_index(unsigned long address)
    2. {
    3.         return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
    4. }

    点击(此处)折叠或打开

    1. static inline unsigned long pmd_index(unsigned long address)
    2. {
    3.         return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
    4. }

    点击(此处)折叠或打开

    1. static inline unsigned long pte_index(unsigned long address)
    2. {
    3.         return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
    4. }
    可以看到这几个函数的形式都是XXX_index(address) = (address >> XXX_SHIFT) & (PTRS_PER_XXX-1)

        其中,XXX是pgd,pud,pmd,pte其中一项,XXX_SHIFT表示到XXX表项需要移动的位数,PTRS_PER_XXX表示XXX表项能够容纳的表项的多少。

     例如pgd_index,PGDIR_SHIFT为15位,先将address右移15位,得到PGD和PUD的部分,然后和PTRS_PER_PMD-1想与,取得PUD的值,并返回,这个函数的作用是返回address对应的pmd。

2、pgd_present,pud_present,pmd_present,pte_present的作用是检查对应的_PRESENT位是否置位


点击(此处)折叠或打开

  1. static inline int pgd_present(pgd_t pgd)
  2. {
  3.         return pgd_flags(pgd) & _PAGE_PRESENT;
  4. }

点击(此处)折叠或打开

  1. static inline int pud_present(pud_t pud)
  2. {
  3.         return pud_flags(pud) & _PAGE_PRESENT;
  4. }

点击(此处)折叠或打开

  1. static inline int pmd_present(pmd_t pmd)
  2. {
  3.         return pmd_flags(pmd) & _PAGE_PRESENT;
  4. }

点击(此处)折叠或打开

  1. static inline int pte_present(pte_t a)
  2. {
  3.         return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE);
  4. }
这几个函数的实现基本都一致,都是先取得flags,然后和_PAGE_PRESENT相与。
下面是pte_flags的实现

点击(此处)折叠或打开

  1. static inline pteval_t pte_flags(pte_t pte)
  2. {
  3.         return native_pte_val(pte) & PTE_FLAGS_MASK;
  4. }
这里通过native_pte_val取得pte,然后用PTE_FLAGS_MASK取得flags
下面是native_pte_val的实现

点击(此处)折叠或打开

  1. static inline pteval_t native_pte_val(pte_t pte)
  2. {
  3.         return pte.pte;
  4. }
这里直接返回pte.pte,pte_t的定义如下:

点击(此处)折叠或打开

  1. typedef union {
  2.         pteval_t pte;
  3.         pteval_t pte_low;
  4. } pte_t;

3、pgd_none,pud_none,pmd_none,pte_none,和上面的函数作用相反
4、pgd_clear,pud_clear,pmd_clear,pte_clear删除传递的页表项
  

点击(此处)折叠或打开

  1. static inline void pgd_clear(pgd_t *pgdp)
  2. {
  3.         set_pgd(pgdp, __pgd(0));
  4. }

这里调用set_pgd设置pgdp指向的pgd项为__pgd(0)
set_pgd的定义如下:

点击(此处)折叠或打开

  1. static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
  2. {
  3.         pgdval_t val = native_pgd_val(pgd);

  4.         if (sizeof(pgdval_t) > sizeof(long))
  5.                 PVOP_VCALL3(pv_mmu_ops.set_pgd, pgdp,
  6.                             val, (u64)val >> 32);
  7.         else
  8.                 PVOP_VCALL2(pv_mmu_ops.set_pgd, pgdp,
  9.                             val);
  10. }

这里又出现了那个神奇的调用,纠结~~
__pgd(val)的定义如下:

点击(此处)折叠或打开

  1. static inline pgd_t __pgd(pgdval_t val)
  2. {
  3.         pgdval_t ret;

  4.         if (sizeof(pgdval_t) > sizeof(long))
  5.                 ret = PVOP_CALLEE2(pgdval_t, pv_mmu_ops.make_pgd,
  6.                                    val, (u64)val >> 32);
  7.         else
  8.                 ret = PVOP_CALLEE1(pgdval_t, pv_mmu_ops.make_pgd,
  9.                                    val);

  10.         return (pgd_t) { ret };
  11. }
5、pgd_bad,pud_bad,pmd_bad检查中间页表项、上层页表项、全局页表项是否无效

点击(此处)折叠或打开

  1. static inline int pud_bad(pud_t pud)
  2. {
  3.         return (pud_flags(pud) & ~(_KERNPG_TABLE | _PAGE_USER)) != 0;
  4. }

6、pmd_page,pud_page,pte_page返回保存页数据的page结构活着中间页目录的项

点击(此处)折叠或打开

  1. #define pmd_page(pmd) pfn_to_page((pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT)
  2. #define pud_page(pud) pfn_to_page(pud_val(pud) >> PAGE_SHIFT)
  3. #define pte_page(pte)   pfn_to_page(pte_pfn(pte))
这里都调用了pfn_to_page函数

点击(此处)折叠或打开

  1. #define __pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET))



阅读(3939) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~