ARM: iwmmxt: Use undef hook to enable coprocessor for task

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>
This commit is contained in:
Ard Biesheuvel 2023-03-20 00:07:20 +01:00
parent 8bcba70cb5
commit 303d6da167
5 changed files with 33 additions and 4 deletions

View 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 *);

View 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 )

View file

@ -58,9 +58,19 @@
.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

View 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;

View 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");