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.c41
1 files changed, 23 insertions, 18 deletions
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 8e90339d6eaa..9edd4485b91e 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -21,6 +21,7 @@
21#include <linux/vt_kern.h> /* For unblank_screen() */ 21#include <linux/vt_kern.h> /* For unblank_screen() */
22#include <linux/highmem.h> 22#include <linux/highmem.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/kprobes.h>
24 25
25#include <asm/system.h> 26#include <asm/system.h>
26#include <asm/uaccess.h> 27#include <asm/uaccess.h>
@@ -199,6 +200,18 @@ static inline int is_prefetch(struct pt_regs *regs, unsigned long addr,
199 return 0; 200 return 0;
200} 201}
201 202
203static noinline void force_sig_info_fault(int si_signo, int si_code,
204 unsigned long address, struct task_struct *tsk)
205{
206 siginfo_t info;
207
208 info.si_signo = si_signo;
209 info.si_errno = 0;
210 info.si_code = si_code;
211 info.si_addr = (void __user *)address;
212 force_sig_info(si_signo, &info, tsk);
213}
214
202fastcall void do_invalid_op(struct pt_regs *, unsigned long); 215fastcall void do_invalid_op(struct pt_regs *, unsigned long);
203 216
204/* 217/*
@@ -211,18 +224,18 @@ fastcall void do_invalid_op(struct pt_regs *, unsigned long);
211 * bit 1 == 0 means read, 1 means write 224 * bit 1 == 0 means read, 1 means write
212 * bit 2 == 0 means kernel, 1 means user-mode 225 * bit 2 == 0 means kernel, 1 means user-mode
213 */ 226 */
214fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code) 227fastcall void __kprobes do_page_fault(struct pt_regs *regs,
228 unsigned long error_code)
215{ 229{
216 struct task_struct *tsk; 230 struct task_struct *tsk;
217 struct mm_struct *mm; 231 struct mm_struct *mm;
218 struct vm_area_struct * vma; 232 struct vm_area_struct * vma;
219 unsigned long address; 233 unsigned long address;
220 unsigned long page; 234 unsigned long page;
221 int write; 235 int write, si_code;
222 siginfo_t info;
223 236
224 /* get the address */ 237 /* get the address */
225 __asm__("movl %%cr2,%0":"=r" (address)); 238 address = read_cr2();
226 239
227 if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, 240 if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
228 SIGSEGV) == NOTIFY_STOP) 241 SIGSEGV) == NOTIFY_STOP)
@@ -233,7 +246,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
233 246
234 tsk = current; 247 tsk = current;
235 248
236 info.si_code = SEGV_MAPERR; 249 si_code = SEGV_MAPERR;
237 250
238 /* 251 /*
239 * We fault-in kernel-space virtual memory on-demand. The 252 * We fault-in kernel-space virtual memory on-demand. The
@@ -313,7 +326,7 @@ fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
313 * we can handle it.. 326 * we can handle it..
314 */ 327 */
315good_area: 328good_area:
316 info.si_code = SEGV_ACCERR; 329 si_code = SEGV_ACCERR;
317 write = 0; 330 write = 0;
318 switch (error_code & 3) { 331 switch (error_code & 3) {
319 default: /* 3: write, present */ 332 default: /* 3: write, present */
@@ -387,11 +400,7 @@ bad_area_nosemaphore:
387 /* Kernel addresses are always protection faults */ 400 /* Kernel addresses are always protection faults */
388 tsk->thread.error_code = error_code | (address >= TASK_SIZE); 401 tsk->thread.error_code = error_code | (address >= TASK_SIZE);
389 tsk->thread.trap_no = 14; 402 tsk->thread.trap_no = 14;
390 info.si_signo = SIGSEGV; 403 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; 404 return;
396 } 405 }
397 406
@@ -446,7 +455,7 @@ no_context:
446 printk(" at virtual address %08lx\n",address); 455 printk(" at virtual address %08lx\n",address);
447 printk(KERN_ALERT " printing eip:\n"); 456 printk(KERN_ALERT " printing eip:\n");
448 printk("%08lx\n", regs->eip); 457 printk("%08lx\n", regs->eip);
449 asm("movl %%cr3,%0":"=r" (page)); 458 page = read_cr3();
450 page = ((unsigned long *) __va(page))[address >> 22]; 459 page = ((unsigned long *) __va(page))[address >> 22];
451 printk(KERN_ALERT "*pde = %08lx\n", page); 460 printk(KERN_ALERT "*pde = %08lx\n", page);
452 /* 461 /*
@@ -500,11 +509,7 @@ do_sigbus:
500 tsk->thread.cr2 = address; 509 tsk->thread.cr2 = address;
501 tsk->thread.error_code = error_code; 510 tsk->thread.error_code = error_code;
502 tsk->thread.trap_no = 14; 511 tsk->thread.trap_no = 14;
503 info.si_signo = SIGBUS; 512 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; 513 return;
509 514
510vmalloc_fault: 515vmalloc_fault:
@@ -523,7 +528,7 @@ vmalloc_fault:
523 pmd_t *pmd, *pmd_k; 528 pmd_t *pmd, *pmd_k;
524 pte_t *pte_k; 529 pte_t *pte_k;
525 530
526 asm("movl %%cr3,%0":"=r" (pgd_paddr)); 531 pgd_paddr = read_cr3();
527 pgd = index + (pgd_t *)__va(pgd_paddr); 532 pgd = index + (pgd_t *)__va(pgd_paddr);
528 pgd_k = init_mm.pgd + index; 533 pgd_k = init_mm.pgd + index;
529 534