diff options
Diffstat (limited to 'arch/sparc/mm/fault_64.c')
-rw-r--r-- | arch/sparc/mm/fault_64.c | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index a9e474bf6385..4ab8993b0863 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/kprobes.h> | 20 | #include <linux/kprobes.h> |
21 | #include <linux/kdebug.h> | 21 | #include <linux/kdebug.h> |
22 | #include <linux/percpu.h> | ||
22 | 23 | ||
23 | #include <asm/page.h> | 24 | #include <asm/page.h> |
24 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
@@ -224,6 +225,30 @@ cannot_handle: | |||
224 | unhandled_fault (address, current, regs); | 225 | unhandled_fault (address, current, regs); |
225 | } | 226 | } |
226 | 227 | ||
228 | static void noinline bogus_32bit_fault_tpc(struct pt_regs *regs) | ||
229 | { | ||
230 | static int times; | ||
231 | |||
232 | if (times++ < 10) | ||
233 | printk(KERN_ERR "FAULT[%s:%d]: 32-bit process reports " | ||
234 | "64-bit TPC [%lx]\n", | ||
235 | current->comm, current->pid, | ||
236 | regs->tpc); | ||
237 | show_regs(regs); | ||
238 | } | ||
239 | |||
240 | static void noinline bogus_32bit_fault_address(struct pt_regs *regs, | ||
241 | unsigned long addr) | ||
242 | { | ||
243 | static int times; | ||
244 | |||
245 | if (times++ < 10) | ||
246 | printk(KERN_ERR "FAULT[%s:%d]: 32-bit process " | ||
247 | "reports 64-bit fault address [%lx]\n", | ||
248 | current->comm, current->pid, addr); | ||
249 | show_regs(regs); | ||
250 | } | ||
251 | |||
227 | asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | 252 | asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) |
228 | { | 253 | { |
229 | struct mm_struct *mm = current->mm; | 254 | struct mm_struct *mm = current->mm; |
@@ -244,6 +269,19 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | |||
244 | (fault_code & FAULT_CODE_DTLB)) | 269 | (fault_code & FAULT_CODE_DTLB)) |
245 | BUG(); | 270 | BUG(); |
246 | 271 | ||
272 | if (test_thread_flag(TIF_32BIT)) { | ||
273 | if (!(regs->tstate & TSTATE_PRIV)) { | ||
274 | if (unlikely((regs->tpc >> 32) != 0)) { | ||
275 | bogus_32bit_fault_tpc(regs); | ||
276 | goto intr_or_no_mm; | ||
277 | } | ||
278 | } | ||
279 | if (unlikely((address >> 32) != 0)) { | ||
280 | bogus_32bit_fault_address(regs, address); | ||
281 | goto intr_or_no_mm; | ||
282 | } | ||
283 | } | ||
284 | |||
247 | if (regs->tstate & TSTATE_PRIV) { | 285 | if (regs->tstate & TSTATE_PRIV) { |
248 | unsigned long tpc = regs->tpc; | 286 | unsigned long tpc = regs->tpc; |
249 | 287 | ||
@@ -264,12 +302,6 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | |||
264 | if (in_atomic() || !mm) | 302 | if (in_atomic() || !mm) |
265 | goto intr_or_no_mm; | 303 | goto intr_or_no_mm; |
266 | 304 | ||
267 | if (test_thread_flag(TIF_32BIT)) { | ||
268 | if (!(regs->tstate & TSTATE_PRIV)) | ||
269 | regs->tpc &= 0xffffffff; | ||
270 | address &= 0xffffffff; | ||
271 | } | ||
272 | |||
273 | if (!down_read_trylock(&mm->mmap_sem)) { | 305 | if (!down_read_trylock(&mm->mmap_sem)) { |
274 | if ((regs->tstate & TSTATE_PRIV) && | 306 | if ((regs->tstate & TSTATE_PRIV) && |
275 | !search_exception_tables(regs->tpc)) { | 307 | !search_exception_tables(regs->tpc)) { |