diff options
Diffstat (limited to 'arch/um/kernel/trap.c')
-rw-r--r-- | arch/um/kernel/trap.c | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 26f15c458574..abab90c3803f 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c | |||
@@ -18,8 +18,9 @@ | |||
18 | #include "asm/current.h" | 18 | #include "asm/current.h" |
19 | #include "asm/irq.h" | 19 | #include "asm/irq.h" |
20 | #include "sysdep/sigcontext.h" | 20 | #include "sysdep/sigcontext.h" |
21 | #include "user_util.h" | ||
22 | #include "kern_util.h" | 21 | #include "kern_util.h" |
22 | #include "as-layout.h" | ||
23 | #include "arch.h" | ||
23 | #include "kern.h" | 24 | #include "kern.h" |
24 | #include "chan_kern.h" | 25 | #include "chan_kern.h" |
25 | #include "mconsole_kern.h" | 26 | #include "mconsole_kern.h" |
@@ -71,8 +72,8 @@ good_area: | |||
71 | goto out; | 72 | goto out; |
72 | 73 | ||
73 | /* Don't require VM_READ|VM_EXEC for write faults! */ | 74 | /* Don't require VM_READ|VM_EXEC for write faults! */ |
74 | if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) | 75 | if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) |
75 | goto out; | 76 | goto out; |
76 | 77 | ||
77 | do { | 78 | do { |
78 | survive: | 79 | survive: |
@@ -156,20 +157,23 @@ static void segv_handler(int sig, union uml_pt_regs *regs) | |||
156 | * the info in the regs. A pointer to the info then would | 157 | * the info in the regs. A pointer to the info then would |
157 | * give us bad data! | 158 | * give us bad data! |
158 | */ | 159 | */ |
159 | unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | 160 | unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, |
161 | union uml_pt_regs *regs) | ||
160 | { | 162 | { |
161 | struct siginfo si; | 163 | struct siginfo si; |
162 | void *catcher; | 164 | void *catcher; |
163 | int err; | 165 | int err; |
164 | int is_write = FAULT_WRITE(fi); | 166 | int is_write = FAULT_WRITE(fi); |
165 | unsigned long address = FAULT_ADDRESS(fi); | 167 | unsigned long address = FAULT_ADDRESS(fi); |
166 | 168 | ||
167 | if(!is_user && (address >= start_vm) && (address < end_vm)){ | 169 | if(!is_user && (address >= start_vm) && (address < end_vm)){ |
168 | flush_tlb_kernel_vm(); | 170 | flush_tlb_kernel_vm(); |
169 | return(0); | 171 | return 0; |
170 | } | 172 | } |
171 | else if(current->mm == NULL) | 173 | else if(current->mm == NULL) { |
172 | panic("Segfault with no mm"); | 174 | show_regs(container_of(regs, struct pt_regs, regs)); |
175 | panic("Segfault with no mm"); | ||
176 | } | ||
173 | 177 | ||
174 | if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi)) | 178 | if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi)) |
175 | err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); | 179 | err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); |
@@ -182,26 +186,28 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | |||
182 | 186 | ||
183 | catcher = current->thread.fault_catcher; | 187 | catcher = current->thread.fault_catcher; |
184 | if(!err) | 188 | if(!err) |
185 | return(0); | 189 | return 0; |
186 | else if(catcher != NULL){ | 190 | else if(catcher != NULL){ |
187 | current->thread.fault_addr = (void *) address; | 191 | current->thread.fault_addr = (void *) address; |
188 | do_longjmp(catcher, 1); | 192 | do_longjmp(catcher, 1); |
189 | } | 193 | } |
190 | else if(current->thread.fault_addr != NULL) | 194 | else if(current->thread.fault_addr != NULL) |
191 | panic("fault_addr set but no fault catcher"); | 195 | panic("fault_addr set but no fault catcher"); |
192 | else if(!is_user && arch_fixup(ip, sc)) | 196 | else if(!is_user && arch_fixup(ip, regs)) |
193 | return(0); | 197 | return 0; |
194 | 198 | ||
195 | if(!is_user) | 199 | if(!is_user) { |
200 | show_regs(container_of(regs, struct pt_regs, regs)); | ||
196 | panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", | 201 | panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", |
197 | address, ip); | 202 | address, ip); |
203 | } | ||
198 | 204 | ||
199 | if (err == -EACCES) { | 205 | if (err == -EACCES) { |
200 | si.si_signo = SIGBUS; | 206 | si.si_signo = SIGBUS; |
201 | si.si_errno = 0; | 207 | si.si_errno = 0; |
202 | si.si_code = BUS_ADRERR; | 208 | si.si_code = BUS_ADRERR; |
203 | si.si_addr = (void __user *)address; | 209 | si.si_addr = (void __user *)address; |
204 | current->thread.arch.faultinfo = fi; | 210 | current->thread.arch.faultinfo = fi; |
205 | force_sig_info(SIGBUS, &si, current); | 211 | force_sig_info(SIGBUS, &si, current); |
206 | } else if (err == -ENOMEM) { | 212 | } else if (err == -ENOMEM) { |
207 | printk("VM: killing process %s\n", current->comm); | 213 | printk("VM: killing process %s\n", current->comm); |
@@ -210,10 +216,10 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | |||
210 | BUG_ON(err != -EFAULT); | 216 | BUG_ON(err != -EFAULT); |
211 | si.si_signo = SIGSEGV; | 217 | si.si_signo = SIGSEGV; |
212 | si.si_addr = (void __user *) address; | 218 | si.si_addr = (void __user *) address; |
213 | current->thread.arch.faultinfo = fi; | 219 | current->thread.arch.faultinfo = fi; |
214 | force_sig_info(SIGSEGV, &si, current); | 220 | force_sig_info(SIGSEGV, &si, current); |
215 | } | 221 | } |
216 | return(0); | 222 | return 0; |
217 | } | 223 | } |
218 | 224 | ||
219 | void relay_signal(int sig, union uml_pt_regs *regs) | 225 | void relay_signal(int sig, union uml_pt_regs *regs) |
@@ -223,12 +229,12 @@ void relay_signal(int sig, union uml_pt_regs *regs) | |||
223 | 229 | ||
224 | if(!UPT_IS_USER(regs)){ | 230 | if(!UPT_IS_USER(regs)){ |
225 | if(sig == SIGBUS) | 231 | if(sig == SIGBUS) |
226 | printk("Bus error - the /dev/shm or /tmp mount likely " | 232 | printk("Bus error - the host /dev/shm or /tmp mount " |
227 | "just ran out of space\n"); | 233 | "likely just ran out of space\n"); |
228 | panic("Kernel mode signal %d", sig); | 234 | panic("Kernel mode signal %d", sig); |
229 | } | 235 | } |
230 | 236 | ||
231 | current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); | 237 | current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); |
232 | force_sig(sig, current); | 238 | force_sig(sig, current); |
233 | } | 239 | } |
234 | 240 | ||