static inline pte_t *get_one_pte_map_nested(struct mm_struct *mm, unsigned long addr) { pgd_t * pgd; pmd_t * pmd; pte_t * pte = NULL; pgd = pgd_offset(mm, addr); if (pgd_none(*pgd)) goto end; if (pgd_bad(*pgd)) { pgd_ERROR(*pgd); pgd_clear(pgd); goto end; } pmd = pmd_offset(pgd, addr); if (pmd_none(*pmd)) goto end; if (pmd_bad(*pmd)) { pmd_ERROR(*pmd); pmd_clear(pmd); goto end; } pte = pte_offset_map_nested(pmd, addr); if (pte_none(*pte)) { pte_unmap_nested(pte); pte = NULL; } end: return pte; }
/* * need to get a 16k page for level 1 */ pgd_t *get_pgd_slow(struct mm_struct *mm) { pgd_t *new_pgd, *init_pgd; pmd_t *new_pmd, *init_pmd; pte_t *new_pte, *init_pte; unsigned long flags; new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2); if (!new_pgd) goto no_pgd; memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); /* * Copy over the kernel and IO PGD entries */ init_pgd = pgd_offset_k(0); pgd_list_lock(flags); memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); pgd_list_add(new_pgd); pgd_list_unlock(flags); clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); if (!vectors_high()) { #ifdef CONFIG_ARM_FCSE /* FCSE does not work without high vectors. */ BUG(); #endif /* CONFIG_ARM_FCSE */ /* * On ARM, first page must always be allocated since it * contains the machine vectors. */ new_pmd = pmd_alloc(mm, new_pgd, 0); if (!new_pmd) goto no_pmd; new_pte = pte_alloc_map(mm, new_pmd, 0); if (!new_pte) goto no_pte; init_pmd = pmd_offset(init_pgd, 0); init_pte = pte_offset_map_nested(init_pmd, 0); set_pte_ext(new_pte, *init_pte, 0); pte_unmap_nested(init_pte); pte_unmap(new_pte); } return new_pgd; no_pte: pmd_free(mm, new_pmd); no_pmd: free_pages((unsigned long)new_pgd, 2); no_pgd: return NULL; }
/* * get_pgd_slow:申请一个pgd项 * notice:一个pgd占用4个页框,每一个pgt项大小为8字节 */ pgd_t *get_pgd_slow(struct mm_struct *mm) { pgd_t *new_pgd, *init_pgd; pmd_t *new_pmd, *init_pmd; pte_t *new_pte, *init_pte; /*pgd占用四个页框*/ new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2); if (!new_pgd) goto no_pgd; memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); /* * 复制内核与I/O PGD entries */ init_pgd = pgd_offset_k(0); memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); if (!vectors_high()) { /* * On ARM, first page must always be allocated since it * contains the machine vectors. */ new_pmd = pmd_alloc(mm, new_pgd, 0); if (!new_pmd) goto no_pmd; /*返回pmd的第0项页表项,因为第0项用于映射中断向量*/ new_pte = pte_alloc_map(mm, new_pmd, 0); if (!new_pte) goto no_pte; /*返回中断向量的页表项,中断向量位于低地址空间时(0地址开始处)*/ init_pmd = pmd_offset(init_pgd, 0); init_pte = pte_offset_map_nested(init_pmd, 0); /*给新的页表项映射中断向量的页表项*/ set_pte_ext(new_pte, *init_pte, 0); pte_unmap_nested(init_pte); /*取消new_pte的高端内存的页表映射*/ pte_unmap(new_pte); } return new_pgd; no_pte: pmd_free(mm, new_pmd); no_pmd: free_pages((unsigned long)new_pgd, 2); no_pgd: return NULL; }
/* * need to get a 16k page for level 1 */ pgd_t *get_pgd_slow(struct mm_struct *mm) { pgd_t *new_pgd, *init_pgd; pmd_t *new_pmd, *init_pmd; pte_t *new_pte, *init_pte; new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2); if (!new_pgd) goto no_pgd; memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); /* * Copy over the kernel and IO PGD entries */ init_pgd = pgd_offset_k(0); memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); if (!vectors_high()) { /* * On ARM, first page must always be allocated since it * contains the machine vectors. */ new_pmd = pmd_alloc(mm, new_pgd, 0); if (!new_pmd) goto no_pmd; new_pte = pte_alloc_map(mm, new_pmd, 0); if (!new_pte) goto no_pte; init_pmd = pmd_offset(init_pgd, 0); init_pte = pte_offset_map_nested(init_pmd, 0); set_pte_ext(new_pte, *init_pte, 0); pte_unmap_nested(init_pte); pte_unmap(new_pte); } return new_pgd; no_pte: pmd_free(mm, new_pmd); no_pmd: free_pages((unsigned long)new_pgd, 2); no_pgd: return NULL; }
static int move_one_page(struct vm_area_struct *vma, unsigned long old_addr, unsigned long new_addr) { struct mm_struct *mm = vma->vm_mm; struct pte_chain * pte_chain; int error = 0; pte_t *src, *dst; pte_chain = pte_chain_alloc(GFP_KERNEL); if (!pte_chain) return -1; spin_lock(&mm->page_table_lock); src = get_one_pte_map_nested(mm, old_addr); if (src) { /* * Look to see whether alloc_one_pte_map needs to perform a * memory allocation. If it does then we need to drop the * atomic kmap */ if (!page_table_present(mm, new_addr)) { pte_unmap_nested(src); src = NULL; } dst = alloc_one_pte_map(mm, new_addr); if (src == NULL) src = get_one_pte_map_nested(mm, old_addr); if (src) { error = copy_one_pte(vma, src, dst, old_addr, new_addr, &pte_chain); pte_unmap_nested(src); } pte_unmap(dst); } flush_tlb_page(vma, old_addr); spin_unlock(&mm->page_table_lock); pte_chain_free(pte_chain); return error; }
/* * need to get a 16k page for level 1 */ pgd_t *get_pgd_slow(struct mm_struct *mm) { pgd_t *new_pgd, *init_pgd; pmd_t *new_pmd, *init_pmd; pte_t *new_pte, *init_pte; new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2); if (!new_pgd) goto no_pgd; memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); /* * Copy over the kernel and IO PGD entries */ //#define pgd_offset_k(addr) pgd_offset(&init_mm, addr) //其实就是要拷贝内核空间的页表项... init_pgd = pgd_offset_k(0); //拷贝内核空间的pgd表项到新创建的pgd表项 memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); //把Dcache行的数据写回到主存,并清除cache行的脏标记. //参数:主存的物理地址,(确定cache行) 需要写回的长度... clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); //异常向量表是在高端地址或是在低端地址... if (!vectors_high()) { //如果是在低端地址.那么异常向量表在第一页.. /* * On ARM, first page must always be allocated since it * contains the machine vectors. */ //该函数是在new_pgd指定的PGD页表上找到地址0对应的表项,然后分配一个页. //接着填充PGD的页表项(PMD). //哦,好像略过了PUD了、对于ARM来说PMD也是直接返回pgd. new_pmd = pmd_alloc(mm, new_pgd, 0); if (!new_pmd) goto no_pmd; //如果为空则分配一个页面,然后设置PGD的页表项. new_pte = pte_alloc_map(mm, new_pmd, 0); if (!new_pte) goto no_pte; //init_pgd就是init进程的页表,这里得到地址0的PGD页表的表项(PMD) init_pmd = pmd_offset(init_pgd, 0); //根据init_pmd,得到了PMD页表,然后根据0地址得到了PMD的表项(PTE) init_pte = pte_offset_map_nested(init_pmd, 0); //new_pte指定了要存放PTE的地址,init_pte就是PTE的值。 set_pte_ext(new_pte, *init_pte, 0); pte_unmap_nested(init_pte); pte_unmap(new_pte); } return new_pgd; no_pte: pmd_free(mm, new_pmd); no_pmd: free_pages((unsigned long)new_pgd, 2); no_pgd: return NULL; }