aboutsummaryrefslogtreecommitdiffstats
path: root/arch/cris/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/cris/mm/fault.c')
-rw-r--r--arch/cris/mm/fault.c45
1 files changed, 29 insertions, 16 deletions
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index 380df1a73a6e..9dcac8ec8fa0 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -1,19 +1,18 @@
1/* 1/*
2 * linux/arch/cris/mm/fault.c 2 * arch/cris/mm/fault.c
3 *
4 * Copyright (C) 2000-2006 Axis Communications AB
5 *
6 * Authors: Bjorn Wesen
7 * 3 *
4 * Copyright (C) 2000-2010 Axis Communications AB
8 */ 5 */
9 6
10#include <linux/mm.h> 7#include <linux/mm.h>
11#include <linux/interrupt.h> 8#include <linux/interrupt.h>
12#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/wait.h>
13#include <asm/uaccess.h> 11#include <asm/uaccess.h>
14 12
15extern int find_fixup_code(struct pt_regs *); 13extern int find_fixup_code(struct pt_regs *);
16extern void die_if_kernel(const char *, struct pt_regs *, long); 14extern void die_if_kernel(const char *, struct pt_regs *, long);
15extern void show_registers(struct pt_regs *regs);
17 16
18/* debug of low-level TLB reload */ 17/* debug of low-level TLB reload */
19#undef DEBUG 18#undef DEBUG
@@ -108,11 +107,11 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
108 info.si_code = SEGV_MAPERR; 107 info.si_code = SEGV_MAPERR;
109 108
110 /* 109 /*
111 * If we're in an interrupt or have no user 110 * If we're in an interrupt or "atomic" operation or have no
112 * context, we must not take the fault.. 111 * user context, we must not take the fault.
113 */ 112 */
114 113
115 if (in_interrupt() || !mm) 114 if (in_atomic() || !mm)
116 goto no_context; 115 goto no_context;
117 116
118 down_read(&mm->mmap_sem); 117 down_read(&mm->mmap_sem);
@@ -193,14 +192,25 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
193 /* User mode accesses just cause a SIGSEGV */ 192 /* User mode accesses just cause a SIGSEGV */
194 193
195 if (user_mode(regs)) { 194 if (user_mode(regs)) {
195 printk(KERN_NOTICE "%s (pid %d) segfaults for page "
196 "address %08lx at pc %08lx\n",
197 tsk->comm, tsk->pid,
198 address, instruction_pointer(regs));
199
200 /* With DPG on, we've already dumped registers above. */
201 DPG(if (0))
202 show_registers(regs);
203
204#ifdef CONFIG_NO_SEGFAULT_TERMINATION
205 DECLARE_WAIT_QUEUE_HEAD(wq);
206 wait_event_interruptible(wq, 0 == 1);
207#else
196 info.si_signo = SIGSEGV; 208 info.si_signo = SIGSEGV;
197 info.si_errno = 0; 209 info.si_errno = 0;
198 /* info.si_code has been set above */ 210 /* info.si_code has been set above */
199 info.si_addr = (void *)address; 211 info.si_addr = (void *)address;
200 force_sig_info(SIGSEGV, &info, tsk); 212 force_sig_info(SIGSEGV, &info, tsk);
201 printk(KERN_NOTICE "%s (pid %d) segfaults for page " 213#endif
202 "address %08lx at pc %08lx\n",
203 tsk->comm, tsk->pid, address, instruction_pointer(regs));
204 return; 214 return;
205 } 215 }
206 216
@@ -245,10 +255,10 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
245 255
246 out_of_memory: 256 out_of_memory:
247 up_read(&mm->mmap_sem); 257 up_read(&mm->mmap_sem);
248 printk("VM: killing process %s\n", tsk->comm); 258 if (!user_mode(regs))
249 if (user_mode(regs)) 259 goto no_context;
250 do_exit(SIGKILL); 260 pagefault_out_of_memory();
251 goto no_context; 261 return;
252 262
253 do_sigbus: 263 do_sigbus:
254 up_read(&mm->mmap_sem); 264 up_read(&mm->mmap_sem);
@@ -334,8 +344,11 @@ int
334find_fixup_code(struct pt_regs *regs) 344find_fixup_code(struct pt_regs *regs)
335{ 345{
336 const struct exception_table_entry *fixup; 346 const struct exception_table_entry *fixup;
347 /* in case of delay slot fault (v32) */
348 unsigned long ip = (instruction_pointer(regs) & ~0x1);
337 349
338 if ((fixup = search_exception_tables(instruction_pointer(regs))) != 0) { 350 fixup = search_exception_tables(ip);
351 if (fixup != 0) {
339 /* Adjust the instruction pointer in the stackframe. */ 352 /* Adjust the instruction pointer in the stackframe. */
340 instruction_pointer(regs) = fixup->fixup; 353 instruction_pointer(regs) = fixup->fixup;
341 arch_fixup(regs); 354 arch_fixup(regs);