Skip to content

Commit 3a2df63

Browse files
greentimepalmer-dabbelt
authored andcommitted
riscv: Add task switch support for vector
This patch adds task switch support for vector. It also supports all lengths of vlen. Suggested-by: Andrew Waterman <[email protected]> Co-developed-by: Nick Knight <[email protected]> Signed-off-by: Nick Knight <[email protected]> Co-developed-by: Guo Ren <[email protected]> Signed-off-by: Guo Ren <[email protected]> Co-developed-by: Vincent Chen <[email protected]> Signed-off-by: Vincent Chen <[email protected]> Co-developed-by: Ruinland Tsai <[email protected]> Signed-off-by: Ruinland Tsai <[email protected]> Signed-off-by: Greentime Hu <[email protected]> Signed-off-by: Vineet Gupta <[email protected]> Signed-off-by: Andy Chiu <[email protected]> Reviewed-by: Conor Dooley <[email protected]> Reviewed-by: Björn Töpel <[email protected]> Reviewed-by: Heiko Stuebner <[email protected]> Tested-by: Heiko Stuebner <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 03c3fcd commit 3a2df63

File tree

5 files changed

+64
-0
lines changed

5 files changed

+64
-0
lines changed

arch/riscv/include/asm/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct thread_struct {
3939
unsigned long s[12]; /* s[0]: frame pointer */
4040
struct __riscv_d_ext_state fstate;
4141
unsigned long bad_cause;
42+
struct __riscv_v_ext_state vstate;
4243
};
4344

4445
/* Whitelist the fstate from the task_struct for hardened usercopy */

arch/riscv/include/asm/switch_to.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/jump_label.h>
1010
#include <linux/sched/task_stack.h>
11+
#include <asm/vector.h>
1112
#include <asm/hwcap.h>
1213
#include <asm/processor.h>
1314
#include <asm/ptrace.h>
@@ -78,6 +79,8 @@ do { \
7879
struct task_struct *__next = (next); \
7980
if (has_fpu()) \
8081
__switch_to_fpu(__prev, __next); \
82+
if (has_vector()) \
83+
__switch_to_vector(__prev, __next); \
8184
((last) = __switch_to(__prev, __next)); \
8285
} while (0)
8386

arch/riscv/include/asm/thread_info.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ struct thread_info {
8181
.preempt_count = INIT_PREEMPT_COUNT, \
8282
}
8383

84+
void arch_release_task_struct(struct task_struct *tsk);
85+
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
86+
8487
#endif /* !__ASSEMBLY__ */
8588

8689
/*

arch/riscv/include/asm/vector.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#ifdef CONFIG_RISCV_ISA_V
1313

1414
#include <linux/stringify.h>
15+
#include <linux/sched.h>
16+
#include <linux/sched/task_stack.h>
17+
#include <asm/ptrace.h>
1518
#include <asm/hwcap.h>
1619
#include <asm/csr.h>
1720
#include <asm/asm.h>
@@ -124,6 +127,38 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
124127
riscv_v_disable();
125128
}
126129

130+
static inline void riscv_v_vstate_save(struct task_struct *task,
131+
struct pt_regs *regs)
132+
{
133+
if ((regs->status & SR_VS) == SR_VS_DIRTY) {
134+
struct __riscv_v_ext_state *vstate = &task->thread.vstate;
135+
136+
__riscv_v_vstate_save(vstate, vstate->datap);
137+
__riscv_v_vstate_clean(regs);
138+
}
139+
}
140+
141+
static inline void riscv_v_vstate_restore(struct task_struct *task,
142+
struct pt_regs *regs)
143+
{
144+
if ((regs->status & SR_VS) != SR_VS_OFF) {
145+
struct __riscv_v_ext_state *vstate = &task->thread.vstate;
146+
147+
__riscv_v_vstate_restore(vstate, vstate->datap);
148+
__riscv_v_vstate_clean(regs);
149+
}
150+
}
151+
152+
static inline void __switch_to_vector(struct task_struct *prev,
153+
struct task_struct *next)
154+
{
155+
struct pt_regs *regs;
156+
157+
regs = task_pt_regs(prev);
158+
riscv_v_vstate_save(prev, regs);
159+
riscv_v_vstate_restore(next, task_pt_regs(next));
160+
}
161+
127162
#else /* ! CONFIG_RISCV_ISA_V */
128163

129164
struct pt_regs;
@@ -132,6 +167,9 @@ static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
132167
static __always_inline bool has_vector(void) { return false; }
133168
static inline bool riscv_v_vstate_query(struct pt_regs *regs) { return false; }
134169
#define riscv_v_vsize (0)
170+
#define riscv_v_vstate_save(task, regs) do {} while (0)
171+
#define riscv_v_vstate_restore(task, regs) do {} while (0)
172+
#define __switch_to_vector(__prev, __next) do {} while (0)
135173
#define riscv_v_vstate_off(regs) do {} while (0)
136174
#define riscv_v_vstate_on(regs) do {} while (0)
137175

arch/riscv/kernel/process.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <asm/switch_to.h>
2525
#include <asm/thread_info.h>
2626
#include <asm/cpuidle.h>
27+
#include <asm/vector.h>
2728

2829
register unsigned long gp_in_global __asm__("gp");
2930

@@ -146,12 +147,28 @@ void flush_thread(void)
146147
fstate_off(current, task_pt_regs(current));
147148
memset(&current->thread.fstate, 0, sizeof(current->thread.fstate));
148149
#endif
150+
#ifdef CONFIG_RISCV_ISA_V
151+
/* Reset vector state */
152+
riscv_v_vstate_off(task_pt_regs(current));
153+
kfree(current->thread.vstate.datap);
154+
memset(&current->thread.vstate, 0, sizeof(struct __riscv_v_ext_state));
155+
#endif
156+
}
157+
158+
void arch_release_task_struct(struct task_struct *tsk)
159+
{
160+
/* Free the vector context of datap. */
161+
if (has_vector())
162+
kfree(tsk->thread.vstate.datap);
149163
}
150164

151165
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
152166
{
153167
fstate_save(src, task_pt_regs(src));
154168
*dst = *src;
169+
/* clear entire V context, including datap for a new task */
170+
memset(&dst->thread.vstate, 0, sizeof(struct __riscv_v_ext_state));
171+
155172
return 0;
156173
}
157174

@@ -176,6 +193,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
176193
p->thread.s[1] = (unsigned long)args->fn_arg;
177194
} else {
178195
*childregs = *(current_pt_regs());
196+
/* Turn off status.VS */
197+
riscv_v_vstate_off(childregs);
179198
if (usp) /* User fork */
180199
childregs->sp = usp;
181200
if (clone_flags & CLONE_SETTLS)

0 commit comments

Comments
 (0)