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)) { |
