Skip to content

Commit

Permalink
riscv: vector: Fixup ptrace when sr_vs is off
Browse files Browse the repository at this point in the history
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: 9300f00 ("RISC-V: Add ptrace support for vectors")
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@kernel.org>
  • Loading branch information
guoren83 committed Apr 11, 2024
1 parent 1a080d0 commit 85dbf11
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 9 deletions.
1 change: 1 addition & 0 deletions arch/riscv/include/asm/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,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)
{
Expand Down
18 changes: 14 additions & 4 deletions arch/riscv/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,13 @@ 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));
if (target == current)
riscv_v_vstate_restore(current, task_pt_regs(current));
}

/*
* Ensure the vector registers have been saved to the memory before
Expand Down Expand Up @@ -124,8 +129,13 @@ 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));
if (target == current)
riscv_v_vstate_restore(current, task_pt_regs(current));
}

/* Copy rest of the vstate except datap */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ptrace_vstate, 0,
Expand Down
11 changes: 6 additions & 5 deletions arch/riscv/kernel/vector.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,18 @@ 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;

datap = kzalloc(riscv_v_vsize, GFP_KERNEL);
if (!datap)
return -ENOMEM;

current->thread.vstate.datap = datap;
memset(&current->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));
tsk->thread.vstate.vlenb = riscv_v_vsize/32;
return 0;
}

Expand Down Expand Up @@ -222,7 +223,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;
}
Expand Down

0 comments on commit 85dbf11

Please sign in to comment.