Messages in this thread Patch in this message | ![/](/images/icornerl.gif) | | From | Clément Léger <> | Subject | [RFC V2 PATCH 8/9] riscv: add support for PR_SET_UNALIGN and PR_GET_UNALIGN | Date | Tue, 4 Jul 2023 16:09:23 +0200 |
| |
Now that trap support is ready to handle misalignment errors in S-mode, allow the user to control the behavior of misalignment accesses using prctl(). Add an align_ctl flag in thread_struct which will be used to determine if we should SIGBUS the process or not on such fault.
Signed-off-by: Clément Léger <cleger@rivosinc.com> --- arch/riscv/include/asm/cpufeature.h | 8 ++++++++ arch/riscv/include/asm/processor.h | 9 +++++++++ arch/riscv/kernel/process.c | 18 ++++++++++++++++++ arch/riscv/kernel/traps_misaligned.c | 7 +++++++ 4 files changed, 42 insertions(+)
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index 7e968499db49..e2fd6fc7157f 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -6,6 +6,8 @@ #ifndef _ASM_CPUFEATURE_H #define _ASM_CPUFEATURE_H +#include <asm/hwprobe.h> + /* * These are probed via a device_initcall(), via either the SBI or directly * from the corresponding CSRs. @@ -20,6 +22,12 @@ DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo); DECLARE_PER_CPU(long, misaligned_access_speed); +static inline bool misaligned_access_emulated(void) +{ + return per_cpu(misaligned_access_speed, 0) == + RISCV_HWPROBE_MISALIGNED_EMULATED; +} + void __init misaligned_emulation_init(void); #endif diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 94a0590c6971..4e6667d5ca68 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -7,6 +7,7 @@ #define _ASM_RISCV_PROCESSOR_H #include <linux/const.h> +#include <linux/prctl.h> #include <vdso/processor.h> @@ -39,6 +40,7 @@ struct thread_struct { unsigned long s[12]; /* s[0]: frame pointer */ struct __riscv_d_ext_state fstate; unsigned long bad_cause; + unsigned long align_ctl; }; /* Whitelist the fstate from the task_struct for hardened usercopy */ @@ -51,6 +53,7 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset, #define INIT_THREAD { \ .sp = sizeof(init_stack) + (long)&init_stack, \ + .align_ctl = PR_UNALIGN_NOPRINT, \ } #define task_pt_regs(tsk) \ @@ -80,6 +83,12 @@ int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid); extern void riscv_fill_hwcap(void); extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); +extern int get_unalign_ctl(struct task_struct *, unsigned long addr); +extern int set_unalign_ctl(struct task_struct *, unsigned int val); + +#define GET_UNALIGN_CTL(tsk, addr) get_unalign_ctl((tsk), (addr)) +#define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val)) + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_PROCESSOR_H */ diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index e2a060066730..88a71359396b 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -24,6 +24,7 @@ #include <asm/switch_to.h> #include <asm/thread_info.h> #include <asm/cpuidle.h> +#include <asm/cpufeature.h> register unsigned long gp_in_global __asm__("gp"); @@ -40,6 +41,23 @@ void arch_cpu_idle(void) cpu_do_idle(); } +int set_unalign_ctl(struct task_struct *tsk, unsigned int val) +{ + if (!misaligned_access_emulated()) + return -EINVAL; + + tsk->thread.align_ctl = val; + return 0; +} + +int get_unalign_ctl(struct task_struct *tsk, unsigned long adr) +{ + if (!misaligned_access_emulated()) + return -EINVAL; + + return put_user(tsk->thread.align_ctl, (unsigned long __user *)adr); +} + void __show_regs(struct pt_regs *regs) { show_regs_print_info(KERN_DEFAULT); diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 243ef9314734..5fb6758b0bf9 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -9,6 +9,7 @@ #include <linux/perf_event.h> #include <linux/irq.h> #include <linux/stringify.h> +#include <linux/prctl.h> #include <asm/processor.h> #include <asm/ptrace.h> @@ -305,6 +306,9 @@ int handle_misaligned_load(struct pt_regs *regs) if (!unaligned_enabled) return -1; + if (user_mode(regs) && (current->thread.align_ctl & PR_UNALIGN_SIGBUS)) + return -1; + if (get_insn(regs, epc, &insn)) return -1; @@ -398,6 +402,9 @@ int handle_misaligned_store(struct pt_regs *regs) if (!unaligned_enabled) return -1; + if (user_mode(regs) && (current->thread.align_ctl & PR_UNALIGN_SIGBUS)) + return -1; + if (get_insn(regs, epc, &insn)) return -1; -- 2.40.1
| ![\](/images/icornerr.gif) |