[PATCH v2 1/6] riscv: Make get_insn public for instruction fault handling
"Yicong Yang" <[email protected]> Tue, 28 Jul 2026 17:46:22 +0800
| Newsgroups | org.infradead.lists.linux-riscv |
|---|---|
| Message-ID | <[email protected]> |
Currently two places (vector and misaligned load/store) need to get fault instructions for handling and they implement the function separately. This is a common function so make get_insn() public in asm/insn.h for doing this job to make it less fragile and improve the maintainability. Signed-off-by: Yicong Yang <[email protected]> --- arch/riscv/include/asm/insn.h | 53 ++++++++++++++++++++++++++++ arch/riscv/kernel/traps_misaligned.c | 52 --------------------------- arch/riscv/kernel/vector.c | 6 ++-- 3 files changed, 56 insertions(+), 55 deletions(-) diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h index c3005573e8c9..5f60367c2abc 100644 --- a/arch/riscv/include/asm/insn.h +++ b/arch/riscv/include/asm/insn.h @@ -600,4 +600,57 @@ static inline void riscv_insn_insert_utype_itype_imm(u32 *utype_insn, u32 *itype *utype_insn |= (imm & RV_U_IMM_31_12_MASK) + ((imm & BIT(11)) << 1); *itype_insn |= ((imm & RV_I_IMM_11_0_MASK) << RV_I_IMM_11_0_OPOFF); } + +#define __read_insn(regs, insn, insn_addr, type) \ +({ \ + int __ret; \ + \ + if (user_mode(regs)) { \ + __ret = get_user(insn, (type __user *) insn_addr); \ + } else { \ + insn = *(type *)insn_addr; \ + __ret = 0; \ + } \ + \ + __ret; \ +}) + +static inline int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn) +{ + ulong insn = 0; + + if (epc & 0x2) { + ulong tmp = 0; + + if (__read_insn(regs, insn, epc, u16)) + return -EFAULT; + /* __get_user() uses regular "lw" which sign extend the loaded + * value make sure to clear higher order bits in case we "or" it + * below with the upper 16 bits half. + */ + insn &= GENMASK(15, 0); + if ((insn & __INSN_LENGTH_MASK) != __INSN_LENGTH_32) { + *r_insn = insn; + return 0; + } + epc += sizeof(u16); + if (__read_insn(regs, tmp, epc, u16)) + return -EFAULT; + *r_insn = (tmp << 16) | insn; + + return 0; + } else { + if (__read_insn(regs, insn, epc, u32)) + return -EFAULT; + if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) { + *r_insn = insn; + return 0; + } + insn &= GENMASK(15, 0); + *r_insn = insn; + + return 0; + } +} + #endif /* _ASM_RISCV_INSN_H */ diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 6e8ae6c66322..f10f14001480 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -129,58 +129,6 @@ static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset, #define GET_F32_RS2C(insn, regs) (get_f32_rs(insn, 2, regs)) #define GET_F32_RS2S(insn, regs) (get_f32_rs(RVC_RS2S(insn), 0, regs)) -#define __read_insn(regs, insn, insn_addr, type) \ -({ \ - int __ret; \ - \ - if (user_mode(regs)) { \ - __ret = get_user(insn, (type __user *) insn_addr); \ - } else { \ - insn = *(type *)insn_addr; \ - __ret = 0; \ - } \ - \ - __ret; \ -}) - -static inline int get_insn(struct pt_regs *regs, ulong epc, ulong *r_insn) -{ - ulong insn = 0; - - if (epc & 0x2) { - ulong tmp = 0; - - if (__read_insn(regs, insn, epc, u16)) - return -EFAULT; - /* __get_user() uses regular "lw" which sign extend the loaded - * value make sure to clear higher order bits in case we "or" it - * below with the upper 16 bits half. - */ - insn &= GENMASK(15, 0); - if ((insn & __INSN_LENGTH_MASK) != __INSN_LENGTH_32) { - *r_insn = insn; - return 0; - } - epc += sizeof(u16); - if (__read_insn(regs, tmp, epc, u16)) - return -EFAULT; - *r_insn = (tmp << 16) | insn; - - return 0; - } else { - if (__read_insn(regs, insn, epc, u32)) - return -EFAULT; - if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) { - *r_insn = insn; - return 0; - } - insn &= GENMASK(15, 0); - *r_insn = insn; - - return 0; - } -} - union reg_data { u8 data_bytes[8]; ulong data_ulong; diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c index b112166d51e9..1e37810035a9 100644 --- a/arch/riscv/kernel/vector.c +++ b/arch/riscv/kernel/vector.c @@ -184,8 +184,8 @@ EXPORT_SYMBOL_GPL(riscv_v_vstate_ctrl_user_allowed); bool riscv_v_first_use_handler(struct pt_regs *regs) { - u32 __user *epc = (u32 __user *)regs->epc; - u32 insn = (u32)regs->badaddr; + unsigned long epc = regs->epc; + unsigned long insn = regs->badaddr; if (!(has_vector() || has_xtheadvector())) return false; @@ -200,7 +200,7 @@ bool riscv_v_first_use_handler(struct pt_regs *regs) /* Get the instruction */ if (!insn) { - if (__get_user(insn, epc)) + if (get_insn(regs, epc, &insn)) return false; } -- 2.50.1 (Apple Git-155) _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv