]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xtensa: improve call0 ABI probing
authorMax Filippov <jcmvbkbc@gmail.com>
Fri, 13 May 2022 15:11:14 +0000 (08:11 -0700)
committerMax Filippov <jcmvbkbc@gmail.com>
Tue, 17 May 2022 10:35:43 +0000 (03:35 -0700)
When call0 userspace ABI support by probing is enabled instructions that
cause illegal instruction exception when PS.WOE is clear are retried
with PS.WOE set before calling c-level exception handler. Record user pc
at which PS.WOE was set in the fast exception handler and clear PS.WOE
in the c-level exception handler if we get there from the same address.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
arch/xtensa/include/asm/thread_info.h
arch/xtensa/kernel/asm-offsets.c
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/traps.c

index 52974317a6b6f5d6423aca9fb25d80a7873158c5..326db1c1d5d8d4c44bacc1f27a4cc39ee4fe4742 100644 (file)
@@ -56,6 +56,10 @@ struct thread_info {
        /* result of the most recent exclusive store */
        unsigned long           atomctl8;
 #endif
+#ifdef CONFIG_USER_ABI_CALL0_PROBE
+       /* Address where PS.WOE was enabled by the ABI probing code */
+       unsigned long           ps_woe_fix_addr;
+#endif
 
        /*
         * If i-th bit is set then coprocessor state is loaded into the
index 9a1db6ffcbf4937b165124e177ef0623230d4cf0..da38de20ae598b1a76b1785bb11a7cce53737d73 100644 (file)
@@ -88,6 +88,9 @@ int main(void)
        OFFSET(TI_STSTUS, thread_info, status);
        OFFSET(TI_CPU, thread_info, cpu);
        OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
+#ifdef CONFIG_USER_ABI_CALL0_PROBE
+       OFFSET(TI_PS_WOE_FIX_ADDR, thread_info, ps_woe_fix_addr);
+#endif
 
        /* struct thread_info (offset from start_struct) */
        DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
index 3224b4ceca340f318d1f598ef7431fef5ec3237e..e3eae648ba2e924f263f4b0feb4ca4ceb4ecbdff 100644 (file)
@@ -1056,6 +1056,11 @@ ENTRY(fast_illegal_instruction_user)
        movi    a3, PS_WOE_MASK
        or      a0, a0, a3
        wsr     a0, ps
+#ifdef CONFIG_USER_ABI_CALL0_PROBE
+       GET_THREAD_INFO(a3, a2)
+       rsr     a0, epc1
+       s32i    a0, a3, TI_PS_WOE_FIX_ADDR
+#endif
        l32i    a3, a2, PT_AREG3
        l32i    a0, a2, PT_AREG0
        rsr     a2, depc
index 2b75b252b62664790cf1fc49e33558155e024739..f97d43a8d13d7cd01311709adb76300e93e1b5d1 100644 (file)
@@ -317,6 +317,18 @@ static bool check_div0(struct pt_regs *regs)
 
 static void do_illegal_instruction(struct pt_regs *regs)
 {
+#ifdef CONFIG_USER_ABI_CALL0_PROBE
+       /*
+        * When call0 application encounters an illegal instruction fast
+        * exception handler will attempt to set PS.WOE and retry failing
+        * instruction.
+        * If we get here we know that that instruction is also illegal
+        * with PS.WOE set, so it's not related to the windowed option
+        * hence PS.WOE may be cleared.
+        */
+       if (regs->pc == current_thread_info()->ps_woe_fix_addr)
+               regs->ps &= ~PS_WOE_MASK;
+#endif
        if (check_div0(regs)) {
                do_div0(regs);
                return;