Unverified Commit 9300f004 authored by Andy Chiu's avatar Andy Chiu Committed by Palmer Dabbelt
Browse files

RISC-V: Add ptrace support for vectors



This patch add back the ptrace support with the following fix:
 - Define NT_RISCV_CSR and re-number NT_RISCV_VECTOR to prevent
   conflicting with gdb's NT_RISCV_CSR.
 - Use struct __riscv_v_regset_state to handle ptrace requests

Since gdb does not directly include the note description header in
Linux and has already defined NT_RISCV_CSR as 0x900, we decide to
sync with gdb and renumber NT_RISCV_VECTOR to solve and prevent future
conflicts.

Fixes: 0c59922c ("riscv: Add ptrace vector support")
Signed-off-by: default avatarAndy Chiu <andy.chiu@sifive.com>
Link: https://lore.kernel.org/r/20230825050248.32681-1-andy.chiu@sifive.com


[Palmer: Drop the unused "size" variable in riscv_vr_set().]
Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent c35f3aa3
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -103,13 +103,18 @@ struct __riscv_v_ext_state {
	 * In signal handler, datap will be set a correct user stack offset
	 * and vector registers will be copied to the address of datap
	 * pointer.
	 *
	 * In ptrace syscall, datap will be set to zero and the vector
	 * registers will be copied to the address right after this
	 * structure.
	 */
};

struct __riscv_v_regset_state {
	unsigned long vstart;
	unsigned long vl;
	unsigned long vtype;
	unsigned long vcsr;
	unsigned long vlenb;
	char vreg[];
};

/*
 * According to spec: The number of bits in a single vector register,
 * VLEN >= ELEN, which must be a power of 2, and must be no greater than
+79 −0
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ enum riscv_regset {
#ifdef CONFIG_FPU
	REGSET_F,
#endif
#ifdef CONFIG_RISCV_ISA_V
	REGSET_V,
#endif
};

static int riscv_gpr_get(struct task_struct *target,
@@ -81,6 +84,71 @@ static int riscv_fpr_set(struct task_struct *target,
}
#endif

#ifdef CONFIG_RISCV_ISA_V
static int riscv_vr_get(struct task_struct *target,
			const struct user_regset *regset,
			struct membuf to)
{
	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;

	/*
	 * Ensure the vector registers have been saved to the memory before
	 * copying them to membuf.
	 */
	if (target == current)
		riscv_v_vstate_save(current, task_pt_regs(current));

	ptrace_vstate.vstart = vstate->vstart;
	ptrace_vstate.vl = vstate->vl;
	ptrace_vstate.vtype = vstate->vtype;
	ptrace_vstate.vcsr = vstate->vcsr;
	ptrace_vstate.vlenb = vstate->vlenb;

	/* Copy vector header from vstate. */
	membuf_write(&to, &ptrace_vstate, sizeof(struct __riscv_v_regset_state));

	/* Copy all the vector registers from vstate. */
	return membuf_write(&to, vstate->datap, riscv_v_vsize);
}

static int riscv_vr_set(struct task_struct *target,
			const struct user_regset *regset,
			unsigned int pos, unsigned int count,
			const void *kbuf, const void __user *ubuf)
{
	int ret;
	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;

	/* Copy rest of the vstate except datap */
	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ptrace_vstate, 0,
				 sizeof(struct __riscv_v_regset_state));
	if (unlikely(ret))
		return ret;

	if (vstate->vlenb != ptrace_vstate.vlenb)
		return -EINVAL;

	vstate->vstart = ptrace_vstate.vstart;
	vstate->vl = ptrace_vstate.vl;
	vstate->vtype = ptrace_vstate.vtype;
	vstate->vcsr = ptrace_vstate.vcsr;

	/* Copy all the vector registers. */
	pos = 0;
	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vstate->datap,
				 0, riscv_v_vsize);
	return ret;
}
#endif

static const struct user_regset riscv_user_regset[] = {
	[REGSET_X] = {
		.core_note_type = NT_PRSTATUS,
@@ -100,6 +168,17 @@ static const struct user_regset riscv_user_regset[] = {
		.set = riscv_fpr_set,
	},
#endif
#ifdef CONFIG_RISCV_ISA_V
	[REGSET_V] = {
		.core_note_type = NT_RISCV_VECTOR,
		.align = 16,
		.n = ((32 * RISCV_MAX_VLENB) +
		      sizeof(struct __riscv_v_regset_state)) / sizeof(__u32),
		.size = sizeof(__u32),
		.regset_get = riscv_vr_get,
		.set = riscv_vr_set,
	},
#endif
};

static const struct user_regset_view riscv_user_native_view = {
+2 −0
Original line number Diff line number Diff line
@@ -443,6 +443,8 @@ typedef struct elf64_shdr {
#define NT_MIPS_DSP	0x800		/* MIPS DSP ASE registers */
#define NT_MIPS_FP_MODE	0x801		/* MIPS floating-point mode */
#define NT_MIPS_MSA	0x802		/* MIPS SIMD registers */
#define NT_RISCV_CSR	0x900		/* RISC-V Control and Status Registers */
#define NT_RISCV_VECTOR	0x901		/* RISC-V vector registers */
#define NT_LOONGARCH_CPUCFG	0xa00	/* LoongArch CPU config registers */
#define NT_LOONGARCH_CSR	0xa01	/* LoongArch control and status registers */
#define NT_LOONGARCH_LSX	0xa02	/* LoongArch Loongson SIMD Extension registers */