页管理与缺页
概念
缺页是操作系统为进程的虚拟内存动态的提供物理内存的一种方式。
- 当CPU访问虚拟地址时,通过页表映射物理内存的过程中,如果发现页表匹配当前的操作,但没有实际的物理内存,就可以动态的为进程调配一页物理内存;
- 当内核在运作过程中,如果物理内存紧张,则动态的选择一些分配给进程的物理内存,将其写入磁盘或文件,然后修改关联的页表,以促使这些换出的页能以第一种方式再次被换入。
缺页组成
缺页由缺页中断进行处理,当进程操作异常的虚拟地址时,触发缺页中断,开始处理这次缺页,CPU将引起缺页的虚拟地址存入寄存器cr2
,然后保存上下文并调用do_page_fault()
进行C代码级别缺页处理流程。
缺页分类
- 匿名缺页
- 文件映射缺
- 写时缺页
- 交换缺页
- 内核非连续内存映射缺页
- 指令预提取缺页
缺页流程介绍
主流程
-
入口函数
__do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address)
- 上下文信息,包含缺页中断发生时CPU的寄存器状态
- 错误码,用以标识缺页的类别
- 缺页的虚拟地址
-
缺页类别标识
入口函数的错误码是下表的宏的或运算的组合,表示缺页的类别信息:
code | comments |
---|---|
PF_PROT |
1. 未设置,缺页 2. 设置,页保护异常 |
PF_WRITE |
1. 未设置,读页异常 2. 设置,写页异常 |
PF_USER |
1. 未设置,内核空间页异常 2. 设置,用户空间页异常 |
PF_RSVD |
设置,使用了页表项保留的标志位 |
PF_INSTR |
设置,指令预提取页异常 |
PF_PK |
- 流程
|We fault-in kernel-space
| virtual memory ?
v use of reserved bit detecte ?
+------------+------------+ NO +-------------------------+ YES +--------------+
| fault_in_kernel_space() |----------->>>>>>------->| error_code & PF_RSVD |------->| pgtable_bad()|
+------------+------------+ +------------+------------+ +--------------+
| YES | NO
| |
+------<-----+----->------+ |
| | v
| | +-------+-------+
v v | find_vma() | find a vma entry associated
+----------+------+ +------+-----------+ +-------+-------+ with this virtual memory
| vmalloc_fault() | | spurious_fault() | |
+-----------------+ +------------------+ v
We fault on We fault by +-------+-------+
vmalloc area a stale TLB entry | expand_stack()| this virtual memory
+-------+-------+ is a user's stack space ?
|
v
+---------+---------+
| fixed page table | maybe need to allocate page
+---------+---------+ for non-existent page table
|
v
+----------------------+--------+-------------+----------------------+
| | | |
| | | |
v v v v
+-------+-------+ +--------+--------+ +---------+----------+ +-------+--------+
| do_wp_page() | | do_fault() | |do_anonymous_page() | | do_swap_page() |
+---------------+ +--------+--------+ +--------------------+ +----------------+
|