关于进程页表内核部分和内核主页表的关系(Linux 2.6.11)

来源:互联网 发布:人工智能百度云资源 编辑:程序博客网 时间:2024/06/04 20:44

用户态页表共享内核主页表的PUD表和PMD表,所以可以看到内核态访问进程页表的时候(内核地址部分),PMD和PUD都是直接使用


/* * 这里在为pgd分配从slab中页面的时候会调用pgd_ctor对页面进行初始化 * 其中就会把swapper_pg_dir(init进程的内核主页表的内容)的内容复制到新的进程页表的内核页表部分中 */void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused){unsigned long flags;if (PTRS_PER_PMD == 1)spin_lock_irqsave(&pgd_lock, flags);    /*      * 把swapper_pg_dir(init进程的内核主页表的内容)的内容复制到新的进程页表的内核页表部分中,     * 通过复制直接让新的pgd执行了swapper_pg_dir中的PUD表和PMD表,复用了swapper_pg_dir中的PMD和PUD表     * 通过这里可以知道,用户态页表共享内核主页表的PUD表和PMD表,     * 所以可以看到内核态访问进程页表的时候(内核地址部分),PMD和PUD都是直接使用     */memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,swapper_pg_dir + USER_PTRS_PER_PGD,(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); /*★*/    /*启用PAE的情况,后面还要再分配用户空间的PMD*/if (PTRS_PER_PMD > 1)return;pgd_list_add(pgd);spin_unlock_irqrestore(&pgd_lock, flags);    /*清空用户态地址的PMD的pgd*/memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));}


注册PGD的SLAB分配初始化函数为pgd_ctor

pgd_cache = kmem_cache_create("pgd",PTRS_PER_PGD*sizeof(pgd_t),PTRS_PER_PGD*sizeof(pgd_t),0,pgd_ctor,PTRS_PER_PMD == 1 ? pgd_dtor : NULL);

pgd_t *pgd_alloc(struct mm_struct *mm){int i;    /*     * 分配一个pgd表项,这里已分配就是一整个页面,对于未启动PAE的情况相当于已经分配了PMD和PUD的空间     * 注意,在pgtable_cache_init中注册了初始化函数为pgd_ctor     * pgd_ctor会把swapper_pg_dir(init进程的内核主页表的内容)的内容复制到新的进程页表的内核页表部分中     */pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);        ......return pgd;out_oom:for (i--; i >= 0; i--)kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));kmem_cache_free(pgd_cache, pgd);return NULL;}



进程地址空间的创建
copy_process->copy_mm->mm_init->mm_alloc_pgd -> pgd_alloc


使用内核页表的举例的情况

fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code){......vmalloc_fault:{    int index = pgd_index(address);unsigned long pgd_paddr;pgd_t *pgd, *pgd_k;pud_t *pud, *pud_k;pmd_t *pmd, *pmd_k;pte_t *pte_k;asm("movl %%cr3,%0":"=r" (pgd_paddr));pgd = index + (pgd_t *)__va(pgd_paddr);/** * 把主内核页全局目录的线性地址赋给pgd_k */pgd_k = init_mm.pgd + index;if (!pgd_present(*pgd_k))goto no_context;pud = pud_offset(pgd, address); //直接用,没有分配,因为共享了内核主页表的PUDpud_k = pud_offset(pgd_k, address);if (!pud_present(*pud_k))goto no_context;pmd = pmd_offset(pud, address); //直接用,没有分配,因为共享了内核主页表的PMD</span>pmd_k = pmd_offset(pud_k, address);if (!pmd_present(*pmd_k))goto no_context;set_pmd(pmd, *pmd_k); //这里有共享了PT,因为PMD,PUD都是共享的,所以vmalloc只可能是因为pgd中的present没有置位引发的pte_k = pte_offset_kernel(pmd_k, address); if (!pte_present(*pte_k))goto no_context;return; }}


0 0