arch/riscv/kernel/traps_misaligned.c

Source file repositories/reference/linux-study-clean/arch/riscv/kernel/traps_misaligned.c

File Facts

System
Linux kernel
Corpus path
arch/riscv/kernel/traps_misaligned.c
Extension
.c
Size
15865 bytes
Lines
649
Domain
Architecture Layer
Bucket
arch/riscv
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

static void set_f64_rd(unsigned long insn, struct pt_regs *regs, u64 val) {}

static unsigned long get_f64_rs(unsigned long insn, u8 fp_reg_offset,
				struct pt_regs *regs)
{
	return 0;
}

static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset,
				struct pt_regs *regs)
{
	return 0;
}

#endif

#define GET_F64_RS2(insn, regs) (get_f64_rs(insn, 20, regs))
#define GET_F64_RS2C(insn, regs) (get_f64_rs(insn, 2, regs))
#define GET_F64_RS2S(insn, regs) (get_f64_rs(RVC_RS2S(insn), 0, regs))

#define GET_F32_RS2(insn, regs) (get_f32_rs(insn, 20, regs))
#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;
	u64 data_u64;
};

/* sysctl hooks */
int unaligned_enabled __read_mostly = 1;	/* Enabled by default */

#ifdef CONFIG_RISCV_VECTOR_MISALIGNED
static int handle_vector_misaligned_load(struct pt_regs *regs)
{
	unsigned long epc = regs->epc;
	unsigned long insn;

Annotation

Implementation Notes