aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/traps.c')
-rw-r--r--arch/arm/kernel/traps.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 6e31718f6008..14df16b983f4 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -218,7 +218,8 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
218 tsk->comm, tsk->pid, tsk->thread_info + 1); 218 tsk->comm, tsk->pid, tsk->thread_info + 1);
219 219
220 if (!user_mode(regs) || in_interrupt()) { 220 if (!user_mode(regs) || in_interrupt()) {
221 dump_mem("Stack: ", regs->ARM_sp, 8192+(unsigned long)tsk->thread_info); 221 dump_mem("Stack: ", regs->ARM_sp,
222 THREAD_SIZE + (unsigned long)tsk->thread_info);
222 dump_backtrace(regs, tsk); 223 dump_backtrace(regs, tsk);
223 dump_instr(regs); 224 dump_instr(regs);
224 } 225 }
@@ -450,13 +451,17 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
450 451
451 case NR(set_tls): 452 case NR(set_tls):
452 thread->tp_value = regs->ARM_r0; 453 thread->tp_value = regs->ARM_r0;
454#if defined(CONFIG_HAS_TLS_REG)
455 asm ("mcr p15, 0, %0, c13, c0, 3" : : "r" (regs->ARM_r0) );
456#elif !defined(CONFIG_TLS_REG_EMUL)
453 /* 457 /*
454 * Our user accessible TLS ptr is located at 0xffff0ffc. 458 * User space must never try to access this directly.
455 * On SMP read access to this address must raise a fault 459 * Expect your app to break eventually if you do so.
456 * and be emulated from the data abort handler. 460 * The user helper at 0xffff0fe0 must be used instead.
457 * m 461 * (see entry-armv.S for details)
458 */ 462 */
459 *((unsigned long *)0xffff0ffc) = thread->tp_value; 463 *((unsigned int *)0xffff0ff0) = regs->ARM_r0;
464#endif
460 return 0; 465 return 0;
461 466
462 default: 467 default:
@@ -493,6 +498,44 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
493 return 0; 498 return 0;
494} 499}
495 500
501#ifdef CONFIG_TLS_REG_EMUL
502
503/*
504 * We might be running on an ARMv6+ processor which should have the TLS
505 * register but for some reason we can't use it, or maybe an SMP system
506 * using a pre-ARMv6 processor (there are apparently a few prototypes like
507 * that in existence) and therefore access to that register must be
508 * emulated.
509 */
510
511static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
512{
513 int reg = (instr >> 12) & 15;
514 if (reg == 15)
515 return 1;
516 regs->uregs[reg] = current_thread_info()->tp_value;
517 regs->ARM_pc += 4;
518 return 0;
519}
520
521static struct undef_hook arm_mrc_hook = {
522 .instr_mask = 0x0fff0fff,
523 .instr_val = 0x0e1d0f70,
524 .cpsr_mask = PSR_T_BIT,
525 .cpsr_val = 0,
526 .fn = get_tp_trap,
527};
528
529static int __init arm_mrc_hook_init(void)
530{
531 register_undef_hook(&arm_mrc_hook);
532 return 0;
533}
534
535late_initcall(arm_mrc_hook_init);
536
537#endif
538
496void __bad_xchg(volatile void *ptr, int size) 539void __bad_xchg(volatile void *ptr, int size)
497{ 540{
498 printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n", 541 printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
@@ -578,9 +621,19 @@ EXPORT_SYMBOL(abort);
578 621
579void __init trap_init(void) 622void __init trap_init(void)
580{ 623{
581 extern void __trap_init(void); 624 extern char __stubs_start[], __stubs_end[];
625 extern char __vectors_start[], __vectors_end[];
626 extern char __kuser_helper_start[], __kuser_helper_end[];
627 int kuser_sz = __kuser_helper_end - __kuser_helper_start;
582 628
583 __trap_init(); 629 /*
630 * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
631 * into the vector page, mapped at 0xffff0000, and ensure these
632 * are visible to the instruction stream.
633 */
634 memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start);
635 memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start);
636 memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz);
584 flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE); 637 flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE);
585 modify_domain(DOMAIN_USER, DOMAIN_CLIENT); 638 modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
586} 639}