diff options
-rw-r--r-- | arch/arm/mm/fault.c | 80 |
1 files changed, 36 insertions, 44 deletions
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 29be1c018949..e25b4fd8412c 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c | |||
@@ -108,14 +108,15 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, | |||
108 | */ | 108 | */ |
109 | static void | 109 | static void |
110 | __do_user_fault(struct task_struct *tsk, unsigned long addr, | 110 | __do_user_fault(struct task_struct *tsk, unsigned long addr, |
111 | unsigned int fsr, int code, struct pt_regs *regs) | 111 | unsigned int fsr, unsigned int sig, int code, |
112 | struct pt_regs *regs) | ||
112 | { | 113 | { |
113 | struct siginfo si; | 114 | struct siginfo si; |
114 | 115 | ||
115 | #ifdef CONFIG_DEBUG_USER | 116 | #ifdef CONFIG_DEBUG_USER |
116 | if (user_debug & UDBG_SEGV) { | 117 | if (user_debug & UDBG_SEGV) { |
117 | printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n", | 118 | printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n", |
118 | tsk->comm, addr, fsr); | 119 | tsk->comm, sig, addr, fsr); |
119 | show_pte(tsk->mm, addr); | 120 | show_pte(tsk->mm, addr); |
120 | show_regs(regs); | 121 | show_regs(regs); |
121 | } | 122 | } |
@@ -124,11 +125,11 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, | |||
124 | tsk->thread.address = addr; | 125 | tsk->thread.address = addr; |
125 | tsk->thread.error_code = fsr; | 126 | tsk->thread.error_code = fsr; |
126 | tsk->thread.trap_no = 14; | 127 | tsk->thread.trap_no = 14; |
127 | si.si_signo = SIGSEGV; | 128 | si.si_signo = sig; |
128 | si.si_errno = 0; | 129 | si.si_errno = 0; |
129 | si.si_code = code; | 130 | si.si_code = code; |
130 | si.si_addr = (void __user *)addr; | 131 | si.si_addr = (void __user *)addr; |
131 | force_sig_info(SIGSEGV, &si, tsk); | 132 | force_sig_info(sig, &si, tsk); |
132 | } | 133 | } |
133 | 134 | ||
134 | void | 135 | void |
@@ -140,7 +141,7 @@ do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, | |||
140 | * have no context to handle this fault with. | 141 | * have no context to handle this fault with. |
141 | */ | 142 | */ |
142 | if (user_mode(regs)) | 143 | if (user_mode(regs)) |
143 | __do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs); | 144 | __do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs); |
144 | else | 145 | else |
145 | __do_kernel_fault(mm, addr, fsr, regs); | 146 | __do_kernel_fault(mm, addr, fsr, regs); |
146 | } | 147 | } |
@@ -201,10 +202,11 @@ survive: | |||
201 | goto out; | 202 | goto out; |
202 | 203 | ||
203 | /* | 204 | /* |
204 | * If we are out of memory for pid1, | 205 | * If we are out of memory for pid1, sleep for a while and retry |
205 | * sleep for a while and retry | ||
206 | */ | 206 | */ |
207 | up_read(&mm->mmap_sem); | ||
207 | yield(); | 208 | yield(); |
209 | down_read(&mm->mmap_sem); | ||
208 | goto survive; | 210 | goto survive; |
209 | 211 | ||
210 | check_stack: | 212 | check_stack: |
@@ -219,7 +221,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
219 | { | 221 | { |
220 | struct task_struct *tsk; | 222 | struct task_struct *tsk; |
221 | struct mm_struct *mm; | 223 | struct mm_struct *mm; |
222 | int fault; | 224 | int fault, sig, code; |
223 | 225 | ||
224 | tsk = current; | 226 | tsk = current; |
225 | mm = tsk->mm; | 227 | mm = tsk->mm; |
@@ -242,55 +244,45 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
242 | return 0; | 244 | return 0; |
243 | 245 | ||
244 | /* | 246 | /* |
245 | * We had some memory, but were unable to | ||
246 | * successfully fix up this page fault. | ||
247 | */ | ||
248 | if (fault == 0) | ||
249 | goto do_sigbus; | ||
250 | |||
251 | /* | ||
252 | * If we are in kernel mode at this point, we | 247 | * If we are in kernel mode at this point, we |
253 | * have no context to handle this fault with. | 248 | * have no context to handle this fault with. |
254 | */ | 249 | */ |
255 | if (!user_mode(regs)) | 250 | if (!user_mode(regs)) |
256 | goto no_context; | 251 | goto no_context; |
257 | 252 | ||
258 | if (fault == VM_FAULT_OOM) { | 253 | switch (fault) { |
254 | case VM_FAULT_OOM: | ||
259 | /* | 255 | /* |
260 | * We ran out of memory, or some other thing happened to | 256 | * We ran out of memory, or some other thing |
261 | * us that made us unable to handle the page fault gracefully. | 257 | * happened to us that made us unable to handle |
258 | * the page fault gracefully. | ||
262 | */ | 259 | */ |
263 | printk("VM: killing process %s\n", tsk->comm); | 260 | printk("VM: killing process %s\n", tsk->comm); |
264 | do_exit(SIGKILL); | 261 | do_exit(SIGKILL); |
265 | } else | 262 | return 0; |
266 | __do_user_fault(tsk, addr, fsr, fault == VM_FAULT_BADACCESS ? | ||
267 | SEGV_ACCERR : SEGV_MAPERR, regs); | ||
268 | return 0; | ||
269 | 263 | ||
264 | case 0: | ||
265 | /* | ||
266 | * We had some memory, but were unable to | ||
267 | * successfully fix up this page fault. | ||
268 | */ | ||
269 | sig = SIGBUS; | ||
270 | code = BUS_ADRERR; | ||
271 | break; | ||
270 | 272 | ||
271 | /* | 273 | default: |
272 | * We ran out of memory, or some other thing happened to us that made | 274 | /* |
273 | * us unable to handle the page fault gracefully. | 275 | * Something tried to access memory that |
274 | */ | 276 | * isn't in our memory map.. |
275 | do_sigbus: | 277 | */ |
276 | /* | 278 | sig = SIGSEGV; |
277 | * Send a sigbus, regardless of whether we were in kernel | 279 | code = fault == VM_FAULT_BADACCESS ? |
278 | * or user mode. | 280 | SEGV_ACCERR : SEGV_MAPERR; |
279 | */ | 281 | break; |
280 | tsk->thread.address = addr; | ||
281 | tsk->thread.error_code = fsr; | ||
282 | tsk->thread.trap_no = 14; | ||
283 | force_sig(SIGBUS, tsk); | ||
284 | #ifdef CONFIG_DEBUG_USER | ||
285 | if (user_debug & UDBG_BUS) { | ||
286 | printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n", | ||
287 | current->comm, addr, instruction_pointer(regs)); | ||
288 | } | 282 | } |
289 | #endif | ||
290 | 283 | ||
291 | /* Kernel mode? Handle exceptions or die */ | 284 | __do_user_fault(tsk, addr, fsr, sig, code, regs); |
292 | if (user_mode(regs)) | 285 | return 0; |
293 | return 0; | ||
294 | 286 | ||
295 | no_context: | 287 | no_context: |
296 | __do_kernel_fault(mm, addr, fsr, regs); | 288 | __do_kernel_fault(mm, addr, fsr, regs); |