[PATCH v1] riscv: uaccess: fallback to byte copy on misaligned fault
Andy Chiu
tchiu at tenstorrent.com
Tue Nov 10 14:23:46 PST 2026
If a machine is advertised to support fast unaligned access but somehow
triggers a S-mode misaligned fault on user copy, we recover it by the
exception fixup, which falls back to byte copy. Meanwhile, schedule a
work to turn off the static branch and redirect the code flow back to
software aligning.
This can happen if we boot an machine that doesn't fully support
misaligned access but somehow it passes the fast unalign access speed
probing (hypothetical). Or, if we specify 'unaligned_scalar_speed=fast'
as boot argument while in fact booting a machine that traps on unaligned
access.
Both have to boot with an OpenSBI that delegates misaligned traps,
enabled by RISCV_SBI_FWFT_DELEGATE_MISALIGNED under NONPORTABLE.
Fixes: 30514aa420fd ("riscv: optmize ucopy for has_fast_unaligned_accesses")
Signed-off-by: Andy Chiu <tchiu at tenstorrent.com>
---
arch/riscv/kernel/traps.c | 43 +++++++++++++++++++++++++++++++++++++++
arch/riscv/lib/uaccess.S | 3 +++
2 files changed, 46 insertions(+)
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index f8292adda099..7b88e9c716d2 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -213,6 +213,45 @@ static const struct {
},
};
+#ifdef CONFIG_RISCV_PROBE_UNALIGNED_ACCESS
+static void disable_misaligned_ucopy_work_fn(struct work_struct *w)
+{
+ static_branch_disable(&fast_unaligned_access_speed_key);
+}
+
+static void disable_misaligned_ucopy_helper(struct irq_work *unused)
+{
+ static DECLARE_WORK(disable_misaligned_ucopy_work, disable_misaligned_ucopy_work_fn);
+
+ schedule_work(&disable_misaligned_ucopy_work);
+}
+
+static bool disable_misaligned_ucopy(struct pt_regs *regs)
+{
+ static DEFINE_IRQ_WORK(disable_misaligned_ucopy_irq_work, disable_misaligned_ucopy_helper);
+ unsigned long addr = regs->badaddr;
+
+ if (!IS_ENABLED(CONFIG_JUMP_LABEL))
+ return false;
+
+ if (!(regs->status & SR_SUM))
+ return false;
+
+ if (!fixup_exception(regs))
+ return false;
+
+ if (static_branch_unlikely(&fast_unaligned_access_speed_key))
+ irq_work_queue(&disable_misaligned_ucopy_irq_work);
+
+ perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
+ *this_cpu_ptr(&misaligned_access_speed) = RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED;
+
+ return true;
+}
+#else
+#define disable_misaligned_ucopy(regs) (false)
+#endif
+
static void do_trap_misaligned(struct pt_regs *regs, enum misaligned_access_type type)
{
irqentry_state_t state;
@@ -222,6 +261,10 @@ static void do_trap_misaligned(struct pt_regs *regs, enum misaligned_access_type
local_irq_enable();
} else {
state = irqentry_nmi_enter(regs);
+ if (disable_misaligned_ucopy(regs)) {
+ irqentry_nmi_exit(regs, state);
+ return;
+ }
}
if (misaligned_handler[type].handler(regs))
diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S
index ad1457e789fb..26316c5fe745 100644
--- a/arch/riscv/lib/uaccess.S
+++ b/arch/riscv/lib/uaccess.S
@@ -114,6 +114,9 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
addi a1, a1, 8*SZREG
bleu a0, t0, 2b
+#if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS) && defined(CONFIG_JUMP_LABEL)
+10:
+#endif
addi t0, t0, 8*SZREG /* revert to original value */
j .Lbyte_copy_tail
base-commit: 551bdd6fcaba4ffc98fd95c4d969d4470eae580f
--
2.43.0
More information about the linux-riscv
mailing list