- 论坛徽章:
- 0
|
本帖最后由 junnyg 于 2013-04-20 19:25 编辑
回复 3# arm-linux-gcc
1. fork一个新进程时,其内核态页表项内容是从init进程的页表中拷贝过来的
do_fork->copy_process->copy_mm->dup_mm->mm_alloc_pgd->mm_alloc_pgd->pgd_alloc
arm- #define pgd_alloc(mm) get_pgd_slow(mm)
复制代码 /*
* 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));
[fly]/*
* 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));[/fly]
... ...
}
x86
- pgd_t *pgd_alloc(struct mm_struct *mm)
- {
- ... ...
- pgd_ctor(pgd);
- ... ...
- }
复制代码 static void pgd_ctor(pgd_t *pgd)
{
/* If the pgd points to a shared pagetable level (either the
ptes in non-PAE, or shared PMD in PAE), then just copy the
references from swapper_pg_dir. */
if (PAGETABLE_LEVELS == 2 ||
(PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD) ||
PAGETABLE_LEVELS == 4) {
clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY,
swapper_pg_dir + KERNEL_PGD_BOUNDARY,
KERNEL_PGD_PTRS);
paravirt_alloc_pmd_clone(__pa(pgd) >> PAGE_SHIFT,
__pa(swapper_pg_dir) >> PAGE_SHIFT,
KERNEL_PGD_BOUNDARY,
KERNEL_PGD_PTRS);
}
/* list required to sync kernel mapping updates */
if (!SHARED_KERNEL_PMD)
pgd_list_add(pgd);
}
回复 4# blake326
2. 内核态页表项何时更改 & 同步
内核页表项会更改并同步的只有vmalloc的映射区,包括ioremap、vmalloc建立的映射,这两个函数调用时会对本进程和init进程的内核空间页表进行修改;其他进程会在缺页异常中从init进程的页表中同步过来,x86在do_page_fault里的vmalloc_fault分支处理里修改,arm则在一级页表解析异常处理函数do_translate_fault中做处理
x86
- /*
- * This routine handles page faults. It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
- dotraplinkage void __kprobes
- do_page_fault(struct pt_regs *regs, unsigned long error_code)
- {
- ... ...
- if (unlikely(fault_in_kernel_space(address))) {
- if (!(error_code & (PF_RSVD | PF_USER | PF_PROT))) {
- if (vmalloc_fault(address) >= 0)
- return;
- if (kmemcheck_fault(regs, address, error_code))
- return;
- }
- ... ...
- }
- ... ...
- }
复制代码 vmalloc_fault->vmalloc_sync_one
32位:
vmalloc_fault->vmalloc_sync_one
if (!pmd_present(*pmd))
set_pmd(pmd, *pmd_k);
else
BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
64位:
vmalloc_fault
if (pgd_none(*pgd))
set_pgd(pgd, *pgd_ref);
else
BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
arm的处理在一级页目录解析异常处理函数do_translation_fault中处理
arm的数据异常处理表:
- static struct fsr_info ifsr_info[] = {
- ... ...
- { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
- { do_bad, SIGSEGV, SEGV_ACCERR, "page access flag fault" },
- { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
- { do_bad, SIGBUS, 0, "external abort on non-linefetch" },
- { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" },
- { do_bad, SIGBUS, 0, "unknown 10" },
- { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" },
- { do_bad, SIGBUS, 0, "external abort on translation" },
- { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
- { do_bad, SIGBUS, 0, "external abort on translation" },
- { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
- ... ...
- };
复制代码 缺页异常处理流程
entry-armv.S->__dabt_svc ->do_DataAbort ->do_translation_fault
if (!pgd_present(*pgd))
set_pgd(pgd, *pgd_k) |
|