对于缺页中断的非法访问由函数bad_area执行,该函数的执行情况分为:
1,如果在用户空间访问,直接发送SEGSEGV信号;
2,如果在内核空间访问分为两种情况:
1)地址是一个错误的系统调用参数,修正码(典型是发送SIGSEGV信号);
2)反之,杀死进程并显示内核的OOPS信息;
static void __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, unsigned long address, int si_code) { struct task_struct *tsk = current; /* User mode accesses just cause a SIGSEGV */ /*如果用户态*/ if (error_code & PF_USER) { /* * It's possible to have interrupts off here: */ local_irq_enable(); /* * Valid to do another page fault here because this one came * from user space: */ if (is_prefetch(regs, error_code, address)) return; if (is_errata100(regs, address)) return; if (unlikely(show_unhandled_signals)) show_signal_msg(regs, error_code, address, tsk); /* Kernel addresses are always protection faults: */ tsk->thread.cr2 = address; tsk->thread.error_code = error_code | (address >= TASK_SIZE); tsk->thread.trap_no = 14; /*发送SIGSEGV信号*/ force_sig_info_fault(SIGSEGV, si_code, address, tsk); return; } if (is_f00f_bug(regs, address)) return; /*内核态访问*/ no_context(regs, error_code, address); }内核访问时
static noinline void no_context(struct pt_regs *regs, unsigned long error_code, unsigned long address) { struct task_struct *tsk = current; unsigned long *stackend; unsigned long flags; int sig; /* Are we prepared to handle this kernel fault? */ /*地址是一个系统调用参数,"修正码",典型情况是发送 SIGSEGV信号*/ if (fixup_exception(regs)) return; /* * 32-bit: * * Valid to do another page fault here, because if this fault * had been triggered by is_prefetch fixup_exception would have * handled it. * * 64-bit: * * Hall of shame of CPU/BIOS bugs. */ if (is_prefetch(regs, error_code, address)) return; if (is_errata93(regs, address)) return; /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice: */ /*下面代码用于oops信息的显示和杀死当前 进程*/ flags = oops_begin(); show_fault_oops(regs, error_code, address); stackend = end_of_stack(tsk); if (*stackend != STACK_END_MAGIC) printk(KERN_ALERT "Thread overran stack, or stack corrupted\n"); tsk->thread.cr2 = address; tsk->thread.trap_no = 14; tsk->thread.error_code = error_code; sig = SIGKILL; if (__die("Oops", regs, error_code)) sig = 0; /* Executive summary in case the body of the oops scrolled away */ printk(KERN_EMERG "CR2: %016lx\n", address); oops_end(flags, regs, sig); }