Import 2.3.40pre5
[davej-history.git] / arch / i386 / mm / fault.c
blob4cdc21fb3d3f7b2340a490c4cac4ca3f062567c1
1 /*
2 * linux/arch/i386/mm/fault.c
4 * Copyright (C) 1995 Linus Torvalds
5 */
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>
15 #include <linux/mm.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;
35 if (!size)
36 return 1;
38 vma = find_vma(current->mm, start);
39 if (!vma)
40 goto bad_area;
41 if (vma->vm_start > start)
42 goto check_stack;
44 good_area:
45 if (!(vma->vm_flags & VM_WRITE))
46 goto bad_area;
47 size--;
48 size += start & ~PAGE_MASK;
49 size >>= PAGE_SHIFT;
50 start &= PAGE_MASK;
52 for (;;) {
53 if (handle_mm_fault(current, vma, start, 1) <= 0)
54 goto bad_area;
55 if (!size)
56 break;
57 size--;
58 start += PAGE_SIZE;
59 if (start < vma->vm_end)
60 continue;
61 vma = vma->vm_next;
62 if (!vma || vma->vm_start != start)
63 goto bad_area;
64 if (!(vma->vm_flags & VM_WRITE))
65 goto bad_area;;
67 return 1;
69 check_stack:
70 if (!(vma->vm_flags & VM_GROWSDOWN))
71 goto bad_area;
72 if (expand_stack(vma, start) == 0)
73 goto good_area;
75 bad_area:
76 return 0;
79 static inline void handle_wp_test (void)
81 const unsigned long vaddr = PAGE_OFFSET;
82 pgd_t *pgd;
83 pmd_t *pmd;
84 pte_t *pte;
87 * make it read/writable temporarily, so that the fault
88 * can be handled.
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);
94 local_flush_tlb();
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.
101 printk("Ok");
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
110 * routines.
112 * error_code:
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;
123 unsigned long page;
124 unsigned long fixup;
125 int write;
126 int si_code = SEGV_MAPERR;
128 /* get the address */
129 __asm__("movl %%cr2,%0":"=r" (address));
131 tsk = current;
132 mm = tsk->mm;
135 * If we're in an interrupt or have no user
136 * context, we must not take the fault..
138 if (in_interrupt() || !mm)
139 goto no_context;
141 down(&mm->mmap_sem);
143 vma = find_vma(mm, address);
144 if (!vma)
145 goto bad_area;
146 if (vma->vm_start <= address)
147 goto good_area;
148 if (!(vma->vm_flags & VM_GROWSDOWN))
149 goto bad_area;
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)
158 goto bad_area;
160 if (expand_stack(vma, address))
161 goto bad_area;
163 * Ok, we have a good vm_area for this memory access, so
164 * we can handle it..
166 good_area:
167 write = 0;
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);
175 #endif
176 /* fall through */
177 case 2: /* write, not present */
178 if (!(vma->vm_flags & VM_WRITE))
179 goto bad_area;
180 write++;
181 break;
182 case 1: /* read, present */
183 goto bad_area;
184 case 0: /* read, not present */
185 if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
186 goto bad_area;
190 * If for any reason at all we couldn't handle the fault,
191 * make sure we exit gracefully rather than endlessly redo
192 * the fault.
195 int fault = handle_mm_fault(tsk, vma, address, write);
196 if (fault < 0)
197 goto out_of_memory;
198 if (!fault)
199 goto do_sigbus;
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;
207 if (bit < 32)
208 tsk->thread.screen_bitmap |= 1 << bit;
210 up(&mm->mmap_sem);
211 return;
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..
217 bad_area:
218 up(&mm->mmap_sem);
220 /* User mode accesses just cause a SIGSEGV */
221 if (error_code & 4) {
222 struct siginfo si;
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);
230 return;
234 * Pentium F0 0F C7 C8 bug workaround.
236 if (boot_cpu_data.f00f_bug) {
237 unsigned long nr;
239 nr = (address - idt) >> 3;
241 if (nr == 6) {
242 do_invalid_op(regs, 0);
243 return;
247 no_context:
248 /* Are we prepared to handle this kernel fault? */
249 if ((fixup = search_exception_table(regs->eip)) != 0) {
250 regs->eip = fixup;
251 return;
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)) {
262 handle_wp_test();
263 return;
266 if (address < PAGE_SIZE)
267 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
268 else
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);
276 if (page & 1) {
277 page &= PAGE_MASK;
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);
283 do_exit(SIGKILL);
286 * We ran out of memory, or some other thing happened to us that made
287 * us unable to handle the page fault gracefully.
289 out_of_memory:
290 up(&mm->mmap_sem);
291 printk("VM: killing process %s\n", tsk->comm);
292 if (error_code & 4)
293 do_exit(SIGKILL);
294 goto no_context;
296 do_sigbus:
297 up(&mm->mmap_sem);
300 * Send a sigbus, regardless of whether we were in kernel
301 * or user mode.
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))
310 goto no_context;