ARM: iwmmxt: Use undef hook to enable coprocessor for task
authorArd Biesheuvel <ardb@kernel.org>
Sun, 19 Mar 2023 23:07:20 +0000 (00:07 +0100)
committerArd Biesheuvel <ardb@kernel.org>
Wed, 17 May 2023 13:08:22 +0000 (15:08 +0200)
Define a undef hook to deal with undef exceptions triggered by iwmmxt
instructions that were issued with the coprocessor disabled. This
removes the dependency on the coprocessor dispatch code in entry-armv.S,
which will be made NWFPE-only in a subsequent patch.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
arch/arm/include/asm/thread_info.h
arch/arm/kernel/entry-armv.S
arch/arm/kernel/iwmmxt.S
arch/arm/kernel/pj4-cp0.c
arch/arm/kernel/xscale-cp0.c

index 85c5f1e..943ffcf 100644 (file)
@@ -40,6 +40,7 @@ struct task_struct;
 DECLARE_PER_CPU(struct task_struct *, __entry_task);
 
 #include <asm/types.h>
+#include <asm/traps.h>
 
 struct cpu_context_save {
        __u32   r4;
@@ -104,6 +105,21 @@ extern void iwmmxt_task_restore(struct thread_info *, void *);
 extern void iwmmxt_task_release(struct thread_info *);
 extern void iwmmxt_task_switch(struct thread_info *);
 
+extern int iwmmxt_undef_handler(struct pt_regs *, u32);
+
+static inline void register_iwmmxt_undef_handler(void)
+{
+       static struct undef_hook iwmmxt_undef_hook = {
+               .instr_mask     = 0x0c000e00,
+               .instr_val      = 0x0c000000,
+               .cpsr_mask      = MODE_MASK | PSR_T_BIT,
+               .cpsr_val       = USR_MODE,
+               .fn             = iwmmxt_undef_handler,
+       };
+
+       register_undef_hook(&iwmmxt_undef_hook);
+}
+
 extern void vfp_sync_hwstate(struct thread_info *);
 extern void vfp_flush_hwstate(struct thread_info *);
 
index aff6cfe..822b2c8 100644 (file)
@@ -507,6 +507,7 @@ ARM_BE8(rev r0, r0)                         @ little endian instruction
        ldr     r5, [r10, #TI_FLAGS]
        rsbs    r7, r8, #(1 << 8)               @ CP 0 or 1 only
        movscs  r7, r5, lsr #(TIF_USING_IWMMXT + 1)
+       movcs   r0, sp                          @ pass struct pt_regs
        bcs     iwmmxt_task_enable
 #endif
  ARM(  add     pc, pc, r8, lsr #6      )
index d2b4ac0..a0218c4 100644 (file)
        .text
        .arm
 
+ENTRY(iwmmxt_undef_handler)
+       push            {r9, r10, lr}
+       get_thread_info r10
+       mov             r9, pc
+       b               iwmmxt_task_enable
+       mov             r0, #0
+       pop             {r9, r10, pc}
+ENDPROC(iwmmxt_undef_handler)
+
 /*
  * Lazy switching of Concan coprocessor context
  *
+ * r0  = struct pt_regs pointer
  * r10 = struct thread_info pointer
  * r9  = ret_from_exception
  * lr  = undefined instr exit
@@ -84,12 +94,12 @@ ENTRY(iwmmxt_task_enable)
        PJ4(mcr p15, 0, r2, c1, c0, 2)
 
        ldr     r3, =concan_owner
-       add     r0, r10, #TI_IWMMXT_STATE       @ get task Concan save area
-       ldr     r2, [sp, #60]                   @ current task pc value
+       ldr     r2, [r0, #S_PC]                 @ current task pc value
        ldr     r1, [r3]                        @ get current Concan owner
-       str     r0, [r3]                        @ this task now owns Concan regs
        sub     r2, r2, #4                      @ adjust pc back
-       str     r2, [sp, #60]
+       str     r2, [r0, #S_PC]
+       add     r0, r10, #TI_IWMMXT_STATE       @ get task Concan save area
+       str     r0, [r3]                        @ this task now owns Concan regs
 
        mrc     p15, 0, r2, c2, c0, 0
        mov     r2, r2                          @ cpwait
index 1d1fb22..4bca809 100644 (file)
@@ -126,6 +126,7 @@ static int __init pj4_cp0_init(void)
        pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers);
        elf_hwcap |= HWCAP_IWMMXT;
        thread_register_notifier(&iwmmxt_notifier_block);
+       register_iwmmxt_undef_handler();
 #endif
 
        return 0;
index ed4f6e7..00d00d3 100644 (file)
@@ -166,6 +166,7 @@ static int __init xscale_cp0_init(void)
                pr_info("XScale iWMMXt coprocessor detected.\n");
                elf_hwcap |= HWCAP_IWMMXT;
                thread_register_notifier(&iwmmxt_notifier_block);
+               register_iwmmxt_undef_handler();
 #endif
        } else {
                pr_info("XScale DSP coprocessor detected.\n");