1
2
3
4
5
6
7#include <linux/mman.h>
8#include <linux/mm.h>
9#include <linux/kernel.h>
10#include <linux/ptrace.h>
11#include <linux/interrupt.h>
12#include <linux/module.h>
13
14#include <asm/setup.h>
15#include <asm/traps.h>
16#include <asm/system.h>
17#include <asm/uaccess.h>
18#include <asm/pgalloc.h>
19
20extern void die_if_kernel(char *, struct pt_regs *, long);
21
22int send_fault_sig(struct pt_regs *regs)
23{
24 siginfo_t siginfo = { 0, 0, 0, };
25
26 siginfo.si_signo = current->thread.signo;
27 siginfo.si_code = current->thread.code;
28 siginfo.si_addr = (void *)current->thread.faddr;
29#ifdef DEBUG
30 printk("send_fault_sig: %p,%d,%d\n", siginfo.si_addr, siginfo.si_signo, siginfo.si_code);
31#endif
32
33 if (user_mode(regs)) {
34 force_sig_info(siginfo.si_signo,
35 &siginfo, current);
36 } else {
37 if (handle_kernel_fault(regs))
38 return -1;
39
40
41
42
43
44
45
46
47
48 if ((unsigned long)siginfo.si_addr < PAGE_SIZE)
49 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
50 else
51 printk(KERN_ALERT "Unable to handle kernel access");
52 printk(" at virtual address %p\n", siginfo.si_addr);
53 die_if_kernel("Oops", regs, 0 );
54 do_exit(SIGKILL);
55 }
56
57 return 1;
58}
59
60
61
62
63
64
65
66
67
68
69
70
71int do_page_fault(struct pt_regs *regs, unsigned long address,
72 unsigned long error_code)
73{
74 struct mm_struct *mm = current->mm;
75 struct vm_area_struct * vma;
76 int write, fault;
77
78#ifdef DEBUG
79 printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
80 regs->sr, regs->pc, address, error_code,
81 current->mm->pgd);
82#endif
83
84
85
86
87
88 if (in_atomic() || !mm)
89 goto no_context;
90
91 down_read(&mm->mmap_sem);
92
93 vma = find_vma(mm, address);
94 if (!vma)
95 goto map_err;
96 if (vma->vm_flags & VM_IO)
97 goto acc_err;
98 if (vma->vm_start <= address)
99 goto good_area;
100 if (!(vma->vm_flags & VM_GROWSDOWN))
101 goto map_err;
102 if (user_mode(regs)) {
103
104
105
106
107 if (address + 256 < rdusp())
108 goto map_err;
109 }
110 if (expand_stack(vma, address))
111 goto map_err;
112
113
114
115
116
117good_area:
118#ifdef DEBUG
119 printk("do_page_fault: good_area\n");
120#endif
121 write = 0;
122 switch (error_code & 3) {
123 default:
124
125 case 2:
126 if (!(vma->vm_flags & VM_WRITE))
127 goto acc_err;
128 write++;
129 break;
130 case 1:
131 goto acc_err;
132 case 0:
133 if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
134 goto acc_err;
135 }
136
137
138
139
140
141
142
143 fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
144#ifdef DEBUG
145 printk("handle_mm_fault returns %d\n",fault);
146#endif
147 if (unlikely(fault & VM_FAULT_ERROR)) {
148 if (fault & VM_FAULT_OOM)
149 goto out_of_memory;
150 else if (fault & VM_FAULT_SIGBUS)
151 goto bus_err;
152 BUG();
153 }
154 if (fault & VM_FAULT_MAJOR)
155 current->maj_flt++;
156 else
157 current->min_flt++;
158
159 up_read(&mm->mmap_sem);
160 return 0;
161
162
163
164
165
166out_of_memory:
167 up_read(&mm->mmap_sem);
168 if (!user_mode(regs))
169 goto no_context;
170 pagefault_out_of_memory();
171 return 0;
172
173no_context:
174 current->thread.signo = SIGBUS;
175 current->thread.faddr = address;
176 return send_fault_sig(regs);
177
178bus_err:
179 current->thread.signo = SIGBUS;
180 current->thread.code = BUS_ADRERR;
181 current->thread.faddr = address;
182 goto send_sig;
183
184map_err:
185 current->thread.signo = SIGSEGV;
186 current->thread.code = SEGV_MAPERR;
187 current->thread.faddr = address;
188 goto send_sig;
189
190acc_err:
191 current->thread.signo = SIGSEGV;
192 current->thread.code = SEGV_ACCERR;
193 current->thread.faddr = address;
194
195send_sig:
196 up_read(&mm->mmap_sem);
197 return send_fault_sig(regs);
198}
199