[PATCH] ARM: iwmmxt: Handle Thumb2 encodings of coproc loads and stores

Ard Biesheuvel ardb+git at google.com
Wed Jan 31 03:40:29 PST 2024


From: Ard Biesheuvel <ardb at 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 at linaro.org>
Cc: Arnd Bergmann <arnd at arndb.de>
Reported-by: walther-it at gmx.de
Fixes: 8bcba70cb5c2204a ("ARM: entry: Disregard Thumb undef exception in coproc dispatch")
Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
---
 arch/arm/kernel/pj4-cp0.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

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;
-- 
2.43.0.429.g432eaa2c6b-goog




More information about the linux-arm-kernel mailing list