diff options
Diffstat (limited to 'arch/arm64/kernel/traps.c')
-rw-r--r-- | arch/arm64/kernel/traps.c | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 4e3e9d9c8151..ace993b5664c 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -426,6 +426,34 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) uaccess_ttbr0_disable(); \ } +#define __user_cache_maint_ivau(insn, address, res) \ + do { \ + if (address >= user_addr_max()) { \ + res = -EFAULT; \ + } else { \ + uaccess_ttbr0_enable(); \ + asm volatile ( \ + "1: " insn "\n" \ + " mov %w0, #0\n" \ + "2:\n" \ + " .pushsection .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %w0, %w2\n" \ + " b 2b\n" \ + " .popsection\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=r" (res) \ + : "r" (address), "i" (-EFAULT)); \ + uaccess_ttbr0_disable(); \ + } \ + } while (0) + +#ifdef CONFIG_IMX_SCU_SOC +extern bool TKT340553_SW_WORKAROUND; +#else +#define TKT340553_SW_WORKAROUND 0 +#endif + static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) { unsigned long address; @@ -452,7 +480,10 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) __user_cache_maint("dc civac", address, ret); break; case ESR_ELx_SYS64_ISS_CRM_IC_IVAU: /* IC IVAU */ - __user_cache_maint("ic ivau", address, ret); + if (TKT340553_SW_WORKAROUND) + __user_cache_maint_ivau("ic ialluis", address, ret); + else + __user_cache_maint("ic ivau", address, ret); break; default: force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc); |