aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/mm/fault.c')
-rw-r--r--arch/i386/mm/fault.c31
1 files changed, 17 insertions, 14 deletions
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 8e90339d6eaa..61d9e34af5a6 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -199,6 +199,18 @@ static inline int is_prefetch(struct pt_regs *regs, unsigned long addr,
199 return 0; 199 return 0;
200} 200}
201 201
202static noinline void force_sig_info_fault(int si_signo, int si_code,
203 unsigned long address, struct task_struct *tsk)
204{
205 siginfo_t info;
206
207 info.si_signo = si_signo;
208 info.si_errno = 0;
209 info.si_code = si_code;
210 info.si_addr = (void __user *)address;
211 force_sig_info(si_signo, &info, tsk);
212}
213
202fastcall void do_invalid_op(struct pt_regs *, unsigned long); 214fastcall void do_invalid_op(struct pt_regs *, unsigned long);
203 215
204/* 216/*
@@ -218,8 +230,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
218 struct vm_area_struct * vma; 230 struct vm_area_struct * vma;
219 unsigned long address; 231 unsigned long address;
220 unsigned long page; 232 unsigned long page;
221 int write; 233 int write, si_code;
222 siginfo_t info;
223 234
224 /* get the address */ 235 /* get the address */
225 __asm__("movl %%cr2,%0":"=r" (address)); 236 __asm__("movl %%cr2,%0":"=r" (address));
@@ -233,7 +244,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
233 244
234 tsk = current; 245 tsk = current;
235 246
236 info.si_code = SEGV_MAPERR; 247 si_code = SEGV_MAPERR;
237 248
238 /* 249 /*
239 * We fault-in kernel-space virtual memory on-demand. The 250 * We fault-in kernel-space virtual memory on-demand. The
@@ -313,7 +324,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
313 * we can handle it.. 324 * we can handle it..
314 */ 325 */
315good_area: 326good_area:
316 info.si_code = SEGV_ACCERR; 327 si_code = SEGV_ACCERR;
317 write = 0; 328 write = 0;
318 switch (error_code & 3) { 329 switch (error_code & 3) {
319 default: /* 3: write, present */ 330 default: /* 3: write, present */
@@ -387,11 +398,7 @@ bad_area_nosemaphore:
387 /* Kernel addresses are always protection faults */ 398 /* Kernel addresses are always protection faults */
388 tsk->thread.error_code = error_code | (address >= TASK_SIZE); 399 tsk->thread.error_code = error_code | (address >= TASK_SIZE);
389 tsk->thread.trap_no = 14; 400 tsk->thread.trap_no = 14;
390 info.si_signo = SIGSEGV; 401 force_sig_info_fault(SIGSEGV, si_code, address, tsk);
391 info.si_errno = 0;
392 /* info.si_code has been set above */
393 info.si_addr = (void __user *)address;
394 force_sig_info(SIGSEGV, &info, tsk);
395 return; 402 return;
396 } 403 }
397 404
@@ -500,11 +507,7 @@ do_sigbus:
500 tsk->thread.cr2 = address; 507 tsk->thread.cr2 = address;
501 tsk->thread.error_code = error_code; 508 tsk->thread.error_code = error_code;
502 tsk->thread.trap_no = 14; 509 tsk->thread.trap_no = 14;
503 info.si_signo = SIGBUS; 510 force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
504 info.si_errno = 0;
505 info.si_code = BUS_ADRERR;
506 info.si_addr = (void __user *)address;
507 force_sig_info(SIGBUS, &info, tsk);
508 return; 511 return;
509 512
510vmalloc_fault: 513vmalloc_fault: