public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode
@ 2023-07-04 14:09 Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 1/9] riscv: remove unused functions in traps_misaligned.c Clément Léger
                   ` (8 more replies)
  0 siblings, 9 replies; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

Since commit 61cadb9 ("Provide new description of misaligned load/store
behavior compatible with privileged architecture.") in the RISC-V ISA
manual, it is stated that misaligned load/store might not be supported.
However, the RISC-V kernel uABI describes that misaligned accesses are
supported. In order to support that, this series adds support for S-mode
handling of misaligned accesses, SBI call for misaligned trap delegation
as well prctl support for PR_SET_UNALIGN.

Handling misaligned access in kernel allows for a finer grain control
of the misaligned accesses behavior, and thanks to the prctl call, can
allow disabling misaligned access emulation to generate SIGBUS. User
space can then optimize its software by removing such access based on
SIGBUS generation.

This series relies on a SBI extension [1] allowing to request delegation of
the misaligned load/store traps to the S-mode software. This extension
has been submitted for review to the riscv tech-prs group. An OpenSBI
implementation for this spec is available at [2].

This series can be tested using the spike simulator [3] which allows to
either handles misaligned access in hardware or let the software do it.

With hardware misaligned access support:
$ ./spike --misaligned --initrd=rootfs.cpio \
  --kernel=arch/riscv/boot/Image opensbi_fw_jump.elf

Without hardware misaligned access support:
$ ./spike --initrd=rootfs.cpio --kernel=arch/riscv/boot/Image \
   opensbi_fw_jump.elf

[1] https://lists.riscv.org/g/tech-prs/message/540
[2] https://github.com/rivosinc/opensbi/tree/dev/cleger/fw_feature_upstream
[3] https://github.com/riscv-software-src/riscv-isa-sim

Changes in V2:
 - Fix prototypes declaration for handle_misaligned_load/store()
 - Fix build for !CONFIG_FPU
 - Added conditional build for various part of misaligned code handling
 - Added in-kernel misalignement fault support to be equivalent to
   existing SBI support
 - Added support for misalignment emulation detection for hwprobe
   reporting
 - Modified set/get_unaligned_ctl to use this detection of emulation
 - Added support for sysctl "unaligned_enabled"

Clément Léger (9):
  riscv: remove unused functions in traps_misaligned.c
  riscv: avoid missing prototypes warning
  riscv: add support for misaligned handling in S-mode
  riscv: report perf event for misaligned fault
  riscv: add support for sysctl unaligned_enabled control
  riscv: add support for SBI misalignment trap delegation
  riscv: report misaligned accesses emulation to hwprobe
  riscv: add support for PR_SET_UNALIGN and PR_GET_UNALIGN
  riscv: add floating point insn support to misaligned access emulation

 arch/riscv/Kconfig                    |   1 +
 arch/riscv/include/asm/cpufeature.h   |  10 +
 arch/riscv/include/asm/entry-common.h |   3 +
 arch/riscv/include/asm/processor.h    |   9 +
 arch/riscv/include/asm/sbi.h          |  11 +
 arch/riscv/kernel/Makefile            |   2 +-
 arch/riscv/kernel/fpu.S               | 117 +++++++++
 arch/riscv/kernel/process.c           |  18 ++
 arch/riscv/kernel/sbi.c               |  21 ++
 arch/riscv/kernel/setup.c             |   2 +
 arch/riscv/kernel/traps.c             |   9 -
 arch/riscv/kernel/traps_misaligned.c  | 352 ++++++++++++++++++++++----
 12 files changed, 498 insertions(+), 57 deletions(-)

-- 
2.40.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 1/9] riscv: remove unused functions in traps_misaligned.c
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 2/9] riscv: avoid missing prototypes warning Clément Léger
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

Replace macros by the only two function calls that are done from this
file, store_u8() and load_u8().

Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/kernel/traps_misaligned.c | 46 +++++-----------------------
 1 file changed, 7 insertions(+), 39 deletions(-)

diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 378f5b151443..e7bfb33089c1 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -151,51 +151,19 @@
 #define PRECISION_S 0
 #define PRECISION_D 1
 
-#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn)			\
-static inline type load_##type(const type *addr)			\
-{									\
-	type val;							\
-	asm (#insn " %0, %1"						\
-	: "=&r" (val) : "m" (*addr));					\
-	return val;							\
-}
+static inline u8 load_u8(const u8 *addr)
+{
+	u8 val;
 
-#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn)			\
-static inline void store_##type(type *addr, type val)			\
-{									\
-	asm volatile (#insn " %0, %1\n"					\
-	: : "r" (val), "m" (*addr));					\
-}
+	asm volatile("lbu %0, %1" : "=&r" (val) : "m" (*addr));
 
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
-#if defined(CONFIG_64BIT)
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
-#else
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
-
-static inline u64 load_u64(const u64 *addr)
-{
-	return load_u32((u32 *)addr)
-		+ ((u64)load_u32((u32 *)addr + 1) << 32);
+	return val;
 }
 
-static inline void store_u64(u64 *addr, u64 val)
+static inline void store_u8(u8 *addr, u8 val)
 {
-	store_u32((u32 *)addr, val);
-	store_u32((u32 *)addr + 1, val >> 32);
+	asm volatile ("sb %0, %1\n" : : "r" (val), "m" (*addr));
 }
-#endif
 
 static inline ulong get_insn(ulong mepc)
 {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 2/9] riscv: avoid missing prototypes warning
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 1/9] riscv: remove unused functions in traps_misaligned.c Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  2023-07-08 19:34   ` Stafford Horne
  2023-07-04 14:09 ` [RFC V2 PATCH 3/9] riscv: add support for misaligned handling in S-mode Clément Léger
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

Declare handle_misaligned_store/load() functions in entry-common.h and
include that file in traps_misaligned.c file to avoid warnings.

Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/include/asm/entry-common.h | 3 +++
 arch/riscv/kernel/traps.c             | 2 --
 arch/riscv/kernel/traps_misaligned.c  | 1 +
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/include/asm/entry-common.h b/arch/riscv/include/asm/entry-common.h
index 6e4dee49d84b..58e9e2976e1b 100644
--- a/arch/riscv/include/asm/entry-common.h
+++ b/arch/riscv/include/asm/entry-common.h
@@ -8,4 +8,7 @@
 void handle_page_fault(struct pt_regs *regs);
 void handle_break(struct pt_regs *regs);
 
+int handle_misaligned_load(struct pt_regs *regs);
+int handle_misaligned_store(struct pt_regs *regs);
+
 #endif /* _ASM_RISCV_ENTRY_COMMON_H */
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index 8c258b78c925..7fcaf2fd27a1 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -155,8 +155,6 @@ DO_ERROR_INFO(do_trap_load_misaligned,
 DO_ERROR_INFO(do_trap_store_misaligned,
 	SIGBUS, BUS_ADRALN, "Oops - store (or AMO) address misaligned");
 #else
-int handle_misaligned_load(struct pt_regs *regs);
-int handle_misaligned_store(struct pt_regs *regs);
 
 asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
 {
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index e7bfb33089c1..0cccac4822a8 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -12,6 +12,7 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/csr.h>
+#include <asm/entry-common.h>
 
 #define INSN_MATCH_LB			0x3
 #define INSN_MASK_LB			0x707f
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 3/9] riscv: add support for misaligned handling in S-mode
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 1/9] riscv: remove unused functions in traps_misaligned.c Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 2/9] riscv: avoid missing prototypes warning Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  2023-07-08 20:08   ` Stafford Horne
  2023-07-04 14:09 ` [RFC V2 PATCH 4/9] riscv: report perf event for misaligned fault Clément Léger
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

Misalignment handling is only supported for M-mode and uses direct
accesses to user memory. in S-mode, this requires to use the
get_user()/put_user() accessors. Implement load_u8(), store_u8() and
get_insn() using these accessors.

Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/kernel/Makefile           |   2 +-
 arch/riscv/kernel/traps.c            |   7 --
 arch/riscv/kernel/traps_misaligned.c | 118 ++++++++++++++++++++++++---
 3 files changed, 106 insertions(+), 21 deletions(-)

diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 153864e4f399..79b8dafc699d 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -55,10 +55,10 @@ obj-y	+= riscv_ksyms.o
 obj-y	+= stacktrace.o
 obj-y	+= cacheinfo.o
 obj-y	+= patch.o
+obj-y	+= traps_misaligned.o
 obj-y	+= probes/
 obj-$(CONFIG_MMU) += vdso.o vdso/
 
-obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o
 obj-$(CONFIG_FPU)		+= fpu.o
 obj-$(CONFIG_SMP)		+= smpboot.o
 obj-$(CONFIG_SMP)		+= smp.o
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index 7fcaf2fd27a1..b2fb2266fb83 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -149,12 +149,6 @@ DO_ERROR_INFO(do_trap_insn_illegal,
 	SIGILL, ILL_ILLOPC, "illegal instruction");
 DO_ERROR_INFO(do_trap_load_fault,
 	SIGSEGV, SEGV_ACCERR, "load access fault");
-#ifndef CONFIG_RISCV_M_MODE
-DO_ERROR_INFO(do_trap_load_misaligned,
-	SIGBUS, BUS_ADRALN, "Oops - load address misaligned");
-DO_ERROR_INFO(do_trap_store_misaligned,
-	SIGBUS, BUS_ADRALN, "Oops - store (or AMO) address misaligned");
-#else
 
 asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
 {
@@ -197,7 +191,6 @@ asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs
 		irqentry_nmi_exit(regs, state);
 	}
 }
-#endif
 DO_ERROR_INFO(do_trap_store_fault,
 	SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
 DO_ERROR_INFO(do_trap_ecall_s,
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 0cccac4822a8..9daed7d756ae 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -152,21 +152,25 @@
 #define PRECISION_S 0
 #define PRECISION_D 1
 
-static inline u8 load_u8(const u8 *addr)
+#ifdef CONFIG_RISCV_M_MODE
+static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val)
 {
 	u8 val;
 
 	asm volatile("lbu %0, %1" : "=&r" (val) : "m" (*addr));
+	*r_val = val;
 
-	return val;
+	return 0;
 }
 
-static inline void store_u8(u8 *addr, u8 val)
+static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val)
 {
 	asm volatile ("sb %0, %1\n" : : "r" (val), "m" (*addr));
+
+	return 0;
 }
 
-static inline ulong get_insn(ulong mepc)
+static inline int get_insn(struct pt_regs *regs, ulong mepc, ulong *r_insn)
 {
 	register ulong __mepc asm ("a2") = mepc;
 	ulong val, rvc_mask = 3, tmp;
@@ -195,9 +199,87 @@ static inline ulong get_insn(ulong mepc)
 	: [addr] "r" (__mepc), [rvc_mask] "r" (rvc_mask),
 	  [xlen_minus_16] "i" (XLEN_MINUS_16));
 
-	return val;
+	*r_insn = val;
+
+	return 0;
+}
+#else
+static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val)
+{
+	if (user_mode(regs)) {
+		return __get_user(*r_val, addr);
+	} else {
+		*r_val = *addr;
+		return 0;
+	}
 }
 
+static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val)
+{
+	if (user_mode(regs)) {
+		return __put_user(val, addr);
+	} else {
+		*addr = val;
+		return 0;
+	}
+}
+
+#define __read_insn(regs, insn, insn_addr)		\
+({							\
+	int __ret;					\
+							\
+	if (user_mode(regs)) {				\
+		__ret = __get_user(insn, insn_addr);	\
+	} else {					\
+		insn = *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;
+		u16 __user *insn_addr = (u16 __user *)epc;
+
+		if (__read_insn(regs, insn, insn_addr))
+			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;
+		}
+		insn_addr++;
+		if (__read_insn(regs, tmp, insn_addr))
+			return -EFAULT;
+		*r_insn = (tmp << 16) | insn;
+
+		return 0;
+	} else {
+		u32 __user *insn_addr = (u32 __user *)epc;
+
+		if (__read_insn(regs, insn, insn_addr))
+			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
+
 union reg_data {
 	u8 data_bytes[8];
 	ulong data_ulong;
@@ -208,10 +290,13 @@ int handle_misaligned_load(struct pt_regs *regs)
 {
 	union reg_data val;
 	unsigned long epc = regs->epc;
-	unsigned long insn = get_insn(epc);
-	unsigned long addr = csr_read(mtval);
+	unsigned long insn;
+	unsigned long addr = regs->badaddr;
 	int i, fp = 0, shift = 0, len = 0;
 
+	if (get_insn(regs, epc, &insn))
+		return -1;
+
 	regs->epc = 0;
 
 	if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
@@ -275,8 +360,10 @@ int handle_misaligned_load(struct pt_regs *regs)
 	}
 
 	val.data_u64 = 0;
-	for (i = 0; i < len; i++)
-		val.data_bytes[i] = load_u8((void *)(addr + i));
+	for (i = 0; i < len; i++) {
+		if (load_u8(regs, (void *)(addr + i), &val.data_bytes[i]))
+			return -1;
+	}
 
 	if (fp)
 		return -1;
@@ -291,10 +378,13 @@ int handle_misaligned_store(struct pt_regs *regs)
 {
 	union reg_data val;
 	unsigned long epc = regs->epc;
-	unsigned long insn = get_insn(epc);
-	unsigned long addr = csr_read(mtval);
+	unsigned long insn;
+	unsigned long addr = regs->badaddr;
 	int i, len = 0;
 
+	if (get_insn(regs, epc, &insn))
+		return -1;
+
 	regs->epc = 0;
 
 	val.data_ulong = GET_RS2(insn, regs);
@@ -328,8 +418,10 @@ int handle_misaligned_store(struct pt_regs *regs)
 		return -1;
 	}
 
-	for (i = 0; i < len; i++)
-		store_u8((void *)(addr + i), val.data_bytes[i]);
+	for (i = 0; i < len; i++) {
+		if (store_u8(regs, (void *)(addr + i), val.data_bytes[i]))
+			return -1;
+	}
 
 	regs->epc = epc + INSN_LEN(insn);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 4/9] riscv: report perf event for misaligned fault
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
                   ` (2 preceding siblings ...)
  2023-07-04 14:09 ` [RFC V2 PATCH 3/9] riscv: add support for misaligned handling in S-mode Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 5/9] riscv: add support for sysctl unaligned_enabled control Clément Léger
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

Add missing calls to account for misaligned fault event using
perf_sw_event().

Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/kernel/traps_misaligned.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 9daed7d756ae..804f6c5e0e44 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -6,6 +6,7 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/perf_event.h>
 #include <linux/irq.h>
 #include <linux/stringify.h>
 
@@ -294,6 +295,8 @@ int handle_misaligned_load(struct pt_regs *regs)
 	unsigned long addr = regs->badaddr;
 	int i, fp = 0, shift = 0, len = 0;
 
+	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
+
 	if (get_insn(regs, epc, &insn))
 		return -1;
 
@@ -382,6 +385,8 @@ int handle_misaligned_store(struct pt_regs *regs)
 	unsigned long addr = regs->badaddr;
 	int i, len = 0;
 
+	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
+
 	if (get_insn(regs, epc, &insn))
 		return -1;
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 5/9] riscv: add support for sysctl unaligned_enabled control
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
                   ` (3 preceding siblings ...)
  2023-07-04 14:09 ` [RFC V2 PATCH 4/9] riscv: report perf event for misaligned fault Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 6/9] riscv: add support for SBI misalignment trap delegation Clément Léger
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

This sysctl tuning option allows the user to disable misaligned access
handling globally on the system. This will also be used by misaligned
detection code to temporarily disable misaligned access handling.

Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/Kconfig                   | 1 +
 arch/riscv/kernel/traps_misaligned.c | 9 +++++++++
 2 files changed, 10 insertions(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index c69572fbe613..99fd951def39 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -139,6 +139,7 @@ config RISCV
 	select RISCV_TIMER if RISCV_SBI
 	select SIFIVE_PLIC
 	select SPARSE_IRQ
+	select SYSCTL_ARCH_UNALIGN_ALLOW
 	select SYSCTL_EXCEPTION_TRACE
 	select THREAD_INFO_IN_TASK
 	select TRACE_IRQFLAGS_SUPPORT
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 804f6c5e0e44..39ec6caa6234 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -287,6 +287,9 @@ union reg_data {
 	u64 data_u64;
 };
 
+/* sysctl hooks */
+int unaligned_enabled __read_mostly = 1;	/* Enabled by default */
+
 int handle_misaligned_load(struct pt_regs *regs)
 {
 	union reg_data val;
@@ -297,6 +300,9 @@ int handle_misaligned_load(struct pt_regs *regs)
 
 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
 
+	if (!unaligned_enabled)
+		return -1;
+
 	if (get_insn(regs, epc, &insn))
 		return -1;
 
@@ -387,6 +393,9 @@ int handle_misaligned_store(struct pt_regs *regs)
 
 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
 
+	if (!unaligned_enabled)
+		return -1;
+
 	if (get_insn(regs, epc, &insn))
 		return -1;
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 6/9] riscv: add support for SBI misalignment trap delegation
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
                   ` (4 preceding siblings ...)
  2023-07-04 14:09 ` [RFC V2 PATCH 5/9] riscv: add support for sysctl unaligned_enabled control Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 7/9] riscv: report misaligned accesses emulation to hwprobe Clément Léger
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

Add support for misalignment trap delegation by setting it with
SBI_EXT_FW_FEATURE SBI extension. This extension allows to control SBI
behavior by requesting to set them to specific value. In order to
implement prctl(PR_SET_UNALIGN, PR_UNALIGN_SIGBUS) behavior properly, we
need to let the kernel handle the misalignment error by itself.

Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/include/asm/sbi.h | 11 +++++++++++
 arch/riscv/kernel/sbi.c      | 21 +++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 5b4a1bf5f439..c1b74c7d0d56 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -30,6 +30,7 @@ enum sbi_ext_id {
 	SBI_EXT_HSM = 0x48534D,
 	SBI_EXT_SRST = 0x53525354,
 	SBI_EXT_PMU = 0x504D55,
+	SBI_EXT_FW_FEATURE = 0x46574654,
 
 	/* Experimentals extensions must lie within this range */
 	SBI_EXT_EXPERIMENTAL_START = 0x08000000,
@@ -236,6 +237,16 @@ enum sbi_pmu_ctr_type {
 /* Flags defined for counter stop function */
 #define SBI_PMU_STOP_FLAG_RESET (1 << 0)
 
+/* SBI function IDs for FW feature extension */
+#define SBI_EXT_FW_FEATURE_SET		0x0
+#define SBI_EXT_FW_FEATURE_GET		0x1
+
+enum sbi_fw_features_t {
+	SBI_FW_FEATURE_MISALIGNED_DELEG	= 0,
+
+	SBI_FW_FEATURE_MAX,
+};
+
 #define SBI_SPEC_VERSION_DEFAULT	0x1
 #define SBI_SPEC_VERSION_MAJOR_SHIFT	24
 #define SBI_SPEC_VERSION_MAJOR_MASK	0x7f
diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
index c672c8ba9a2a..3be48791455a 100644
--- a/arch/riscv/kernel/sbi.c
+++ b/arch/riscv/kernel/sbi.c
@@ -494,6 +494,16 @@ int sbi_remote_hfence_vvma_asid(const struct cpumask *cpu_mask,
 }
 EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid);
 
+static int sbi_fw_feature_set(enum sbi_fw_features_t feature, bool set)
+{
+	struct sbiret ret;
+
+	ret = sbi_ecall(SBI_EXT_FW_FEATURE, SBI_EXT_FW_FEATURE_SET, feature,
+			set, 0, 0, 0, 0);
+
+	return sbi_err_map_linux_errno(ret.error);
+}
+
 static void sbi_srst_reset(unsigned long type, unsigned long reason)
 {
 	sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason,
@@ -624,6 +634,17 @@ void __init sbi_init(void)
 			sbi_srst_reboot_nb.priority = 192;
 			register_restart_handler(&sbi_srst_reboot_nb);
 		}
+		/*
+		 * TODO: this will likely need to be updated when SBI extension
+		 * is ratified
+		 */
+		if ((sbi_spec_version >= sbi_mk_version(1, 0)) &&
+		    (sbi_probe_extension(SBI_EXT_FW_FEATURE) > 0)) {
+			pr_info("SBI FW_FEATURE extension detected\n");
+			/* Request misaligned handling delegation */
+			sbi_fw_feature_set(SBI_FW_FEATURE_MISALIGNED_DELEG,
+					   true);
+		}
 	} else {
 		__sbi_set_timer = __sbi_set_timer_v01;
 		__sbi_send_ipi	= __sbi_send_ipi_v01;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 7/9] riscv: report misaligned accesses emulation to hwprobe
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
                   ` (5 preceding siblings ...)
  2023-07-04 14:09 ` [RFC V2 PATCH 6/9] riscv: add support for SBI misalignment trap delegation Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 8/9] riscv: add support for PR_SET_UNALIGN and PR_GET_UNALIGN Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 9/9] riscv: add floating point insn support to misaligned access emulation Clément Léger
  8 siblings, 0 replies; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

hwprobe provides a way to report if misaligned access are emulated. In
order to correctly populate that feature, if the SBI delegated us
misaligned access handling, then we can check if it actually traps when
doing a misaligned access. This can be checked using an exception table
entry which will actually be used when a misaligned access is done from
kernel mode.

Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/include/asm/cpufeature.h  |  2 ++
 arch/riscv/kernel/setup.c            |  2 ++
 arch/riscv/kernel/traps_misaligned.c | 32 ++++++++++++++++++++++++++++
 3 files changed, 36 insertions(+)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 808d5403f2ac..7e968499db49 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -20,4 +20,6 @@ DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
 
 DECLARE_PER_CPU(long, misaligned_access_speed);
 
+void __init misaligned_emulation_init(void);
+
 #endif
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index 36b026057503..820a8158e4f7 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -23,6 +23,7 @@
 
 #include <asm/alternative.h>
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
 #include <asm/early_ioremap.h>
 #include <asm/pgtable.h>
@@ -284,6 +285,7 @@ void __init setup_arch(char **cmdline_p)
 
 	init_resources();
 	sbi_init();
+	misaligned_emulation_init();
 
 #ifdef CONFIG_KASAN
 	kasan_init();
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 39ec6caa6234..243ef9314734 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -14,6 +14,8 @@
 #include <asm/ptrace.h>
 #include <asm/csr.h>
 #include <asm/entry-common.h>
+#include <asm/hwprobe.h>
+#include <asm/cpufeature.h>
 
 #define INSN_MATCH_LB			0x3
 #define INSN_MASK_LB			0x707f
@@ -441,3 +443,33 @@ int handle_misaligned_store(struct pt_regs *regs)
 
 	return 0;
 }
+
+void __init misaligned_emulation_init(void)
+{
+	int cpu;
+	unsigned long emulated = 1, tmp_var;
+
+	/* Temporarily disable unaligned accesses support so that we fixup the
+	 * exception for code below.
+	 */
+	unaligned_enabled = 0;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"	ld %[tmp], 1(%[ptr])\n"
+		"	li %[emulated], 0\n"
+		"2:\n"
+		_ASM_EXTABLE(1b, 2b)
+	: [emulated] "+r" (emulated), [tmp] "=r" (tmp_var)
+	: [ptr] "r" (&tmp_var)
+	: "memory" );
+
+	unaligned_enabled = 1;
+	if (!emulated)
+		return;
+
+	for_each_possible_cpu(cpu) {
+		per_cpu(misaligned_access_speed, cpu) =
+					RISCV_HWPROBE_MISALIGNED_EMULATED;
+	}
+}
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 8/9] riscv: add support for PR_SET_UNALIGN and PR_GET_UNALIGN
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
                   ` (6 preceding siblings ...)
  2023-07-04 14:09 ` [RFC V2 PATCH 7/9] riscv: report misaligned accesses emulation to hwprobe Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  2023-07-04 14:09 ` [RFC V2 PATCH 9/9] riscv: add floating point insn support to misaligned access emulation Clément Léger
  8 siblings, 0 replies; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

Now that trap support is ready to handle misalignment errors in S-mode,
allow the user to control the behavior of misalignment accesses using
prctl(). 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>
---
 arch/riscv/include/asm/cpufeature.h  |  8 ++++++++
 arch/riscv/include/asm/processor.h   |  9 +++++++++
 arch/riscv/kernel/process.c          | 18 ++++++++++++++++++
 arch/riscv/kernel/traps_misaligned.c |  7 +++++++
 4 files changed, 42 insertions(+)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 7e968499db49..e2fd6fc7157f 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -6,6 +6,8 @@
 #ifndef _ASM_CPUFEATURE_H
 #define _ASM_CPUFEATURE_H
 
+#include <asm/hwprobe.h>
+
 /*
  * These are probed via a device_initcall(), via either the SBI or directly
  * from the corresponding CSRs.
@@ -20,6 +22,12 @@ DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
 
 DECLARE_PER_CPU(long, misaligned_access_speed);
 
+static inline bool misaligned_access_emulated(void)
+{
+	return per_cpu(misaligned_access_speed, 0) ==
+					RISCV_HWPROBE_MISALIGNED_EMULATED;
+}
+
 void __init misaligned_emulation_init(void);
 
 #endif
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 94a0590c6971..4e6667d5ca68 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -7,6 +7,7 @@
 #define _ASM_RISCV_PROCESSOR_H
 
 #include <linux/const.h>
+#include <linux/prctl.h>
 
 #include <vdso/processor.h>
 
@@ -39,6 +40,7 @@ struct thread_struct {
 	unsigned long s[12];	/* s[0]: frame pointer */
 	struct __riscv_d_ext_state fstate;
 	unsigned long bad_cause;
+	unsigned long align_ctl;
 };
 
 /* Whitelist the fstate from the task_struct for hardened usercopy */
@@ -51,6 +53,7 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset,
 
 #define INIT_THREAD {					\
 	.sp = sizeof(init_stack) + (long)&init_stack,	\
+	.align_ctl = PR_UNALIGN_NOPRINT,		\
 }
 
 #define task_pt_regs(tsk)						\
@@ -80,6 +83,12 @@ int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid);
 extern void riscv_fill_hwcap(void);
 extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 
+extern int get_unalign_ctl(struct task_struct *, unsigned long addr);
+extern int set_unalign_ctl(struct task_struct *, unsigned int val);
+
+#define GET_UNALIGN_CTL(tsk, addr)	get_unalign_ctl((tsk), (addr))
+#define SET_UNALIGN_CTL(tsk, val)	set_unalign_ctl((tsk), (val))
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_RISCV_PROCESSOR_H */
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index e2a060066730..88a71359396b 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -24,6 +24,7 @@
 #include <asm/switch_to.h>
 #include <asm/thread_info.h>
 #include <asm/cpuidle.h>
+#include <asm/cpufeature.h>
 
 register unsigned long gp_in_global __asm__("gp");
 
@@ -40,6 +41,23 @@ void arch_cpu_idle(void)
 	cpu_do_idle();
 }
 
+int set_unalign_ctl(struct task_struct *tsk, unsigned int val)
+{
+	if (!misaligned_access_emulated())
+		return -EINVAL;
+
+	tsk->thread.align_ctl = val;
+	return 0;
+}
+
+int get_unalign_ctl(struct task_struct *tsk, unsigned long adr)
+{
+	if (!misaligned_access_emulated())
+		return -EINVAL;
+
+	return put_user(tsk->thread.align_ctl, (unsigned long __user *)adr);
+}
+
 void __show_regs(struct pt_regs *regs)
 {
 	show_regs_print_info(KERN_DEFAULT);
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 243ef9314734..5fb6758b0bf9 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -9,6 +9,7 @@
 #include <linux/perf_event.h>
 #include <linux/irq.h>
 #include <linux/stringify.h>
+#include <linux/prctl.h>
 
 #include <asm/processor.h>
 #include <asm/ptrace.h>
@@ -305,6 +306,9 @@ int handle_misaligned_load(struct pt_regs *regs)
 	if (!unaligned_enabled)
 		return -1;
 
+	if (user_mode(regs) && (current->thread.align_ctl & PR_UNALIGN_SIGBUS))
+		return -1;
+
 	if (get_insn(regs, epc, &insn))
 		return -1;
 
@@ -398,6 +402,9 @@ int handle_misaligned_store(struct pt_regs *regs)
 	if (!unaligned_enabled)
 		return -1;
 
+	if (user_mode(regs) && (current->thread.align_ctl & PR_UNALIGN_SIGBUS))
+		return -1;
+
 	if (get_insn(regs, epc, &insn))
 		return -1;
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC V2 PATCH 9/9] riscv: add floating point insn support to misaligned access emulation
  2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
                   ` (7 preceding siblings ...)
  2023-07-04 14:09 ` [RFC V2 PATCH 8/9] riscv: add support for PR_SET_UNALIGN and PR_GET_UNALIGN Clément Léger
@ 2023-07-04 14:09 ` Clément Léger
  8 siblings, 0 replies; 12+ messages in thread
From: Clément Léger @ 2023-07-04 14:09 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou
  Cc: Clément Léger, Stafford Horne, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

This support is partially based of openSBI misaligned emulation floating
point instruction support. It provides support for the existing
floating point instructions (both for 32/64 bits as well as compressed
ones). Since floating point registers are not part of the pt_regs
struct, we need to modify them directly using some assembly. We also
dirty the pt_regs status in case we modify them to be sure context
switch will save FP state. With this support, Linux is on par with
openSBI support.

Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/kernel/fpu.S              | 117 +++++++++++++++++++++
 arch/riscv/kernel/traps_misaligned.c | 152 ++++++++++++++++++++++++++-
 2 files changed, 265 insertions(+), 4 deletions(-)

diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S
index dd2205473de7..2785badb247c 100644
--- a/arch/riscv/kernel/fpu.S
+++ b/arch/riscv/kernel/fpu.S
@@ -104,3 +104,120 @@ ENTRY(__fstate_restore)
 	csrc CSR_STATUS, t1
 	ret
 ENDPROC(__fstate_restore)
+
+#define get_f32(which) fmv.x.s a0, which; j 2f
+#define put_f32(which) fmv.s.x which, a1; j 2f
+#if __riscv_xlen == 64
+# define get_f64(which) fmv.x.d a0, which; j 2f
+# define put_f64(which) fmv.d.x which, a1; j 2f
+#else
+# define get_f64(which) fsd which, 0(a1); j 2f
+# define put_f64(which) fld which, 0(a1); j 2f
+#endif
+
+.macro fp_access_prologue
+	/*
+	 * Compute jump offset to store the correct FP register since we don't
+	 * have indirect FP register access
+	 */
+	sll t0, a0, 3
+	la t2, 1f
+	add t0, t0, t2
+	li t1, SR_FS
+	csrs CSR_STATUS, t1
+	jr t0
+1:
+.endm
+
+.macro fp_access_epilogue
+2:
+	csrc CSR_STATUS, t1
+	ret
+.endm
+
+#define fp_access_body(__access_func) \
+	__access_func(f0); \
+	__access_func(f1); \
+	__access_func(f2); \
+	__access_func(f3); \
+	__access_func(f4); \
+	__access_func(f5); \
+	__access_func(f6); \
+	__access_func(f7); \
+	__access_func(f8); \
+	__access_func(f9); \
+	__access_func(f10); \
+	__access_func(f11); \
+	__access_func(f12); \
+	__access_func(f13); \
+	__access_func(f14); \
+	__access_func(f15); \
+	__access_func(f16); \
+	__access_func(f17); \
+	__access_func(f18); \
+	__access_func(f19); \
+	__access_func(f20); \
+	__access_func(f21); \
+	__access_func(f22); \
+	__access_func(f23); \
+	__access_func(f24); \
+	__access_func(f25); \
+	__access_func(f26); \
+	__access_func(f27); \
+	__access_func(f28); \
+	__access_func(f29); \
+	__access_func(f30); \
+	__access_func(f31)
+
+
+/*
+ * Disable compressed instructions set to keep a constant offset between FP
+ * load/store/move instructions
+ */
+.option norvc
+/*
+ * put_f32_reg - Set a FP register from a register containing the value
+ * a0 = FP register index to be set
+ * a1 = value to be loaded in the FP register
+ */
+SYM_FUNC_START(put_f32_reg)
+	fp_access_prologue
+	fp_access_body(put_f32)
+	fp_access_epilogue
+SYM_FUNC_END(put_f32_reg)
+
+/*
+ * get_f32_reg - Get a FP register value and return it
+ * a0 = FP register index to be retrieved
+ */
+SYM_FUNC_START(get_f32_reg)
+	fp_access_prologue
+	fp_access_body(get_f32)
+	fp_access_epilogue
+SYM_FUNC_END(put_f32_reg)
+
+/*
+ * put_f64_reg - Set a 64 bits FP register from a value or a pointer.
+ * a0 = FP register index to be set
+ * a1 = value/pointer to be loaded in the FP register (when xlen == 32 bits, we
+ * load the value to a pointer).
+ */
+SYM_FUNC_START(put_f64_reg)
+	fp_access_prologue
+	fp_access_body(put_f64)
+	fp_access_epilogue
+SYM_FUNC_END(put_f64_reg)
+
+/*
+ * put_f64_reg - Get a 64 bits FP register value and returned it or store it to
+ *	 	 a pointer.
+ * a0 = FP register index to be retrieved
+ * a1 = If xlen == 32, pointer which should be loaded with the FP register value
+ *	or unused if xlen == 64. In which case the FP register value is returned
+ *	through a0
+ */
+SYM_FUNC_START(get_f64_reg)
+	fp_access_prologue
+	fp_access_body(get_f64)
+	fp_access_epilogue
+SYM_FUNC_END(get_f64_reg)
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 5fb6758b0bf9..c4c4672a4554 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -156,6 +156,115 @@
 #define PRECISION_S 0
 #define PRECISION_D 1
 
+#ifdef CONFIG_FPU
+
+#define FP_GET_RD(insn)		(insn >> 7 & 0x1F)
+
+extern void put_f32_reg(unsigned long fp_reg, unsigned long value);
+
+static int set_f32_rd(unsigned long insn, struct pt_regs *regs,
+		      unsigned long val)
+{
+	unsigned long fp_reg = FP_GET_RD(insn);
+
+	put_f32_reg(fp_reg, val);
+	regs->status |= SR_FS_DIRTY;
+
+	return 0;
+}
+
+extern void put_f64_reg(unsigned long fp_reg, unsigned long value);
+
+static int set_f64_rd(unsigned long insn, struct pt_regs *regs, u64 val)
+{
+	unsigned long fp_reg = FP_GET_RD(insn);
+	unsigned long value;
+
+#if __riscv_xlen == 32
+	value = (unsigned long) &val;
+#else
+	value = val;
+#endif
+	put_f64_reg(fp_reg, value);
+	regs->status |= SR_FS_DIRTY;
+
+	return 0;
+}
+
+#if __riscv_xlen == 32
+extern void get_f64_reg(unsigned long fp_reg, u64 *value);
+
+static u64 get_f64_rs(unsigned long insn, u8 fp_reg_offset,
+		      struct pt_regs *regs)
+{
+	unsigned long fp_reg = (insn >> fp_reg_offset) & 0x1F;
+	u64 val;
+
+	get_f64_reg(fp_reg, &val);
+	regs->status |= SR_FS_DIRTY;
+
+	return val;
+}
+#else
+
+extern unsigned long get_f64_reg(unsigned long fp_reg);
+
+static unsigned long get_f64_rs(unsigned long insn, u8 fp_reg_offset,
+				struct pt_regs *regs)
+{
+	unsigned long fp_reg = (insn >> fp_reg_offset) & 0x1F;
+	unsigned long val;
+
+	val = get_f64_reg(fp_reg);
+	regs->status |= SR_FS_DIRTY;
+
+	return val;
+}
+
+#endif
+
+extern unsigned long get_f32_reg(unsigned long fp_reg);
+
+static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset,
+				struct pt_regs *regs)
+{
+	unsigned long fp_reg = (insn >> fp_reg_offset) & 0x1F;
+	unsigned long val;
+
+	val = get_f32_reg(fp_reg);
+	regs->status |= SR_FS_DIRTY;
+
+	return val;
+}
+
+#else /* CONFIG_FPU */
+static void set_f32_rd(unsigned long insn, struct pt_regs *regs,
+		       unsigned long val) {}
+
+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))
+
 #ifdef CONFIG_RISCV_M_MODE
 static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val)
 {
@@ -374,15 +483,21 @@ int handle_misaligned_load(struct pt_regs *regs)
 		return -1;
 	}
 
+	if (!IS_ENABLED(CONFIG_FPU) && fp)
+		return -EOPNOTSUPP;
+
 	val.data_u64 = 0;
 	for (i = 0; i < len; i++) {
 		if (load_u8(regs, (void *)(addr + i), &val.data_bytes[i]))
 			return -1;
 	}
 
-	if (fp)
-		return -1;
-	SET_RD(insn, regs, val.data_ulong << shift >> shift);
+	if (!fp)
+		SET_RD(insn, regs, val.data_ulong << shift >> shift);
+	else if (len == 8)
+		set_f64_rd(insn, regs, val.data_u64);
+	else
+		set_f32_rd(insn, regs, val.data_ulong);
 
 	regs->epc = epc + INSN_LEN(insn);
 
@@ -395,7 +510,7 @@ int handle_misaligned_store(struct pt_regs *regs)
 	unsigned long epc = regs->epc;
 	unsigned long insn;
 	unsigned long addr = regs->badaddr;
-	int i, len = 0;
+	int i, len = 0, fp = 0;
 
 	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
 
@@ -418,6 +533,14 @@ int handle_misaligned_store(struct pt_regs *regs)
 	} else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
 		len = 8;
 #endif
+	} else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
+		fp = 1;
+		len = 8;
+		val.data_u64 = GET_F64_RS2(insn, regs);
+	} else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
+		fp = 1;
+		len = 4;
+		val.data_ulong = GET_F32_RS2(insn, regs);
 	} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
 		len = 2;
 #if defined(CONFIG_64BIT)
@@ -436,11 +559,32 @@ int handle_misaligned_store(struct pt_regs *regs)
 		   ((insn >> SH_RD) & 0x1f)) {
 		len = 4;
 		val.data_ulong = GET_RS2C(insn, regs);
+	} else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
+		fp = 1;
+		len = 8;
+		val.data_u64 = GET_F64_RS2S(insn, regs);
+	} else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) {
+		fp = 1;
+		len = 8;
+		val.data_u64 = GET_F64_RS2C(insn, regs);
+#if !defined(CONFIG_64BIT)
+	} else if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) {
+		fp = 1;
+		len = 4;
+		val.data_ulong = GET_F32_RS2S(insn, regs);
+	} else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) {
+		fp = 1;
+		len = 4;
+		val.data_ulong = GET_F32_RS2C(insn, regs);
+#endif
 	} else {
 		regs->epc = epc;
 		return -1;
 	}
 
+	if (!IS_ENABLED(CONFIG_FPU) && fp)
+		return -EOPNOTSUPP;
+
 	for (i = 0; i < len; i++) {
 		if (store_u8(regs, (void *)(addr + i), val.data_bytes[i]))
 			return -1;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [RFC V2 PATCH 2/9] riscv: avoid missing prototypes warning
  2023-07-04 14:09 ` [RFC V2 PATCH 2/9] riscv: avoid missing prototypes warning Clément Léger
@ 2023-07-08 19:34   ` Stafford Horne
  0 siblings, 0 replies; 12+ messages in thread
From: Stafford Horne @ 2023-07-08 19:34 UTC (permalink / raw)
  To: Clément Léger
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

On Tue, Jul 04, 2023 at 04:09:17PM +0200, Clément Léger wrote:
> Declare handle_misaligned_store/load() functions in entry-common.h and
> include that file in traps_misaligned.c file to avoid warnings.
> 
> Signed-off-by: Clément Léger <cleger@rivosinc.com>
> ---
>  arch/riscv/include/asm/entry-common.h | 3 +++
>  arch/riscv/kernel/traps.c             | 2 --
>  arch/riscv/kernel/traps_misaligned.c  | 1 +
>  3 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/riscv/include/asm/entry-common.h b/arch/riscv/include/asm/entry-common.h
> index 6e4dee49d84b..58e9e2976e1b 100644
> --- a/arch/riscv/include/asm/entry-common.h
> +++ b/arch/riscv/include/asm/entry-common.h
> @@ -8,4 +8,7 @@
>  void handle_page_fault(struct pt_regs *regs);
>  void handle_break(struct pt_regs *regs);
>  
> +int handle_misaligned_load(struct pt_regs *regs);
> +int handle_misaligned_store(struct pt_regs *regs);
> +

Would this work when CONFIG_RISCV_M_MODE is disabled?

The handle_misaligned_load/store functions are only defined if
CONFIG_RISCV_M_MODE is enabled.  I would expect warnings if CONFIG_RISCV_M_MODE
is siabled.

-Stafford

>  #endif /* _ASM_RISCV_ENTRY_COMMON_H */
> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
> index 8c258b78c925..7fcaf2fd27a1 100644
> --- a/arch/riscv/kernel/traps.c
> +++ b/arch/riscv/kernel/traps.c
> @@ -155,8 +155,6 @@ DO_ERROR_INFO(do_trap_load_misaligned,
>  DO_ERROR_INFO(do_trap_store_misaligned,
>  	SIGBUS, BUS_ADRALN, "Oops - store (or AMO) address misaligned");
>  #else
> -int handle_misaligned_load(struct pt_regs *regs);
> -int handle_misaligned_store(struct pt_regs *regs);
>  
>  asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
>  {
> diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
> index e7bfb33089c1..0cccac4822a8 100644
> --- a/arch/riscv/kernel/traps_misaligned.c
> +++ b/arch/riscv/kernel/traps_misaligned.c
> @@ -12,6 +12,7 @@
>  #include <asm/processor.h>
>  #include <asm/ptrace.h>
>  #include <asm/csr.h>
> +#include <asm/entry-common.h>
>  
>  #define INSN_MATCH_LB			0x3
>  #define INSN_MASK_LB			0x707f
> -- 
> 2.40.1
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC V2 PATCH 3/9] riscv: add support for misaligned handling in S-mode
  2023-07-04 14:09 ` [RFC V2 PATCH 3/9] riscv: add support for misaligned handling in S-mode Clément Léger
@ 2023-07-08 20:08   ` Stafford Horne
  0 siblings, 0 replies; 12+ messages in thread
From: Stafford Horne @ 2023-07-08 20:08 UTC (permalink / raw)
  To: Clément Léger
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Brian Cain, Kefeng Wang,
	Russell King (Oracle), Michael Ellerman, Sunil V L, Anup Patel,
	Atish Patra, Andrew Jones, Conor Dooley, Heiko Stuebner, Guo Ren,
	Alexandre Ghiti, Masahiro Yamada, Xianting Tian, Sia Jee Heng,
	Li Zhengyu, Jisheng Zhang, Gautham R. Shenoy, Mark Rutland,
	Peter Zijlstra, Marc Zyngier, Björn Töpel,
	Krzysztof Kozlowski, Evan Green, linux-riscv, linux-kernel

On Tue, Jul 04, 2023 at 04:09:18PM +0200, Clément Léger wrote:
> Misalignment handling is only supported for M-mode and uses direct
> accesses to user memory. in S-mode, this requires to use the
> get_user()/put_user() accessors. Implement load_u8(), store_u8() and
> get_insn() using these accessors.
> 
> Signed-off-by: Clément Léger <cleger@rivosinc.com>
> ---
>  arch/riscv/kernel/Makefile           |   2 +-
>  arch/riscv/kernel/traps.c            |   7 --
>  arch/riscv/kernel/traps_misaligned.c | 118 ++++++++++++++++++++++++---
>  3 files changed, 106 insertions(+), 21 deletions(-)
> 
> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
> index 153864e4f399..79b8dafc699d 100644
> --- a/arch/riscv/kernel/Makefile
> +++ b/arch/riscv/kernel/Makefile
> @@ -55,10 +55,10 @@ obj-y	+= riscv_ksyms.o
>  obj-y	+= stacktrace.o
>  obj-y	+= cacheinfo.o
>  obj-y	+= patch.o
> +obj-y	+= traps_misaligned.o
>  obj-y	+= probes/
>  obj-$(CONFIG_MMU) += vdso.o vdso/
>  
> -obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o

I think it would be better to combine this wath with "[PATCH 2/9] riscv: avoid
missing prototypes warning" from the series to avoid the breakage on commit 2/9.

Also, it would be a bit more clear of the intent.

>  obj-$(CONFIG_FPU)		+= fpu.o
>  obj-$(CONFIG_SMP)		+= smpboot.o
>  obj-$(CONFIG_SMP)		+= smp.o
> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
> index 7fcaf2fd27a1..b2fb2266fb83 100644
> --- a/arch/riscv/kernel/traps.c
> +++ b/arch/riscv/kernel/traps.c
> @@ -149,12 +149,6 @@ DO_ERROR_INFO(do_trap_insn_illegal,
>  	SIGILL, ILL_ILLOPC, "illegal instruction");
>  DO_ERROR_INFO(do_trap_load_fault,
>  	SIGSEGV, SEGV_ACCERR, "load access fault");
> -#ifndef CONFIG_RISCV_M_MODE
> -DO_ERROR_INFO(do_trap_load_misaligned,
> -	SIGBUS, BUS_ADRALN, "Oops - load address misaligned");
> -DO_ERROR_INFO(do_trap_store_misaligned,
> -	SIGBUS, BUS_ADRALN, "Oops - store (or AMO) address misaligned");
> -#else
>  
>  asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
>  {
> @@ -197,7 +191,6 @@ asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs
>  		irqentry_nmi_exit(regs, state);
>  	}
>  }
> -#endif
>  DO_ERROR_INFO(do_trap_store_fault,
>  	SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
>  DO_ERROR_INFO(do_trap_ecall_s,
> diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
> index 0cccac4822a8..9daed7d756ae 100644
> --- a/arch/riscv/kernel/traps_misaligned.c
> +++ b/arch/riscv/kernel/traps_misaligned.c
> @@ -152,21 +152,25 @@
>  #define PRECISION_S 0
>  #define PRECISION_D 1
>  
> -static inline u8 load_u8(const u8 *addr)
> +#ifdef CONFIG_RISCV_M_MODE
> +static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val)
>  {
>  	u8 val;
>  
>  	asm volatile("lbu %0, %1" : "=&r" (val) : "m" (*addr));
> +	*r_val = val;
>  
> -	return val;
> +	return 0;
>  }
>  
> -static inline void store_u8(u8 *addr, u8 val)
> +static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val)
>  {
>  	asm volatile ("sb %0, %1\n" : : "r" (val), "m" (*addr));
> +
> +	return 0;
>  }
>  
> -static inline ulong get_insn(ulong mepc)
> +static inline int get_insn(struct pt_regs *regs, ulong mepc, ulong *r_insn)
>  {
>  	register ulong __mepc asm ("a2") = mepc;
>  	ulong val, rvc_mask = 3, tmp;
> @@ -195,9 +199,87 @@ static inline ulong get_insn(ulong mepc)
>  	: [addr] "r" (__mepc), [rvc_mask] "r" (rvc_mask),
>  	  [xlen_minus_16] "i" (XLEN_MINUS_16));
>  
> -	return val;
> +	*r_insn = val;
> +
> +	return 0;
> +}
> +#else
> +static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val)
> +{
> +	if (user_mode(regs)) {
> +		return __get_user(*r_val, addr);
> +	} else {
> +		*r_val = *addr;
> +		return 0;
> +	}
>  }
>  
> +static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val)
> +{
> +	if (user_mode(regs)) {
> +		return __put_user(val, addr);
> +	} else {
> +		*addr = val;
> +		return 0;
> +	}
> +}
> +
> +#define __read_insn(regs, insn, insn_addr)		\
> +({							\
> +	int __ret;					\
> +							\
> +	if (user_mode(regs)) {				\
> +		__ret = __get_user(insn, insn_addr);	\
> +	} else {					\
> +		insn = *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;
> +		u16 __user *insn_addr = (u16 __user *)epc;
> +
> +		if (__read_insn(regs, insn, insn_addr))
> +			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;
> +		}
> +		insn_addr++;
> +		if (__read_insn(regs, tmp, insn_addr))
> +			return -EFAULT;
> +		*r_insn = (tmp << 16) | insn;
> +
> +		return 0;
> +	} else {
> +		u32 __user *insn_addr = (u32 __user *)epc;
> +
> +		if (__read_insn(regs, insn, insn_addr))
> +			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
> +
>  union reg_data {
>  	u8 data_bytes[8];
>  	ulong data_ulong;
> @@ -208,10 +290,13 @@ int handle_misaligned_load(struct pt_regs *regs)
>  {
>  	union reg_data val;
>  	unsigned long epc = regs->epc;
> -	unsigned long insn = get_insn(epc);
> -	unsigned long addr = csr_read(mtval);
> +	unsigned long insn;
> +	unsigned long addr = regs->badaddr;

Could your commit messages talk a bit about the change from using mtval to
regs->badaddr?  Will this sill work in M-mode? I think so, but it would be good
to explain the change.

>  	int i, fp = 0, shift = 0, len = 0;
>  
> +	if (get_insn(regs, epc, &insn))
> +		return -1;
> +
>  	regs->epc = 0;
>  
>  	if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
> @@ -275,8 +360,10 @@ int handle_misaligned_load(struct pt_regs *regs)
>  	}
>  
>  	val.data_u64 = 0;
> -	for (i = 0; i < len; i++)
> -		val.data_bytes[i] = load_u8((void *)(addr + i));
> +	for (i = 0; i < len; i++) {
> +		if (load_u8(regs, (void *)(addr + i), &val.data_bytes[i]))
> +			return -1;
> +	}
>  
>  	if (fp)
>  		return -1;
> @@ -291,10 +378,13 @@ int handle_misaligned_store(struct pt_regs *regs)
>  {
>  	union reg_data val;
>  	unsigned long epc = regs->epc;
> -	unsigned long insn = get_insn(epc);
> -	unsigned long addr = csr_read(mtval);
> +	unsigned long insn;
> +	unsigned long addr = regs->badaddr;
>  	int i, len = 0;
>  
> +	if (get_insn(regs, epc, &insn))
> +		return -1;
> +
>  	regs->epc = 0;
>  
>  	val.data_ulong = GET_RS2(insn, regs);
> @@ -328,8 +418,10 @@ int handle_misaligned_store(struct pt_regs *regs)
>  		return -1;
>  	}
>  
> -	for (i = 0; i < len; i++)
> -		store_u8((void *)(addr + i), val.data_bytes[i]);
> +	for (i = 0; i < len; i++) {
> +		if (store_u8(regs, (void *)(addr + i), val.data_bytes[i]))
> +			return -1;
> +	}
>  
>  	regs->epc = epc + INSN_LEN(insn);
>  
> -- 
> 2.40.1
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2023-07-08 20:08 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-04 14:09 [RFC V2 PATCH 0/9] Add support to handle misaligned accesses in S-mode Clément Léger
2023-07-04 14:09 ` [RFC V2 PATCH 1/9] riscv: remove unused functions in traps_misaligned.c Clément Léger
2023-07-04 14:09 ` [RFC V2 PATCH 2/9] riscv: avoid missing prototypes warning Clément Léger
2023-07-08 19:34   ` Stafford Horne
2023-07-04 14:09 ` [RFC V2 PATCH 3/9] riscv: add support for misaligned handling in S-mode Clément Léger
2023-07-08 20:08   ` Stafford Horne
2023-07-04 14:09 ` [RFC V2 PATCH 4/9] riscv: report perf event for misaligned fault Clément Léger
2023-07-04 14:09 ` [RFC V2 PATCH 5/9] riscv: add support for sysctl unaligned_enabled control Clément Léger
2023-07-04 14:09 ` [RFC V2 PATCH 6/9] riscv: add support for SBI misalignment trap delegation Clément Léger
2023-07-04 14:09 ` [RFC V2 PATCH 7/9] riscv: report misaligned accesses emulation to hwprobe Clément Léger
2023-07-04 14:09 ` [RFC V2 PATCH 8/9] riscv: add support for PR_SET_UNALIGN and PR_GET_UNALIGN Clément Léger
2023-07-04 14:09 ` [RFC V2 PATCH 9/9] riscv: add floating point insn support to misaligned access emulation Clément Léger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox