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

84 篇文章 6 订阅
15 篇文章 1 订阅

用户态页表共享内核主页表的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); //直接用,没有分配,因为共享了内核主页表的PUD
	pud_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;
 }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值