以下讨论不考虑页表隔离的情况下。
一、do_page_fault()
内核初始阶段结束后,任何进程或内核线程都不能直接使用内核页表,当内核态进程对vmalloc分配非连续内存区的第一次访问时,当把内核虚拟地址转换为物理地址时,CPU的内存管理单元遇到空的页表项并产生一个缺页。vmalloc也会产生do_page_fault()。
We fault-in kernel-space virtual memory on-demand. The’reference’ page table is init_mm.pgd.
do\_page\_fault()
-->\_\_do\_page\_fault()
-->vmalloc\_fault()
// linux-3.10.1/arch/x86/mm/fault.c
/\*
\* This routine handles page faults. It determines the address,
\* and the problem, and then passes it off to one of the appropriate
\* routines.
\*/
static void __kprobes
\_\_do\_page\_fault(struct pt\_regs \*regs, unsigned long error_code)
{
/\* Get the faulting address: \*/
address = read\_cr2();
/\*
\* We fault-in kernel-space virtual memory on-demand. The
\* 'reference' page table is init\_mm.pgd.
\*
\* NOTE! We MUST NOT take any locks for this case. We may
\* be in an interrupt or a critical region, and should
\* only copy the information from the master page table,
\* nothing more.
\*
\* This verifies that the fault happens in kernel space
\* (error\_code & 4) == 0, and that the fault was not a
\* protection error (error\_code & 9) == 0.
\*/
fault\_in\_kernel\_space(address);
vmalloc\_fault(address);
......
}
vmalloc_fault缺页异常只会发生在内核态且缺页的虚拟地址空间大于TASK_SIZE_MAX。因此vmalloc_fault检查相应的内核页表init_mm.pgd。
// linux-3.10.1/arch/x86/include/asm/processor.h
/\*
\* User space process size. 47bits minus one guard page.
\*/
#define TASK\_SIZE\_MAX ((1UL << 47) - PAGE\_SIZE)
// linux-3.10.1/arch/x86/mm/fault.c
static int fault\_in\_kernel\_space(unsigned long address)
{
return address >= TASK_SIZE_MAX;
}
二、vmalloc_fault
vmalloc_fault主要是发生vmalloc缺页异常时用于关联内核页表项,将内核页表同步到用户进程的页表中。
// linux-3.10.1/arch/x86/include/asm/pgtable\_64\_types.h
#define VMALLOC_START \_AC(0xffffc90000000000, UL)
#define VMALLOC_END \_AC(0xffffe8ffffffffff, UL)
// linux-3.10.1/arch/x86/mm/fault.c
/\*
\* 64-bit:
\*
\* Handle a fault on the vmalloc area
\*
\* This assumes no large pages in there.
\*/
static noinline __kprobes int vmalloc\_fault(unsigned long address)
{
//分别定义用户进程页表的pgd、pud、pmd、pte和内核页表的pgd、pud、pmd、pte
//然后准备将内核页表同步到用户进程的页表中
pgd_t \*pgd, \*pgd_ref;
pud_t \*pud, \*pud_ref;
pmd_t \*pmd, \*pmd_ref;
pte_t \*pte, \*pte_ref;
/\* Make sure we are in vmalloc area: \*/
if (!(address >= VMALLOC_START && address < VMALLOC_END))
return -1;
WARN\_ON\_ONCE(in\_nmi());
/\*
\* Copy kernel mappings over when needed. This can also
\* happen within a race in page table update. In the later
\* case just flush:
\*/
//将内核页表同步到用户进程的页表中
/\*读取当前进程PGD \*/
pgd = pgd\_offset(current->active_mm, address);
/\*pgd\_ref 为vmalloc建立的内核页表 \*/
pgd_ref = pgd\_offset\_k(address);
if (pgd\_none(\*pgd_ref))
return -1;
if (pgd\_none(\*pgd)) {
set\_pgd(pgd, \*pgd_ref);
arch\_flush\_lazy\_mmu\_mode();
} else {
BUG\_ON(pgd\_page\_vaddr(\*pgd) != pgd\_page\_vaddr(\*pgd_ref));
}
/\*
\* Below here mismatches are bugs because these lower tables
\* are shared:
\*/
/\*依次复制内核页表的PUD->PMD->PTE \*/
pud = pud\_offset(pgd, address);
pud_ref = pud\_offset(pgd_ref, address);
if (pud\_none(\*pud_ref))
return -1;
if (pud\_none(\*pud) || pud\_page\_vaddr(\*pud) != pud\_page\_vaddr(\*pud_ref))
BUG();
pmd = pmd\_offset(pud, address);
pmd_ref = pmd\_offset(pud_ref, address);
if (pmd\_none(\*pmd_ref))
return -1;
if (pmd\_none(\*pmd) || pmd\_page(\*pmd) != pmd\_page(\*pmd_ref))
BUG();
pte_ref = pte\_offset\_kernel(pmd_ref, address);
if (!pte\_present(\*pte_ref))
return -1;
pte = pte\_offset\_kernel(pmd, address);
/\*
\* Don't use pte\_page here, because the mappings can point
\* outside mem\_map, and the NUMA hash lookup cannot handle
\* that:
\*/
if (!pte\_present(\*pte) || pte\_pfn(\*pte) != pte\_pfn(\*pte_ref))
BUG();
return 0;
}
(1)pgd_offset
最全的Linux教程,Linux从入门到精通
======================
-
linux从入门到精通(第2版)
-
Linux系统移植
-
Linux驱动开发入门与实战
-
LINUX 系统移植 第2版
-
Linux开源网络全栈详解 从DPDK到OpenFlow
第一份《Linux从入门到精通》466页
====================
内容简介
====
本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。
本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。
需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论
详情docs.qq.com/doc/DSmdCdUNwcEJDTXFK