Commit 3013c33d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'riscv-for-linus-6.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux

Pull RISC-V fixes from Palmer Dabbelt:

 - The compressed half-word misaligned access instructions (c.lhu, c.lh,
   and c.sh) from the Zcb extension are now properly emulated

 - A series of fixes to properly emulate permissions while handling
   userspace misaligned accesses

 - A pair of fixes for PR_GET_TAGGED_ADDR_CTRL to avoid accessing the
   envcfg CSR on systems that don't support that CSR, and to report
   those failures up to userspace

 - The .rela.dyn section is no longer stripped from vmlinux, as it is
   necessary to relocate the kernel under some conditions (including
   kexec)

* tag 'riscv-for-linus-6.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
  riscv: Disallow PR_GET_TAGGED_ADDR_CTRL without Supm
  scripts: Do not strip .rela.dyn section
  riscv: Fix kernel crash due to PR_SET_TAGGED_ADDR_CTRL
  riscv: misaligned: use get_user() instead of __get_user()
  riscv: misaligned: enable IRQs while handling misaligned accesses
  riscv: misaligned: factorize trap handling
  riscv: misaligned: Add handling for ZCB instructions
parents cc9f0629 01534f3e
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -275,6 +275,9 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
	unsigned long pmm;
	u8 pmlen;

	if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM))
		return -EINVAL;

	if (is_compat_thread(ti))
		return -EINVAL;

@@ -330,6 +333,9 @@ long get_tagged_addr_ctrl(struct task_struct *task)
	struct thread_info *ti = task_thread_info(task);
	long ret = 0;

	if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM))
		return -EINVAL;

	if (is_compat_thread(ti))
		return -EINVAL;

+37 −27
Original line number Diff line number Diff line
@@ -198,47 +198,57 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
DO_ERROR_INFO(do_trap_load_fault,
	SIGSEGV, SEGV_ACCERR, "load access fault");

asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
enum misaligned_access_type {
	MISALIGNED_STORE,
	MISALIGNED_LOAD,
};
static const struct {
	const char *type_str;
	int (*handler)(struct pt_regs *regs);
} misaligned_handler[] = {
	[MISALIGNED_STORE] = {
		.type_str = "Oops - store (or AMO) address misaligned",
		.handler = handle_misaligned_store,
	},
	[MISALIGNED_LOAD] = {
		.type_str = "Oops - load address misaligned",
		.handler = handle_misaligned_load,
	},
};

static void do_trap_misaligned(struct pt_regs *regs, enum misaligned_access_type type)
{
	irqentry_state_t state;

	if (user_mode(regs)) {
		irqentry_enter_from_user_mode(regs);
		local_irq_enable();
	} else {
		state = irqentry_nmi_enter(regs);
	}

		if (handle_misaligned_load(regs))
	if (misaligned_handler[type].handler(regs))
		do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
			      "Oops - load address misaligned");
			      misaligned_handler[type].type_str);

	if (user_mode(regs)) {
		local_irq_disable();
		irqentry_exit_to_user_mode(regs);
	} else {
		irqentry_state_t state = irqentry_nmi_enter(regs);

		if (handle_misaligned_load(regs))
			do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
			      "Oops - load address misaligned");

		irqentry_nmi_exit(regs, state);
	}
}

asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs *regs)
asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
{
	if (user_mode(regs)) {
		irqentry_enter_from_user_mode(regs);

		if (handle_misaligned_store(regs))
			do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
				"Oops - store (or AMO) address misaligned");

		irqentry_exit_to_user_mode(regs);
	} else {
		irqentry_state_t state = irqentry_nmi_enter(regs);

		if (handle_misaligned_store(regs))
			do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
				"Oops - store (or AMO) address misaligned");

		irqentry_nmi_exit(regs, state);
	do_trap_misaligned(regs, MISALIGNED_LOAD);
}

asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs *regs)
{
	do_trap_misaligned(regs, MISALIGNED_STORE);
}

DO_ERROR_INFO(do_trap_store_fault,
	SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
DO_ERROR_INFO(do_trap_ecall_s,
+18 −1
Original line number Diff line number Diff line
@@ -88,6 +88,13 @@
#define INSN_MATCH_C_FSWSP		0xe002
#define INSN_MASK_C_FSWSP		0xe003

#define INSN_MATCH_C_LHU		0x8400
#define INSN_MASK_C_LHU			0xfc43
#define INSN_MATCH_C_LH			0x8440
#define INSN_MASK_C_LH			0xfc43
#define INSN_MATCH_C_SH			0x8c00
#define INSN_MASK_C_SH			0xfc43

#define INSN_LEN(insn)			((((insn) & 0x3) < 0x3) ? 2 : 4)

#if defined(CONFIG_64BIT)
@@ -268,7 +275,7 @@ static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset,
	int __ret;					\
							\
	if (user_mode(regs)) {				\
		__ret = __get_user(insn, (type __user *) insn_addr); \
		__ret = get_user(insn, (type __user *) insn_addr); \
	} else {					\
		insn = *(type *)insn_addr;		\
		__ret = 0;				\
@@ -431,6 +438,13 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs)
		fp = 1;
		len = 4;
#endif
	} else if ((insn & INSN_MASK_C_LHU) == INSN_MATCH_C_LHU) {
		len = 2;
		insn = RVC_RS2S(insn) << SH_RD;
	} else if ((insn & INSN_MASK_C_LH) == INSN_MATCH_C_LH) {
		len = 2;
		shift = 8 * (sizeof(ulong) - len);
		insn = RVC_RS2S(insn) << SH_RD;
	} else {
		regs->epc = epc;
		return -1;
@@ -530,6 +544,9 @@ static int handle_scalar_misaligned_store(struct pt_regs *regs)
		len = 4;
		val.data_ulong = GET_F32_RS2C(insn, regs);
#endif
	} else if ((insn & INSN_MASK_C_SH) == INSN_MATCH_C_SH) {
		len = 2;
		val.data_ulong = GET_RS2S(insn, regs);
	} else {
		regs->epc = epc;
		return -1;
+1 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ ifdef CONFIG_ARCH_VMLINUX_NEEDS_RELOCS
vmlinux-final := vmlinux.unstripped

quiet_cmd_strip_relocs = RSTRIP  $@
      cmd_strip_relocs = $(OBJCOPY) --remove-section='.rel*' $< $@
      cmd_strip_relocs = $(OBJCOPY) --remove-section='.rel*' --remove-section=!'.rel*.dyn' $< $@

vmlinux: $(vmlinux-final) FORCE
	$(call if_changed,strip_relocs)