aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/trap.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel/trap.c')
-rw-r--r--arch/um/kernel/trap.c50
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 {
78survive: 79survive:
@@ -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 */
159unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) 160unsigned 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
219void relay_signal(int sig, union uml_pt_regs *regs) 225void 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