diff options
Diffstat (limited to 'arch/cris/mm/fault.c')
-rw-r--r-- | arch/cris/mm/fault.c | 45 |
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 | ||
15 | extern int find_fixup_code(struct pt_regs *); | 13 | extern int find_fixup_code(struct pt_regs *); |
16 | extern void die_if_kernel(const char *, struct pt_regs *, long); | 14 | extern void die_if_kernel(const char *, struct pt_regs *, long); |
15 | extern 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 | |||
334 | find_fixup_code(struct pt_regs *regs) | 344 | find_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); |