aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakpm@osdl.org <akpm@osdl.org>2005-04-16 18:23:55 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:23:55 -0400
commit2d137c24e9f433e37ffd10b3d5f418157589a8d2 (patch)
tree9924bec3f5646b6fe6eaa597ccd2f2dc6aa05673
parentbaaa2c512dc1c47e3afeb9d558c5323c9240bd21 (diff)
[PATCH] arm: fix SIGBUS handling
) From: Russell King <rmk+lkml@arm.linux.org.uk> ARM wasn't raising a SIGBUS with a siginfo structure. Fix __do_user_fault() to allow us to use it for SIGBUS conditions, and arrange for the sigbus path to use this. We need to prevent the siginfo code being called if we do not have a user space context to call it, so consolidate the "user_mode()" tests. Thanks to Ian Campbell who spotted this oversight. Signed-off-by: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-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);