Skip to content

Commit 9f23a5d

Browse files
clementlegerpalmer-dabbelt
authored andcommitted
riscv: add support for PR_SET_UNALIGN and PR_GET_UNALIGN
Now that trap support is ready to handle misalignment errors in S-mode, allow the user to control the behavior of misaligned accesses using prctl(PR_SET_UNALIGN). 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> Reviewed-by: Björn Töpel <bjorn@rivosinc.com> Link: https://lore.kernel.org/r/20231004151405.521596-9-cleger@rivosinc.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
1 parent 71c54b3 commit 9f23a5d

3 files changed

Lines changed: 33 additions & 0 deletions

File tree

arch/riscv/include/asm/processor.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/const.h>
1010
#include <linux/cache.h>
11+
#include <linux/prctl.h>
1112

1213
#include <vdso/processor.h>
1314

@@ -82,6 +83,7 @@ struct thread_struct {
8283
unsigned long bad_cause;
8384
unsigned long vstate_ctrl;
8485
struct __riscv_v_ext_state vstate;
86+
unsigned long align_ctl;
8587
};
8688

8789
/* Whitelist the fstate from the task_struct for hardened usercopy */
@@ -94,6 +96,7 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset,
9496

9597
#define INIT_THREAD { \
9698
.sp = sizeof(init_stack) + (long)&init_stack, \
99+
.align_ctl = PR_UNALIGN_NOPRINT, \
97100
}
98101

99102
#define task_pt_regs(tsk) \
@@ -134,6 +137,12 @@ extern long riscv_v_vstate_ctrl_set_current(unsigned long arg);
134137
extern long riscv_v_vstate_ctrl_get_current(void);
135138
#endif /* CONFIG_RISCV_ISA_V */
136139

140+
extern int get_unalign_ctl(struct task_struct *tsk, unsigned long addr);
141+
extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
142+
143+
#define GET_UNALIGN_CTL(tsk, addr) get_unalign_ctl((tsk), (addr))
144+
#define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val))
145+
137146
#endif /* __ASSEMBLY__ */
138147

139148
#endif /* _ASM_RISCV_PROCESSOR_H */

arch/riscv/kernel/process.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <asm/thread_info.h>
2626
#include <asm/cpuidle.h>
2727
#include <asm/vector.h>
28+
#include <asm/cpufeature.h>
2829

2930
register unsigned long gp_in_global __asm__("gp");
3031

@@ -41,6 +42,23 @@ void arch_cpu_idle(void)
4142
cpu_do_idle();
4243
}
4344

45+
int set_unalign_ctl(struct task_struct *tsk, unsigned int val)
46+
{
47+
if (!unaligned_ctl_available())
48+
return -EINVAL;
49+
50+
tsk->thread.align_ctl = val;
51+
return 0;
52+
}
53+
54+
int get_unalign_ctl(struct task_struct *tsk, unsigned long adr)
55+
{
56+
if (!unaligned_ctl_available())
57+
return -EINVAL;
58+
59+
return put_user(tsk->thread.align_ctl, (unsigned long __user *)adr);
60+
}
61+
4462
void __show_regs(struct pt_regs *regs)
4563
{
4664
show_regs_print_info(KERN_DEFAULT);

arch/riscv/kernel/traps_misaligned.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,9 @@ int handle_misaligned_load(struct pt_regs *regs)
418418
if (!unaligned_enabled)
419419
return -1;
420420

421+
if (user_mode(regs) && (current->thread.align_ctl & PR_UNALIGN_SIGBUS))
422+
return -1;
423+
421424
if (get_insn(regs, epc, &insn))
422425
return -1;
423426

@@ -517,6 +520,9 @@ int handle_misaligned_store(struct pt_regs *regs)
517520
if (!unaligned_enabled)
518521
return -1;
519522

523+
if (user_mode(regs) && (current->thread.align_ctl & PR_UNALIGN_SIGBUS))
524+
return -1;
525+
520526
if (get_insn(regs, epc, &insn))
521527
return -1;
522528

0 commit comments

Comments
 (0)