aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/trap_kern.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel/trap_kern.c')
-rw-r--r--arch/um/kernel/trap_kern.c64
1 files changed, 21 insertions, 43 deletions
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index 47e766e6ba10..c20aef120598 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -23,7 +23,6 @@
23#include "kern.h" 23#include "kern.h"
24#include "chan_kern.h" 24#include "chan_kern.h"
25#include "mconsole_kern.h" 25#include "mconsole_kern.h"
26#include "2_5compat.h"
27#include "mem.h" 26#include "mem.h"
28#include "mem_kern.h" 27#include "mem_kern.h"
29 28
@@ -48,7 +47,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,
48 goto good_area; 47 goto good_area;
49 else if(!(vma->vm_flags & VM_GROWSDOWN)) 48 else if(!(vma->vm_flags & VM_GROWSDOWN))
50 goto out; 49 goto out;
51 else if(!ARCH_IS_STACKGROW(address)) 50 else if(is_user && !ARCH_IS_STACKGROW(address))
52 goto out; 51 goto out;
53 else if(expand_stack(vma, address)) 52 else if(expand_stack(vma, address))
54 goto out; 53 goto out;
@@ -57,10 +56,11 @@ int handle_page_fault(unsigned long address, unsigned long ip,
57 *code_out = SEGV_ACCERR; 56 *code_out = SEGV_ACCERR;
58 if(is_write && !(vma->vm_flags & VM_WRITE)) 57 if(is_write && !(vma->vm_flags & VM_WRITE))
59 goto out; 58 goto out;
59
60 if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
61 goto out;
62
60 page = address & PAGE_MASK; 63 page = address & PAGE_MASK;
61 pgd = pgd_offset(mm, page);
62 pud = pud_offset(pgd, page);
63 pmd = pmd_offset(pud, page);
64 do { 64 do {
65 survive: 65 survive:
66 switch (handle_mm_fault(mm, vma, address, is_write)){ 66 switch (handle_mm_fault(mm, vma, address, is_write)){
@@ -106,46 +106,24 @@ out_of_memory:
106 goto out; 106 goto out;
107} 107}
108 108
109LIST_HEAD(physmem_remappers); 109/*
110 110 * We give a *copy* of the faultinfo in the regs to segv.
111void register_remapper(struct remapper *info) 111 * This must be done, since nesting SEGVs could overwrite
112{ 112 * the info in the regs. A pointer to the info then would
113 list_add(&info->list, &physmem_remappers); 113 * give us bad data!
114} 114 */
115 115unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
116static int check_remapped_addr(unsigned long address, int is_write)
117{
118 struct remapper *remapper;
119 struct list_head *ele;
120 __u64 offset;
121 int fd;
122
123 fd = phys_mapping(__pa(address), &offset);
124 if(fd == -1)
125 return(0);
126
127 list_for_each(ele, &physmem_remappers){
128 remapper = list_entry(ele, struct remapper, list);
129 if((*remapper->proc)(fd, address, is_write, offset))
130 return(1);
131 }
132
133 return(0);
134}
135
136unsigned long segv(unsigned long address, unsigned long ip, int is_write,
137 int is_user, void *sc)
138{ 116{
139 struct siginfo si; 117 struct siginfo si;
140 void *catcher; 118 void *catcher;
141 int err; 119 int err;
120 int is_write = FAULT_WRITE(fi);
121 unsigned long address = FAULT_ADDRESS(fi);
142 122
143 if(!is_user && (address >= start_vm) && (address < end_vm)){ 123 if(!is_user && (address >= start_vm) && (address < end_vm)){
144 flush_tlb_kernel_vm(); 124 flush_tlb_kernel_vm();
145 return(0); 125 return(0);
146 } 126 }
147 else if(check_remapped_addr(address & PAGE_MASK, is_write))
148 return(0);
149 else if(current->mm == NULL) 127 else if(current->mm == NULL)
150 panic("Segfault with no mm"); 128 panic("Segfault with no mm");
151 err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); 129 err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
@@ -159,7 +137,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
159 } 137 }
160 else if(current->thread.fault_addr != NULL) 138 else if(current->thread.fault_addr != NULL)
161 panic("fault_addr set but no fault catcher"); 139 panic("fault_addr set but no fault catcher");
162 else if(arch_fixup(ip, sc)) 140 else if(!is_user && arch_fixup(ip, sc))
163 return(0); 141 return(0);
164 142
165 if(!is_user) 143 if(!is_user)
@@ -171,6 +149,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
171 si.si_errno = 0; 149 si.si_errno = 0;
172 si.si_code = BUS_ADRERR; 150 si.si_code = BUS_ADRERR;
173 si.si_addr = (void *)address; 151 si.si_addr = (void *)address;
152 current->thread.arch.faultinfo = fi;
174 force_sig_info(SIGBUS, &si, current); 153 force_sig_info(SIGBUS, &si, current);
175 } 154 }
176 else if(err == -ENOMEM){ 155 else if(err == -ENOMEM){
@@ -180,22 +159,20 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
180 else { 159 else {
181 si.si_signo = SIGSEGV; 160 si.si_signo = SIGSEGV;
182 si.si_addr = (void *) address; 161 si.si_addr = (void *) address;
183 current->thread.cr2 = address; 162 current->thread.arch.faultinfo = fi;
184 current->thread.err = is_write;
185 force_sig_info(SIGSEGV, &si, current); 163 force_sig_info(SIGSEGV, &si, current);
186 } 164 }
187 return(0); 165 return(0);
188} 166}
189 167
190void bad_segv(unsigned long address, unsigned long ip, int is_write) 168void bad_segv(struct faultinfo fi, unsigned long ip)
191{ 169{
192 struct siginfo si; 170 struct siginfo si;
193 171
194 si.si_signo = SIGSEGV; 172 si.si_signo = SIGSEGV;
195 si.si_code = SEGV_ACCERR; 173 si.si_code = SEGV_ACCERR;
196 si.si_addr = (void *) address; 174 si.si_addr = (void *) FAULT_ADDRESS(fi);
197 current->thread.cr2 = address; 175 current->thread.arch.faultinfo = fi;
198 current->thread.err = is_write;
199 force_sig_info(SIGSEGV, &si, current); 176 force_sig_info(SIGSEGV, &si, current);
200} 177}
201 178
@@ -204,6 +181,7 @@ void relay_signal(int sig, union uml_pt_regs *regs)
204 if(arch_handle_signal(sig, regs)) return; 181 if(arch_handle_signal(sig, regs)) return;
205 if(!UPT_IS_USER(regs)) 182 if(!UPT_IS_USER(regs))
206 panic("Kernel mode signal %d", sig); 183 panic("Kernel mode signal %d", sig);
184 current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
207 force_sig(sig, current); 185 force_sig(sig, current);
208} 186}
209 187