Skip to contentSkip to conversation

riscv: Add vector ISA support

PATCH Superseded Greentime Hu 5 participants 35 messages Nov 9, 2021 – Jan 7, 2022

Subsystems (3)

v9 of 10 Superseded Latest is v10 →

lore
Share & tools
lore
#0 lore raw

v9 cover riscv: Add vector ISA support

This patchset is implemented based on vector 1.0 spec to add vector support in riscv Linux kernel. There are some assumptions for this implementations.

1. We assume all harts has the same ISA in the system.
2. We use vector like FPU in some ways instead of using vector like a specific IP.
3. We disable vector in kernel space by default unless kernel uses kernel mode vector kernel_rvv_begin()/kernel_rvv_end().
4. We detect "riscv,isa" to determine whether vector is support or not.

We defined a new structure __riscv_v_state in struct thread_struct to save /restore the vector related registers. It is used for both kernel space and user space.

- In kernel space, the datap pointer in __riscv_v_state will be allocated to save vector registers.
- In user space,
- In signal handler of user space, datap will point to the address of the __riscv_v_state data structure to save vector registers in stack. We also create a __reserved[] array in sigcontext for future extensions.
- In ptrace, the data will be put in ubuf in which we use riscv_vr_get()/riscv_vr_set() to get or set the __riscv_v_state data structure from/to it, datap pointer would be zeroed and vector registers will be copied to the address right after the __riscv_v_state structure in ubuf.

This patchset also adds support for kernel mode vector, kernel XOR implementation with vector ISA and includes several bug fixes and code refinement.

This patchset is rebased to v5.15 and it is tested by running several vector programs simultaneously. It also can get the correct ucontext_t in signal handler and restore correct context after sigreturn. It is also tested with ptrace() syscall to use PTRACE_GETREGSET/PTRACE_SETREGSET to get/set the vector registers.

We have sent patches for vector support to glibc mailing list.

TODO
1. Refine the __riscv_v_state allocation in start_thread()
2. Refine the vector context switching functions by lazy save/restore
3. Add AMP support. To support harts with different ISA

[1] https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc
[2] https://sourceware.org/pipermail/libc-alpha/2021-September/130897.html
[3] https://github.com/sifive/qemu/tree/rvv-1.0-upstream-v9

---
Changelog V9
- Rebase to v5.15
- Merge several patches
- Refine codes
- Fix a kernel panic issue

Changelog V8
- Rebase to v5.14
- Refine struct __riscv_v_state with struct __riscv_ctx_hdr
- Refine has_vector into a static key
- Defined __reserved space in struct sigcontext for vector and future extensions

Changelog V7
- Add support for kernel mode vector
- Add vector extension XOR implementation
- Optimize task switch codes of vector
- Allocate space for vector registers in start_thread()
- Fix an illegal instruction exception when accessing vlenb
- Optimize vector registers initialization
- Initialize vector registers with proper vsetvli then it can work normally
- Refine ptrace porting due to generic API changed
- Code clean up

Changelog V6
- Replace vle.v/vse.v instructions with vle8.v/vse8.v based on 0.9 spec
- Add comments based on mailinglist feedback
- Fix rv32 build error

Changelog V5
- Using regset_size() correctly in generic ptrace
- Fix the ptrace porting
- Fix compile warning

Changelog V4
- Support dynamic vlen
- Fix bugs: lazy save/resotre, not saving vtype
- Update VS bit offset based on latest vector spec
- Add new vector csr based on latest vector spec
- Code refine and removed unused macros

Changelog V3
- Rebase linux-5.6-rc3 and tested with qemu
- Seperate patches with Anup's advice
- Give out a ABI puzzle with unlimited vlen

Changelog V2
- Fixup typo "vecotr, fstate_save->vstate_save".
- Fixup wrong saved registers' length in vector.S.
- Seperate unrelated patches from this one.

Greentime Hu (11):
riscv: Add new csr defines related to vector extension
riscv: Add has_vector/riscv_vsize to save vector features.
riscv: Add vector struct and assembler definitions
riscv: Add task switch support for vector
riscv: Add ptrace vector support
riscv: Add sigcontext save/restore for vector
riscv: Add support for kernel mode vector
riscv: Use CSR_STATUS to replace sstatus in vector.S
riscv: Add vector extension XOR implementation
riscv: Fix an illegal instruction exception when accessing vlenb
without enable vector first
riscv: Fix a kernel panic issue if $s2 is set to a specific value
before entering Linux

Guo Ren (5):
riscv: Separate patch for cflags and aflags
riscv: Rename __switch_to_aux -> fpu
riscv: Extending cpufeature.c to detect V-extension
riscv: Add vector feature to compile
riscv: Reset vector register

Vincent Chen (1):
riscv: signal: Report signal frame size to userspace via auxv

 arch/riscv/Kconfig                       |   9 ++
 arch/riscv/Makefile                      |  19 ++-
 arch/riscv/include/asm/csr.h             |  16 ++-
 arch/riscv/include/asm/elf.h             |  41 +++---
 arch/riscv/include/asm/processor.h       |   3 +
 arch/riscv/include/asm/switch_to.h       |  72 +++++++++-
 arch/riscv/include/asm/vector.h          |  16 +++
 arch/riscv/include/asm/xor.h             |  66 +++++++++
 arch/riscv/include/uapi/asm/auxvec.h     |   1 +
 arch/riscv/include/uapi/asm/hwcap.h      |   1 +
 arch/riscv/include/uapi/asm/ptrace.h     |  25 ++++
 arch/riscv/include/uapi/asm/sigcontext.h |  24 ++++
 arch/riscv/kernel/Makefile               |   2 +
 arch/riscv/kernel/asm-offsets.c          |   8 ++
 arch/riscv/kernel/cpufeature.c           |  16 +++
 arch/riscv/kernel/entry.S                |   6 +-
 arch/riscv/kernel/head.S                 |  24 +++-
 arch/riscv/kernel/kernel_mode_vector.c   | 146 +++++++++++++++++++
 arch/riscv/kernel/process.c              |  49 +++++++
 arch/riscv/kernel/ptrace.c               |  71 ++++++++++
 arch/riscv/kernel/setup.c                |   4 +
 arch/riscv/kernel/signal.c               | 173 ++++++++++++++++++++++-
 arch/riscv/kernel/vector.S               |  90 ++++++++++++
 arch/riscv/lib/Makefile                  |   1 +
 arch/riscv/lib/xor.S                     |  81 +++++++++++
 include/uapi/linux/elf.h                 |   1 +
 26 files changed, 929 insertions(+), 36 deletions(-)
 create mode 100644 arch/riscv/include/asm/vector.h
 create mode 100644 arch/riscv/include/asm/xor.h
 create mode 100644 arch/riscv/kernel/kernel_mode_vector.c
 create mode 100644 arch/riscv/kernel/vector.S
 create mode 100644 arch/riscv/lib/xor.S
Signature · 1 line
2.31.1
#1 lore raw

PATCH v9 1/17 riscv: Separate patch for cflags and aflags

From: Guo Ren <[email protected]>

Use "subst fd" in Makefile is a hack way and it's not convenient to add new ISA feature. Just separate them into riscv-march-cflags and riscv-march-aflags.

---
 arch/riscv/Makefile | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)
arch/riscv/Makefile +12 -6
index 0eb4568fbd29..37de70df4fae 100644
@@ -48,12 +48,18 @@ endif
 endif
 
 # ISA string setting
-riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32ima
-riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64ima
-riscv-march-$(CONFIG_FPU)		:= $(riscv-march-y)fd
-riscv-march-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-y)c
-KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
-KBUILD_AFLAGS += -march=$(riscv-march-y)
+riscv-march-cflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
+riscv-march-cflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
+riscv-march-$(CONFIG_FPU)			:= $(riscv-march-y)fd
+riscv-march-cflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-cflags-y)c
+
+riscv-march-aflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
+riscv-march-aflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
+riscv-march-aflags-$(CONFIG_FPU)		:= $(riscv-march-aflags-y)fd
+riscv-march-aflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-aflags-y)c
+
+KBUILD_CFLAGS += -march=$(riscv-march-cflags-y)
+KBUILD_AFLAGS += -march=$(riscv-march-aflags-y)
 
 KBUILD_CFLAGS += -mno-save-restore
 KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET)
Signature · 1 line
2.31.1
maintainer Reviewed-by on v9 1/17
#2 lore raw

Re: [PATCH v9 01/17] riscv: Separate patch for cflags and aflags

Quoted 32 lines · On Tue, 09 Nov 2021 01:48:13 PST (-0800), [email protected] wrote:

From: Guo Ren <[email protected]>

Use "subst fd" in Makefile is a hack way and it's not convenient to add new ISA feature. Just separate them into riscv-march-cflags and riscv-march-aflags.

---
 arch/riscv/Makefile | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)
arch/riscv/Makefile +5 -6
index 0eb4568fbd29..37de70df4fae 100644
@@ -48,12 +48,18 @@ endif
 endif
 
 # ISA string setting
-riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32ima
-riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64ima
-riscv-march-$(CONFIG_FPU)		:= $(riscv-march-y)fd
-riscv-march-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-y)c
-KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
-KBUILD_AFLAGS += -march=$(riscv-march-y)
+riscv-march-cflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
+riscv-march-cflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
+riscv-march-$(CONFIG_FPU)			:= $(riscv-march-y)fd
+riscv-march-cflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-cflags-y)c
+

arch/riscv/Makefile endif · line 65

Quoted 10 lines
arch/riscv/Makefile +7 -0
+riscv-march-aflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
+riscv-march-aflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
+riscv-march-aflags-$(CONFIG_FPU)		:= $(riscv-march-aflags-y)fd
+riscv-march-aflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-aflags-y)c
+
+KBUILD_CFLAGS += -march=$(riscv-march-cflags-y)
+KBUILD_AFLAGS += -march=$(riscv-march-aflags-y)
 
 KBUILD_CFLAGS += -mno-save-restore
 KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET)
#3 lore raw

PATCH v9 2/17 riscv: Rename __switch_to_aux -> fpu

In reply to Greentime Hu

From: Guo Ren <[email protected]>

The name of __switch_to_aux is not clear and rename it with the determine function: __switch_to_fpu. Next we could add other regs' switch.

---
 arch/riscv/include/asm/switch_to.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/riscv/include/asm/switch_to.h +3 -3
index 0a3f4f95c555..ec83770b3d98 100644
@@ -45,7 +45,7 @@ static inline void fstate_restore(struct task_struct *task,
 	}
 }
 
-static inline void __switch_to_aux(struct task_struct *prev,
+static inline void __switch_to_fpu(struct task_struct *prev,
 				   struct task_struct *next)
 {
 	struct pt_regs *regs;
@@ -65,7 +65,7 @@ static __always_inline bool has_fpu(void)
 static __always_inline bool has_fpu(void) { return false; }
 #define fstate_save(task, regs) do { } while (0)
 #define fstate_restore(task, regs) do { } while (0)
-#define __switch_to_aux(__prev, __next) do { } while (0)
+#define __switch_to_fpu(__prev, __next) do { } while (0)
 #endif
 
 extern struct task_struct *__switch_to(struct task_struct *,
@@ -76,7 +76,7 @@ do {							\
 	struct task_struct *__prev = (prev);		\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
-		__switch_to_aux(__prev, __next);	\
+		__switch_to_fpu(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
 
Signature · 1 line
2.31.1
maintainer Reviewed-by on v9 2/17
#4 lore raw

Re: [PATCH v9 02/17] riscv: Rename __switch_to_aux -> fpu

Quoted 38 lines · On Tue, 09 Nov 2021 01:48:14 PST (-0800), [email protected] wrote:

From: Guo Ren <[email protected]>

The name of __switch_to_aux is not clear and rename it with the determine function: __switch_to_fpu. Next we could add other regs' switch.

---
 arch/riscv/include/asm/switch_to.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/riscv/include/asm/switch_to.h +2 -2
index 0a3f4f95c555..ec83770b3d98 100644
@@ -45,7 +45,7 @@ static inline void fstate_restore(struct task_struct *task,
 	}
 }
 
-static inline void __switch_to_aux(struct task_struct *prev,
+static inline void __switch_to_fpu(struct task_struct *prev,
 				   struct task_struct *next)
 {
 	struct pt_regs *regs;
@@ -65,7 +65,7 @@ static __always_inline bool has_fpu(void)
 static __always_inline bool has_fpu(void) { return false; }
 #define fstate_save(task, regs) do { } while (0)
 #define fstate_restore(task, regs) do { } while (0)
-#define __switch_to_aux(__prev, __next) do { } while (0)
+#define __switch_to_fpu(__prev, __next) do { } while (0)
 #endif
 
 extern struct task_struct *__switch_to(struct task_struct *,

arch/riscv/include/asm/switch_to.h do { \ · line 81

Quoted 7 lines
arch/riscv/include/asm/switch_to.h +1 -1
@@ -76,7 +76,7 @@ do {							\
 	struct task_struct *__prev = (prev);		\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
-		__switch_to_aux(__prev, __next);	\
+		__switch_to_fpu(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
#5 lore raw

PATCH v9 3/17 riscv: Extending cpufeature.c to detect V-extension

In reply to Greentime Hu

From: Guo Ren <[email protected]>

Current cpufeature.c doesn't support detecting V-extension, because "rv64" also contain a 'v' letter and we need to skip it.

---
 arch/riscv/include/uapi/asm/hwcap.h | 1 +
 arch/riscv/kernel/cpufeature.c      | 1 +
 2 files changed, 2 insertions(+)
arch/riscv/include/uapi/asm/hwcap.h +1 -0
index 46dc3f5ee99f..c52bb7bbbabe 100644
@@ -21,5 +21,6 @@
 #define COMPAT_HWCAP_ISA_F	(1 << ('F' - 'A'))
 #define COMPAT_HWCAP_ISA_D	(1 << ('D' - 'A'))
 #define COMPAT_HWCAP_ISA_C	(1 << ('C' - 'A'))
+#define COMPAT_HWCAP_ISA_V	(1 << ('V' - 'A'))
 
 #endif /* _UAPI_ASM_RISCV_HWCAP_H */
arch/riscv/kernel/cpufeature.c +1 -0
index d959d207a40d..7069e55335d0 100644
@@ -73,6 +73,7 @@ void __init riscv_fill_hwcap(void)
 	isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
 	isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
 	isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
+	isa2hwcap['v'] = isa2hwcap['V'] = COMPAT_HWCAP_ISA_V;
 
 	elf_hwcap = 0;
 
Signature · 1 line
2.31.1
maintainer Reviewed-by on v9 3/17
#6 lore raw

Re: [PATCH v9 03/17] riscv: Extending cpufeature.c to detect V-extension

Quoted 31 lines · On Tue, 09 Nov 2021 01:48:15 PST (-0800), [email protected] wrote:

From: Guo Ren <[email protected]>

Current cpufeature.c doesn't support detecting V-extension, because "rv64" also contain a 'v' letter and we need to skip it.

---
 arch/riscv/include/uapi/asm/hwcap.h | 1 +
 arch/riscv/kernel/cpufeature.c      | 1 +
 2 files changed, 2 insertions(+)
arch/riscv/include/uapi/asm/hwcap.h +1 -0
index 46dc3f5ee99f..c52bb7bbbabe 100644
@@ -21,5 +21,6 @@
 #define COMPAT_HWCAP_ISA_F	(1 << ('F' - 'A'))
 #define COMPAT_HWCAP_ISA_D	(1 << ('D' - 'A'))
 #define COMPAT_HWCAP_ISA_C	(1 << ('C' - 'A'))
+#define COMPAT_HWCAP_ISA_V	(1 << ('V' - 'A'))
 
 #endif /* _UAPI_ASM_RISCV_HWCAP_H */
arch/riscv/kernel/cpufeature.c +0 -0
index d959d207a40d..7069e55335d0 100644

arch/riscv/kernel/cpufeature.c void __init riscv_fill_hwcap(void) · line 78

Quoted 6 lines
arch/riscv/kernel/cpufeature.c +1 -0
@@ -73,6 +73,7 @@ void __init riscv_fill_hwcap(void)
 	isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
 	isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
 	isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
+	isa2hwcap['v'] = isa2hwcap['V'] = COMPAT_HWCAP_ISA_V;
 
 	elf_hwcap = 0;
#7 lore raw

PATCH v9 4/17 riscv: Add new csr defines related to vector extension

In reply to Greentime Hu

Follow the riscv vector spec to add new csr numbers.

---
 arch/riscv/include/asm/csr.h | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
arch/riscv/include/asm/csr.h +14 -2
index 87ac65696871..069743102fac 100644
@@ -24,6 +24,12 @@
 #define SR_FS_CLEAN	_AC(0x00004000, UL)
 #define SR_FS_DIRTY	_AC(0x00006000, UL)
 
+#define SR_VS           _AC(0x00000600, UL) /* Vector Status */
+#define SR_VS_OFF       _AC(0x00000000, UL)
+#define SR_VS_INITIAL   _AC(0x00000200, UL)
+#define SR_VS_CLEAN     _AC(0x00000400, UL)
+#define SR_VS_DIRTY     _AC(0x00000600, UL)
+
 #define SR_XS		_AC(0x00018000, UL) /* Extension Status */
 #define SR_XS_OFF	_AC(0x00000000, UL)
 #define SR_XS_INITIAL	_AC(0x00008000, UL)
@@ -31,9 +37,9 @@
 #define SR_XS_DIRTY	_AC(0x00018000, UL)
 
 #ifndef CONFIG_64BIT
-#define SR_SD		_AC(0x80000000, UL) /* FS/XS dirty */
+#define SR_SD		_AC(0x80000000, UL) /* FS/VS/XS dirty */
 #else
-#define SR_SD		_AC(0x8000000000000000, UL) /* FS/XS dirty */
+#define SR_SD		_AC(0x8000000000000000, UL) /* FS/VS/XS dirty */
 #endif
 
 /* SATP flags */
@@ -120,6 +126,12 @@
 #define CSR_MIMPID		0xf13
 #define CSR_MHARTID		0xf14
 
+#define CSR_VSTART		0x8
+#define CSR_VCSR		0xf
+#define CSR_VL			0xc20
+#define CSR_VTYPE		0xc21
+#define CSR_VLENB		0xc22
+
 #ifdef CONFIG_RISCV_M_MODE
 # define CSR_STATUS	CSR_MSTATUS
 # define CSR_IE		CSR_MIE
Signature · 1 line
2.31.1
maintainer Reviewed-by on v9 4/17
#8 lore raw

Re: [PATCH v9 04/17] riscv: Add new csr defines related to vector extension

Quoted 45 lines · On Tue, 09 Nov 2021 01:48:16 PST (-0800), [email protected] wrote:

Follow the riscv vector spec to add new csr numbers.

---
 arch/riscv/include/asm/csr.h | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
arch/riscv/include/asm/csr.h +8 -2
index 87ac65696871..069743102fac 100644
@@ -24,6 +24,12 @@
 #define SR_FS_CLEAN	_AC(0x00004000, UL)
 #define SR_FS_DIRTY	_AC(0x00006000, UL)
 
+#define SR_VS           _AC(0x00000600, UL) /* Vector Status */
+#define SR_VS_OFF       _AC(0x00000000, UL)
+#define SR_VS_INITIAL   _AC(0x00000200, UL)
+#define SR_VS_CLEAN     _AC(0x00000400, UL)
+#define SR_VS_DIRTY     _AC(0x00000600, UL)
+
 #define SR_XS		_AC(0x00018000, UL) /* Extension Status */
 #define SR_XS_OFF	_AC(0x00000000, UL)
 #define SR_XS_INITIAL	_AC(0x00008000, UL)
@@ -31,9 +37,9 @@
 #define SR_XS_DIRTY	_AC(0x00018000, UL)
 
 #ifndef CONFIG_64BIT
-#define SR_SD		_AC(0x80000000, UL) /* FS/XS dirty */
+#define SR_SD		_AC(0x80000000, UL) /* FS/VS/XS dirty */
 #else
-#define SR_SD		_AC(0x8000000000000000, UL) /* FS/XS dirty */
+#define SR_SD		_AC(0x8000000000000000, UL) /* FS/VS/XS dirty */
 #endif
 
 /* SATP flags */
@@ -120,6 +126,12 @@
 #define CSR_MIMPID		0xf13
 #define CSR_MHARTID		0xf14

arch/riscv/include/asm/csr.h line 137

Quoted 10 lines
arch/riscv/include/asm/csr.h +6 -0
 
+#define CSR_VSTART		0x8
+#define CSR_VCSR		0xf
+#define CSR_VL			0xc20
+#define CSR_VTYPE		0xc21
+#define CSR_VLENB		0xc22
+
 #ifdef CONFIG_RISCV_M_MODE
 # define CSR_STATUS	CSR_MSTATUS
 # define CSR_IE		CSR_MIE
#9 lore raw

PATCH v9 5/17 riscv: Add vector feature to compile

In reply to Greentime Hu

From: Guo Ren <[email protected]>

This patch adds a new config option which could enable assembler's vector feature.

---
 arch/riscv/Kconfig  | 9 +++++++++
 arch/riscv/Makefile | 1 +
 2 files changed, 10 insertions(+)
arch/riscv/Kconfig +9 -0
index f076cee11af6..0311579920b9 100644
@@ -389,6 +389,15 @@ config FPU
 
 	  If you don't know what to do here, say Y.
 
+config VECTOR
+	bool "VECTOR support"
+	default n
+	help
+	  Say N here if you want to disable all vector related procedure
+	  in the kernel.
+
+	  If you don't know what to do here, say Y.
+
 endmenu
 
 menu "Kernel features"
arch/riscv/Makefile +1 -0
index 37de70df4fae..f109214a2d7f 100644
@@ -57,6 +57,7 @@ riscv-march-aflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
 riscv-march-aflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
 riscv-march-aflags-$(CONFIG_FPU)		:= $(riscv-march-aflags-y)fd
 riscv-march-aflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-aflags-y)c
+riscv-march-aflags-$(CONFIG_VECTOR)		:= $(riscv-march-aflags-y)v
 
 KBUILD_CFLAGS += -march=$(riscv-march-cflags-y)
 KBUILD_AFLAGS += -march=$(riscv-march-aflags-y)
Signature · 1 line
2.31.1
#10 lore raw

Re: [PATCH v9 05/17] riscv: Add vector feature to compile

I love your patch! Yet something to improve:

Hi Greentime,

I love your patch! Yet something to improve:

[auto build test ERROR on v5.15]
[cannot apply to linus/master next-20211111]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Greentime-Hu/riscv-Add-vector-ISA-support/20211109-175222
base:   DEBUG invalid remote for branch v5.15 8bb7eca972ad531c9b149c0a51ab43a417385813
config: riscv-allyesconfig (attached as .config)
compiler: riscv64-linux-gcc (GCC) 11.2.0

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/b164ca135b641a96cea32346baec67e96bf468a2
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Greentime-Hu/riscv-Add-vector-ISA-support/20211109-175222 git checkout b164ca135b641a96cea32346baec67e96bf468a2
# save the attached .config to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=riscv prepare

If you fix the issue, kindly add following tag as appropriate

All errors (new ones prefixed by >>):

scripts/genksyms/parse.y: warning: 9 shift/reduce conflicts [-Wconflicts-sr] scripts/genksyms/parse.y: warning: 5 reduce/reduce conflicts [-Wconflicts-rr] Assembler messages:

>> Error: cannot find default versions of the ISA extension `v'
   make[2]: *** [scripts/Makefile.build:379: arch/riscv/kernel/vdso/rt_sigreturn.o] Error 1
   Assembler messages:
>> Error: cannot find default versions of the ISA extension `v'
   Assembler messages:
>> Error: cannot find default versions of the ISA extension `v'
   make[2]: *** [scripts/Makefile.build:379: arch/riscv/kernel/vdso/getcpu.o] Error 1
   make[2]: *** [scripts/Makefile.build:379: arch/riscv/kernel/vdso/note.o] Error 1
   Assembler messages:
>> Error: cannot find default versions of the ISA extension `v'

make[2]: *** [scripts/Makefile.build:379: arch/riscv/kernel/vdso/flush_icache.o] Error 1 make[2]: Target 'include/generated/vdso-offsets.h' not remade because of errors. make[1]: *** [arch/riscv/Makefile:121: vdso_prepare] Error 2
make[1]: Target 'prepare' not remade because of errors.
make: *** [Makefile:219: __sub-make] Error 2
make: Target 'prepare' not remade because of errors.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

maintainer
#11 lore raw

Re: [PATCH v9 05/17] riscv: Add vector feature to compile

In reply to Greentime Hu
Quoted 21 lines · On Tue, 09 Nov 2021 01:48:17 PST (-0800), [email protected] wrote:

From: Guo Ren <[email protected]>

This patch adds a new config option which could enable assembler's vector feature.

---
 arch/riscv/Kconfig  | 9 +++++++++
 arch/riscv/Makefile | 1 +
 2 files changed, 10 insertions(+)
arch/riscv/Kconfig +0 -0
index f076cee11af6..0311579920b9 100644
@@ -389,6 +389,15 @@ config FPU
 
 	  If you don't know what to do here, say Y.
 

arch/riscv/Kconfig config FPU · line 401

Quoted 10 lines
arch/riscv/Kconfig +9 -0
+config VECTOR
+	bool "VECTOR support"
+	default n
+	help
+	  Say N here if you want to disable all vector related procedure
+	  in the kernel.
+
+	  If you don't know what to do here, say Y.
+
 endmenu

As the kernel build robot points out, this should have some sort of dependency on a vector toolchain. Not sure if there's a better way to do it that cc-option, looks like there are some other tests for assembler arguments that way.

Quoted 14 lines
arch/riscv/Kconfig +0 -0
 menu "Kernel features"
arch/riscv/Makefile +1 -0
index 37de70df4fae..f109214a2d7f 100644
@@ -57,6 +57,7 @@ riscv-march-aflags-$(CONFIG_ARCH_RV32I)		:= rv32ima
 riscv-march-aflags-$(CONFIG_ARCH_RV64I)		:= rv64ima
 riscv-march-aflags-$(CONFIG_FPU)		:= $(riscv-march-aflags-y)fd
 riscv-march-aflags-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-aflags-y)c
+riscv-march-aflags-$(CONFIG_VECTOR)		:= $(riscv-march-aflags-y)v
 
 KBUILD_CFLAGS += -march=$(riscv-march-cflags-y)
 KBUILD_AFLAGS += -march=$(riscv-march-aflags-y)
#12 lore raw

PATCH v9 6/17 riscv: Add has_vector/riscv_vsize to save vector features.

In reply to Greentime Hu

This patch is used to detect vector support status of CPU and use riscv_vsize to save the size of all the vector registers. It assumes all harts has the same capabilities in SMP system.

---
 arch/riscv/kernel/cpufeature.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/riscv/kernel/cpufeature.c +13 -0
index 7069e55335d0..8e7557980faf 100644
@@ -21,6 +21,11 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 #ifdef CONFIG_FPU
 __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
+#ifdef CONFIG_VECTOR
+#include <asm/vector.h>
+__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_vector);
+unsigned long riscv_vsize __read_mostly;
+#endif
 
 /**
  * riscv_isa_extension_base() - Get base extension word
@@ -149,4 +154,12 @@ void __init riscv_fill_hwcap(void)
 	if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
 		static_branch_enable(&cpu_hwcap_fpu);
 #endif
+
+#ifdef CONFIG_VECTOR
+	if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
+		static_branch_enable(&cpu_hwcap_vector);
+		/* There are 32 vector registers with vlenb length. */
+		riscv_vsize = csr_read(CSR_VLENB) * 32;
+	}
+#endif
 }
Signature · 1 line
2.31.1
maintainer Reviewed-by on v9 6/17
#13 lore raw

Re: [PATCH v9 06/17] riscv: Add has_vector/riscv_vsize to save vector features.

Quoted 10 lines · On Tue, 09 Nov 2021 01:48:18 PST (-0800), [email protected] wrote:

This patch is used to detect vector support status of CPU and use riscv_vsize to save the size of all the vector registers. It assumes all harts has the same capabilities in SMP system.

IMO those SOB flags are a bit out of order, but checkpatch isn't complaining so I'm not sure it matters. Otherwise:

Quoted 33 lines
---
 arch/riscv/kernel/cpufeature.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/riscv/kernel/cpufeature.c +13 -0
index 7069e55335d0..8e7557980faf 100644
@@ -21,6 +21,11 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 #ifdef CONFIG_FPU
 __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
+#ifdef CONFIG_VECTOR
+#include <asm/vector.h>
+__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_vector);
+unsigned long riscv_vsize __read_mostly;
+#endif
 
 /**
  * riscv_isa_extension_base() - Get base extension word
@@ -149,4 +154,12 @@ void __init riscv_fill_hwcap(void)
 	if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
 		static_branch_enable(&cpu_hwcap_fpu);
 #endif
+
+#ifdef CONFIG_VECTOR
+	if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
+		static_branch_enable(&cpu_hwcap_vector);
+		/* There are 32 vector registers with vlenb length. */
+		riscv_vsize = csr_read(CSR_VLENB) * 32;
+	}
+#endif
 }
#14 lore raw

PATCH v9 7/17 riscv: Reset vector register

In reply to Greentime Hu

From: Guo Ren <[email protected]>

Reset vector registers at boot-time and disable vector instructions execution for kernel mode.

---
 arch/riscv/kernel/entry.S |  6 +++---
 arch/riscv/kernel/head.S  | 22 ++++++++++++++++++++--
 2 files changed, 23 insertions(+), 5 deletions(-)
arch/riscv/kernel/entry.S +3 -3
index 98f502654edd..ad0fa80ada81 100644
@@ -77,10 +77,10 @@ _save_context:
 	 * Disable user-mode memory access as it should only be set in the
 	 * actual user copy routines.
 	 *
-	 * Disable the FPU to detect illegal usage of floating point in kernel
-	 * space.
+	 * Disable the FPU/Vector to detect illegal usage of floating point
+	 * or vector in kernel space.
 	 */
-	li t0, SR_SUM | SR_FS
+	li t0, SR_SUM | SR_FS | SR_VS
 
 	REG_L s0, TASK_TI_USER_SP(tp)
 	csrrc s1, CSR_STATUS, t0
arch/riscv/kernel/head.S +20 -2
index 52c5ff9804c5..551afe1de85e 100644
@@ -242,10 +242,10 @@ pmp_done:
 .option pop
 
 	/*
-	 * Disable FPU to detect illegal usage of
+	 * Disable FPU & VECTOR to detect illegal usage of
 	 * floating point in kernel space
 	 */
-	li t0, SR_FS
+	li t0, SR_FS | SR_VS
 	csrc CSR_STATUS, t0
 
 #ifdef CONFIG_SMP
@@ -433,6 +433,24 @@ ENTRY(reset_regs)
 	csrw	fcsr, 0
 	/* note that the caller must clear SR_FS */
 #endif /* CONFIG_FPU */
+
+#ifdef CONFIG_VECTOR
+	csrr	t0, CSR_MISA
+	li	t1, (COMPAT_HWCAP_ISA_V >> 16)
+	slli	t1, t1, 16
+	and	t0, t0, t1
+	beqz	t0, .Lreset_regs_done
+
+	li	t1, SR_VS
+	csrs	CSR_STATUS, t1
+	vsetvli t1, x0, e8, m8
+	vmv.v.i v0, 0
+	vmv.v.i v8, 0
+	vmv.v.i v16, 0
+	vmv.v.i v24, 0
+	/* note that the caller must clear SR_VS */
+#endif /* CONFIG_VECTOR */
+
 .Lreset_regs_done:
 	ret
 END(reset_regs)
Signature · 1 line
2.31.1
maintainer Reviewed-by on v9 7/17
#15 lore raw

Re: [PATCH v9 07/17] riscv: Reset vector register

Quoted 40 lines · On Tue, 09 Nov 2021 01:48:19 PST (-0800), [email protected] wrote:

From: Guo Ren <[email protected]>

Reset vector registers at boot-time and disable vector instructions execution for kernel mode.

---
 arch/riscv/kernel/entry.S |  6 +++---
 arch/riscv/kernel/head.S  | 22 ++++++++++++++++++++--
 2 files changed, 23 insertions(+), 5 deletions(-)
arch/riscv/kernel/entry.S +3 -3
index 98f502654edd..ad0fa80ada81 100644
@@ -77,10 +77,10 @@ _save_context:
 	 * Disable user-mode memory access as it should only be set in the
 	 * actual user copy routines.
 	 *
-	 * Disable the FPU to detect illegal usage of floating point in kernel
-	 * space.
+	 * Disable the FPU/Vector to detect illegal usage of floating point
+	 * or vector in kernel space.
 	 */
-	li t0, SR_SUM | SR_FS
+	li t0, SR_SUM | SR_FS | SR_VS
 
 	REG_L s0, TASK_TI_USER_SP(tp)
 	csrrc s1, CSR_STATUS, t0
arch/riscv/kernel/head.S +0 -0
index 52c5ff9804c5..551afe1de85e 100644

arch/riscv/kernel/head.S pmp_done: · line 246

Quoted 6 lines
arch/riscv/kernel/head.S +1 -1
@@ -242,10 +242,10 @@ pmp_done:
 .option pop
 
 	/*
-	 * Disable FPU to detect illegal usage of
+	 * Disable FPU & VECTOR to detect illegal usage of
 	 * floating point in kernel space

Presumably that should be "floating point or vector", like the other one?

Quoted 7 lines
arch/riscv/kernel/head.S +1 -1
 	 */
-	li t0, SR_FS
+	li t0, SR_FS | SR_VS
 	csrc CSR_STATUS, t0
 
 #ifdef CONFIG_SMP

arch/riscv/kernel/head.S ENTRY(reset_regs) · line 440

Quoted 8 lines
arch/riscv/kernel/head.S +5 -0
@@ -433,6 +433,24 @@ ENTRY(reset_regs)
 	csrw	fcsr, 0
 	/* note that the caller must clear SR_FS */
 #endif /* CONFIG_FPU */
+
+#ifdef CONFIG_VECTOR
+	csrr	t0, CSR_MISA
+	li	t1, (COMPAT_HWCAP_ISA_V >> 16)
+	slli	t1, t1, 16

Why? Shouldn't the "li" pseudo handle generating that constant fine? It generates the expected lui for me.

arch/riscv/kernel/head.S ENTRY(reset_regs) · line 450

Quoted 10 lines
arch/riscv/kernel/head.S +10 -0
+	and	t0, t0, t1
+	beqz	t0, .Lreset_regs_done
+
+	li	t1, SR_VS
+	csrs	CSR_STATUS, t1
+	vsetvli t1, x0, e8, m8
+	vmv.v.i v0, 0
+	vmv.v.i v8, 0
+	vmv.v.i v16, 0
+	vmv.v.i v24, 0

I don't see anything resetting vcsr here, which is explicitly required by ISA manual.

Otherwise this looks OK to me: I wasn't actually sure this was guaranteed to hit every bit in the vector register file, but IIUC it does -- VLMAX has a defined value, VLEN is a constant, and this form of vsetvli is defined to set vl to VLMAX. Probably worth a comment, though.

arch/riscv/kernel/head.S ENTRY(reset_regs) · line 456

Quoted 6 lines
arch/riscv/kernel/head.S +3 -0
+	/* note that the caller must clear SR_VS */
+#endif /* CONFIG_VECTOR */
+
 .Lreset_regs_done:
 	ret
 END(reset_regs)

With those minor bits fixed,

#16 lore raw

Re: [PATCH v9 07/17] riscv: Reset vector register

Palmer Dabbelt <[email protected]> 於 2021年12月15日 週三 上午12:29寫道:

Quoted 44 lines · On Tue, 09 Nov 2021 01:48:19 PST (-0800), [email protected] wrote:
Quoted 42 lines

From: Guo Ren <[email protected]>

Reset vector registers at boot-time and disable vector instructions execution for kernel mode.

---
 arch/riscv/kernel/entry.S |  6 +++---
 arch/riscv/kernel/head.S  | 22 ++++++++++++++++++++--
 2 files changed, 23 insertions(+), 5 deletions(-)
arch/riscv/kernel/entry.S +3 -3
index 98f502654edd..ad0fa80ada81 100644
@@ -77,10 +77,10 @@ _save_context:
       * Disable user-mode memory access as it should only be set in the
       * actual user copy routines.
       *
-      * Disable the FPU to detect illegal usage of floating point in kernel
-      * space.
+      * Disable the FPU/Vector to detect illegal usage of floating point
+      * or vector in kernel space.
       */
-     li t0, SR_SUM | SR_FS
+     li t0, SR_SUM | SR_FS | SR_VS
 
      REG_L s0, TASK_TI_USER_SP(tp)
      csrrc s1, CSR_STATUS, t0
arch/riscv/kernel/head.S +0 -0
index 52c5ff9804c5..551afe1de85e 100644
@@ -242,10 +242,10 @@ pmp_done:
 .option pop
 
Quoted 7 lines

arch/riscv/kernel/head.S pmp_done: · line 246

Quoted 4 lines
arch/riscv/kernel/head.S +1 -1
      /*
-      * Disable FPU to detect illegal usage of
+      * Disable FPU & VECTOR to detect illegal usage of
       * floating point in kernel space

Presumably that should be "floating point or vector", like the other one?

Thank you, Palmer. I'll update this and I also found another issue in secondary_start_sbi.
We should also disable vector there.

Quoted 5 lines
Quoted 5 lines
arch/riscv/kernel/head.S +1 -1
       */
-     li t0, SR_FS
+     li t0, SR_FS | SR_VS
      csrc CSR_STATUS, t0
 
Quoted 13 lines

arch/riscv/kernel/head.S ENTRY(reset_regs) · line 440

Quoted 10 lines
arch/riscv/kernel/head.S +5 -0
 #ifdef CONFIG_SMP
@@ -433,6 +433,24 @@ ENTRY(reset_regs)
      csrw    fcsr, 0
      /* note that the caller must clear SR_FS */
 #endif /* CONFIG_FPU */
+
+#ifdef CONFIG_VECTOR
+     csrr    t0, CSR_MISA
+     li      t1, (COMPAT_HWCAP_ISA_V >> 16)
+     slli    t1, t1, 16

Why? Shouldn't the "li" pseudo handle generating that constant fine? It generates the expected lui for me.

That's right.
I'll update the code here to
#ifdef CONFIG_VECTOR

        csrr    t0, CSR_MISA
        li      t1, COMPAT_HWCAP_ISA_V
        and     t0, t0, t1
        beqz    t0, .Lreset_regs_done
Quoted 11 lines

arch/riscv/kernel/head.S ENTRY(reset_regs) · line 450

Quoted 10 lines
arch/riscv/kernel/head.S +10 -0
+     and     t0, t0, t1
+     beqz    t0, .Lreset_regs_done
+
+     li      t1, SR_VS
+     csrs    CSR_STATUS, t1
+     vsetvli t1, x0, e8, m8
+     vmv.v.i v0, 0
+     vmv.v.i v8, 0
+     vmv.v.i v16, 0
+     vmv.v.i v24, 0
Quoted 8 lines

I don't see anything resetting vcsr here, which is explicitly required by ISA manual.

Otherwise this looks OK to me: I wasn't actually sure this was guaranteed to hit every bit in the vector register file, but IIUC it does -- VLMAX has a defined value, VLEN is a constant, and this form of vsetvli is defined to set vl to VLMAX. Probably worth a comment, though.

/*
* Clear vector registers and reset vcsr
* VLMAX has a defined value, VLEN is a constant,
* and this form of vsetvli is defined to set vl to VLMAX. */

li      t1, SR_VS
csrs    CSR_STATUS, t1
csrs    CSR_VCSR, x0

vsetvli t1, x0, e8, m8
vmv.v.i v0, 0
vmv.v.i v8, 0
vmv.v.i v16, 0
vmv.v.i v24, 0

Quoted 10 lines

arch/riscv/kernel/head.S ENTRY(reset_regs) · line 456

Quoted 6 lines
arch/riscv/kernel/head.S +3 -0
+     /* note that the caller must clear SR_VS */
+#endif /* CONFIG_VECTOR */
+
 .Lreset_regs_done:
      ret
 END(reset_regs)

With those minor bits fixed,

#17 lore raw

PATCH v9 8/17 riscv: Add vector struct and assembler definitions

In reply to Greentime Hu

Add vector state context struct in struct thread and asm-offsets.c definitions.

The vector registers will be saved in datap pointer of __riscv_v_state. It will be dynamically allocated in kernel space. It will be put right after the __riscv_v_state data structure in user space.

---
 arch/riscv/include/asm/processor.h   |  1 +
 arch/riscv/include/uapi/asm/ptrace.h | 11 +++++++++++
 arch/riscv/kernel/asm-offsets.c      |  6 ++++++
 3 files changed, 18 insertions(+)
arch/riscv/include/asm/processor.h +1 -0
index 46b492c78cbb..a268f1382e52 100644
@@ -35,6 +35,7 @@ struct thread_struct {
 	unsigned long s[12];	/* s[0]: frame pointer */
 	struct __riscv_d_ext_state fstate;
 	unsigned long bad_cause;
+	struct __riscv_v_state vstate;
 };
 
 /* Whitelist the fstate from the task_struct for hardened usercopy */
arch/riscv/include/uapi/asm/ptrace.h +11 -0
index 882547f6bd5c..bd3b8a710246 100644
@@ -77,6 +77,17 @@ union __riscv_fp_state {
 	struct __riscv_q_ext_state q;
 };
 
+struct __riscv_v_state {
+	unsigned long vstart;
+	unsigned long vl;
+	unsigned long vtype;
+	unsigned long vcsr;
+	void *datap;
+#if __riscv_xlen == 32
+	__u32 __padding;
+#endif
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_ASM_RISCV_PTRACE_H */
arch/riscv/kernel/asm-offsets.c +6 -0
index 90f8ce64fa6f..34f43c84723a 100644
@@ -72,6 +72,12 @@ void asm_offsets(void)
 	OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
 #endif
 
+	OFFSET(RISCV_V_STATE_VSTART, __riscv_v_state, vstart);
+	OFFSET(RISCV_V_STATE_VL, __riscv_v_state, vl);
+	OFFSET(RISCV_V_STATE_VTYPE, __riscv_v_state, vtype);
+	OFFSET(RISCV_V_STATE_VCSR, __riscv_v_state, vcsr);
+	OFFSET(RISCV_V_STATE_DATAP, __riscv_v_state, datap);
+
 	DEFINE(PT_SIZE, sizeof(struct pt_regs));
 	OFFSET(PT_EPC, pt_regs, epc);
 	OFFSET(PT_RA, pt_regs, ra);
Signature · 1 line
2.31.1
maintainer
#18 lore raw

Re: [PATCH v9 08/17] riscv: Add vector struct and assembler definitions

Quoted 33 lines · On Tue, 09 Nov 2021 01:48:20 PST (-0800), [email protected] wrote:

Add vector state context struct in struct thread and asm-offsets.c definitions.

The vector registers will be saved in datap pointer of __riscv_v_state. It will be dynamically allocated in kernel space. It will be put right after the __riscv_v_state data structure in user space.

---
 arch/riscv/include/asm/processor.h   |  1 +
 arch/riscv/include/uapi/asm/ptrace.h | 11 +++++++++++
 arch/riscv/kernel/asm-offsets.c      |  6 ++++++
 3 files changed, 18 insertions(+)
arch/riscv/include/asm/processor.h +1 -0
index 46b492c78cbb..a268f1382e52 100644
@@ -35,6 +35,7 @@ struct thread_struct {
 	unsigned long s[12];	/* s[0]: frame pointer */
 	struct __riscv_d_ext_state fstate;
 	unsigned long bad_cause;
+	struct __riscv_v_state vstate;
 };
 
 /* Whitelist the fstate from the task_struct for hardened usercopy */
arch/riscv/include/uapi/asm/ptrace.h +0 -0
index 882547f6bd5c..bd3b8a710246 100644

arch/riscv/include/uapi/asm/ptrace.h union __riscv_fp_state { · line 84

Quoted 8 lines
arch/riscv/include/uapi/asm/ptrace.h +5 -0
@@ -77,6 +77,17 @@ union __riscv_fp_state {
 	struct __riscv_q_ext_state q;
 };
 
+struct __riscv_v_state {
+	unsigned long vstart;
+	unsigned long vl;
+	unsigned long vtype;
+	unsigned long vcsr;

Don't we also need vlen to adequately determine the vector state? Otherwise we're going to end up dropping some state when vl isn't vlmax, which IIUC isn't legal.

arch/riscv/include/uapi/asm/ptrace.h union __riscv_fp_state { · line 88

Quoted 4 lines
arch/riscv/include/uapi/asm/ptrace.h +4 -0
+	void *datap;
+#if __riscv_xlen == 32
+	__u32 __padding;
+#endif

Why is there padding?

Quoted 22 lines
arch/riscv/include/uapi/asm/ptrace.h +2 -0
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_ASM_RISCV_PTRACE_H */
arch/riscv/kernel/asm-offsets.c +6 -0
index 90f8ce64fa6f..34f43c84723a 100644
@@ -72,6 +72,12 @@ void asm_offsets(void)
 	OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
 #endif
 
+	OFFSET(RISCV_V_STATE_VSTART, __riscv_v_state, vstart);
+	OFFSET(RISCV_V_STATE_VL, __riscv_v_state, vl);
+	OFFSET(RISCV_V_STATE_VTYPE, __riscv_v_state, vtype);
+	OFFSET(RISCV_V_STATE_VCSR, __riscv_v_state, vcsr);
+	OFFSET(RISCV_V_STATE_DATAP, __riscv_v_state, datap);
+
 	DEFINE(PT_SIZE, sizeof(struct pt_regs));
 	OFFSET(PT_EPC, pt_regs, epc);
 	OFFSET(PT_RA, pt_regs, ra);
#19 lore raw

Re: [PATCH v9 08/17] riscv: Add vector struct and assembler definitions

Palmer Dabbelt <[email protected]> 於 2021年12月15日 週三 上午12:29寫道:

Quoted 38 lines · On Tue, 09 Nov 2021 01:48:20 PST (-0800), [email protected] wrote:
Quoted 36 lines

Add vector state context struct in struct thread and asm-offsets.c definitions.

The vector registers will be saved in datap pointer of __riscv_v_state. It will be dynamically allocated in kernel space. It will be put right after the __riscv_v_state data structure in user space.

---
 arch/riscv/include/asm/processor.h   |  1 +
 arch/riscv/include/uapi/asm/ptrace.h | 11 +++++++++++
 arch/riscv/kernel/asm-offsets.c      |  6 ++++++
 3 files changed, 18 insertions(+)
arch/riscv/include/asm/processor.h +1 -0
index 46b492c78cbb..a268f1382e52 100644
@@ -35,6 +35,7 @@ struct thread_struct {
      unsigned long s[12];    /* s[0]: frame pointer */
      struct __riscv_d_ext_state fstate;
      unsigned long bad_cause;
+     struct __riscv_v_state vstate;
 };
 
 /* Whitelist the fstate from the task_struct for hardened usercopy */
arch/riscv/include/uapi/asm/ptrace.h +0 -0
index 882547f6bd5c..bd3b8a710246 100644
@@ -77,6 +77,17 @@ union __riscv_fp_state {
      struct __riscv_q_ext_state q;
 };
 
Quoted 9 lines

arch/riscv/include/uapi/asm/ptrace.h union __riscv_fp_state { · line 84

Quoted 5 lines
arch/riscv/include/uapi/asm/ptrace.h +5 -0
+struct __riscv_v_state {
+     unsigned long vstart;
+     unsigned long vl;
+     unsigned long vtype;
+     unsigned long vcsr;

Don't we also need vlen to adequately determine the vector state? Otherwise we're going to end up dropping some state when vl isn't vlmax, which IIUC isn't legal.

Do you mean vlenb? Since it is a constant value, we don't need to save/restore it in the context.

Quoted 6 lines

arch/riscv/include/uapi/asm/ptrace.h union __riscv_fp_state { · line 88

Quoted 4 lines
arch/riscv/include/uapi/asm/ptrace.h +4 -0
+     void *datap;
+#if __riscv_xlen == 32
+     __u32 __padding;
+#endif

Why is there padding?

To keep vector registers saved in a 16-bytes aligned address for rv32.

struct __riscv_ctx_hdr {
        __u32 magic;
        __u32 size;
};
struct __sc_riscv_v_state {
        struct __riscv_ctx_hdr head;
        struct __riscv_v_state v_state;
} __attribute__((aligned(16)));

rv64 => 48bytes -> 16byte aligned
rv32 => 32bytes -> 16byte aligned

This struct and vector registers will be copied to sigcontext.reserved[] for signal handler so we'd like to keep it is 16-byte aligned.

struct sigcontext {
        struct user_regs_struct sc_regs;
        union __riscv_fp_state sc_fpregs;
        /*
         * 4K + 128 reserved for vector state and future expansion.
         * This space is enough to store the vector context whose VLENB
         * is less or equal to 128.
         * (The size of the vector context is 4144 byte as VLENB is 128)
         */
        __u8 __reserved[4224] __attribute__((__aligned__(16)));
};
Quoted 22 lines
Quoted 22 lines
arch/riscv/include/uapi/asm/ptrace.h +2 -0
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_ASM_RISCV_PTRACE_H */
arch/riscv/kernel/asm-offsets.c +6 -0
index 90f8ce64fa6f..34f43c84723a 100644
@@ -72,6 +72,12 @@ void asm_offsets(void)
      OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
 #endif
 
+     OFFSET(RISCV_V_STATE_VSTART, __riscv_v_state, vstart);
+     OFFSET(RISCV_V_STATE_VL, __riscv_v_state, vl);
+     OFFSET(RISCV_V_STATE_VTYPE, __riscv_v_state, vtype);
+     OFFSET(RISCV_V_STATE_VCSR, __riscv_v_state, vcsr);
+     OFFSET(RISCV_V_STATE_DATAP, __riscv_v_state, datap);
+
      DEFINE(PT_SIZE, sizeof(struct pt_regs));
      OFFSET(PT_EPC, pt_regs, epc);
      OFFSET(PT_RA, pt_regs, ra);
#20 lore raw

Re: [PATCH v9 08/17] riscv: Add vector struct and assembler definitions

Quoted 53 lines · Greentime Hu

Palmer Dabbelt <[email protected]> 於 2021年12月15日 週三 上午12:29寫道:

Quoted 38 lines · On Tue, 09 Nov 2021 01:48:20 PST (-0800), [email protected] wrote:
Quoted 36 lines

Add vector state context struct in struct thread and asm-offsets.c definitions.

The vector registers will be saved in datap pointer of __riscv_v_state. It will be dynamically allocated in kernel space. It will be put right after the __riscv_v_state data structure in user space.

---

arch/riscv/include/asm/processor.h   |  1 +
arch/riscv/include/uapi/asm/ptrace.h | 11 +++++++++++
arch/riscv/kernel/asm-offsets.c      |  6 ++++++
3 files changed, 18 insertions(+)
arch/riscv/include/asm/processor.h +1 -0
index 46b492c78cbb..a268f1382e52 100644
@@ -35,6 +35,7 @@ struct thread_struct {
     unsigned long s[12];    /* s[0]: frame pointer */
     struct __riscv_d_ext_state fstate;
     unsigned long bad_cause;
+     struct __riscv_v_state vstate;
 };
 
 /* Whitelist the fstate from the task_struct for hardened usercopy */
arch/riscv/include/uapi/asm/ptrace.h +0 -0
index 882547f6bd5c..bd3b8a710246 100644
@@ -77,6 +77,17 @@ union __riscv_fp_state {
     struct __riscv_q_ext_state q;
 };
 
Quoted 9 lines

arch/riscv/include/uapi/asm/ptrace.h union __riscv_fp_state { · line 84

Quoted 5 lines
arch/riscv/include/uapi/asm/ptrace.h +5 -0
+struct __riscv_v_state {
+     unsigned long vstart;
+     unsigned long vl;
+     unsigned long vtype;
+     unsigned long vcsr;

Don't we also need vlen to adequately determine the vector state? Otherwise we're going to end up dropping some state when vl isn't vlmax, which IIUC isn't legal.

Do you mean vlenb? Since it is a constant value, we don't need to save/restore it in the context.

Quoted 8 lines
Quoted 6 lines

arch/riscv/include/uapi/asm/ptrace.h union __riscv_fp_state { · line 88

Quoted 4 lines
arch/riscv/include/uapi/asm/ptrace.h +4 -0
+     void *datap;
+#if __riscv_xlen == 32
+     __u32 __padding;
+#endif

Why is there padding?

To keep vector registers saved in a 16-bytes aligned address for rv32.

That struct has an alignment of 4 bytes. It doesn’t make sense to put the padding there; it should be wherever the 16 byte alignment is introduced, which looks like your __sc_riscv_v_state below (assuming you need to explicitly name the padding and can’t just rely on implicit compiler padding; presumably you need it so you can guarantee it’s zero when written to userspace memory?).

Especially since the amount of padding you need in __riscv_v_state if doing it this way depends on the size of __riscv_ctx_hdr, because that happens to be in __sc_riscv_v_state. This is quite fragile and non-obvious as it stands.

Jess

Quoted 56 lines
struct __riscv_ctx_hdr {
       __u32 magic;
       __u32 size;
};
struct __sc_riscv_v_state {
       struct __riscv_ctx_hdr head;
       struct __riscv_v_state v_state;
} __attribute__((aligned(16)));

rv64 => 48bytes -> 16byte aligned
rv32 => 32bytes -> 16byte aligned

This struct and vector registers will be copied to sigcontext.reserved[] for signal handler so we'd like to keep it is 16-byte aligned.

struct sigcontext {
       struct user_regs_struct sc_regs;
       union __riscv_fp_state sc_fpregs;
       /*
        * 4K + 128 reserved for vector state and future expansion.
        * This space is enough to store the vector context whose VLENB
        * is less or equal to 128.
        * (The size of the vector context is 4144 byte as VLENB is 128)
        */
       __u8 __reserved[4224] __attribute__((__aligned__(16)));
};
Quoted 13 lines
Quoted 13 lines
arch/riscv/include/uapi/asm/ptrace.h +2 -0
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_ASM_RISCV_PTRACE_H */
arch/riscv/kernel/asm-offsets.c +0 -0
index 90f8ce64fa6f..34f43c84723a 100644
@@ -72,6 +72,12 @@ void asm_offsets(void)
     OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
 #endif
 
Quoted 9 lines

arch/riscv/kernel/asm-offsets.c void asm_offsets(void) · line 83

Quoted 9 lines
arch/riscv/kernel/asm-offsets.c +6 -0
+     OFFSET(RISCV_V_STATE_VSTART, __riscv_v_state, vstart);
+     OFFSET(RISCV_V_STATE_VL, __riscv_v_state, vl);
+     OFFSET(RISCV_V_STATE_VTYPE, __riscv_v_state, vtype);
+     OFFSET(RISCV_V_STATE_VCSR, __riscv_v_state, vcsr);
+     OFFSET(RISCV_V_STATE_DATAP, __riscv_v_state, datap);
+
     DEFINE(PT_SIZE, sizeof(struct pt_regs));
     OFFSET(PT_EPC, pt_regs, epc);
     OFFSET(PT_RA, pt_regs, ra);

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv

#21 lore raw

PATCH v9 9/17 riscv: Add task switch support for vector

In reply to Greentime Hu

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]
[[email protected]: Optimize task switch codes of vector]

---
 arch/riscv/include/asm/switch_to.h | 65 ++++++++++++++++++++++++
 arch/riscv/kernel/Makefile         |  1 +
 arch/riscv/kernel/process.c        | 49 ++++++++++++++++++
 arch/riscv/kernel/vector.S         | 81 ++++++++++++++++++++++++++++++
 4 files changed, 196 insertions(+)
 create mode 100644 arch/riscv/kernel/vector.S
arch/riscv/include/asm/switch_to.h +65 -0
index ec83770b3d98..576204217e0f 100644
@@ -7,10 +7,12 @@
 #define _ASM_RISCV_SWITCH_TO_H
 
 #include <linux/jump_label.h>
+#include <linux/slab.h>
 #include <linux/sched/task_stack.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
 #ifdef CONFIG_FPU
 extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,67 @@ static __always_inline bool has_fpu(void) { return false; }
 #define __switch_to_fpu(__prev, __next) do { } while (0)
 #endif
 
+#ifdef CONFIG_VECTOR
+extern struct static_key_false cpu_hwcap_vector;
+static __always_inline bool has_vector(void)
+{
+	return static_branch_likely(&cpu_hwcap_vector);
+}
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+	regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+			      struct pt_regs *regs)
+{
+	regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+			       struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+		struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+		__vstate_save(vstate, vstate->datap);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void vstate_restore(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) != SR_VS_OFF) {
+		struct __riscv_v_state *vstate = &(task->thread.vstate);
+		__vstate_restore(vstate, vstate->datap);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+				   struct task_struct *next)
+{
+	struct pt_regs *regs;
+
+	regs = task_pt_regs(prev);
+	if (unlikely(regs->status & SR_SD))
+		vstate_save(prev, regs);
+	vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+static __always_inline bool has_vector(void) { return false; }
+#define riscv_vsize (0)
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
 extern struct task_struct *__switch_to(struct task_struct *,
 				       struct task_struct *);
 
@@ -77,6 +140,8 @@ do {							\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
 		__switch_to_fpu(__prev, __next);	\
+	if (has_vector())					\
+		__switch_to_vector(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
 obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o
 obj-$(CONFIG_FPU)		+= fpu.o
+obj-$(CONFIG_VECTOR)		+= vector.o
 obj-$(CONFIG_SMP)		+= smpboot.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SMP)		+= cpu_ops.o
arch/riscv/kernel/process.c +49 -0

70 lines not on this page · raw message

arch/riscv/kernel/vector.S new file +81 -0

81 lines not on this page · raw message

Signature · 1 line
2.31.1
#22 lore raw

Re: [PATCH v9 09/17] riscv: Add task switch support for vector

I love your patch! Yet something to improve:

Hi Greentime,

I love your patch! Yet something to improve:

[auto build test ERROR on v5.15]
[cannot apply to linus/master next-20211111]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Greentime-Hu/riscv-Add-vector-ISA-support/20211109-175222
base:   DEBUG invalid remote for branch v5.15 8bb7eca972ad531c9b149c0a51ab43a417385813
config: riscv-buildonly-randconfig-r002-20211111 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 63ef0e17e28827eae53133b3467bdac7d9729318)

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/0day-ci/linux/commit/93773de66911ee019c1fb31ae8e53a1221a540db
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Greentime-Hu/riscv-Add-vector-ISA-support/20211109-175222 git checkout 93773de66911ee019c1fb31ae8e53a1221a540db
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 ARCH=riscv

If you fix the issue, kindly add following tag as appropriate

All errors (new ones prefixed by >>):

>> arch/riscv/kernel/process.c:164:6: error: no previous prototype for function 'arch_release_task_struct' [-Werror,-Wmissing-prototypes]
   void arch_release_task_struct(struct task_struct *tsk)
        ^

arch/riscv/kernel/process.c:164:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void arch_release_task_struct(struct task_struct *tsk)
^
static
1 error generated.

vim +/arch_release_task_struct +164 arch/riscv/kernel/process.c

163

 > 164	void arch_release_task_struct(struct task_struct *tsk)

165 {
166 /* Free the vector context of datap. */
167 if (has_vector())
168 kfree(tsk->thread.vstate.datap);
169 }
170

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

#23 lore raw

Re: [PATCH v9 09/17] riscv: Add task switch support for vector

In reply to Greentime Hu
I love your patch! Perhaps something to improve:

Hi Greentime,

I love your patch! Perhaps something to improve:

[auto build test WARNING on v5.15]
[cannot apply to linus/master next-20211111]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Greentime-Hu/riscv-Add-vector-ISA-support/20211109-175222
base:   DEBUG invalid remote for branch v5.15 8bb7eca972ad531c9b149c0a51ab43a417385813
config: riscv-nommu_k210_defconfig (attached as .config)
compiler: riscv64-linux-gcc (GCC) 11.2.0

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/93773de66911ee019c1fb31ae8e53a1221a540db
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Greentime-Hu/riscv-Add-vector-ISA-support/20211109-175222 git checkout 93773de66911ee019c1fb31ae8e53a1221a540db
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross ARCH=riscv

If you fix the issue, kindly add following tag as appropriate

All warnings (new ones prefixed by >>):

>> arch/riscv/kernel/process.c:164:6: warning: no previous prototype for 'arch_release_task_struct' [-Wmissing-prototypes]

164 | void arch_release_task_struct(struct task_struct *tsk)
| ^~~~~~~~~~~~~~~~~~~~~~~~

vim +/arch_release_task_struct +164 arch/riscv/kernel/process.c

163

 > 164	void arch_release_task_struct(struct task_struct *tsk)

165 {
166 /* Free the vector context of datap. */
167 if (has_vector())
168 kfree(tsk->thread.vstate.datap);
169 }
170

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

maintainer
#24 lore raw

Re: [PATCH v9 09/17] riscv: Add task switch support for vector

In reply to Greentime Hu
Quoted 172 lines · On Tue, 09 Nov 2021 01:48:21 PST (-0800), [email protected] wrote:

This patch adds task switch support for vector. It supports partial lazy save and restore mechanism. It also supports all lengths of vlen.

[[email protected]: First available porting to support vector context switching]
[[email protected]: Rewrite vector.S to support dynamic vlen, xlen and code refine]
[[email protected]: Fix the might_sleep issue in vstate_save, vstate_restore]
[[email protected]: Optimize task switch codes of vector]

---
 arch/riscv/include/asm/switch_to.h | 65 ++++++++++++++++++++++++
 arch/riscv/kernel/Makefile         |  1 +
 arch/riscv/kernel/process.c        | 49 ++++++++++++++++++
 arch/riscv/kernel/vector.S         | 81 ++++++++++++++++++++++++++++++
 4 files changed, 196 insertions(+)
 create mode 100644 arch/riscv/kernel/vector.S
arch/riscv/include/asm/switch_to.h +65 -0
index ec83770b3d98..576204217e0f 100644
@@ -7,10 +7,12 @@
 #define _ASM_RISCV_SWITCH_TO_H
 
 #include <linux/jump_label.h>
+#include <linux/slab.h>
 #include <linux/sched/task_stack.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/csr.h>
+#include <asm/asm-offsets.h>
 
 #ifdef CONFIG_FPU
 extern void __fstate_save(struct task_struct *save_to);
@@ -68,6 +70,67 @@ static __always_inline bool has_fpu(void) { return false; }
 #define __switch_to_fpu(__prev, __next) do { } while (0)
 #endif
 
+#ifdef CONFIG_VECTOR
+extern struct static_key_false cpu_hwcap_vector;
+static __always_inline bool has_vector(void)
+{
+	return static_branch_likely(&cpu_hwcap_vector);
+}
+extern unsigned long riscv_vsize;
+extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
+extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+	regs->status = (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_off(struct task_struct *task,
+			      struct pt_regs *regs)
+{
+	regs->status = (regs->status & ~SR_VS) | SR_VS_OFF;
+}
+
+static inline void vstate_save(struct task_struct *task,
+			       struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+		struct __riscv_v_state *vstate = &(task->thread.vstate);
+
+		__vstate_save(vstate, vstate->datap);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void vstate_restore(struct task_struct *task,
+				  struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) != SR_VS_OFF) {
+		struct __riscv_v_state *vstate = &(task->thread.vstate);
+		__vstate_restore(vstate, vstate->datap);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+				   struct task_struct *next)
+{
+	struct pt_regs *regs;
+
+	regs = task_pt_regs(prev);
+	if (unlikely(regs->status & SR_SD))
+		vstate_save(prev, regs);
+	vstate_restore(next, task_pt_regs(next));
+}
+
+#else
+static __always_inline bool has_vector(void) { return false; }
+#define riscv_vsize (0)
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
 extern struct task_struct *__switch_to(struct task_struct *,
 				       struct task_struct *);
 
@@ -77,6 +140,8 @@ do {							\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
 		__switch_to_fpu(__prev, __next);	\
+	if (has_vector())					\
+		__switch_to_vector(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
 
arch/riscv/kernel/Makefile +1 -0
index 3397ddac1a30..344078080839 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
 obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o
 obj-$(CONFIG_FPU)		+= fpu.o
+obj-$(CONFIG_VECTOR)		+= vector.o
 obj-$(CONFIG_SMP)		+= smpboot.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SMP)		+= cpu_ops.o
arch/riscv/kernel/process.c +24 -0
index 03ac3aa611f5..62540815ba1c 100644
@@ -95,6 +95,25 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
 		 */
 		fstate_restore(current, regs);
 	}
+
+	if (has_vector()) {
+		struct __riscv_v_state *vstate = &(current->thread.vstate);
+
+		/* Enable vector and allocate memory for vector registers. */
+		if (!vstate->datap) {
+			vstate->datap = kzalloc(riscv_vsize, GFP_KERNEL);
+			if (WARN_ON(!vstate->datap))
+				return;
+		}
+		regs->status |= SR_VS_INITIAL;
+
+		/*
+		 * Restore the initial value to the vector register
+		 * before starting the user program.
+		 */
+		vstate_restore(current, regs);
+	}
+
 	regs->epc = pc;
 	regs->sp = sp;
 }
@@ -110,15 +129,45 @@ void flush_thread(void)
 	fstate_off(current, task_pt_regs(current));
 	memset(&current->thread.fstate, 0, sizeof(current->thread.fstate));
 #endif
+#ifdef CONFIG_VECTOR
+	/* Reset vector state and keep datap pointer. */
+	vstate_off(current, task_pt_regs(current));
+	memset(&current->thread.vstate, 0, RISCV_V_STATE_DATAP);
+	if (current->thread.vstate.datap)

arch/riscv/kernel/process.c void flush_thread(void) · line 146

Quoted 10 lines
arch/riscv/kernel/process.c +5 -0
+		memset(current->thread.vstate.datap, 0, riscv_vsize);
+#endif
 }
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	fstate_save(src, task_pt_regs(src));
+	if (has_vector())
+		/* To make sure every dirty vector context is saved. */
+		vstate_save(src, task_pt_regs(src));

Isn't the has_vector() check unnecessary? It looks to be thes ame as fstate_save(), where we can just rely in the internal check.

arch/riscv/kernel/process.c void flush_thread(void) · line 149

Quoted 3 lines
arch/riscv/kernel/process.c +2 -0
 	*dst = *src;
+	if (has_vector()) {
+		/* Copy vector context to the forked task from parent. */

Unless I'm missing something, this shouldn't be necessary: we got here via some syscall, and since those all follow the standard ABI the V registers have all been clobbered. Thus we should be able to just toss the vector state here. arm64 goes a step farther and explicitly tosses the SVE state on syscalls, which seems reasonable to me as that'd allow us to avoid some unnecessary save/restore overhead.

A few bits of the V state are defined with thread-duration storage, so we'd need to split those out to be saved (I guess we could define them as clobbered by syscalls, but that seems like the wrong way to go to me).

Quoted 111 lines
arch/riscv/kernel/process.c +18 -0
+		if ((task_pt_regs(src)->status & SR_VS) != SR_VS_OFF) {
+			dst->thread.vstate.datap = kzalloc(riscv_vsize, GFP_KERNEL);
+			/* Failed to allocate memory. */
+			if (!dst->thread.vstate.datap)
+				return -ENOMEM;
+			/* Copy the src vector context to dst. */
+			memcpy(dst->thread.vstate.datap,
+			       src->thread.vstate.datap, riscv_vsize);
+		}
+	}
+
 	return 0;
 }
 
+void arch_release_task_struct(struct task_struct *tsk)
+{
+	/* Free the vector context of datap. */
+	if (has_vector())
+		kfree(tsk->thread.vstate.datap);
+}
+
 int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
 		struct task_struct *p, unsigned long tls)
 {
arch/riscv/kernel/vector.S new file +81 -0
new file mode 100644
index 000000000000..7f3e3a838424
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2012 Regents of the University of California
+ * Copyright (C) 2017 SiFive
+ * Copyright (C) 2019 Alibaba Group Holding Limited
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm.h>
+#include <asm/csr.h>
+#include <asm/asm-offsets.h>
+
+#define vstatep  a0
+#define datap    a1
+#define x_vstart t0
+#define x_vtype  t1
+#define x_vl     t2
+#define x_vcsr   t3
+#define incr     t4
+#define status   t5
+
+ENTRY(__vstate_save)
+	li      status, SR_VS
+	csrs    sstatus, status
+
+	csrr    x_vstart, CSR_VSTART
+	csrr    x_vtype, CSR_VTYPE
+	csrr    x_vl, CSR_VL
+	csrr    x_vcsr, CSR_VCSR
+	vsetvli incr, x0, e8, m8
+	vse8.v   v0, (datap)
+	add     datap, datap, incr
+	vse8.v   v8, (datap)
+	add     datap, datap, incr
+	vse8.v   v16, (datap)
+	add     datap, datap, incr
+	vse8.v   v24, (datap)
+
+	REG_S   x_vstart, RISCV_V_STATE_VSTART(vstatep)
+	REG_S   x_vtype, RISCV_V_STATE_VTYPE(vstatep)
+	REG_S   x_vl, RISCV_V_STATE_VL(vstatep)
+	REG_S   x_vcsr, RISCV_V_STATE_VCSR(vstatep)
+
+	csrc	sstatus, status
+	ret
+ENDPROC(__vstate_save)
+
+ENTRY(__vstate_restore)
+	li      status, SR_VS
+	csrs    sstatus, status
+
+	vsetvli incr, x0, e8, m8
+	vle8.v   v0, (datap)
+	add     datap, datap, incr
+	vle8.v   v8, (datap)
+	add     datap, datap, incr
+	vle8.v   v16, (datap)
+	add     datap, datap, incr
+	vle8.v   v24, (datap)
+
+	REG_L   x_vstart, RISCV_V_STATE_VSTART(vstatep)
+	REG_L   x_vtype, RISCV_V_STATE_VTYPE(vstatep)
+	REG_L   x_vl, RISCV_V_STATE_VL(vstatep)
+	REG_L   x_vcsr, RISCV_V_STATE_VCSR(vstatep)
+	vsetvl  x0, x_vl, x_vtype
+	csrw    CSR_VSTART, x_vstart
+	csrw    CSR_VCSR, x_vcsr
+
+	csrc	sstatus, status
+	ret
+ENDPROC(__vstate_restore)
#25 lore raw

PATCH v9 10/17 riscv: Add ptrace vector support

In reply to Greentime Hu

This patch adds ptrace support for riscv vector. The vector registers will be saved in datap pointer of __riscv_v_state. This pointer will be set right after the __riscv_v_state data structure then it will be put in ubuf for ptrace system call to get or set. It will check if the datap got from ubuf is set to the correct address or not when the ptrace system call is trying to set the vector registers.

---
 arch/riscv/include/uapi/asm/ptrace.h | 14 ++++++
 arch/riscv/kernel/ptrace.c           | 71 ++++++++++++++++++++++++++++
 include/uapi/linux/elf.h             |  1 +
 3 files changed, 86 insertions(+)
arch/riscv/include/uapi/asm/ptrace.h +14 -0
index bd3b8a710246..c3760395236c 100644
@@ -83,11 +83,25 @@ struct __riscv_v_state {
 	unsigned long vtype;
 	unsigned long vcsr;
 	void *datap;
+	/*
+	 * In signal handler, datap will be set a correct user stack offset
+	 * and vector registers will be copied to the address of datap
+	 * pointer.
+	 *
+	 * In ptrace syscall, datap will be set to zero and the vector
+	 * registers will be copied to the address right after this
+	 * structure.
+	 */
 #if __riscv_xlen == 32
 	__u32 __padding;
 #endif
 };
 
+/*
+ * To define a practical maximum vlenb for ptrace and it may need to be
+ * extended someday.
+ */
+#define RISCV_MAX_VLENB (16384)
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_ASM_RISCV_PTRACE_H */
arch/riscv/kernel/ptrace.c +71 -0

89 lines not on this page · raw message

include/uapi/linux/elf.h +1 -0
index 61bf4774b8f2..60c5b873a8f6 100644
@@ -432,6 +432,7 @@ typedef struct elf64_shdr {
 #define NT_MIPS_DSP	0x800		/* MIPS DSP ASE registers */
 #define NT_MIPS_FP_MODE	0x801		/* MIPS floating-point mode */
 #define NT_MIPS_MSA	0x802		/* MIPS SIMD registers */
+#define NT_RISCV_VECTOR	0x900		/* RISC-V vector registers */
 
 /* Note types with note name "GNU" */
 #define NT_GNU_PROPERTY_TYPE_0	5
Signature · 1 line
2.31.1
#26 lore raw

PATCH v9 11/17 riscv: Add sigcontext save/restore for vector

In reply to Greentime Hu

This patch adds sigcontext save/restore for vector. The vector registers will be saved in datap pointer. The datap pointer will be allocated dynamically when the task needs in kernel space. The datap pointer will be set right after the __riscv_v_state data structure to save all the vector registers in the signal handler stack.

---
 arch/riscv/include/uapi/asm/sigcontext.h |  24 ++++
 arch/riscv/kernel/asm-offsets.c          |   2 +
 arch/riscv/kernel/setup.c                |   4 +
 arch/riscv/kernel/signal.c               | 165 ++++++++++++++++++++++-
 4 files changed, 191 insertions(+), 4 deletions(-)
arch/riscv/include/uapi/asm/sigcontext.h +24 -0
index 84f2dfcfdbce..b8a0fd7d7cfc 100644
@@ -8,6 +8,23 @@
 
 #include <asm/ptrace.h>
 
+/* The Magic number for signal context frame header. */
+#define RVV_MAGIC	0x53465457
+#define END_MAGIC	0x0
+
+/* The size of END signal context header. */
+#define END_HDR_SIZE	0x0
+
+struct __riscv_ctx_hdr {
+	__u32 magic;
+	__u32 size;
+};
+
+struct __sc_riscv_v_state {
+	struct __riscv_ctx_hdr head;
+	struct __riscv_v_state v_state;
+} __attribute__((aligned(16)));
+
 /*
  * Signal context structure
  *
@@ -17,6 +34,13 @@
 struct sigcontext {
 	struct user_regs_struct sc_regs;
 	union __riscv_fp_state sc_fpregs;
+	/*
+	 * 4K + 128 reserved for vector state and future expansion.
+	 * This space is enough to store the vector context whose VLENB
+	 * is less or equal to 128.
+	 * (The size of the vector context is 4144 byte as VLENB is 128)
+	 */
+	__u8 __reserved[4224] __attribute__((__aligned__(16)));
 };
 
 #endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */
arch/riscv/kernel/asm-offsets.c +2 -0
index 34f43c84723a..62a766d54540 100644
@@ -72,6 +72,8 @@ void asm_offsets(void)
 	OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
 #endif
 
+	OFFSET(RISCV_V_STATE_MAGIC, __riscv_ctx_hdr, magic);
+	OFFSET(RISCV_V_STATE_SIZE, __riscv_ctx_hdr, size);
 	OFFSET(RISCV_V_STATE_VSTART, __riscv_v_state, vstart);
 	OFFSET(RISCV_V_STATE_VL, __riscv_v_state, vl);
 	OFFSET(RISCV_V_STATE_VTYPE, __riscv_v_state, vtype);
arch/riscv/kernel/setup.c +4 -0
index b9620e5f00ba..f4f6c595e6db 100644
@@ -260,6 +260,8 @@ static void __init parse_dtb(void)
 #endif
 }
 
+extern void __init init_rt_signal_env(void);
+
 void __init setup_arch(char **cmdline_p)
 {
 	parse_dtb();
@@ -295,6 +297,8 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
 	riscv_fill_hwcap();
+
+	init_rt_signal_env();
 }
 
 static int __init topology_init(void)
arch/riscv/kernel/signal.c +161 -4

228 lines not on this page · raw message

Signature · 1 line
2.31.1
#27 lore raw

PATCH v9 12/17 riscv: signal: Report signal frame size to userspace via auxv

In reply to Greentime Hu

From: Vincent Chen <[email protected]>

The vector register belongs to the signal context. They need to be stored and restored as entering and leaving the signal handler. According to the V-extension specification, the maximum length of the vector registers can be 2^(XLEN-1). Hence, if userspace refers to the MINSIGSTKSZ to create a sigframe, it may not be enough. To resolve this problem, this patch refers to the commit 94b07c1f8c39c
("arm64: signal: Report signal frame size to userspace via auxv") to enable userspace to know the minimum required sigframe size through the auxiliary vector and use it to allocate enough memory for signal context.

---
 arch/riscv/include/asm/elf.h         | 41 +++++++++++++++++-----------
 arch/riscv/include/asm/processor.h   |  2 ++
 arch/riscv/include/uapi/asm/auxvec.h |  1 +
 arch/riscv/kernel/signal.c           |  8 ++++++
 4 files changed, 36 insertions(+), 16 deletions(-)
arch/riscv/include/asm/elf.h +25 -16
index f53c40026c7a..72e02a31a279 100644
@@ -61,22 +61,31 @@ extern unsigned long elf_hwcap;
 #define ELF_PLATFORM	(NULL)
 
 #ifdef CONFIG_MMU
-#define ARCH_DLINFO						\
-do {								\
-	NEW_AUX_ENT(AT_SYSINFO_EHDR,				\
-		(elf_addr_t)current->mm->context.vdso);		\
-	NEW_AUX_ENT(AT_L1I_CACHESIZE,				\
-		get_cache_size(1, CACHE_TYPE_INST));		\
-	NEW_AUX_ENT(AT_L1I_CACHEGEOMETRY,			\
-		get_cache_geometry(1, CACHE_TYPE_INST));	\
-	NEW_AUX_ENT(AT_L1D_CACHESIZE,				\
-		get_cache_size(1, CACHE_TYPE_DATA));		\
-	NEW_AUX_ENT(AT_L1D_CACHEGEOMETRY,			\
-		get_cache_geometry(1, CACHE_TYPE_DATA));	\
-	NEW_AUX_ENT(AT_L2_CACHESIZE,				\
-		get_cache_size(2, CACHE_TYPE_UNIFIED));		\
-	NEW_AUX_ENT(AT_L2_CACHEGEOMETRY,			\
-		get_cache_geometry(2, CACHE_TYPE_UNIFIED));	\
+#define ARCH_DLINFO						 \
+do {								 \
+	NEW_AUX_ENT(AT_SYSINFO_EHDR,				 \
+		(elf_addr_t)current->mm->context.vdso);		 \
+	NEW_AUX_ENT(AT_L1I_CACHESIZE,				 \
+		get_cache_size(1, CACHE_TYPE_INST));		 \
+	NEW_AUX_ENT(AT_L1I_CACHEGEOMETRY,			 \
+		get_cache_geometry(1, CACHE_TYPE_INST));	 \
+	NEW_AUX_ENT(AT_L1D_CACHESIZE,				 \
+		get_cache_size(1, CACHE_TYPE_DATA));		 \
+	NEW_AUX_ENT(AT_L1D_CACHEGEOMETRY,			 \
+		get_cache_geometry(1, CACHE_TYPE_DATA));	 \
+	NEW_AUX_ENT(AT_L2_CACHESIZE,				 \
+		get_cache_size(2, CACHE_TYPE_UNIFIED));		 \
+	NEW_AUX_ENT(AT_L2_CACHEGEOMETRY,			 \
+		get_cache_geometry(2, CACHE_TYPE_UNIFIED));	 \
+	/*							 \
+	 * Should always be nonzero unless there's a kernel bug. \
+	 * If we haven't determined a sensible value to give to	 \
+	 * userspace, omit the entry:				 \
+	 */							 \
+	if (likely(signal_minsigstksz))				 \
+		NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz); \
+	else							 \
+		NEW_AUX_ENT(AT_IGNORE, 0);			 \
 } while (0)
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
arch/riscv/include/asm/processor.h +2 -0
index a268f1382e52..e41e9d2b466c 100644
@@ -7,6 +7,7 @@
 #define _ASM_RISCV_PROCESSOR_H
 
 #include <linux/const.h>
+#include <linux/cache.h>
 
 #include <vdso/processor.h>
 
@@ -82,6 +83,7 @@ int riscv_of_parent_hartid(struct device_node *node);
 extern void riscv_fill_hwcap(void);
 extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 
+extern unsigned long signal_minsigstksz __ro_after_init;
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_RISCV_PROCESSOR_H */
arch/riscv/include/uapi/asm/auxvec.h +1 -0
index 32c73ba1d531..6610d24e6662 100644
@@ -33,5 +33,6 @@
 
 /* entries in ARCH_DLINFO */
 #define AT_VECTOR_SIZE_ARCH	7
+#define AT_MINSIGSTKSZ 51
 
 #endif /* _UAPI_ASM_RISCV_AUXVEC_H */
arch/riscv/kernel/signal.c +8 -0
index 6eb52890266e..ec6092987d82 100644
@@ -471,8 +471,16 @@ asmlinkage __visible void do_notify_resume(struct pt_regs *regs,
 		tracehook_notify_resume(regs);
 }
 
+unsigned long __ro_after_init signal_minsigstksz;
+
 void init_rt_signal_env(void);
 void __init init_rt_signal_env(void)
 {
 	rvv_sc_size = sizeof(struct __sc_riscv_v_state) + riscv_vsize;
+	/*
+	 * Determine the stack space required for guaranteed signal delivery.
+	 * The signal_minsigstksz will be populated into the AT_MINSIGSTKSZ entry
+	 * in the auxiliary array at process startup.
+	 */
+	signal_minsigstksz = cal_rt_frame_size();
 }
Signature · 1 line
2.31.1
#28 lore raw

PATCH v9 13/17 riscv: Add support for kernel mode vector

In reply to Greentime Hu

Add <asm/vector.h> containing kernel_rvv_begin()/kernel_rvv_end() function declarations and corresponding definitions in kernel_mode_vector.c

These are needed to wrap uses of vector in kernel mode.

---
 arch/riscv/include/asm/switch_to.h     |   1 +
 arch/riscv/include/asm/vector.h        |  14 +++
 arch/riscv/kernel/Makefile             |   1 +
 arch/riscv/kernel/kernel_mode_vector.c | 144 +++++++++++++++++++++++++
 arch/riscv/kernel/vector.S             |   9 ++
 5 files changed, 169 insertions(+)
 create mode 100644 arch/riscv/include/asm/vector.h
 create mode 100644 arch/riscv/kernel/kernel_mode_vector.c
arch/riscv/include/asm/switch_to.h +1 -0
index 576204217e0f..b02064a3effd 100644
@@ -79,6 +79,7 @@ static __always_inline bool has_vector(void)
 extern unsigned long riscv_vsize;
 extern void __vstate_save(struct __riscv_v_state *save_to, void *datap);
 extern void __vstate_restore(struct __riscv_v_state *restore_from, void *datap);
+void vector_flush_cpu_state(void);
 
 static inline void __vstate_clean(struct pt_regs *regs)
 {
arch/riscv/include/asm/vector.h new file +14 -0
new file mode 100644
index 000000000000..5d7f14453f68
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 SiFive
+ */
+
+#ifndef __ASM_RISCV_VECTOR_H
+#define __ASM_RISCV_VECTOR_H
+
+#include <linux/types.h>
+
+void kernel_rvv_begin(void);
+void kernel_rvv_end(void);
+
+#endif /* ! __ASM_RISCV_VECTOR_H */
arch/riscv/kernel/Makefile +1 -0
index 344078080839..8feda6312187 100644
@@ -41,6 +41,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o
 obj-$(CONFIG_FPU)		+= fpu.o
 obj-$(CONFIG_VECTOR)		+= vector.o
+obj-$(CONFIG_VECTOR)		+= kernel_mode_vector.o
 obj-$(CONFIG_SMP)		+= smpboot.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SMP)		+= cpu_ops.o
arch/riscv/kernel/kernel_mode_vector.c new file +144 -0

144 lines not on this page · raw message

arch/riscv/kernel/vector.S +9 -0
index 7f3e3a838424..a973532d2e7f 100644
@@ -79,3 +79,12 @@ ENTRY(__vstate_restore)
 	csrc	sstatus, status
 	ret
 ENDPROC(__vstate_restore)
+
+ENTRY(vector_flush_cpu_state)
+	vsetvli t0, x0, e8, m8
+	vmv.v.i v0, 0
+	vmv.v.i v8, 0
+	vmv.v.i v16, 0
+	vmv.v.i v24, 0
+	ret
+ENDPROC(vector_flush_cpu_state)
Signature · 1 line
2.31.1
#29 lore raw

PATCH v9 14/17 riscv: Use CSR_STATUS to replace sstatus in vector.S

In reply to Greentime Hu

It should use the same logic here in both m-mode and s-mode.

---
 arch/riscv/kernel/vector.S | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/riscv/kernel/vector.S +4 -4
index a973532d2e7f..1a79e2485bfa 100644
@@ -31,7 +31,7 @@
 
 ENTRY(__vstate_save)
 	li      status, SR_VS
-	csrs    sstatus, status
+	csrs    CSR_STATUS, status
 
 	csrr    x_vstart, CSR_VSTART
 	csrr    x_vtype, CSR_VTYPE
@@ -51,13 +51,13 @@ ENTRY(__vstate_save)
 	REG_S   x_vl, RISCV_V_STATE_VL(vstatep)
 	REG_S   x_vcsr, RISCV_V_STATE_VCSR(vstatep)
 
-	csrc	sstatus, status
+	csrc	CSR_STATUS, status
 	ret
 ENDPROC(__vstate_save)
 
 ENTRY(__vstate_restore)
 	li      status, SR_VS
-	csrs    sstatus, status
+	csrs    CSR_STATUS, status
 
 	vsetvli incr, x0, e8, m8
 	vle8.v   v0, (datap)
@@ -76,7 +76,7 @@ ENTRY(__vstate_restore)
 	csrw    CSR_VSTART, x_vstart
 	csrw    CSR_VCSR, x_vcsr
 
-	csrc	sstatus, status
+	csrc	CSR_STATUS, status
 	ret
 ENDPROC(__vstate_restore)
 
Signature · 1 line
2.31.1
#30 lore raw

PATCH v9 15/17 riscv: Add vector extension XOR implementation

In reply to Greentime Hu

This patch adds support for vector optimized XOR it is tested in spike and qemu.

Logs in spike:

[    0.008365] xor: measuring software checksum speed
[    0.048885]    8regs     :  1719.000 MB/sec
[    0.089080]    32regs    :  1717.000 MB/sec
[    0.129275]    rvv       :  7043.000 MB/sec
[    0.129525] xor: using function: rvv (7043.000 MB/sec)

Logs in qemu:

[    0.098943] xor: measuring software checksum speed
[    0.139391]    8regs     :  2911.000 MB/sec
[    0.181079]    32regs    :  2813.000 MB/sec
[    0.224260]    rvv       :    45.000 MB/sec
[    0.225586] xor: using function: 8regs (2911.000 MB/sec)
---
 arch/riscv/include/asm/xor.h | 66 +++++++++++++++++++++++++++++
 arch/riscv/lib/Makefile      |  1 +
 arch/riscv/lib/xor.S         | 81 ++++++++++++++++++++++++++++++++++++
 3 files changed, 148 insertions(+)
 create mode 100644 arch/riscv/include/asm/xor.h
 create mode 100644 arch/riscv/lib/xor.S
arch/riscv/include/asm/xor.h new file +66 -0
new file mode 100644
index 000000000000..5e86277364b5
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2021 SiFive
+ */
+
+#include <linux/hardirq.h>
+#include <asm-generic/xor.h>
+#ifdef CONFIG_VECTOR
+#include <asm/vector.h>
+#include <asm/switch_to.h>
+
+void xor_regs_2_(unsigned long bytes, unsigned long *p1, unsigned long *p2);
+void xor_regs_3_(unsigned long bytes, unsigned long *p1, unsigned long *p2, unsigned long *p3);
+void xor_regs_4_(unsigned long bytes, unsigned long *p1, unsigned long *p2, unsigned long *p3,
+		 unsigned long *p4);
+void xor_regs_5_(unsigned long bytes, unsigned long *p1, unsigned long *p2, unsigned long *p3,
+		 unsigned long *p4, unsigned long *p5);
+
+static void xor_rvv_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	kernel_rvv_begin();
+	xor_regs_2_(bytes, p1, p2);
+	kernel_rvv_end();
+}
+
+static void xor_rvv_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, unsigned long *p3)
+{
+	kernel_rvv_begin();
+	xor_regs_3_(bytes, p1, p2, p3);
+	kernel_rvv_end();
+}
+
+static void xor_rvv_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, unsigned long *p3,
+		      unsigned long *p4)
+{
+	kernel_rvv_begin();
+	xor_regs_4_(bytes, p1, p2, p3, p4);
+	kernel_rvv_end();
+}
+
+static void xor_rvv_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, unsigned long *p3,
+		      unsigned long *p4, unsigned long *p5)
+{
+	kernel_rvv_begin();
+	xor_regs_5_(bytes, p1, p2, p3, p4, p5);
+	kernel_rvv_end();
+}
+
+static struct xor_block_template xor_block_rvv = {
+	.name = "rvv",
+	.do_2 = xor_rvv_2,
+	.do_3 = xor_rvv_3,
+	.do_4 = xor_rvv_4,
+	.do_5 = xor_rvv_5
+};
+
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES           \
+	do {        \
+		xor_speed(&xor_block_8regs);    \
+		xor_speed(&xor_block_32regs);    \
+		if (has_vector()) { \
+			xor_speed(&xor_block_rvv);\
+		} \
+	} while (0)
+#endif
arch/riscv/lib/Makefile +1 -0
index 25d5c9664e57..acd87ac86d24 100644
@@ -7,3 +7,4 @@ lib-$(CONFIG_MMU)	+= uaccess.o
 lib-$(CONFIG_64BIT)	+= tishift.o
 
 obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
+lib-$(CONFIG_VECTOR)	+= xor.o
arch/riscv/lib/xor.S new file +81 -0

81 lines not on this page · raw message

Signature · 1 line
2.31.1
#31 lore raw

PATCH v9 16/17 riscv: Fix an illegal instruction exception when accessing vlenb without enable vector first

In reply to Greentime Hu

It triggered an illegal instruction exception when accessing vlenb CSR without enable vector first. To fix this issue, we should enable vector before using it and disable vector after using it.

---
 arch/riscv/include/asm/vector.h        | 2 ++
 arch/riscv/kernel/cpufeature.c         | 2 ++
 arch/riscv/kernel/kernel_mode_vector.c | 6 ++++--
 3 files changed, 8 insertions(+), 2 deletions(-)
arch/riscv/include/asm/vector.h +2 -0
index 5d7f14453f68..ca063c8f47f2 100644
@@ -8,6 +8,8 @@
 
 #include <linux/types.h>
 
+void rvv_enable(void);
+void rvv_disable(void);
 void kernel_rvv_begin(void);
 void kernel_rvv_end(void);
 
arch/riscv/kernel/cpufeature.c +2 -0
index 8e7557980faf..0139ec20adce 100644
@@ -159,7 +159,9 @@ void __init riscv_fill_hwcap(void)
 	if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
 		static_branch_enable(&cpu_hwcap_vector);
 		/* There are 32 vector registers with vlenb length. */
+		rvv_enable();
 		riscv_vsize = csr_read(CSR_VLENB) * 32;
+		rvv_disable();
 	}
 #endif
 }
arch/riscv/kernel/kernel_mode_vector.c +4 -2
index 8d2e53ea25c1..1ecb6ec5c56d 100644
@@ -71,15 +71,17 @@ static void put_cpu_vector_context(void)
 	preempt_enable();
 }
 
-static void rvv_enable(void)
+void rvv_enable(void)
 {
 	csr_set(CSR_STATUS, SR_VS);
 }
+EXPORT_SYMBOL(rvv_enable);
 
-static void rvv_disable(void)
+void rvv_disable(void)
 {
 	csr_clear(CSR_STATUS, SR_VS);
 }
+EXPORT_SYMBOL(rvv_disable);
 
 /*
  * kernel_rvv_begin(): obtain the CPU vector registers for use by the calling
Signature · 1 line
2.31.1
#32 lore raw

Re: [PATCH v9 16/17] riscv: Fix an illegal instruction exception when accessing vlenb without enable vector first

Quoted 31 lines · Greentime Hu

It triggered an illegal instruction exception when accessing vlenb CSR without enable vector first. To fix this issue, we should enable vector before using it and disable vector after using it.

---
  arch/riscv/include/asm/vector.h        | 2 ++
  arch/riscv/kernel/cpufeature.c         | 2 ++
  arch/riscv/kernel/kernel_mode_vector.c | 6 ++++--
  3 files changed, 8 insertions(+), 2 deletions(-)
arch/riscv/include/asm/vector.h +2 -0
index 5d7f14453f68..ca063c8f47f2 100644
@@ -8,6 +8,8 @@
 
  #include <linux/types.h>
 
+void rvv_enable(void);
+void rvv_disable(void);
  void kernel_rvv_begin(void);
  void kernel_rvv_end(void);
 
arch/riscv/kernel/cpufeature.c +0 -0
index 8e7557980faf..0139ec20adce 100644

arch/riscv/kernel/cpufeature.c void __init riscv_fill_hwcap(void) · line 166

Quoted 8 lines
arch/riscv/kernel/cpufeature.c +2 -0
@@ -159,7 +159,9 @@ void __init riscv_fill_hwcap(void)
  	if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
  		static_branch_enable(&cpu_hwcap_vector);
  		/* There are 32 vector registers with vlenb length. */
+		rvv_enable();
  		riscv_vsize = csr_read(CSR_VLENB) * 32;
+		rvv_disable();
  	}
  #endif

Would it be better to enable this here, and then restore the original state instead of calling rvv_disable? If it was enabled then maybe something else is going to rely on that state?

Maybe something like:

		prev = rvv_enable()
		riscv_vsize = csr_read(CSR_VLENB) * 32;
		rvv_restore(prev);
Quoted 26 lines
arch/riscv/kernel/cpufeature.c +0 -0
  }
arch/riscv/kernel/kernel_mode_vector.c +4 -2
index 8d2e53ea25c1..1ecb6ec5c56d 100644
@@ -71,15 +71,17 @@ static void put_cpu_vector_context(void)
  	preempt_enable();
  }
 
-static void rvv_enable(void)
+void rvv_enable(void)
  {
  	csr_set(CSR_STATUS, SR_VS);
  }
+EXPORT_SYMBOL(rvv_enable);
 
-static void rvv_disable(void)
+void rvv_disable(void)
  {
  	csr_clear(CSR_STATUS, SR_VS);
  }
+EXPORT_SYMBOL(rvv_disable);
 
  /*
   * kernel_rvv_begin(): obtain the CPU vector registers for use by the calling
Signature · 9 lines
Ben Dooks				http://www.codethink.co.uk/
Senior Engineer				Codethink - Providing Genius

https://www.codethink.co.uk/privacy.html

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv
#33 lore raw

Re: [PATCH v9 16/17] riscv: Fix an illegal instruction exception when accessing vlenb without enable vector first

Ben Dooks <[email protected]> 於 2021年11月10日 週三 下午6:38寫道:

Quoted 46 lines · Greentime Hu
Quoted 31 lines

It triggered an illegal instruction exception when accessing vlenb CSR without enable vector first. To fix this issue, we should enable vector before using it and disable vector after using it.

---
  arch/riscv/include/asm/vector.h        | 2 ++
  arch/riscv/kernel/cpufeature.c         | 2 ++
  arch/riscv/kernel/kernel_mode_vector.c | 6 ++++--
  3 files changed, 8 insertions(+), 2 deletions(-)
arch/riscv/include/asm/vector.h +2 -0
index 5d7f14453f68..ca063c8f47f2 100644
@@ -8,6 +8,8 @@
 
  #include <linux/types.h>
 
+void rvv_enable(void);
+void rvv_disable(void);
  void kernel_rvv_begin(void);
  void kernel_rvv_end(void);
 
arch/riscv/kernel/cpufeature.c +0 -0
index 8e7557980faf..0139ec20adce 100644

arch/riscv/kernel/cpufeature.c void __init riscv_fill_hwcap(void) · line 166

Quoted 8 lines
arch/riscv/kernel/cpufeature.c +2 -0
@@ -159,7 +159,9 @@ void __init riscv_fill_hwcap(void)
      if (elf_hwcap & COMPAT_HWCAP_ISA_V) {
              static_branch_enable(&cpu_hwcap_vector);
              /* There are 32 vector registers with vlenb length. */
+             rvv_enable();
              riscv_vsize = csr_read(CSR_VLENB) * 32;
+             rvv_disable();
      }
  #endif

Would it be better to enable this here, and then restore the original state instead of calling rvv_disable? If it was enabled then maybe something else is going to rely on that state?

Quoted 7 lines

Maybe something like:

                prev = rvv_enable()
                riscv_vsize = csr_read(CSR_VLENB) * 32;
                rvv_restore(prev);

Hi Ben,

Thank you for reviewing this. The rvv won't be enabled here because we disable it in head.S at beginning and this stage is still doing some initialization work for rvv to set riscv_vsize, so we can assume that kernel mode vector should not be allowed to use vector yet.

Quoted 33 lines
Quoted 16 lines
arch/riscv/kernel/cpufeature.c +0 -0
  }
arch/riscv/kernel/kernel_mode_vector.c +2 -1
index 8d2e53ea25c1..1ecb6ec5c56d 100644
@@ -71,15 +71,17 @@ static void put_cpu_vector_context(void)
      preempt_enable();
  }
 
-static void rvv_enable(void)
+void rvv_enable(void)
  {
      csr_set(CSR_STATUS, SR_VS);
  }
+EXPORT_SYMBOL(rvv_enable);

arch/riscv/kernel/kernel_mode_vector.c static void put_cpu_vector_context(void) · line 87

Quoted 10 lines
arch/riscv/kernel/kernel_mode_vector.c +2 -1
 
-static void rvv_disable(void)
+void rvv_disable(void)
  {
      csr_clear(CSR_STATUS, SR_VS);
  }
+EXPORT_SYMBOL(rvv_disable);
 
  /*
   * kernel_rvv_begin(): obtain the CPU vector registers for use by the calling

--
Ben Dooks http://www.codethink.co.uk/
Senior Engineer Codethink - Providing Genius

https://www.codethink.co.uk/privacy.html

#34 lore raw

PATCH v9 17/17 riscv: Fix a kernel panic issue if $s2 is set to a specific value before entering Linux

In reply to Greentime Hu

Panic log:

[    0.018707] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[    0.023060] Oops [#1]
[    0.023214] Modules linked in:
[    0.023725] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.14.0 #33
[    0.023955] Hardware name: SiFive,FU800 (DT)
[    0.024150] epc : __vstate_save+0x1c/0x48
[    0.024654]  ra : arch_dup_task_struct+0x70/0x108
[    0.024815] epc : ffffffff80005ad8 ra : ffffffff800035a8 sp : ffffffff81203d50
[    0.025020]  gp : ffffffff812e8290 tp : ffffffff8120bdc0 t0 : 0000000000000000
[    0.025216]  t1 : 0000000000000000 t2 : 0000000000000000 s0 : ffffffff81203d80
[    0.025424]  s1 : ffffffff8120bdc0 a0 : ffffffff8120c820 a1 : 0000000000000000
[    0.025659]  a2 : 0000000000001000 a3 : 0000000000000000 a4 : 0000000000000600
[    0.025869]  a5 : ffffffff8120cdc0 a6 : ffffffe00160b400 a7 : ffffffff80a1fe60
[    0.026069]  s2 : ffffffe0016b8000 s3 : ffffffff81204000 s4 : 0000000000004000
[    0.026267]  s5 : 0000000000000000 s6 : ffffffe0016b8000 s7 : ffffffe0016b9000
[    0.026475]  s8 : ffffffff81203ee0 s9 : 0000000000800300 s10: ffffffff812e9088
[    0.026689]  s11: ffffffd004008000 t3 : 0000000000000000 t4 : 0000000000000100
[    0.026900]  t5 : 0000000000000600 t6 : ffffffe00167bcc4
[    0.027057] status: 8000000000000720 badaddr: 0000000000000000 cause: 000000000000000f
[    0.027344] [<ffffffff80005ad8>] __vstate_save+0x1c/0x48
[    0.027567] [<ffffffff8000abe8>] copy_process+0x266/0x11a0
[    0.027739] [<ffffffff8000bc98>] kernel_clone+0x90/0x2aa
[    0.027915] [<ffffffff8000c062>] kernel_thread+0x76/0x92
[    0.028075] [<ffffffff8072e34c>] rest_init+0x26/0xfc
[    0.028242] [<ffffffff80800638>] arch_call_rest_init+0x10/0x18
[    0.028423] [<ffffffff80800c4a>] start_kernel+0x5ce/0x5fe
[    0.029188] ---[ end trace 9a59af33f7ba3df4 ]---
[    0.029479] Kernel panic - not syncing: Attempted to kill the idle task!
[    0.029907] ---[ end Kernel panic - not syncing: Attempted to kill the idle task! ]---

The NULL pointer accessing caused the kernel panic. There is a NULL pointer is because in vstate_save() function it will check (regs->status & SR_VS) == SR_VS_DIRTY and this is true, but it shouldn't be true because vector is not used here. Since vector is not used, datap won't be allocated so it is NULL. The reason why regs->status is set to a wrong value is because pt_regs->status is put in stack and it is polluted after setup_vm() called.

In prologue of setup_vm(), we can observe it will save s2 to stack however s2 is meaningless here because the caller is assembly code and s2 is just some value from previous stage. The compiler will base on calling convention to save the register to stack. Then 0x80008638 in s2 is saved to stack. It might be any value. In this failure case it is 0x80008638 and it will accidentally cause SR_VS_DIRTY to call the vstate_save() function.

(gdb) info addr setup_vm
Symbol "setup_vm" is a function at address 0xffffffff80802c8a. (gdb) va2pa 0xffffffff80802c8a
$64 = 0x80a02c8a
(gdb) x/10i 0x80a02c8a

   0x80a02c8a:  addi    sp,sp,-48
   0x80a02c8c:  li      a3,-1
   0x80a02c8e:  auipc   a5,0xff7fd
   0x80a02c92:  addi    a5,a5,882
   0x80a02c96:  sd      s0,32(sp)
   0x80a02c98:  sd      s2,16(sp) <-- store to stack

After returning from setup_vm()
(gdb) x/20i 0x0000000080201138

   0x80201138:  mv      a0,s1
   0x8020113a:  auipc   ra,0x802
   0x8020113e:  jalr    -1200(ra)    <-- jump to setup_vm()
   0x80201142:  auipc   a0,0xa03

(gdb) p/x $sp
$70 = 0x81404000
(gdb) p/x *(struct pt_regs*)($sp-0x120)
$71 = {
epc = 0x0,
ra = 0x0,
sp = 0x0,
gp = 0x0,
tp = 0x0,
t0 = 0x0,
t1 = 0x0,
t2 = 0x0,
s0 = 0x0,
s1 = 0x0,
a0 = 0x0,
a1 = 0x0,
a2 = 0x0,
a3 = 0x81403f90,
a4 = 0x80c04000,
a5 = 0x1,
a6 = 0xffffffff81337000,
a7 = 0x81096700,
s2 = 0x81400000,
s3 = 0xffffffff81200000,
s4 = 0x81403fd0,
s5 = 0x80a02c6c,
s6 = 0x8000000000006800,
s7 = 0x0,
s8 = 0xfffffffffffffff3,
s9 = 0x80c01000,
s10 = 0x81096700,
s11 = 0x82200000,
t3 = 0x81404000,
t4 = 0x80a02dea,
t5 = 0x0,
t6 = 0x82200000,
status = 0x80008638, <- Wrong value in stack!!!
badaddr = 0x82200000,
cause = 0x0,
orig_a0 = 0x80201142
}
(gdb) p/x $pc
$72 = 0x80201142
(gdb) p/x sizeof(struct pt_regs)
$73 = 0x120

---
 arch/riscv/kernel/head.S | 2 ++
 1 file changed, 2 insertions(+)
arch/riscv/kernel/head.S +2 -0
index 551afe1de85e..3f881a26527d 100644
@@ -303,6 +303,7 @@ clear_bss_done:
 	/* Initialize page tables and relocate to virtual addresses */
 	la sp, init_thread_union + THREAD_SIZE
 	XIP_FIXUP_OFFSET sp
+	addi sp, sp, -PT_SIZE
 #ifdef CONFIG_BUILTIN_DTB
 	la a0, __dtb_start
 #else
@@ -320,6 +321,7 @@ clear_bss_done:
 	la tp, init_task
 	sw zero, TASK_TI_CPU(tp)
 	la sp, init_thread_union + THREAD_SIZE
+	addi sp, sp, -PT_SIZE
 
 #ifdef CONFIG_KASAN
 	call kasan_early_init
Signature · 1 line
2.31.1