2 * linux/arch/i386/mm/fault.c
4 * Copyright (C) 1995 Linus Torvalds
7 #include <linux/signal.h>
8 #include <linux/sched.h>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/string.h>
12 #include <linux/types.h>
13 #include <linux/ptrace.h>
14 #include <linux/mman.h>
16 #include <linux/smp.h>
17 #include <linux/smp_lock.h>
18 #include <linux/interrupt.h>
20 #include <asm/system.h>
21 #include <asm/uaccess.h>
22 #include <asm/pgalloc.h>
23 #include <asm/hardirq.h>
25 extern void die(const char *,struct pt_regs
*,long);
28 * Ugly, ugly, but the goto's result in better assembly..
30 int __verify_write(const void * addr
, unsigned long size
)
32 struct vm_area_struct
* vma
;
33 unsigned long start
= (unsigned long) addr
;
38 vma
= find_vma(current
->mm
, start
);
41 if (vma
->vm_start
> start
)
45 if (!(vma
->vm_flags
& VM_WRITE
))
48 size
+= start
& ~PAGE_MASK
;
53 if (handle_mm_fault(current
, vma
, start
, 1) <= 0)
59 if (start
< vma
->vm_end
)
62 if (!vma
|| vma
->vm_start
!= start
)
64 if (!(vma
->vm_flags
& VM_WRITE
))
70 if (!(vma
->vm_flags
& VM_GROWSDOWN
))
72 if (expand_stack(vma
, start
) == 0)
79 static inline void handle_wp_test (void)
81 const unsigned long vaddr
= PAGE_OFFSET
;
87 * make it read/writable temporarily, so that the fault
90 pgd
= swapper_pg_dir
+ __pgd_offset(vaddr
);
91 pmd
= pmd_offset(pgd
, vaddr
);
92 pte
= pte_offset(pmd
, vaddr
);
93 *pte
= mk_pte_phys(0, PAGE_KERNEL
);
96 boot_cpu_data
.wp_works_ok
= 1;
98 * Beware: Black magic here. The printk is needed here to flush
99 * CPU state on certain buggy processors.
104 asmlinkage
void do_invalid_op(struct pt_regs
*, unsigned long);
105 extern unsigned long idt
;
108 * This routine handles page faults. It determines the address,
109 * and the problem, and then passes it off to one of the appropriate
113 * bit 0 == 0 means no page found, 1 means protection fault
114 * bit 1 == 0 means read, 1 means write
115 * bit 2 == 0 means kernel, 1 means user-mode
117 asmlinkage
void do_page_fault(struct pt_regs
*regs
, unsigned long error_code
)
119 struct task_struct
*tsk
;
120 struct mm_struct
*mm
;
121 struct vm_area_struct
* vma
;
122 unsigned long address
;
126 int si_code
= SEGV_MAPERR
;
128 /* get the address */
129 __asm__("movl %%cr2,%0":"=r" (address
));
135 * If we're in an interrupt or have no user
136 * context, we must not take the fault..
138 if (in_interrupt() || !mm
)
143 vma
= find_vma(mm
, address
);
146 if (vma
->vm_start
<= address
)
148 if (!(vma
->vm_flags
& VM_GROWSDOWN
))
150 if (error_code
& 4) {
152 * accessing the stack below %esp is always a bug.
153 * The "+ 32" is there due to some instructions (like
154 * pusha) doing post-decrement on the stack and that
155 * doesn't show up until later..
157 if (address
+ 32 < regs
->esp
)
160 if (expand_stack(vma
, address
))
163 * Ok, we have a good vm_area for this memory access, so
168 si_code
= SEGV_ACCERR
;
170 switch (error_code
& 3) {
171 default: /* 3: write, present */
172 #ifdef TEST_VERIFY_AREA
173 if (regs
->cs
== KERNEL_CS
)
174 printk("WP fault at %08lx\n", regs
->eip
);
177 case 2: /* write, not present */
178 if (!(vma
->vm_flags
& VM_WRITE
))
182 case 1: /* read, present */
184 case 0: /* read, not present */
185 if (!(vma
->vm_flags
& (VM_READ
| VM_EXEC
)))
190 * If for any reason at all we couldn't handle the fault,
191 * make sure we exit gracefully rather than endlessly redo
195 int fault
= handle_mm_fault(tsk
, vma
, address
, write
);
203 * Did it hit the DOS screen memory VA from vm86 mode?
205 if (regs
->eflags
& VM_MASK
) {
206 unsigned long bit
= (address
- 0xA0000) >> PAGE_SHIFT
;
208 tsk
->thread
.screen_bitmap
|= 1 << bit
;
214 * Something tried to access memory that isn't in our memory map..
215 * Fix it, but check if it's kernel or user first..
220 /* User mode accesses just cause a SIGSEGV */
221 if (error_code
& 4) {
223 tsk
->thread
.cr2
= address
;
224 tsk
->thread
.error_code
= error_code
;
225 tsk
->thread
.trap_no
= 14;
226 si
.si_signo
= SIGSEGV
;
227 si
.si_code
= si_code
;
228 si
.si_addr
= (void*) address
;
229 force_sig_info(SIGSEGV
, &si
, tsk
);
234 * Pentium F0 0F C7 C8 bug workaround.
236 if (boot_cpu_data
.f00f_bug
) {
239 nr
= (address
- idt
) >> 3;
242 do_invalid_op(regs
, 0);
248 /* Are we prepared to handle this kernel fault? */
249 if ((fixup
= search_exception_table(regs
->eip
)) != 0) {
255 * Oops. The kernel tried to access some bad page. We'll have to
256 * terminate things with extreme prejudice.
258 * First we check if it was the bootup rw-test, though..
260 if (boot_cpu_data
.wp_works_ok
< 0 &&
261 address
== PAGE_OFFSET
&& (error_code
& 1)) {
266 if (address
< PAGE_SIZE
)
267 printk(KERN_ALERT
"Unable to handle kernel NULL pointer dereference");
269 printk(KERN_ALERT
"Unable to handle kernel paging request");
270 printk(" at virtual address %08lx\n",address
);
271 printk(" printing eip:\n");
272 printk("%08lx\n", regs
->eip
);
273 asm("movl %%cr3,%0":"=r" (page
));
274 page
= ((unsigned long *) __va(page
))[address
>> 22];
275 printk(KERN_ALERT
"*pde = %08lx\n", page
);
278 address
&= 0x003ff000;
279 page
= ((unsigned long *) __va(page
))[address
>> PAGE_SHIFT
];
280 printk(KERN_ALERT
"*pte = %08lx\n", page
);
282 die("Oops", regs
, error_code
);
286 * We ran out of memory, or some other thing happened to us that made
287 * us unable to handle the page fault gracefully.
291 printk("VM: killing process %s\n", tsk
->comm
);
300 * Send a sigbus, regardless of whether we were in kernel
303 tsk
->thread
.cr2
= address
;
304 tsk
->thread
.error_code
= error_code
;
305 tsk
->thread
.trap_no
= 14;
306 force_sig(SIGBUS
, tsk
);
308 /* Kernel mode? Handle exceptions or die */
309 if (!(error_code
& 4))