2021.12.25

do_page_fault源码分析

  • 源码:Linux 3.18
  • 编译平台:ubuntu16 x64默认编译环境
  • 编译参数:defconfig
    • scripts/config --set-val DEBUG_INFO y --set-val DEBUG y --set-val GDB_SCRIPTS y --set-val DEBUG_DRIVER y
  • 批注注释用///符号

源码arch/x86/mm/fault.c:

do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
	unsigned long address = read_cr2(); /* Get the faulting address */
	enum ctx_state prev_state;

	/*
	 * We must have this function tagged with __kprobes, notrace and call
	 * read_cr2() before calling anything else. To avoid calling any kind
	 * of tracing machinery before we've observed the CR2 value.
	 *
	 * exception_{enter,exit}() contain all sorts of tracepoints.
	 */

	prev_state = exception_enter();
	__do_page_fault(regs, error_code, address);
	exception_exit(prev_state);
}

__do_page_fault是处理page fault的函数。

首先是检测出错的访存是否是在访问内核空间。

...
	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;
		}

		/* Can handle a stale RO->RW TLB: */
		if (spurious_fault(error_code, address))
			return;

		/* kprobes don't want to hook the spurious faults: */
		if (kprobes_fault(regs))
			return;
		/*
		 * Don't take the mm semaphore here. If we fixup a prefetch
		 * fault we could otherwise deadlock:
		 */
		bad_area_nosemaphore(regs, error_code, address);

		return;
	}
...
2022.01.03

__do_page_fault开始的函数执行流程如下:

page_fault.dot