Skip to content

Commit

Permalink
Merge tag 'riscv-for-linus-6.15-rc6' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Linus Torvalds committed May 9, 2025
2 parents cc9f062 + 01534f3 commit 3013c33
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 29 deletions.
6 changes: 6 additions & 0 deletions arch/riscv/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down
64 changes: 37 additions & 27 deletions arch/riscv/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
"Oops - load address misaligned");
if (misaligned_handler[type].handler(regs))
do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
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");
do_trap_misaligned(regs, MISALIGNED_LOAD);
}

irqentry_nmi_exit(regs, state);
}
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,
Expand Down
19 changes: 18 additions & 1 deletion arch/riscv/kernel/traps_misaligned.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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; \
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion scripts/Makefile.vmlinux
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 3013c33

Please sign in to comment.