From d0f58642ca16724c4c05cc87ef51c9b04339236e Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Sun, 7 Apr 2024 19:01:30 +0800 Subject: [PATCH] riscv: vector: Fixup ptrace when sr_vs is off When sr_vs is off state, the kernel shouldn't simply return -EINVAL to the gdb request. Some vector regs' values may come from the parent. Change vr_get & vr_set to use a mechanism similar to the riscv_v_first_use_handler. Fixes: 9300f0043974 ("RISC-V: Add ptrace support for vectors") Signed-off-by: Guo Ren Signed-off-by: Guo Ren --- arch/riscv/include/asm/vector.h | 1 + arch/riscv/kernel/ptrace.c | 14 ++++++++++---- arch/riscv/kernel/vector.c | 10 +++++----- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h index d4dd29cf745a0..be9d84bf5facc 100644 --- a/arch/riscv/include/asm/vector.h +++ b/arch/riscv/include/asm/vector.h @@ -106,6 +106,7 @@ static inline void __riscv_m_mstate_restore(struct __riscv_m_ext_state *restore_ extern unsigned long riscv_v_vsize; int riscv_v_setup_vsize(void); bool riscv_v_first_use_handler(struct pt_regs *regs); +int riscv_v_thread_zalloc(struct task_struct *tsk); static __always_inline bool has_vector(void) { diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index 0735796f81e18..829ccca3b82fe 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -92,8 +92,11 @@ static int riscv_vr_get(struct task_struct *target, struct __riscv_v_ext_state *vstate = &target->thread.vstate; struct __riscv_v_regset_state ptrace_vstate; - if (!riscv_v_vstate_query(task_pt_regs(target))) - return -EINVAL; + if (!riscv_v_vstate_query(task_pt_regs(target))) { + if (riscv_v_thread_zalloc(target)) + return -EINVAL; + riscv_v_vstate_on(task_pt_regs(target)); + } /* * Ensure the vector registers have been saved to the memory before @@ -124,8 +127,11 @@ static int riscv_vr_set(struct task_struct *target, struct __riscv_v_ext_state *vstate = &target->thread.vstate; struct __riscv_v_regset_state ptrace_vstate; - if (!riscv_v_vstate_query(task_pt_regs(target))) - return -EINVAL; + if (!riscv_v_vstate_query(task_pt_regs(target))) { + if (riscv_v_thread_zalloc(target)) + return -EINVAL; + riscv_v_vstate_on(task_pt_regs(target)); + } /* Copy rest of the vstate except datap */ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ptrace_vstate, 0, diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c index 6e2d5d97f7468..7a6e166b8f1af 100644 --- a/arch/riscv/kernel/vector.c +++ b/arch/riscv/kernel/vector.c @@ -113,7 +113,7 @@ static bool insn_is_matrix(u32 insn_buf) return false; } -static int riscv_v_thread_zalloc(void) +int riscv_v_thread_zalloc(struct task_struct *tsk) { void *datap; @@ -121,9 +121,9 @@ static int riscv_v_thread_zalloc(void) if (!datap) return -ENOMEM; - current->thread.vstate.datap = datap; - memset(¤t->thread.vstate, 0, offsetof(struct __riscv_v_ext_state, - datap)); + tsk->thread.vstate.datap = datap; + memset(&tsk->thread.vstate, 0, offsetof(struct __riscv_v_ext_state, + datap)); return 0; } @@ -222,7 +222,7 @@ static bool __riscv_v_first_use_handler(struct pt_regs *regs) * context where VS has been off. So, try to allocate the user's V * context and resume execution. */ - if (riscv_v_thread_zalloc()) { + if (riscv_v_thread_zalloc(current)) { force_sig(SIGBUS); return true; }