linux内核 缺页,linux 内核缺页异常

static int __kprobes

do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)

{

struct task_struct *tsk;

struct mm_struct *mm;

int fault, sig, code;

int write = fsr & FSR_WRITE;

unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |

(write ? FAULT_FLAG_WRITE : 0);

if (notify_page_fault(regs, fsr))

return 0;

tsk = current;

mm  = tsk->mm;

/* Enable interrupts if they were enabled in the parent context. */

if (interrupts_enabled(regs))

local_irq_enable();

/*

* If we're in an interrupt or have no user

* context, we must not take the fault..

*/

if (in_atomic() || !mm)

goto no_context;

/*

* As per x86, we may deadlock here.  However, since the kernel only

* validly references user space from well defined areas of the code,

* we can bug out early if this is from code which shouldn't.

*/

if (!down_read_trylock(&mm->mmap_sem)) {

if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc))

goto no_context;

retry:

down_read(&mm->mmap_sem);

} else {

/*

* The above down_read_trylock() might have succeeded in

* which case, we'll have missed the might_sleep() from

* down_read()

*/

might_sleep();

#ifdef CONFIG_DEBUG_VM

if (!user_mode(regs) &&

!search_exception_tables(regs->ARM_pc))

goto no_context;

#endif

}

fault = __do_page_fault(mm, addr, fsr, flags, tsk);

/* If we need to retry but a fatal signal is pending, handle the

* signal first. We do not need to release the mmap_sem because

* it would already be released in __lock_page_or_retry in

* mm/filemap.c. */

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))

return 0;

/*

* Major/minor page fault accounting is only done on the

* initial attempt. If we go through a retry, it is extremely

* likely that the page will be found in page cache at that point.

*/

perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);

if (!(fault & VM_FAULT_ERROR) && flags & FAULT_FLAG_ALLOW_RETRY) {

if (fault & VM_FAULT_MAJOR) {

tsk->maj_flt++;

perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,

regs, addr);

} else {

tsk->min_flt++;

perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,

regs, addr);

}

if (fault & VM_FAULT_RETRY) {

/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk

* of starvation. */

flags &= ~FAULT_FLAG_ALLOW_RETRY;

goto retry;

}

}

up_read(&mm->mmap_sem);

/*

* Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR

*/

if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))

return 0;

if (fault & VM_FAULT_OOM) {

/*

* We ran out of memory, call the OOM killer, and return to

* userspace (which will retry the fault, or kill us if we

* got oom-killed)

*/

pagefault_out_of_memory();

return 0;

}

/*

* If we are in kernel mode at this point, we

* have no context to handle this fault with.

*/

if (!user_mode(regs))

goto no_context;

if (fault & VM_FAULT_SIGBUS) {

/*

* We had some memory, but were unable to

* successfully fix up this page fault.

*/

sig = SIGBUS;

code = BUS_ADRERR;

} else {

/*

* Something tried to access memory that

* isn't in our memory map..

*/

sig = SIGSEGV;

code = fault == VM_FAULT_BADACCESS ?

SEGV_ACCERR : SEGV_MAPERR;

}

__do_user_fault(tsk, addr, fsr, sig, code, regs);

return 0;

no_context:

__do_kernel_fault(mm, addr, fsr, regs);

return 0;

}

/*

* Something tried to access memory that isn't in our memory map..

* User mode accesses just cause a SIGSEGV

*/

static void

__do_user_fault(struct task_struct *tsk, unsigned long addr,

unsigned int fsr, unsigned int sig, int code,

struct pt_regs *regs)

{

struct siginfo si;

#ifdef CONFIG_DEBUG_USER

if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||

((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {

printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",

tsk->comm, sig, addr, fsr);

show_pte(tsk->mm, addr);

show_regs(regs);

}

#endif

tsk->thread.address = addr;

tsk->thread.error_code = fsr;

tsk->thread.trap_no = 14;

si.si_signo = sig;

si.si_errno = 0;

si.si_code = code;

si.si_addr = (void __user *)addr;

force_sig_info(sig, &si, tsk);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值