diff mbox series

ARM: iwmmxt: Handle Thumb2 encodings of coproc loads and stores

Message ID 20240131114028.625373-2-ardb+git@google.com (mailing list archive)
State New, archived
Headers show
Series ARM: iwmmxt: Handle Thumb2 encodings of coproc loads and stores | expand

Commit Message

Ard Biesheuvel Jan. 31, 2024, 11:40 a.m. UTC
From: Ard Biesheuvel <ardb@kernel.org>

The iWMMXt ISA only exists in a 32-bit encoding, but the generic load
and store instructions operating on coprocessor #1, which iWMMXt
repurposes as WLDR/WSTR instructions, can in fact be emitted as Thumb2
encodings as well.

The register file preserve/restore logic that glibc has as part of its
implementation setjmp/longjmp (among other things) uses the generic
LDC/STC mnemonics, which the assembler happily emits as Thumb2 if that
happens to be how the file is being built.

This means that, even though iWMMXt itself is only defined for ARM mode,
we need to take into account the possibility that we UNDEF in Thumb2
code when attempting to access iWMMXt registers, and trigger the
associated lazy preserve/restore logic as usual.

Given that this only applies to PJ4 and not to Xscale, add this handling
to PJ4 only.

Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Reported-by: walther-it@gmx.de
Fixes: 8bcba70cb5c2204a ("ARM: entry: Disregard Thumb undef exception in coproc dispatch")
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/arm/kernel/pj4-cp0.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm/kernel/pj4-cp0.c b/arch/arm/kernel/pj4-cp0.c
index 4bca8098c4ff..2ef4f8a2bce0 100644
--- a/arch/arm/kernel/pj4-cp0.c
+++ b/arch/arm/kernel/pj4-cp0.c
@@ -101,6 +101,19 @@  static int __init pj4_get_iwmmxt_version(void)
 	return -EINVAL;
 }
 
+/*
+ * The iWMMXt ISA is only defined in ARM mode, but the generic coprocessor
+ * load/store instructions (LDC/STC) exist in a Thumb2 encoding as well, and
+ * may be used (e.g., by glibc) to preserve/restore the iWMMXt register file.
+ */
+static struct undef_hook iwmmxt_undef_t2_hook = {
+       .instr_mask     = 0xee000f00,
+       .instr_val      = 0xec000100,
+       .cpsr_mask      = MODE_MASK | PSR_T_BIT,
+       .cpsr_val       = USR_MODE | PSR_T_BIT,
+       .fn             = iwmmxt_undef_handler,
+};
+
 /*
  * Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
  * switch code handle iWMMXt context switching.
@@ -127,6 +140,9 @@  static int __init pj4_cp0_init(void)
 	elf_hwcap |= HWCAP_IWMMXT;
 	thread_register_notifier(&iwmmxt_notifier_block);
 	register_iwmmxt_undef_handler();
+
+	if (IS_ENABLED(CONFIG_ARM_THUMB))
+		register_undef_hook(&iwmmxt_undef_t2_hook);
 #endif
 
 	return 0;