diff options
Diffstat (limited to 'arch/sparc')
-rw-r--r-- | arch/sparc/mm/fault_64.c | 49 |
1 files changed, 35 insertions, 14 deletions
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 1a786abdada3..4ab8993b0863 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c | |||
@@ -225,6 +225,30 @@ cannot_handle: | |||
225 | unhandled_fault (address, current, regs); | 225 | unhandled_fault (address, current, regs); |
226 | } | 226 | } |
227 | 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 | |||
228 | asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | 252 | asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) |
229 | { | 253 | { |
230 | struct mm_struct *mm = current->mm; | 254 | struct mm_struct *mm = current->mm; |
@@ -246,13 +270,20 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | |||
246 | BUG(); | 270 | BUG(); |
247 | 271 | ||
248 | if (test_thread_flag(TIF_32BIT)) { | 272 | if (test_thread_flag(TIF_32BIT)) { |
249 | if (!(regs->tstate & TSTATE_PRIV)) | 273 | if (!(regs->tstate & TSTATE_PRIV)) { |
250 | regs->tpc &= 0xffffffff; | 274 | if (unlikely((regs->tpc >> 32) != 0)) { |
251 | address &= 0xffffffff; | 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 | } | ||
252 | } | 283 | } |
253 | 284 | ||
254 | if (regs->tstate & TSTATE_PRIV) { | 285 | if (regs->tstate & TSTATE_PRIV) { |
255 | unsigned long eaddr, tpc = regs->tpc; | 286 | unsigned long tpc = regs->tpc; |
256 | 287 | ||
257 | /* Sanity check the PC. */ | 288 | /* Sanity check the PC. */ |
258 | if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) || | 289 | if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) || |
@@ -262,16 +293,6 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) | |||
262 | bad_kernel_pc(regs, address); | 293 | bad_kernel_pc(regs, address); |
263 | return; | 294 | return; |
264 | } | 295 | } |
265 | |||
266 | insn = get_fault_insn(regs, insn); | ||
267 | eaddr = compute_effective_address(regs, insn, 0); | ||
268 | if (WARN_ON_ONCE((eaddr & PAGE_MASK) != (address & PAGE_MASK))){ | ||
269 | printk(KERN_ERR "FAULT: Mismatch kernel fault " | ||
270 | "address: addr[%lx] eaddr[%lx] TPC[%lx]\n", | ||
271 | address, eaddr, tpc); | ||
272 | show_regs(regs); | ||
273 | goto handle_kernel_fault; | ||
274 | } | ||
275 | } | 296 | } |
276 | 297 | ||
277 | /* | 298 | /* |