aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mm/fault.c')
-rw-r--r--arch/arm/mm/fault.c80
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 */
109static void 109static 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
134void 135void
@@ -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
210check_stack: 212check_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..
275do_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
295no_context: 287no_context:
296 __do_kernel_fault(mm, addr, fsr, regs); 288 __do_kernel_fault(mm, addr, fsr, regs);