aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc/mm
diff options
context:
space:
mode:
authorKyle McMartin <kyle@mcmartin.ca>2008-12-19 21:29:06 -0500
committerKyle McMartin <kyle@mcmartin.ca>2009-01-05 14:16:46 -0500
commitc61c25eb02757ecf697015ef4ae3675c5e114e2e (patch)
treedb955b3bcd10a69dbb68366203ee0d6b64cbfe3d /arch/parisc/mm
parentaefa8b6bf48fdcc904de4f166e59ab37fb750dec (diff)
parisc: fix kernel crash (protection id trap) when compiling ruby1.9
On Wed, Dec 17, 2008 at 11:46:05PM +0100, Helge Deller wrote: > Honestly, I can't decide whether to apply this. It really should never happen in the kernel, since the kernel can guarantee it won't get the access rights failure (highest privilege level, and can set %sr and %protid to whatever it wants.) It really genuinely is a bug that probably should panic the kernel. The only precedent I can easily see is x86 fixing up a bad iret with a general protection fault, which is more or less analogous to code 27 here. On the other hand, taking the exception on a userspace access really isn't all that critical, and there's fundamentally little reason for the kernel not to SIGSEGV the process, and continue... Argh. (btw, I've instrumented my do_sys_poll with a pile of assertions that %cr8 << 1 == %sr3 == current->mm.context... let's see if where we're getting corrupted is deterministic, though, I would guess that it won't be.) Signed-off-by: Kyle McMartin <kyle@mcmartin.ca>
Diffstat (limited to 'arch/parisc/mm')
-rw-r--r--arch/parisc/mm/fault.c58
1 files changed, 31 insertions, 27 deletions
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index b2e3e9a8cece..92c7fa4ecc3f 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -139,13 +139,41 @@ parisc_acctyp(unsigned long code, unsigned int inst)
139 } 139 }
140#endif 140#endif
141 141
142int fixup_exception(struct pt_regs *regs)
143{
144 const struct exception_table_entry *fix;
145
146 fix = search_exception_tables(regs->iaoq[0]);
147 if (fix) {
148 struct exception_data *d;
149 d = &__get_cpu_var(exception_data);
150 d->fault_ip = regs->iaoq[0];
151 d->fault_space = regs->isr;
152 d->fault_addr = regs->ior;
153
154 regs->iaoq[0] = ((fix->fixup) & ~3);
155 /*
156 * NOTE: In some cases the faulting instruction
157 * may be in the delay slot of a branch. We
158 * don't want to take the branch, so we don't
159 * increment iaoq[1], instead we set it to be
160 * iaoq[0]+4, and clear the B bit in the PSW
161 */
162 regs->iaoq[1] = regs->iaoq[0] + 4;
163 regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */
164
165 return 1;
166 }
167
168 return 0;
169}
170
142void do_page_fault(struct pt_regs *regs, unsigned long code, 171void do_page_fault(struct pt_regs *regs, unsigned long code,
143 unsigned long address) 172 unsigned long address)
144{ 173{
145 struct vm_area_struct *vma, *prev_vma; 174 struct vm_area_struct *vma, *prev_vma;
146 struct task_struct *tsk = current; 175 struct task_struct *tsk = current;
147 struct mm_struct *mm = tsk->mm; 176 struct mm_struct *mm = tsk->mm;
148 const struct exception_table_entry *fix;
149 unsigned long acc_type; 177 unsigned long acc_type;
150 int fault; 178 int fault;
151 179
@@ -229,32 +257,8 @@ bad_area:
229 257
230no_context: 258no_context:
231 259
232 if (!user_mode(regs)) { 260 if (!user_mode(regs) && fixup_exception(regs)) {
233 fix = search_exception_tables(regs->iaoq[0]); 261 return;
234
235 if (fix) {
236 struct exception_data *d;
237
238 d = &__get_cpu_var(exception_data);
239 d->fault_ip = regs->iaoq[0];
240 d->fault_space = regs->isr;
241 d->fault_addr = regs->ior;
242
243 regs->iaoq[0] = ((fix->fixup) & ~3);
244
245 /*
246 * NOTE: In some cases the faulting instruction
247 * may be in the delay slot of a branch. We
248 * don't want to take the branch, so we don't
249 * increment iaoq[1], instead we set it to be
250 * iaoq[0]+4, and clear the B bit in the PSW
251 */
252
253 regs->iaoq[1] = regs->iaoq[0] + 4;
254 regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */
255
256 return;
257 }
258 } 262 }
259 263
260 parisc_terminate("Bad Address (null pointer deref?)", regs, code, address); 264 parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);