aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/traps.c
diff options
context:
space:
mode:
authorSuzuki K Poulose <suzuki.poulose@arm.com>2016-09-09 09:07:15 -0400
committerWill Deacon <will.deacon@arm.com>2016-09-09 10:03:29 -0400
commit9dbd5bb25c56e35e6b4c34d968689a1ded850924 (patch)
treef81f727180de3d8eef52c1d69d72a46cc196eea5 /arch/arm64/kernel/traps.c
parent072f0a633838aca13b5a8b211eb64f5c445cfd7c (diff)
arm64: Refactor sysinstr exception handling
Right now we trap some of the user space data cache operations based on a few Errata (ARM 819472, 826319, 827319 and 824069). We need to trap userspace access to CTR_EL0, if we detect mismatched cache line size. Since both these traps share the EC, refactor the handler a little bit to make it a bit more reader friendly. Cc: Mark Rutland <mark.rutland@arm.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Andre Przywara <andre.przywara@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel/traps.c')
-rw-r--r--arch/arm64/kernel/traps.c73
1 files changed, 47 insertions, 26 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index e04f83873af7..224f64eddd93 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -447,36 +447,29 @@ void cpu_enable_cache_maint_trap(void *__unused)
447 : "=r" (res) \ 447 : "=r" (res) \
448 : "r" (address), "i" (-EFAULT) ) 448 : "r" (address), "i" (-EFAULT) )
449 449
450asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs) 450static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
451{ 451{
452 unsigned long address; 452 unsigned long address;
453 int ret; 453 int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;
454 int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
455 int ret = 0;
454 456
455 /* if this is a write with: Op0=1, Op2=1, Op1=3, CRn=7 */ 457 address = (rt == 31) ? 0 : regs->regs[rt];
456 if ((esr & 0x01fffc01) == 0x0012dc00) {
457 int rt = (esr >> 5) & 0x1f;
458 int crm = (esr >> 1) & 0x0f;
459 458
460 address = (rt == 31) ? 0 : regs->regs[rt]; 459 switch (crm) {
461 460 case ESR_ELx_SYS64_ISS_CRM_DC_CVAU: /* DC CVAU, gets promoted */
462 switch (crm) { 461 __user_cache_maint("dc civac", address, ret);
463 case 11: /* DC CVAU, gets promoted */ 462 break;
464 __user_cache_maint("dc civac", address, ret); 463 case ESR_ELx_SYS64_ISS_CRM_DC_CVAC: /* DC CVAC, gets promoted */
465 break; 464 __user_cache_maint("dc civac", address, ret);
466 case 10: /* DC CVAC, gets promoted */ 465 break;
467 __user_cache_maint("dc civac", address, ret); 466 case ESR_ELx_SYS64_ISS_CRM_DC_CIVAC: /* DC CIVAC */
468 break; 467 __user_cache_maint("dc civac", address, ret);
469 case 14: /* DC CIVAC */ 468 break;
470 __user_cache_maint("dc civac", address, ret); 469 case ESR_ELx_SYS64_ISS_CRM_IC_IVAU: /* IC IVAU */
471 break; 470 __user_cache_maint("ic ivau", address, ret);
472 case 5: /* IC IVAU */ 471 break;
473 __user_cache_maint("ic ivau", address, ret); 472 default:
474 break;
475 default:
476 force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
477 return;
478 }
479 } else {
480 force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0); 473 force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
481 return; 474 return;
482 } 475 }
@@ -487,6 +480,34 @@ asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
487 regs->pc += 4; 480 regs->pc += 4;
488} 481}
489 482
483struct sys64_hook {
484 unsigned int esr_mask;
485 unsigned int esr_val;
486 void (*handler)(unsigned int esr, struct pt_regs *regs);
487};
488
489static struct sys64_hook sys64_hooks[] = {
490 {
491 .esr_mask = ESR_ELx_SYS64_ISS_EL0_CACHE_OP_MASK,
492 .esr_val = ESR_ELx_SYS64_ISS_EL0_CACHE_OP_VAL,
493 .handler = user_cache_maint_handler,
494 },
495 {},
496};
497
498asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
499{
500 struct sys64_hook *hook;
501
502 for (hook = sys64_hooks; hook->handler; hook++)
503 if ((hook->esr_mask & esr) == hook->esr_val) {
504 hook->handler(esr, regs);
505 return;
506 }
507
508 force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
509}
510
490long compat_arm_syscall(struct pt_regs *regs); 511long compat_arm_syscall(struct pt_regs *regs);
491 512
492asmlinkage long do_ni_syscall(struct pt_regs *regs) 513asmlinkage long do_ni_syscall(struct pt_regs *regs)