linux内核分析之缺页中断(二)

对于缺页中断的非法访问由函数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);
}



 

 

你可能感兴趣的:(linux进程地址空间,Linux内核学习笔记)