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); |
