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 <andrew@sifive.com> Co-developed-by: Nick Knight <nick.knight@sifive.com> Signed-off-by: Nick Knight <nick.knight@sifive.com> Co-developed-by: Guo Ren <guoren@linux.alibaba.com> Signed-off-by: Guo Ren <guoren@linux.alibaba.com> Co-developed-by: Vincent Chen <vincent.chen@sifive.com> Signed-off-by: Vincent Chen <vincent.chen@sifive.com> Co-developed-by: Ruinland Tsai <ruinland.tsai@sifive.com> Signed-off-by: Ruinland Tsai <ruinland.tsai@sifive.com> Signed-off-by: Greentime Hu <greentime.hu@sifive.com> Signed-off-by: Vineet Gupta <vineetg@rivosinc.com> Signed-off-by: Andy Chiu <andy.chiu@sifive.com> Reviewed-by: Conor Dooley <conor.dooley@microchip.com> Reviewed-by: Björn Töpel <bjorn@rivosinc.com> Reviewed-by: Heiko Stuebner <heiko.stuebner@vrull.eu> Tested-by: Heiko Stuebner <heiko.stuebner@vrull.eu> Link: https://lore.kernel.org/r/20230605110724.21391-11-andy.chiu@sifive.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
This commit is contained in:
committed by
Palmer Dabbelt
parent
03c3fcd994
commit
3a2df6323d
@@ -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 @@
|
|||||||
|
|
||||||
#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 { \
|
|||||||
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 {
|
|||||||
.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 @@
|
|||||||
#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_
|
|||||||
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; }
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
fstate_off(current, task_pt_regs(current));
|
fstate_off(current, task_pt_regs(current));
|
||||||
memset(¤t->thread.fstate, 0, sizeof(current->thread.fstate));
|
memset(¤t->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(¤t->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)
|
|||||||
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)
|
||||||
|
Reference in New Issue
Block a user