关于进程页表内核部分和内核主页表的关系(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_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
- 关于进程页表内核部分和内核主页表的关系(Linux 2.6.11)
- Linux内核:轻量级进程间的关系
- Linux内核 2.4和2.6的进程内核
- 内核中的进程管理部分2-pidhash和链表
- linux内核关于进程的数据结构
- 关于内核页表和进程页表的一个问题
- linux内核和文件系统的关系
- linux发行版和内核的关系
- 理解android和linux内核的关系
- linux内核内核和进程有关的数据结构
- 内核页表和进程页表
- 内核页表和进程页表
- 内核页表和进程页表
- linux 进程的虚拟地址和内核中的虚拟地址有什么关系
- Linux内核 2.4和2.6的进程内核堆栈和task描述符
- 进程虚拟地址空间和内核空间的关系
- linux内核线程和进程
- linux 内核的启动部分
- Linux 加,减,乘,除
- InvocationTargetException
- LeetCode——001
- 如何才能取到没有在.h文件中声明,但在.m文件中实现的方法
- 分享一个链接
- 关于进程页表内核部分和内核主页表的关系(Linux 2.6.11)
- java要整理的一些知识
- maven两个错误的解决方式
- AOAPC:Chapter1Example2 (UVa 11729)
- .net / C#程序读取MAC地址的几种方法
- Android studio 快捷键
- Java中的PushbackReader流理解
- 最大流和最小割
- Flume NG与MySQL整合开发