aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/traps.c
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2016-06-28 13:07:32 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2016-07-01 06:46:00 -0400
commit7dd01aef055792260287c6708daf75aac3918f66 (patch)
treef064a41ff4949170f335e4fd495cdafb9d810903 /arch/arm64/kernel/traps.c
parent390bf1773c7eba3b45df62ae82b3d2be911185b7 (diff)
arm64: trap userspace "dc cvau" cache operation on errata-affected core
The ARM errata 819472, 826319, 827319 and 824069 for affected Cortex-A53 cores demand to promote "dc cvau" instructions to "dc civac". Since we allow userspace to also emit those instructions, we should make sure that "dc cvau" gets promoted there too. So lets grasp the nettle here and actually trap every userland cache maintenance instruction once we detect at least one affected core in the system. We then emulate the instruction by executing it on behalf of userland, promoting "dc cvau" to "dc civac" on the way and injecting access fault back into userspace. Signed-off-by: Andre Przywara <andre.przywara@arm.com> [catalin.marinas@arm.com: s/set_segfault/arm64_notify_segfault/] Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/kernel/traps.c')
-rw-r--r--arch/arm64/kernel/traps.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index d8a5366dcc24..e04f83873af7 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -41,6 +41,7 @@
41#include <asm/stacktrace.h> 41#include <asm/stacktrace.h>
42#include <asm/exception.h> 42#include <asm/exception.h>
43#include <asm/system_misc.h> 43#include <asm/system_misc.h>
44#include <asm/sysreg.h>
44 45
45static const char *handler[]= { 46static const char *handler[]= {
46 "Synchronous Abort", 47 "Synchronous Abort",
@@ -427,6 +428,65 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
427 force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0); 428 force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
428} 429}
429 430
431void cpu_enable_cache_maint_trap(void *__unused)
432{
433 config_sctlr_el1(SCTLR_EL1_UCI, 0);
434}
435
436#define __user_cache_maint(insn, address, res) \
437 asm volatile ( \
438 "1: " insn ", %1\n" \
439 " mov %w0, #0\n" \
440 "2:\n" \
441 " .pushsection .fixup,\"ax\"\n" \
442 " .align 2\n" \
443 "3: mov %w0, %w2\n" \
444 " b 2b\n" \
445 " .popsection\n" \
446 _ASM_EXTABLE(1b, 3b) \
447 : "=r" (res) \
448 : "r" (address), "i" (-EFAULT) )
449
450asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
451{
452 unsigned long address;
453 int ret;
454
455 /* if this is a write with: Op0=1, Op2=1, Op1=3, CRn=7 */
456 if ((esr & 0x01fffc01) == 0x0012dc00) {
457 int rt = (esr >> 5) & 0x1f;
458 int crm = (esr >> 1) & 0x0f;
459
460 address = (rt == 31) ? 0 : regs->regs[rt];
461
462 switch (crm) {
463 case 11: /* DC CVAU, gets promoted */
464 __user_cache_maint("dc civac", address, ret);
465 break;
466 case 10: /* DC CVAC, gets promoted */
467 __user_cache_maint("dc civac", address, ret);
468 break;
469 case 14: /* DC CIVAC */
470 __user_cache_maint("dc civac", address, ret);
471 break;
472 case 5: /* IC IVAU */
473 __user_cache_maint("ic ivau", address, ret);
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);
481 return;
482 }
483
484 if (ret)
485 arm64_notify_segfault(regs, address);
486 else
487 regs->pc += 4;
488}
489
430long compat_arm_syscall(struct pt_regs *regs); 490long compat_arm_syscall(struct pt_regs *regs);
431 491
432asmlinkage long do_ni_syscall(struct pt_regs *regs) 492asmlinkage long do_ni_syscall(struct pt_regs *regs)