Commit 3a2df632 authored by Greentime Hu's avatar Greentime Hu Committed by Palmer Dabbelt

riscv: Add task switch support for vector

This patch adds task switch support for vector. It also supports all
lengths of vlen.
Suggested-by: default avatarAndrew Waterman <andrew@sifive.com>
Co-developed-by: default avatarNick Knight <nick.knight@sifive.com>
Signed-off-by: default avatarNick Knight <nick.knight@sifive.com>
Co-developed-by: default avatarGuo Ren <guoren@linux.alibaba.com>
Signed-off-by: default avatarGuo Ren <guoren@linux.alibaba.com>
Co-developed-by: default avatarVincent Chen <vincent.chen@sifive.com>
Signed-off-by: default avatarVincent Chen <vincent.chen@sifive.com>
Co-developed-by: default avatarRuinland Tsai <ruinland.tsai@sifive.com>
Signed-off-by: default avatarRuinland Tsai <ruinland.tsai@sifive.com>
Signed-off-by: default avatarGreentime Hu <greentime.hu@sifive.com>
Signed-off-by: default avatarVineet Gupta <vineetg@rivosinc.com>
Signed-off-by: default avatarAndy Chiu <andy.chiu@sifive.com>
Reviewed-by: default avatarConor Dooley <conor.dooley@microchip.com>
Reviewed-by: default avatarBjörn Töpel <bjorn@rivosinc.com>
Reviewed-by: default avatarHeiko Stuebner <heiko.stuebner@vrull.eu>
Tested-by: default avatarHeiko Stuebner <heiko.stuebner@vrull.eu>
Link: https://lore.kernel.org/r/20230605110724.21391-11-andy.chiu@sifive.comSigned-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent 03c3fcd9
...@@ -39,6 +39,7 @@ struct thread_struct { ...@@ -39,6 +39,7 @@ struct thread_struct {
unsigned long s[12]; /* s[0]: frame pointer */ unsigned long s[12]; /* s[0]: frame pointer */
struct __riscv_d_ext_state fstate; struct __riscv_d_ext_state fstate;
unsigned long bad_cause; unsigned long bad_cause;
struct __riscv_v_ext_state vstate;
}; };
/* Whitelist the fstate from the task_struct for hardened usercopy */ /* Whitelist the fstate from the task_struct for hardened usercopy */
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/jump_label.h> #include <linux/jump_label.h>
#include <linux/sched/task_stack.h> #include <linux/sched/task_stack.h>
#include <asm/vector.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
...@@ -78,6 +79,8 @@ do { \ ...@@ -78,6 +79,8 @@ do { \
struct task_struct *__next = (next); \ struct task_struct *__next = (next); \
if (has_fpu()) \ if (has_fpu()) \
__switch_to_fpu(__prev, __next); \ __switch_to_fpu(__prev, __next); \
if (has_vector()) \
__switch_to_vector(__prev, __next); \
((last) = __switch_to(__prev, __next)); \ ((last) = __switch_to(__prev, __next)); \
} while (0) } while (0)
......
...@@ -81,6 +81,9 @@ struct thread_info { ...@@ -81,6 +81,9 @@ struct thread_info {
.preempt_count = INIT_PREEMPT_COUNT, \ .preempt_count = INIT_PREEMPT_COUNT, \
} }
void arch_release_task_struct(struct task_struct *tsk);
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
/* /*
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#ifdef CONFIG_RISCV_ISA_V #ifdef CONFIG_RISCV_ISA_V
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <asm/ptrace.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include <asm/csr.h> #include <asm/csr.h>
#include <asm/asm.h> #include <asm/asm.h>
...@@ -124,6 +127,38 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_ ...@@ -124,6 +127,38 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
riscv_v_disable(); riscv_v_disable();
} }
static inline void riscv_v_vstate_save(struct task_struct *task,
struct pt_regs *regs)
{
if ((regs->status & SR_VS) == SR_VS_DIRTY) {
struct __riscv_v_ext_state *vstate = &task->thread.vstate;
__riscv_v_vstate_save(vstate, vstate->datap);
__riscv_v_vstate_clean(regs);
}
}
static inline void riscv_v_vstate_restore(struct task_struct *task,
struct pt_regs *regs)
{
if ((regs->status & SR_VS) != SR_VS_OFF) {
struct __riscv_v_ext_state *vstate = &task->thread.vstate;
__riscv_v_vstate_restore(vstate, vstate->datap);
__riscv_v_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);
riscv_v_vstate_save(prev, regs);
riscv_v_vstate_restore(next, task_pt_regs(next));
}
#else /* ! CONFIG_RISCV_ISA_V */ #else /* ! CONFIG_RISCV_ISA_V */
struct pt_regs; struct pt_regs;
...@@ -132,6 +167,9 @@ static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; } ...@@ -132,6 +167,9 @@ static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
static __always_inline bool has_vector(void) { return false; } static __always_inline bool has_vector(void) { return false; }
static inline bool riscv_v_vstate_query(struct pt_regs *regs) { return false; } static inline bool riscv_v_vstate_query(struct pt_regs *regs) { return false; }
#define riscv_v_vsize (0) #define riscv_v_vsize (0)
#define riscv_v_vstate_save(task, regs) do {} while (0)
#define riscv_v_vstate_restore(task, regs) do {} while (0)
#define __switch_to_vector(__prev, __next) do {} while (0)
#define riscv_v_vstate_off(regs) do {} while (0) #define riscv_v_vstate_off(regs) do {} while (0)
#define riscv_v_vstate_on(regs) do {} while (0) #define riscv_v_vstate_on(regs) do {} while (0)
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <asm/switch_to.h> #include <asm/switch_to.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/cpuidle.h> #include <asm/cpuidle.h>
#include <asm/vector.h>
register unsigned long gp_in_global __asm__("gp"); register unsigned long gp_in_global __asm__("gp");
...@@ -146,12 +147,28 @@ void flush_thread(void) ...@@ -146,12 +147,28 @@ void flush_thread(void)
fstate_off(current, task_pt_regs(current)); fstate_off(current, task_pt_regs(current));
memset(&current->thread.fstate, 0, sizeof(current->thread.fstate)); memset(&current->thread.fstate, 0, sizeof(current->thread.fstate));
#endif #endif
#ifdef CONFIG_RISCV_ISA_V
/* Reset vector state */
riscv_v_vstate_off(task_pt_regs(current));
kfree(current->thread.vstate.datap);
memset(&current->thread.vstate, 0, sizeof(struct __riscv_v_ext_state));
#endif
}
void arch_release_task_struct(struct task_struct *tsk)
{
/* Free the vector context of datap. */
if (has_vector())
kfree(tsk->thread.vstate.datap);
} }
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{ {
fstate_save(src, task_pt_regs(src)); fstate_save(src, task_pt_regs(src));
*dst = *src; *dst = *src;
/* clear entire V context, including datap for a new task */
memset(&dst->thread.vstate, 0, sizeof(struct __riscv_v_ext_state));
return 0; return 0;
} }
...@@ -176,6 +193,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) ...@@ -176,6 +193,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
p->thread.s[1] = (unsigned long)args->fn_arg; p->thread.s[1] = (unsigned long)args->fn_arg;
} else { } else {
*childregs = *(current_pt_regs()); *childregs = *(current_pt_regs());
/* Turn off status.VS */
riscv_v_vstate_off(childregs);
if (usp) /* User fork */ if (usp) /* User fork */
childregs->sp = usp; childregs->sp = usp;
if (clone_flags & CLONE_SETTLS) if (clone_flags & CLONE_SETTLS)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment