arm64/sve: ptrace and ELF coredump support
This patch defines and implements a new regset NT_ARM_SVE, which describes a thread's SVE register state. This allows a debugger to manipulate the SVE state, as well as being included in ELF coredumps for post-mortem debugging. Because the regset size and layout are dependent on the thread's current vector length, it is not possible to define a C struct to describe the regset contents as is done for existing regsets. Instead, and for the same reasons, NT_ARM_SVE is based on the freeform variable-layout approach used for the SVE signal frame. Additionally, to reduce debug overhead when debugging threads that might or might not have live SVE register state, NT_ARM_SVE may be presented in one of two different formats: the old struct user_fpsimd_state format is embedded for describing the state of a thread with no live SVE state, whereas a new variable-layout structure is embedded for describing live SVE state. This avoids a debugger needing to poll NT_PRFPREG in addition to NT_ARM_SVE, and allows existing userspace code to handle the non-SVE case without too much modification. For this to work, NT_ARM_SVE is defined with a fixed-format header of type struct user_sve_header, which the recipient can use to figure out the content, size and layout of the reset of the regset. Accessor macros are defined to allow the vector-length-dependent parts of the regset to be manipulated. Signed-off-by: Alan Hayward <alan.hayward@arm.com> Signed-off-by: Dave Martin <Dave.Martin@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Alex Bennée <alex.bennee@linaro.org> Cc: Okamoto Takayuki <tokamoto@jp.fujitsu.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
@@ -428,6 +428,66 @@ void sve_alloc(struct task_struct *task)
|
||||
BUG_ON(!task->thread.sve_state);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Ensure that task->thread.sve_state is up to date with respect to
|
||||
* the user task, irrespective of when SVE is in use or not.
|
||||
*
|
||||
* This should only be called by ptrace. task must be non-runnable.
|
||||
* task->thread.sve_state must point to at least sve_state_size(task)
|
||||
* bytes of allocated kernel memory.
|
||||
*/
|
||||
void fpsimd_sync_to_sve(struct task_struct *task)
|
||||
{
|
||||
if (!test_tsk_thread_flag(task, TIF_SVE))
|
||||
fpsimd_to_sve(task);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that task->thread.fpsimd_state is up to date with respect to
|
||||
* the user task, irrespective of whether SVE is in use or not.
|
||||
*
|
||||
* This should only be called by ptrace. task must be non-runnable.
|
||||
* task->thread.sve_state must point to at least sve_state_size(task)
|
||||
* bytes of allocated kernel memory.
|
||||
*/
|
||||
void sve_sync_to_fpsimd(struct task_struct *task)
|
||||
{
|
||||
if (test_tsk_thread_flag(task, TIF_SVE))
|
||||
sve_to_fpsimd(task);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that task->thread.sve_state is up to date with respect to
|
||||
* the task->thread.fpsimd_state.
|
||||
*
|
||||
* This should only be called by ptrace to merge new FPSIMD register
|
||||
* values into a task for which SVE is currently active.
|
||||
* task must be non-runnable.
|
||||
* task->thread.sve_state must point to at least sve_state_size(task)
|
||||
* bytes of allocated kernel memory.
|
||||
* task->thread.fpsimd_state must already have been initialised with
|
||||
* the new FPSIMD register values to be merged in.
|
||||
*/
|
||||
void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
|
||||
{
|
||||
unsigned int vq;
|
||||
void *sst = task->thread.sve_state;
|
||||
struct fpsimd_state const *fst = &task->thread.fpsimd_state;
|
||||
unsigned int i;
|
||||
|
||||
if (!test_tsk_thread_flag(task, TIF_SVE))
|
||||
return;
|
||||
|
||||
vq = sve_vq_from_vl(task->thread.sve_vl);
|
||||
|
||||
memset(sst, 0, SVE_SIG_REGS_SIZE(vq));
|
||||
|
||||
for (i = 0; i < 32; ++i)
|
||||
memcpy(ZREG(sst, vq, i), &fst->vregs[i],
|
||||
sizeof(fst->vregs[i]));
|
||||
}
|
||||
|
||||
int sve_set_vector_length(struct task_struct *task,
|
||||
unsigned long vl, unsigned long flags)
|
||||
{
|
||||
|
Reference in New Issue
Block a user