2019-06-03 07:44:50 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2012-03-05 11:49:33 +00:00
/*
* Based on arch / arm / kernel / ptrace . c
*
* By Ross Biro 1 / 23 / 92
* edited by Linus Torvalds
* ARM modifications Copyright ( C ) 2000 Russell King
* Copyright ( C ) 2012 ARM Ltd .
*/
2014-07-04 08:28:31 +01:00
# include <linux/audit.h>
2014-04-30 10:51:32 +01:00
# include <linux/compat.h>
2012-03-05 11:49:33 +00:00
# include <linux/kernel.h>
2017-02-08 18:51:30 +01:00
# include <linux/sched/signal.h>
2017-02-08 18:51:37 +01:00
# include <linux/sched/task_stack.h>
2012-03-05 11:49:33 +00:00
# include <linux/mm.h>
2018-04-25 17:13:40 +01:00
# include <linux/nospec.h>
2012-03-05 11:49:33 +00:00
# include <linux/smp.h>
# include <linux/ptrace.h>
# include <linux/user.h>
2014-11-28 05:26:39 +00:00
# include <linux/seccomp.h>
2012-03-05 11:49:33 +00:00
# include <linux/security.h>
# include <linux/init.h>
# include <linux/signal.h>
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>
2017-10-31 15:51:13 +00:00
# include <linux/string.h>
2012-03-05 11:49:33 +00:00
# include <linux/uaccess.h>
# include <linux/perf_event.h>
# include <linux/hw_breakpoint.h>
# include <linux/regset.h>
# include <linux/elf.h>
# include <asm/compat.h>
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>
2017-10-31 15:51:13 +00:00
# include <asm/cpufeature.h>
2012-03-05 11:49:33 +00:00
# include <asm/debug-monitors.h>
2018-04-12 16:47:20 +01:00
# include <asm/fpsimd.h>
2020-03-30 10:29:38 +01:00
# include <asm/mte.h>
2018-12-07 18:39:26 +00:00
# include <asm/pointer_auth.h>
2017-07-20 12:26:48 +01:00
# include <asm/stacktrace.h>
2014-07-04 08:28:31 +01:00
# include <asm/syscall.h>
2012-03-05 11:49:33 +00:00
# include <asm/traps.h>
# include <asm/system_misc.h>
2014-04-30 10:54:36 +01:00
# define CREATE_TRACE_POINTS
# include <trace/events/syscalls.h>
2016-07-08 12:35:45 -04:00
struct pt_regs_offset {
const char * name ;
int offset ;
} ;
# define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
# define REG_OFFSET_END {.name = NULL, .offset = 0}
# define GPR_OFFSET_NAME(r) \
{ . name = " x " # r , . offset = offsetof ( struct pt_regs , regs [ r ] ) }
static const struct pt_regs_offset regoffset_table [ ] = {
GPR_OFFSET_NAME ( 0 ) ,
GPR_OFFSET_NAME ( 1 ) ,
GPR_OFFSET_NAME ( 2 ) ,
GPR_OFFSET_NAME ( 3 ) ,
GPR_OFFSET_NAME ( 4 ) ,
GPR_OFFSET_NAME ( 5 ) ,
GPR_OFFSET_NAME ( 6 ) ,
GPR_OFFSET_NAME ( 7 ) ,
GPR_OFFSET_NAME ( 8 ) ,
GPR_OFFSET_NAME ( 9 ) ,
GPR_OFFSET_NAME ( 10 ) ,
GPR_OFFSET_NAME ( 11 ) ,
GPR_OFFSET_NAME ( 12 ) ,
GPR_OFFSET_NAME ( 13 ) ,
GPR_OFFSET_NAME ( 14 ) ,
GPR_OFFSET_NAME ( 15 ) ,
GPR_OFFSET_NAME ( 16 ) ,
GPR_OFFSET_NAME ( 17 ) ,
GPR_OFFSET_NAME ( 18 ) ,
GPR_OFFSET_NAME ( 19 ) ,
GPR_OFFSET_NAME ( 20 ) ,
GPR_OFFSET_NAME ( 21 ) ,
GPR_OFFSET_NAME ( 22 ) ,
GPR_OFFSET_NAME ( 23 ) ,
GPR_OFFSET_NAME ( 24 ) ,
GPR_OFFSET_NAME ( 25 ) ,
GPR_OFFSET_NAME ( 26 ) ,
GPR_OFFSET_NAME ( 27 ) ,
GPR_OFFSET_NAME ( 28 ) ,
GPR_OFFSET_NAME ( 29 ) ,
GPR_OFFSET_NAME ( 30 ) ,
{ . name = " lr " , . offset = offsetof ( struct pt_regs , regs [ 30 ] ) } ,
REG_OFFSET_NAME ( sp ) ,
REG_OFFSET_NAME ( pc ) ,
REG_OFFSET_NAME ( pstate ) ,
REG_OFFSET_END ,
} ;
/**
* regs_query_register_offset ( ) - query register offset from its name
* @ name : the name of a register
*
* regs_query_register_offset ( ) returns the offset of a register in struct
* pt_regs from its name . If the name is invalid , this returns - EINVAL ;
*/
int regs_query_register_offset ( const char * name )
{
const struct pt_regs_offset * roff ;
for ( roff = regoffset_table ; roff - > name ! = NULL ; roff + + )
if ( ! strcmp ( roff - > name , name ) )
return roff - > offset ;
return - EINVAL ;
}
/**
* regs_within_kernel_stack ( ) - check the address in the stack
* @ regs : pt_regs which contains kernel stack pointer .
* @ addr : address which is checked .
*
* regs_within_kernel_stack ( ) checks @ addr is within the kernel stack page ( s ) .
* If @ addr is within the kernel stack , it returns true . If not , returns false .
*/
static bool regs_within_kernel_stack ( struct pt_regs * regs , unsigned long addr )
{
return ( ( addr & ~ ( THREAD_SIZE - 1 ) ) = =
( kernel_stack_pointer ( regs ) & ~ ( THREAD_SIZE - 1 ) ) ) | |
2022-09-01 14:06:43 +01:00
on_irq_stack ( addr , sizeof ( unsigned long ) ) ;
2016-07-08 12:35:45 -04:00
}
/**
* regs_get_kernel_stack_nth ( ) - get Nth entry of the stack
* @ regs : pt_regs which contains kernel stack pointer .
* @ n : stack entry number .
*
* regs_get_kernel_stack_nth ( ) returns @ n th entry of the kernel stack which
* is specified by @ regs . If the @ n th entry is NOT in the kernel stack ,
* this returns 0.
*/
unsigned long regs_get_kernel_stack_nth ( struct pt_regs * regs , unsigned int n )
{
unsigned long * addr = ( unsigned long * ) kernel_stack_pointer ( regs ) ;
addr + = n ;
if ( regs_within_kernel_stack ( regs , ( unsigned long ) addr ) )
return * addr ;
else
return 0 ;
}
2012-03-05 11:49:33 +00:00
/*
* TODO : does not yet catch signals sent when the child dies .
* in exit . c or in signal . c .
*/
/*
* Called by kernel / ptrace . c when detaching . .
*/
void ptrace_disable ( struct task_struct * child )
{
2015-12-07 11:50:34 +00:00
/*
* This would be better off in core code , but PTRACE_DETACH has
* grown its fair share of arch - specific worts and changing it
* is likely to cause regressions on obscure architectures .
*/
user_disable_single_step ( child ) ;
2012-03-05 11:49:33 +00:00
}
# ifdef CONFIG_HAVE_HW_BREAKPOINT
/*
* Handle hitting a HW - breakpoint .
*/
static void ptrace_hbptriggered ( struct perf_event * bp ,
struct perf_sample_data * data ,
struct pt_regs * regs )
{
struct arch_hw_breakpoint * bkpt = counter_arch_bp ( bp ) ;
2018-09-22 10:47:54 +02:00
const char * desc = " Hardware breakpoint trap (ptrace) " ;
2012-03-05 11:49:33 +00:00
# ifdef CONFIG_COMPAT
2018-01-22 14:50:53 -06:00
if ( is_compat_task ( ) ) {
2018-01-22 14:37:25 -06:00
int si_errno = 0 ;
2018-01-22 14:50:53 -06:00
int i ;
for ( i = 0 ; i < ARM_MAX_BRP ; + + i ) {
if ( current - > thread . debug . hbp_break [ i ] = = bp ) {
2018-01-22 14:37:25 -06:00
si_errno = ( i < < 1 ) + 1 ;
2018-01-22 14:50:53 -06:00
break ;
}
2012-03-05 11:49:33 +00:00
}
2014-08-22 14:13:24 +01:00
2018-01-22 14:50:53 -06:00
for ( i = 0 ; i < ARM_MAX_WRP ; + + i ) {
if ( current - > thread . debug . hbp_watch [ i ] = = bp ) {
2018-01-22 14:37:25 -06:00
si_errno = - ( ( i < < 1 ) + 1 ) ;
2018-01-22 14:50:53 -06:00
break ;
}
2012-03-05 11:49:33 +00:00
}
2020-11-20 12:33:46 -08:00
arm64_force_sig_ptrace_errno_trap ( si_errno , bkpt - > trigger ,
2018-09-22 10:52:41 +02:00
desc ) ;
2021-02-01 19:21:09 -05:00
return ;
2012-03-05 11:49:33 +00:00
}
# endif
2020-11-20 12:33:46 -08:00
arm64_force_sig_fault ( SIGTRAP , TRAP_HWBKPT , bkpt - > trigger , desc ) ;
2012-03-05 11:49:33 +00:00
}
/*
* Unregister breakpoints from this task and reset the pointers in
* the thread_struct .
*/
void flush_ptrace_hw_breakpoint ( struct task_struct * tsk )
{
int i ;
struct thread_struct * t = & tsk - > thread ;
for ( i = 0 ; i < ARM_MAX_BRP ; i + + ) {
if ( t - > debug . hbp_break [ i ] ) {
unregister_hw_breakpoint ( t - > debug . hbp_break [ i ] ) ;
t - > debug . hbp_break [ i ] = NULL ;
}
}
for ( i = 0 ; i < ARM_MAX_WRP ; i + + ) {
if ( t - > debug . hbp_watch [ i ] ) {
unregister_hw_breakpoint ( t - > debug . hbp_watch [ i ] ) ;
t - > debug . hbp_watch [ i ] = NULL ;
}
}
}
void ptrace_hw_copy_thread ( struct task_struct * tsk )
{
memset ( & tsk - > thread . debug , 0 , sizeof ( struct debug_info ) ) ;
}
static struct perf_event * ptrace_hbp_get_event ( unsigned int note_type ,
struct task_struct * tsk ,
unsigned long idx )
{
struct perf_event * bp = ERR_PTR ( - EINVAL ) ;
switch ( note_type ) {
case NT_ARM_HW_BREAK :
2018-04-25 17:13:40 +01:00
if ( idx > = ARM_MAX_BRP )
goto out ;
idx = array_index_nospec ( idx , ARM_MAX_BRP ) ;
bp = tsk - > thread . debug . hbp_break [ idx ] ;
2012-03-05 11:49:33 +00:00
break ;
case NT_ARM_HW_WATCH :
2018-04-25 17:13:40 +01:00
if ( idx > = ARM_MAX_WRP )
goto out ;
idx = array_index_nospec ( idx , ARM_MAX_WRP ) ;
bp = tsk - > thread . debug . hbp_watch [ idx ] ;
2012-03-05 11:49:33 +00:00
break ;
}
2018-04-25 17:13:40 +01:00
out :
2012-03-05 11:49:33 +00:00
return bp ;
}
static int ptrace_hbp_set_event ( unsigned int note_type ,
struct task_struct * tsk ,
unsigned long idx ,
struct perf_event * bp )
{
int err = - EINVAL ;
switch ( note_type ) {
case NT_ARM_HW_BREAK :
2018-07-10 19:01:22 +01:00
if ( idx > = ARM_MAX_BRP )
goto out ;
idx = array_index_nospec ( idx , ARM_MAX_BRP ) ;
tsk - > thread . debug . hbp_break [ idx ] = bp ;
err = 0 ;
2012-03-05 11:49:33 +00:00
break ;
case NT_ARM_HW_WATCH :
2018-07-10 19:01:22 +01:00
if ( idx > = ARM_MAX_WRP )
goto out ;
idx = array_index_nospec ( idx , ARM_MAX_WRP ) ;
tsk - > thread . debug . hbp_watch [ idx ] = bp ;
err = 0 ;
2012-03-05 11:49:33 +00:00
break ;
}
2018-07-10 19:01:22 +01:00
out :
2012-03-05 11:49:33 +00:00
return err ;
}
static struct perf_event * ptrace_hbp_create ( unsigned int note_type ,
struct task_struct * tsk ,
unsigned long idx )
{
struct perf_event * bp ;
struct perf_event_attr attr ;
int err , type ;
switch ( note_type ) {
case NT_ARM_HW_BREAK :
type = HW_BREAKPOINT_X ;
break ;
case NT_ARM_HW_WATCH :
type = HW_BREAKPOINT_RW ;
break ;
default :
return ERR_PTR ( - EINVAL ) ;
}
ptrace_breakpoint_init ( & attr ) ;
/*
* Initialise fields to sane defaults
* ( i . e . values that will pass validation ) .
*/
attr . bp_addr = 0 ;
attr . bp_len = HW_BREAKPOINT_LEN_4 ;
attr . bp_type = type ;
attr . disabled = 1 ;
bp = register_user_hw_breakpoint ( & attr , ptrace_hbptriggered , NULL , tsk ) ;
if ( IS_ERR ( bp ) )
return bp ;
err = ptrace_hbp_set_event ( note_type , tsk , idx , bp ) ;
if ( err )
return ERR_PTR ( err ) ;
return bp ;
}
static int ptrace_hbp_fill_attr_ctrl ( unsigned int note_type ,
struct arch_hw_breakpoint_ctrl ctrl ,
struct perf_event_attr * attr )
{
2016-11-14 19:32:43 +05:30
int err , len , type , offset , disabled = ! ctrl . enabled ;
2012-10-18 15:17:00 +01:00
2013-12-17 17:09:08 +00:00
attr - > disabled = disabled ;
if ( disabled )
return 0 ;
2016-11-14 19:32:43 +05:30
err = arch_bp_generic_fields ( ctrl , & len , & type , & offset ) ;
2013-12-17 17:09:08 +00:00
if ( err )
return err ;
switch ( note_type ) {
case NT_ARM_HW_BREAK :
if ( ( type & HW_BREAKPOINT_X ) ! = type )
2012-03-05 11:49:33 +00:00
return - EINVAL ;
2013-12-17 17:09:08 +00:00
break ;
case NT_ARM_HW_WATCH :
if ( ( type & HW_BREAKPOINT_RW ) ! = type )
return - EINVAL ;
break ;
default :
return - EINVAL ;
2012-03-05 11:49:33 +00:00
}
attr - > bp_len = len ;
attr - > bp_type = type ;
2016-11-14 19:32:43 +05:30
attr - > bp_addr + = offset ;
2012-03-05 11:49:33 +00:00
return 0 ;
}
static int ptrace_hbp_get_resource_info ( unsigned int note_type , u32 * info )
{
u8 num ;
u32 reg = 0 ;
switch ( note_type ) {
case NT_ARM_HW_BREAK :
num = hw_breakpoint_slots ( TYPE_INST ) ;
break ;
case NT_ARM_HW_WATCH :
num = hw_breakpoint_slots ( TYPE_DATA ) ;
break ;
default :
return - EINVAL ;
}
reg | = debug_monitors_arch ( ) ;
reg < < = 8 ;
reg | = num ;
* info = reg ;
return 0 ;
}
static int ptrace_hbp_get_ctrl ( unsigned int note_type ,
struct task_struct * tsk ,
unsigned long idx ,
u32 * ctrl )
{
struct perf_event * bp = ptrace_hbp_get_event ( note_type , tsk , idx ) ;
if ( IS_ERR ( bp ) )
return PTR_ERR ( bp ) ;
* ctrl = bp ? encode_ctrl_reg ( counter_arch_bp ( bp ) - > ctrl ) : 0 ;
return 0 ;
}
static int ptrace_hbp_get_addr ( unsigned int note_type ,
struct task_struct * tsk ,
unsigned long idx ,
u64 * addr )
{
struct perf_event * bp = ptrace_hbp_get_event ( note_type , tsk , idx ) ;
if ( IS_ERR ( bp ) )
return PTR_ERR ( bp ) ;
2016-11-14 19:32:43 +05:30
* addr = bp ? counter_arch_bp ( bp ) - > address : 0 ;
2012-03-05 11:49:33 +00:00
return 0 ;
}
static struct perf_event * ptrace_hbp_get_initialised_bp ( unsigned int note_type ,
struct task_struct * tsk ,
unsigned long idx )
{
struct perf_event * bp = ptrace_hbp_get_event ( note_type , tsk , idx ) ;
if ( ! bp )
bp = ptrace_hbp_create ( note_type , tsk , idx ) ;
return bp ;
}
static int ptrace_hbp_set_ctrl ( unsigned int note_type ,
struct task_struct * tsk ,
unsigned long idx ,
u32 uctrl )
{
int err ;
struct perf_event * bp ;
struct perf_event_attr attr ;
struct arch_hw_breakpoint_ctrl ctrl ;
bp = ptrace_hbp_get_initialised_bp ( note_type , tsk , idx ) ;
if ( IS_ERR ( bp ) ) {
err = PTR_ERR ( bp ) ;
return err ;
}
attr = bp - > attr ;
decode_ctrl_reg ( uctrl , & ctrl ) ;
err = ptrace_hbp_fill_attr_ctrl ( note_type , ctrl , & attr ) ;
if ( err )
return err ;
return modify_user_hw_breakpoint ( bp , & attr ) ;
}
static int ptrace_hbp_set_addr ( unsigned int note_type ,
struct task_struct * tsk ,
unsigned long idx ,
u64 addr )
{
int err ;
struct perf_event * bp ;
struct perf_event_attr attr ;
bp = ptrace_hbp_get_initialised_bp ( note_type , tsk , idx ) ;
if ( IS_ERR ( bp ) ) {
err = PTR_ERR ( bp ) ;
return err ;
}
attr = bp - > attr ;
attr . bp_addr = addr ;
err = modify_user_hw_breakpoint ( bp , & attr ) ;
return err ;
}
# define PTRACE_HBP_ADDR_SZ sizeof(u64)
# define PTRACE_HBP_CTRL_SZ sizeof(u32)
2012-10-11 12:10:57 +01:00
# define PTRACE_HBP_PAD_SZ sizeof(u32)
2012-03-05 11:49:33 +00:00
static int hw_break_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2012-03-05 11:49:33 +00:00
{
unsigned int note_type = regset - > core_note_type ;
2020-05-27 19:09:44 -04:00
int ret , idx = 0 ;
2012-03-05 11:49:33 +00:00
u32 info , ctrl ;
u64 addr ;
/* Resource info */
ret = ptrace_hbp_get_resource_info ( note_type , & info ) ;
if ( ret )
return ret ;
2020-05-27 19:09:44 -04:00
membuf_write ( & to , & info , sizeof ( info ) ) ;
membuf_zero ( & to , sizeof ( u32 ) ) ;
2012-03-05 11:49:33 +00:00
/* (address, ctrl) registers */
2020-05-27 19:09:44 -04:00
while ( to . left ) {
2012-03-05 11:49:33 +00:00
ret = ptrace_hbp_get_addr ( note_type , target , idx , & addr ) ;
if ( ret )
return ret ;
ret = ptrace_hbp_get_ctrl ( note_type , target , idx , & ctrl ) ;
if ( ret )
return ret ;
2020-05-27 19:09:44 -04:00
membuf_store ( & to , addr ) ;
membuf_store ( & to , ctrl ) ;
membuf_zero ( & to , sizeof ( u32 ) ) ;
2012-03-05 11:49:33 +00:00
idx + + ;
}
return 0 ;
}
static int hw_break_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
unsigned int note_type = regset - > core_note_type ;
2012-10-11 12:10:57 +01:00
int ret , idx = 0 , offset , limit ;
2012-03-05 11:49:33 +00:00
u32 ctrl ;
u64 addr ;
2012-10-11 12:10:57 +01:00
/* Resource info and pad */
offset = offsetof ( struct user_hwdebug_state , dbg_regs ) ;
2022-10-15 00:22:25 +03:00
user_regset_copyin_ignore ( & pos , & count , & kbuf , & ubuf , 0 , offset ) ;
2012-03-05 11:49:33 +00:00
/* (address, ctrl) registers */
limit = regset - > n * regset - > size ;
while ( count & & offset < limit ) {
2017-01-18 16:25:24 +00:00
if ( count < PTRACE_HBP_ADDR_SZ )
return - EINVAL ;
2012-03-05 11:49:33 +00:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & addr ,
offset , offset + PTRACE_HBP_ADDR_SZ ) ;
if ( ret )
return ret ;
ret = ptrace_hbp_set_addr ( note_type , target , idx , addr ) ;
if ( ret )
return ret ;
offset + = PTRACE_HBP_ADDR_SZ ;
2017-01-18 16:25:24 +00:00
if ( ! count )
break ;
2012-03-05 11:49:33 +00:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & ctrl ,
offset , offset + PTRACE_HBP_CTRL_SZ ) ;
if ( ret )
return ret ;
ret = ptrace_hbp_set_ctrl ( note_type , target , idx , ctrl ) ;
if ( ret )
return ret ;
offset + = PTRACE_HBP_CTRL_SZ ;
2012-10-11 12:10:57 +01:00
2022-10-15 00:22:25 +03:00
user_regset_copyin_ignore ( & pos , & count , & kbuf , & ubuf ,
offset , offset + PTRACE_HBP_PAD_SZ ) ;
2012-10-11 12:10:57 +01:00
offset + = PTRACE_HBP_PAD_SZ ;
2012-03-05 11:49:33 +00:00
idx + + ;
}
return 0 ;
}
# endif /* CONFIG_HAVE_HW_BREAKPOINT */
static int gpr_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2012-03-05 11:49:33 +00:00
{
struct user_pt_regs * uregs = & task_pt_regs ( target ) - > user_regs ;
2020-05-27 19:09:44 -04:00
return membuf_write ( & to , uregs , sizeof ( * uregs ) ) ;
2012-03-05 11:49:33 +00:00
}
static int gpr_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 ;
2017-01-18 16:25:20 +00:00
struct user_pt_regs newregs = task_pt_regs ( target ) - > user_regs ;
2012-03-05 11:49:33 +00:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & newregs , 0 , - 1 ) ;
if ( ret )
return ret ;
2016-03-01 14:18:50 +00:00
if ( ! valid_user_regs ( & newregs , target ) )
2012-03-05 11:49:33 +00:00
return - EINVAL ;
task_pt_regs ( target ) - > user_regs = newregs ;
return 0 ;
}
2020-01-13 23:30:21 +00:00
static int fpr_active ( struct task_struct * target , const struct user_regset * regset )
{
if ( ! system_supports_fpsimd ( ) )
return - ENODEV ;
return regset - > n ;
}
2012-03-05 11:49:33 +00:00
/*
* TODO : update fp accessors for lazy context switching ( sync / flush hwstate )
*/
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>
2017-10-31 15:51:13 +00:00
static int __fpr_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2012-03-05 11:49:33 +00:00
{
struct user_fpsimd_state * uregs ;
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>
2017-10-31 15:51:13 +00:00
sve_sync_to_fpsimd ( target ) ;
2018-03-28 10:50:49 +01:00
uregs = & target - > thread . uw . fpsimd_state ;
2017-06-21 16:00:43 +01:00
2020-05-27 19:09:44 -04:00
return membuf_write ( & to , uregs , sizeof ( * uregs ) ) ;
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>
2017-10-31 15:51:13 +00:00
}
static int fpr_get ( struct task_struct * target , const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
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>
2017-10-31 15:51:13 +00:00
{
2020-01-13 23:30:21 +00:00
if ( ! system_supports_fpsimd ( ) )
return - EINVAL ;
2017-06-21 16:00:43 +01:00
if ( target = = current )
fpsimd_preserve_current_state ( ) ;
2020-05-27 19:09:44 -04:00
return __fpr_get ( target , regset , to ) ;
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>
2017-10-31 15:51:13 +00:00
}
static int __fpr_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf ,
unsigned int start_pos )
{
int ret ;
struct user_fpsimd_state newstate ;
/*
2018-03-28 10:50:49 +01:00
* Ensure target - > thread . uw . fpsimd_state is up to date , so that a
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>
2017-10-31 15:51:13 +00:00
* short copyin can ' t resurrect stale data .
*/
sve_sync_to_fpsimd ( target ) ;
2018-03-28 10:50:49 +01:00
newstate = target - > thread . uw . fpsimd_state ;
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>
2017-10-31 15:51:13 +00:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & newstate ,
start_pos , start_pos + sizeof ( newstate ) ) ;
if ( ret )
return ret ;
2018-03-28 10:50:49 +01:00
target - > thread . uw . fpsimd_state = newstate ;
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>
2017-10-31 15:51:13 +00:00
return ret ;
2012-03-05 11:49:33 +00:00
}
static int fpr_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 ;
2020-01-13 23:30:21 +00:00
if ( ! system_supports_fpsimd ( ) )
return - EINVAL ;
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>
2017-10-31 15:51:13 +00:00
ret = __fpr_set ( target , regset , pos , count , kbuf , ubuf , 0 ) ;
2012-03-05 11:49:33 +00:00
if ( ret )
return ret ;
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>
2017-10-31 15:51:13 +00:00
sve_sync_from_fpsimd_zeropad ( target ) ;
2014-05-08 11:20:23 +02:00
fpsimd_flush_task_state ( target ) ;
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>
2017-10-31 15:51:13 +00:00
2012-03-05 11:49:33 +00:00
return ret ;
}
static int tls_get ( struct task_struct * target , const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2012-03-05 11:49:33 +00:00
{
2022-08-29 16:49:20 +01:00
int ret ;
2017-06-21 16:00:44 +01:00
if ( target = = current )
tls_preserve_current_state ( ) ;
2022-08-29 16:49:20 +01:00
ret = membuf_store ( & to , target - > thread . uw . tp_value ) ;
if ( system_supports_tpidr2 ( ) )
ret = membuf_store ( & to , target - > thread . tpidr2_el0 ) ;
else
ret = membuf_zero ( & to , sizeof ( u64 ) ) ;
return ret ;
2012-03-05 11:49:33 +00:00
}
static int tls_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 ;
2022-08-29 16:49:20 +01:00
unsigned long tls [ 2 ] ;
tls [ 0 ] = target - > thread . uw . tp_value ;
2022-12-27 13:01:08 +00:00
if ( system_supports_tpidr2 ( ) )
2022-08-29 16:49:20 +01:00
tls [ 1 ] = target - > thread . tpidr2_el0 ;
2012-03-05 11:49:33 +00:00
2022-08-29 16:49:20 +01:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , tls , 0 , count ) ;
2012-03-05 11:49:33 +00:00
if ( ret )
return ret ;
2022-08-29 16:49:20 +01:00
target - > thread . uw . tp_value = tls [ 0 ] ;
2022-12-27 13:01:08 +00:00
if ( system_supports_tpidr2 ( ) )
2022-08-29 16:49:20 +01:00
target - > thread . tpidr2_el0 = tls [ 1 ] ;
2012-03-05 11:49:33 +00:00
return ret ;
}
2014-11-28 05:26:34 +00:00
static int system_call_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2014-11-28 05:26:34 +00:00
{
2020-05-27 19:09:44 -04:00
return membuf_store ( & to , task_pt_regs ( target ) - > syscallno ) ;
2014-11-28 05:26:34 +00:00
}
static int system_call_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
2017-01-18 16:25:21 +00:00
int syscallno = task_pt_regs ( target ) - > syscallno ;
int ret ;
2014-11-28 05:26:34 +00:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & syscallno , 0 , - 1 ) ;
if ( ret )
return ret ;
task_pt_regs ( target ) - > syscallno = syscallno ;
return ret ;
}
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>
2017-10-31 15:51:13 +00:00
# ifdef CONFIG_ARM64_SVE
static void sve_init_header_from_task ( struct user_sve_header * header ,
2022-04-19 12:22:28 +01:00
struct task_struct * target ,
enum vec_type type )
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>
2017-10-31 15:51:13 +00:00
{
unsigned int vq ;
2022-04-19 12:22:28 +01:00
bool active ;
bool fpsimd_only ;
enum vec_type task_type ;
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>
2017-10-31 15:51:13 +00:00
memset ( header , 0 , sizeof ( * header ) ) ;
2022-04-19 12:22:28 +01:00
/* Check if the requested registers are active for the task */
if ( thread_sm_enabled ( & target - > thread ) )
task_type = ARM64_VEC_SME ;
else
task_type = ARM64_VEC_SVE ;
active = ( task_type = = type ) ;
switch ( type ) {
case ARM64_VEC_SVE :
if ( test_tsk_thread_flag ( target , TIF_SVE_VL_INHERIT ) )
header - > flags | = SVE_PT_VL_INHERIT ;
fpsimd_only = ! test_tsk_thread_flag ( target , TIF_SVE ) ;
break ;
case ARM64_VEC_SME :
if ( test_tsk_thread_flag ( target , TIF_SME_VL_INHERIT ) )
header - > flags | = SVE_PT_VL_INHERIT ;
fpsimd_only = false ;
break ;
default :
WARN_ON_ONCE ( 1 ) ;
return ;
}
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>
2017-10-31 15:51:13 +00:00
2022-04-19 12:22:28 +01:00
if ( active ) {
if ( fpsimd_only ) {
header - > flags | = SVE_PT_REGS_FPSIMD ;
} else {
header - > flags | = SVE_PT_REGS_SVE ;
}
}
header - > vl = task_get_vl ( target , type ) ;
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>
2017-10-31 15:51:13 +00:00
vq = sve_vq_from_vl ( header - > vl ) ;
2022-04-19 12:22:28 +01:00
header - > max_vl = vec_max_vl ( type ) ;
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>
2017-10-31 15:51:13 +00:00
header - > size = SVE_PT_SIZE ( vq , header - > flags ) ;
header - > max_size = SVE_PT_SIZE ( sve_vq_from_vl ( header - > max_vl ) ,
SVE_PT_REGS_SVE ) ;
}
static unsigned int sve_size_from_header ( struct user_sve_header const * header )
{
return ALIGN ( header - > size , SVE_VQ_BYTES ) ;
}
2022-04-19 12:22:28 +01:00
static int sve_get_common ( struct task_struct * target ,
const struct user_regset * regset ,
struct membuf to ,
enum vec_type type )
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>
2017-10-31 15:51:13 +00:00
{
struct user_sve_header header ;
unsigned int vq ;
unsigned long start , end ;
/* Header */
2022-04-19 12:22:28 +01:00
sve_init_header_from_task ( & header , target , type ) ;
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>
2017-10-31 15:51:13 +00:00
vq = sve_vq_from_vl ( header . vl ) ;
2020-05-27 19:09:44 -04:00
membuf_write ( & to , & header , sizeof ( header ) ) ;
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>
2017-10-31 15:51:13 +00:00
if ( target = = current )
fpsimd_preserve_current_state ( ) ;
BUILD_BUG_ON ( SVE_PT_FPSIMD_OFFSET ! = sizeof ( header ) ) ;
2022-04-19 12:22:28 +01:00
BUILD_BUG_ON ( SVE_PT_SVE_OFFSET ! = sizeof ( header ) ) ;
switch ( ( header . flags & SVE_PT_REGS_MASK ) ) {
case SVE_PT_REGS_FPSIMD :
2020-05-27 19:09:44 -04:00
return __fpr_get ( target , regset , to ) ;
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>
2017-10-31 15:51:13 +00:00
2022-04-19 12:22:28 +01:00
case SVE_PT_REGS_SVE :
start = SVE_PT_SVE_OFFSET ;
end = SVE_PT_SVE_FFR_OFFSET ( vq ) + SVE_PT_SVE_FFR_SIZE ( vq ) ;
membuf_write ( & to , target - > thread . sve_state , end - start ) ;
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>
2017-10-31 15:51:13 +00:00
2022-04-19 12:22:28 +01:00
start = end ;
end = SVE_PT_SVE_FPSR_OFFSET ( vq ) ;
membuf_zero ( & to , end - start ) ;
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>
2017-10-31 15:51:13 +00:00
2022-04-19 12:22:28 +01:00
/*
* Copy fpsr , and fpcr which must follow contiguously in
* struct fpsimd_state :
*/
start = end ;
end = SVE_PT_SVE_FPCR_OFFSET ( vq ) + SVE_PT_SVE_FPCR_SIZE ;
membuf_write ( & to , & target - > thread . uw . fpsimd_state . fpsr ,
end - start ) ;
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>
2017-10-31 15:51:13 +00:00
2022-04-19 12:22:28 +01:00
start = end ;
end = sve_size_from_header ( & header ) ;
return membuf_zero ( & to , end - start ) ;
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>
2017-10-31 15:51:13 +00:00
2022-04-19 12:22:28 +01:00
default :
return 0 ;
}
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>
2017-10-31 15:51:13 +00:00
}
2022-04-19 12:22:28 +01:00
static int sve_get ( struct task_struct * target ,
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>
2017-10-31 15:51:13 +00:00
const struct user_regset * regset ,
2022-04-19 12:22:28 +01:00
struct membuf to )
{
if ( ! system_supports_sve ( ) )
return - EINVAL ;
return sve_get_common ( target , regset , to , ARM64_VEC_SVE ) ;
}
static int sve_set_common ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf ,
enum vec_type type )
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>
2017-10-31 15:51:13 +00:00
{
int ret ;
struct user_sve_header header ;
unsigned int vq ;
unsigned long start , end ;
/* Header */
if ( count < sizeof ( header ) )
return - EINVAL ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & header ,
0 , sizeof ( header ) ) ;
if ( ret )
goto out ;
/*
2019-08-07 11:34:45 +01:00
* Apart from SVE_PT_REGS_MASK , all SVE_PT_ * flags are consumed by
2021-12-10 18:40:58 +00:00
* vec_set_vector_length ( ) , which will also validate them for us :
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>
2017-10-31 15:51:13 +00:00
*/
2022-04-19 12:22:28 +01:00
ret = vec_set_vector_length ( target , type , header . vl ,
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>
2017-10-31 15:51:13 +00:00
( ( unsigned long ) header . flags & ~ SVE_PT_REGS_MASK ) < < 16 ) ;
if ( ret )
goto out ;
/* Actual VL set may be less than the user asked for: */
2022-04-19 12:22:28 +01:00
vq = sve_vq_from_vl ( task_get_vl ( target , type ) ) ;
/* Enter/exit streaming mode */
if ( system_supports_sme ( ) ) {
u64 old_svcr = target - > thread . svcr ;
switch ( type ) {
case ARM64_VEC_SVE :
2022-05-10 17:12:01 +01:00
target - > thread . svcr & = ~ SVCR_SM_MASK ;
2022-04-19 12:22:28 +01:00
break ;
case ARM64_VEC_SME :
2022-05-10 17:12:01 +01:00
target - > thread . svcr | = SVCR_SM_MASK ;
2022-04-19 12:22:28 +01:00
break ;
default :
WARN_ON_ONCE ( 1 ) ;
return - EINVAL ;
}
/*
* If we switched then invalidate any existing SVE
* state and ensure there ' s storage .
*/
if ( target - > thread . svcr ! = old_svcr )
2022-08-17 19:23:23 +01:00
sve_alloc ( target , true ) ;
2022-04-19 12:22:28 +01:00
}
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>
2017-10-31 15:51:13 +00:00
/* Registers: FPSIMD-only case */
BUILD_BUG_ON ( SVE_PT_FPSIMD_OFFSET ! = sizeof ( header ) ) ;
if ( ( header . flags & SVE_PT_REGS_MASK ) = = SVE_PT_REGS_FPSIMD ) {
ret = __fpr_set ( target , regset , pos , count , kbuf , ubuf ,
SVE_PT_FPSIMD_OFFSET ) ;
clear_tsk_thread_flag ( target , TIF_SVE ) ;
2022-11-15 09:46:34 +00:00
target - > thread . fp_type = FP_STATE_FPSIMD ;
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>
2017-10-31 15:51:13 +00:00
goto out ;
}
2022-04-19 12:22:28 +01:00
/*
* Otherwise : no registers or full SVE case . For backwards
* compatibility reasons we treat empty flags as SVE registers .
*/
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>
2017-10-31 15:51:13 +00:00
/*
* If setting a different VL from the requested VL and there is
* register data , the data layout will be wrong : don ' t even
* try to set the registers in this case .
*/
if ( count & & vq ! = sve_vq_from_vl ( header . vl ) ) {
ret = - EIO ;
goto out ;
}
2022-08-17 19:23:23 +01:00
sve_alloc ( target , true ) ;
2021-08-24 16:34:17 +01:00
if ( ! target - > thread . sve_state ) {
ret = - ENOMEM ;
clear_tsk_thread_flag ( target , TIF_SVE ) ;
2022-11-15 09:46:34 +00:00
target - > thread . fp_type = FP_STATE_FPSIMD ;
2021-08-24 16:34:17 +01:00
goto out ;
}
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>
2017-10-31 15:51:13 +00:00
/*
* Ensure target - > thread . sve_state is up to date with target ' s
2022-04-19 12:22:28 +01:00
* FPSIMD regs , so that a short copyin leaves trailing
* registers unmodified . Always enable SVE even if going into
* streaming mode .
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>
2017-10-31 15:51:13 +00:00
*/
fpsimd_sync_to_sve ( target ) ;
set_tsk_thread_flag ( target , TIF_SVE ) ;
2022-11-15 09:46:34 +00:00
target - > thread . fp_type = FP_STATE_SVE ;
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>
2017-10-31 15:51:13 +00:00
BUILD_BUG_ON ( SVE_PT_SVE_OFFSET ! = sizeof ( header ) ) ;
start = SVE_PT_SVE_OFFSET ;
end = SVE_PT_SVE_FFR_OFFSET ( vq ) + SVE_PT_SVE_FFR_SIZE ( vq ) ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
target - > thread . sve_state ,
start , end ) ;
if ( ret )
goto out ;
start = end ;
end = SVE_PT_SVE_FPSR_OFFSET ( vq ) ;
2022-10-15 00:22:25 +03:00
user_regset_copyin_ignore ( & pos , & count , & kbuf , & ubuf , start , end ) ;
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>
2017-10-31 15:51:13 +00:00
/*
* Copy fpsr , and fpcr which must follow contiguously in
* struct fpsimd_state :
*/
start = end ;
end = SVE_PT_SVE_FPCR_OFFSET ( vq ) + SVE_PT_SVE_FPCR_SIZE ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
2018-03-28 10:50:49 +01:00
& target - > thread . uw . fpsimd_state . fpsr ,
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>
2017-10-31 15:51:13 +00:00
start , end ) ;
out :
fpsimd_flush_task_state ( target ) ;
return ret ;
}
2022-04-19 12:22:28 +01:00
static int sve_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
if ( ! system_supports_sve ( ) )
return - EINVAL ;
return sve_set_common ( target , regset , pos , count , kbuf , ubuf ,
ARM64_VEC_SVE ) ;
}
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>
2017-10-31 15:51:13 +00:00
# endif /* CONFIG_ARM64_SVE */
2022-04-19 12:22:28 +01:00
# ifdef CONFIG_ARM64_SME
static int ssve_get ( struct task_struct * target ,
const struct user_regset * regset ,
struct membuf to )
{
if ( ! system_supports_sme ( ) )
return - EINVAL ;
return sve_get_common ( target , regset , to , ARM64_VEC_SME ) ;
}
static int ssve_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
if ( ! system_supports_sme ( ) )
return - EINVAL ;
return sve_set_common ( target , regset , pos , count , kbuf , ubuf ,
ARM64_VEC_SME ) ;
}
2022-04-19 12:22:29 +01:00
static int za_get ( struct task_struct * target ,
const struct user_regset * regset ,
struct membuf to )
{
struct user_za_header header ;
unsigned int vq ;
unsigned long start , end ;
if ( ! system_supports_sme ( ) )
return - EINVAL ;
/* Header */
memset ( & header , 0 , sizeof ( header ) ) ;
if ( test_tsk_thread_flag ( target , TIF_SME_VL_INHERIT ) )
header . flags | = ZA_PT_VL_INHERIT ;
header . vl = task_get_sme_vl ( target ) ;
vq = sve_vq_from_vl ( header . vl ) ;
header . max_vl = sme_max_vl ( ) ;
header . max_size = ZA_PT_SIZE ( vq ) ;
/* If ZA is not active there is only the header */
if ( thread_za_enabled ( & target - > thread ) )
header . size = ZA_PT_SIZE ( vq ) ;
else
header . size = ZA_PT_ZA_OFFSET ;
membuf_write ( & to , & header , sizeof ( header ) ) ;
BUILD_BUG_ON ( ZA_PT_ZA_OFFSET ! = sizeof ( header ) ) ;
end = ZA_PT_ZA_OFFSET ;
if ( target = = current )
fpsimd_preserve_current_state ( ) ;
/* Any register data to include? */
if ( thread_za_enabled ( & target - > thread ) ) {
start = end ;
end = ZA_PT_SIZE ( vq ) ;
2023-01-16 16:04:36 +00:00
membuf_write ( & to , target - > thread . sme_state , end - start ) ;
2022-04-19 12:22:29 +01:00
}
/* Zero any trailing padding */
start = end ;
end = ALIGN ( header . size , SVE_VQ_BYTES ) ;
return membuf_zero ( & to , end - start ) ;
}
static int za_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 user_za_header header ;
unsigned int vq ;
unsigned long start , end ;
if ( ! system_supports_sme ( ) )
return - EINVAL ;
/* Header */
if ( count < sizeof ( header ) )
return - EINVAL ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & header ,
0 , sizeof ( header ) ) ;
if ( ret )
goto out ;
/*
* All current ZA_PT_ * flags are consumed by
* vec_set_vector_length ( ) , which will also validate them for
* us :
*/
ret = vec_set_vector_length ( target , ARM64_VEC_SME , header . vl ,
( ( unsigned long ) header . flags ) < < 16 ) ;
if ( ret )
goto out ;
/* Actual VL set may be less than the user asked for: */
vq = sve_vq_from_vl ( task_get_sme_vl ( target ) ) ;
/* Ensure there is some SVE storage for streaming mode */
if ( ! target - > thread . sve_state ) {
2022-08-17 19:23:23 +01:00
sve_alloc ( target , false ) ;
2022-04-19 12:22:29 +01:00
if ( ! target - > thread . sve_state ) {
ret = - ENOMEM ;
goto out ;
}
}
/* Allocate/reinit ZA storage */
sme_alloc ( target ) ;
2023-01-16 16:04:36 +00:00
if ( ! target - > thread . sme_state ) {
2022-04-19 12:22:29 +01:00
ret = - ENOMEM ;
goto out ;
}
/* If there is no data then disable ZA */
if ( ! count ) {
2022-05-10 17:12:01 +01:00
target - > thread . svcr & = ~ SVCR_ZA_MASK ;
2022-04-19 12:22:29 +01:00
goto out ;
}
/*
* If setting a different VL from the requested VL and there is
* register data , the data layout will be wrong : don ' t even
* try to set the registers in this case .
*/
if ( vq ! = sve_vq_from_vl ( header . vl ) ) {
ret = - EIO ;
goto out ;
}
BUILD_BUG_ON ( ZA_PT_ZA_OFFSET ! = sizeof ( header ) ) ;
start = ZA_PT_ZA_OFFSET ;
end = ZA_PT_SIZE ( vq ) ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
2023-01-16 16:04:36 +00:00
target - > thread . sme_state ,
2022-04-19 12:22:29 +01:00
start , end ) ;
if ( ret )
goto out ;
/* Mark ZA as active and let userspace use it */
set_tsk_thread_flag ( target , TIF_SME ) ;
2022-05-10 17:12:01 +01:00
target - > thread . svcr | = SVCR_ZA_MASK ;
2022-04-19 12:22:29 +01:00
out :
fpsimd_flush_task_state ( target ) ;
return ret ;
}
2023-01-16 16:04:47 +00:00
static int zt_get ( struct task_struct * target ,
const struct user_regset * regset ,
struct membuf to )
{
if ( ! system_supports_sme2 ( ) )
return - EINVAL ;
/*
* If PSTATE . ZA is not set then ZT will be zeroed when it is
* enabled so report the current register value as zero .
*/
if ( thread_za_enabled ( & target - > thread ) )
membuf_write ( & to , thread_zt_state ( & target - > thread ) ,
ZT_SIG_REG_BYTES ) ;
else
membuf_zero ( & to , ZT_SIG_REG_BYTES ) ;
return 0 ;
}
static int zt_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 ;
if ( ! system_supports_sme2 ( ) )
return - EINVAL ;
if ( ! thread_za_enabled ( & target - > thread ) ) {
sme_alloc ( target ) ;
if ( ! target - > thread . sme_state )
return - ENOMEM ;
}
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
thread_zt_state ( & target - > thread ) ,
0 , ZT_SIG_REG_BYTES ) ;
if ( ret = = 0 )
target - > thread . svcr | = SVCR_ZA_MASK ;
return ret ;
}
2022-04-19 12:22:28 +01:00
# endif /* CONFIG_ARM64_SME */
2018-12-07 18:39:26 +00:00
# ifdef CONFIG_ARM64_PTR_AUTH
static int pac_mask_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2018-12-07 18:39:26 +00:00
{
/*
* The PAC bits can differ across data and instruction pointers
* depending on TCR_EL1 . TBID * , which we may make use of in future , so
* we expose separate masks .
*/
unsigned long mask = ptrauth_user_pac_mask ( ) ;
struct user_pac_mask uregs = {
. data_mask = mask ,
. insn_mask = mask ,
} ;
if ( ! system_supports_address_auth ( ) )
return - EINVAL ;
2020-05-27 19:09:44 -04:00
return membuf_write ( & to , & uregs , sizeof ( uregs ) ) ;
2018-12-07 18:39:26 +00:00
}
2019-01-30 12:02:44 +00:00
2021-03-18 20:10:53 -07:00
static int pac_enabled_keys_get ( struct task_struct * target ,
const struct user_regset * regset ,
struct membuf to )
{
long enabled_keys = ptrauth_get_enabled_keys ( target ) ;
if ( IS_ERR_VALUE ( enabled_keys ) )
return enabled_keys ;
return membuf_write ( & to , & enabled_keys , sizeof ( enabled_keys ) ) ;
}
static int pac_enabled_keys_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 ;
long enabled_keys = ptrauth_get_enabled_keys ( target ) ;
if ( IS_ERR_VALUE ( enabled_keys ) )
return enabled_keys ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & enabled_keys , 0 ,
sizeof ( long ) ) ;
if ( ret )
return ret ;
return ptrauth_set_enabled_keys ( target , PR_PAC_ENABLED_KEYS_MASK ,
enabled_keys ) ;
}
2019-01-30 12:02:44 +00:00
# ifdef CONFIG_CHECKPOINT_RESTORE
static __uint128_t pac_key_to_user ( const struct ptrauth_key * key )
{
return ( __uint128_t ) key - > hi < < 64 | key - > lo ;
}
static struct ptrauth_key pac_key_from_user ( __uint128_t ukey )
{
struct ptrauth_key key = {
. lo = ( unsigned long ) ukey ,
. hi = ( unsigned long ) ( ukey > > 64 ) ,
} ;
return key ;
}
static void pac_address_keys_to_user ( struct user_pac_address_keys * ukeys ,
2020-03-13 14:34:50 +05:30
const struct ptrauth_keys_user * keys )
2019-01-30 12:02:44 +00:00
{
ukeys - > apiakey = pac_key_to_user ( & keys - > apia ) ;
ukeys - > apibkey = pac_key_to_user ( & keys - > apib ) ;
ukeys - > apdakey = pac_key_to_user ( & keys - > apda ) ;
ukeys - > apdbkey = pac_key_to_user ( & keys - > apdb ) ;
}
2020-03-13 14:34:50 +05:30
static void pac_address_keys_from_user ( struct ptrauth_keys_user * keys ,
2019-01-30 12:02:44 +00:00
const struct user_pac_address_keys * ukeys )
{
keys - > apia = pac_key_from_user ( ukeys - > apiakey ) ;
keys - > apib = pac_key_from_user ( ukeys - > apibkey ) ;
keys - > apda = pac_key_from_user ( ukeys - > apdakey ) ;
keys - > apdb = pac_key_from_user ( ukeys - > apdbkey ) ;
}
static int pac_address_keys_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2019-01-30 12:02:44 +00:00
{
2020-03-13 14:34:50 +05:30
struct ptrauth_keys_user * keys = & target - > thread . keys_user ;
2019-01-30 12:02:44 +00:00
struct user_pac_address_keys user_keys ;
if ( ! system_supports_address_auth ( ) )
return - EINVAL ;
pac_address_keys_to_user ( & user_keys , keys ) ;
2020-05-27 19:09:44 -04:00
return membuf_write ( & to , & user_keys , sizeof ( user_keys ) ) ;
2019-01-30 12:02:44 +00:00
}
static int pac_address_keys_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
2020-03-13 14:34:50 +05:30
struct ptrauth_keys_user * keys = & target - > thread . keys_user ;
2019-01-30 12:02:44 +00:00
struct user_pac_address_keys user_keys ;
int ret ;
if ( ! system_supports_address_auth ( ) )
return - EINVAL ;
pac_address_keys_to_user ( & user_keys , keys ) ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
& user_keys , 0 , - 1 ) ;
if ( ret )
return ret ;
pac_address_keys_from_user ( keys , & user_keys ) ;
return 0 ;
}
static void pac_generic_keys_to_user ( struct user_pac_generic_keys * ukeys ,
2020-03-13 14:34:50 +05:30
const struct ptrauth_keys_user * keys )
2019-01-30 12:02:44 +00:00
{
ukeys - > apgakey = pac_key_to_user ( & keys - > apga ) ;
}
2020-03-13 14:34:50 +05:30
static void pac_generic_keys_from_user ( struct ptrauth_keys_user * keys ,
2019-01-30 12:02:44 +00:00
const struct user_pac_generic_keys * ukeys )
{
keys - > apga = pac_key_from_user ( ukeys - > apgakey ) ;
}
static int pac_generic_keys_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2019-01-30 12:02:44 +00:00
{
2020-03-13 14:34:50 +05:30
struct ptrauth_keys_user * keys = & target - > thread . keys_user ;
2019-01-30 12:02:44 +00:00
struct user_pac_generic_keys user_keys ;
if ( ! system_supports_generic_auth ( ) )
return - EINVAL ;
pac_generic_keys_to_user ( & user_keys , keys ) ;
2020-05-27 19:09:44 -04:00
return membuf_write ( & to , & user_keys , sizeof ( user_keys ) ) ;
2019-01-30 12:02:44 +00:00
}
static int pac_generic_keys_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
2020-03-13 14:34:50 +05:30
struct ptrauth_keys_user * keys = & target - > thread . keys_user ;
2019-01-30 12:02:44 +00:00
struct user_pac_generic_keys user_keys ;
int ret ;
if ( ! system_supports_generic_auth ( ) )
return - EINVAL ;
pac_generic_keys_to_user ( & user_keys , keys ) ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf ,
& user_keys , 0 , - 1 ) ;
if ( ret )
return ret ;
pac_generic_keys_from_user ( keys , & user_keys ) ;
return 0 ;
}
# endif /* CONFIG_CHECKPOINT_RESTORE */
2018-12-07 18:39:26 +00:00
# endif /* CONFIG_ARM64_PTR_AUTH */
2020-07-03 15:12:57 +01:00
# ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
static int tagged_addr_ctrl_get ( struct task_struct * target ,
const struct user_regset * regset ,
struct membuf to )
{
long ctrl = get_tagged_addr_ctrl ( target ) ;
if ( IS_ERR_VALUE ( ctrl ) )
return ctrl ;
return membuf_write ( & to , & ctrl , sizeof ( ctrl ) ) ;
}
static int tagged_addr_ctrl_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 ;
long ctrl ;
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & ctrl , 0 , - 1 ) ;
if ( ret )
return ret ;
return set_tagged_addr_ctrl ( target , ctrl ) ;
}
# endif
2012-03-05 11:49:33 +00:00
enum aarch64_regset {
REGSET_GPR ,
REGSET_FPR ,
REGSET_TLS ,
# ifdef CONFIG_HAVE_HW_BREAKPOINT
REGSET_HW_BREAK ,
REGSET_HW_WATCH ,
# endif
2014-11-28 05:26:34 +00:00
REGSET_SYSTEM_CALL ,
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>
2017-10-31 15:51:13 +00:00
# ifdef CONFIG_ARM64_SVE
REGSET_SVE ,
# endif
2022-04-19 12:22:28 +01:00
# ifdef CONFIG_ARM64_SVE
REGSET_SSVE ,
2022-04-19 12:22:29 +01:00
REGSET_ZA ,
2023-01-16 16:04:47 +00:00
REGSET_ZT ,
2022-04-19 12:22:28 +01:00
# endif
2018-12-07 18:39:26 +00:00
# ifdef CONFIG_ARM64_PTR_AUTH
REGSET_PAC_MASK ,
2021-03-18 20:10:53 -07:00
REGSET_PAC_ENABLED_KEYS ,
2019-01-30 12:02:44 +00:00
# ifdef CONFIG_CHECKPOINT_RESTORE
REGSET_PACA_KEYS ,
REGSET_PACG_KEYS ,
# endif
2018-12-07 18:39:26 +00:00
# endif
2020-07-03 15:12:57 +01:00
# ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
REGSET_TAGGED_ADDR_CTRL ,
# endif
2012-03-05 11:49:33 +00:00
} ;
static const struct user_regset aarch64_regsets [ ] = {
[ REGSET_GPR ] = {
. core_note_type = NT_PRSTATUS ,
. n = sizeof ( struct user_pt_regs ) / sizeof ( u64 ) ,
. size = sizeof ( u64 ) ,
. align = sizeof ( u64 ) ,
2020-05-27 19:09:44 -04:00
. regset_get = gpr_get ,
2012-03-05 11:49:33 +00:00
. set = gpr_set
} ,
[ REGSET_FPR ] = {
. core_note_type = NT_PRFPREG ,
. n = sizeof ( struct user_fpsimd_state ) / sizeof ( u32 ) ,
/*
* We pretend we have 32 - bit registers because the fpsr and
* fpcr are 32 - bits wide .
*/
. size = sizeof ( u32 ) ,
. align = sizeof ( u32 ) ,
2020-01-13 23:30:21 +00:00
. active = fpr_active ,
2020-05-27 19:09:44 -04:00
. regset_get = fpr_get ,
2012-03-05 11:49:33 +00:00
. set = fpr_set
} ,
[ REGSET_TLS ] = {
. core_note_type = NT_ARM_TLS ,
2022-08-29 16:49:20 +01:00
. n = 2 ,
2012-03-05 11:49:33 +00:00
. size = sizeof ( void * ) ,
. align = sizeof ( void * ) ,
2020-05-27 19:09:44 -04:00
. regset_get = tls_get ,
2012-03-05 11:49:33 +00:00
. set = tls_set ,
} ,
# ifdef CONFIG_HAVE_HW_BREAKPOINT
[ REGSET_HW_BREAK ] = {
. core_note_type = NT_ARM_HW_BREAK ,
. n = sizeof ( struct user_hwdebug_state ) / sizeof ( u32 ) ,
. size = sizeof ( u32 ) ,
. align = sizeof ( u32 ) ,
2020-05-27 19:09:44 -04:00
. regset_get = hw_break_get ,
2012-03-05 11:49:33 +00:00
. set = hw_break_set ,
} ,
[ REGSET_HW_WATCH ] = {
. core_note_type = NT_ARM_HW_WATCH ,
. n = sizeof ( struct user_hwdebug_state ) / sizeof ( u32 ) ,
. size = sizeof ( u32 ) ,
. align = sizeof ( u32 ) ,
2020-05-27 19:09:44 -04:00
. regset_get = hw_break_get ,
2012-03-05 11:49:33 +00:00
. set = hw_break_set ,
} ,
# endif
2014-11-28 05:26:34 +00:00
[ REGSET_SYSTEM_CALL ] = {
. core_note_type = NT_ARM_SYSTEM_CALL ,
. n = 1 ,
. size = sizeof ( int ) ,
. align = sizeof ( int ) ,
2020-05-27 19:09:44 -04:00
. regset_get = system_call_get ,
2014-11-28 05:26:34 +00:00
. set = system_call_set ,
} ,
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>
2017-10-31 15:51:13 +00:00
# ifdef CONFIG_ARM64_SVE
[ REGSET_SVE ] = { /* Scalable Vector Extension */
. core_note_type = NT_ARM_SVE ,
. n = DIV_ROUND_UP ( SVE_PT_SIZE ( SVE_VQ_MAX , SVE_PT_REGS_SVE ) ,
SVE_VQ_BYTES ) ,
. size = SVE_VQ_BYTES ,
. align = SVE_VQ_BYTES ,
2020-05-27 19:09:44 -04:00
. regset_get = sve_get ,
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>
2017-10-31 15:51:13 +00:00
. set = sve_set ,
} ,
# endif
2022-04-19 12:22:28 +01:00
# ifdef CONFIG_ARM64_SME
[ REGSET_SSVE ] = { /* Streaming mode SVE */
. core_note_type = NT_ARM_SSVE ,
2022-05-05 23:15:17 +01:00
. n = DIV_ROUND_UP ( SVE_PT_SIZE ( SME_VQ_MAX , SVE_PT_REGS_SVE ) ,
2022-04-19 12:22:28 +01:00
SVE_VQ_BYTES ) ,
. size = SVE_VQ_BYTES ,
. align = SVE_VQ_BYTES ,
. regset_get = ssve_get ,
. set = ssve_set ,
} ,
2022-04-19 12:22:29 +01:00
[ REGSET_ZA ] = { /* SME ZA */
. core_note_type = NT_ARM_ZA ,
2022-05-05 23:15:17 +01:00
/*
* ZA is a single register but it ' s variably sized and
* the ptrace core requires that the size of any data
* be an exact multiple of the configured register
* size so report as though we had SVE_VQ_BYTES
* registers . These values aren ' t exposed to
* userspace .
*/
. n = DIV_ROUND_UP ( ZA_PT_SIZE ( SME_VQ_MAX ) , SVE_VQ_BYTES ) ,
2022-04-19 12:22:29 +01:00
. size = SVE_VQ_BYTES ,
. align = SVE_VQ_BYTES ,
. regset_get = za_get ,
. set = za_set ,
} ,
2023-01-16 16:04:47 +00:00
[ REGSET_ZT ] = { /* SME ZT */
. core_note_type = NT_ARM_ZT ,
. n = 1 ,
. size = ZT_SIG_REG_BYTES ,
. align = sizeof ( u64 ) ,
. regset_get = zt_get ,
. set = zt_set ,
} ,
2022-04-19 12:22:28 +01:00
# endif
2018-12-07 18:39:26 +00:00
# ifdef CONFIG_ARM64_PTR_AUTH
[ REGSET_PAC_MASK ] = {
. core_note_type = NT_ARM_PAC_MASK ,
. n = sizeof ( struct user_pac_mask ) / sizeof ( u64 ) ,
. size = sizeof ( u64 ) ,
. align = sizeof ( u64 ) ,
2020-05-27 19:09:44 -04:00
. regset_get = pac_mask_get ,
2018-12-07 18:39:26 +00:00
/* this cannot be set dynamically */
} ,
2021-03-18 20:10:53 -07:00
[ REGSET_PAC_ENABLED_KEYS ] = {
. core_note_type = NT_ARM_PAC_ENABLED_KEYS ,
. n = 1 ,
. size = sizeof ( long ) ,
. align = sizeof ( long ) ,
. regset_get = pac_enabled_keys_get ,
. set = pac_enabled_keys_set ,
} ,
2019-01-30 12:02:44 +00:00
# ifdef CONFIG_CHECKPOINT_RESTORE
[ REGSET_PACA_KEYS ] = {
. core_note_type = NT_ARM_PACA_KEYS ,
. n = sizeof ( struct user_pac_address_keys ) / sizeof ( __uint128_t ) ,
. size = sizeof ( __uint128_t ) ,
. align = sizeof ( __uint128_t ) ,
2020-05-27 19:09:44 -04:00
. regset_get = pac_address_keys_get ,
2019-01-30 12:02:44 +00:00
. set = pac_address_keys_set ,
} ,
[ REGSET_PACG_KEYS ] = {
. core_note_type = NT_ARM_PACG_KEYS ,
. n = sizeof ( struct user_pac_generic_keys ) / sizeof ( __uint128_t ) ,
. size = sizeof ( __uint128_t ) ,
. align = sizeof ( __uint128_t ) ,
2020-05-27 19:09:44 -04:00
. regset_get = pac_generic_keys_get ,
2019-01-30 12:02:44 +00:00
. set = pac_generic_keys_set ,
} ,
# endif
2018-12-07 18:39:26 +00:00
# endif
2020-07-03 15:12:57 +01:00
# ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
[ REGSET_TAGGED_ADDR_CTRL ] = {
. core_note_type = NT_ARM_TAGGED_ADDR_CTRL ,
. n = 1 ,
. size = sizeof ( long ) ,
. align = sizeof ( long ) ,
. regset_get = tagged_addr_ctrl_get ,
. set = tagged_addr_ctrl_set ,
} ,
# endif
2012-03-05 11:49:33 +00:00
} ;
static const struct user_regset_view user_aarch64_view = {
. name = " aarch64 " , . e_machine = EM_AARCH64 ,
. regsets = aarch64_regsets , . n = ARRAY_SIZE ( aarch64_regsets )
} ;
# ifdef CONFIG_COMPAT
enum compat_regset {
REGSET_COMPAT_GPR ,
REGSET_COMPAT_VFP ,
} ;
2020-05-15 11:22:26 -04:00
static inline compat_ulong_t compat_get_user_reg ( struct task_struct * task , int idx )
{
struct pt_regs * regs = task_pt_regs ( task ) ;
switch ( idx ) {
case 15 :
return regs - > pc ;
case 16 :
return pstate_to_compat_psr ( regs - > pstate ) ;
case 17 :
return regs - > orig_x0 ;
default :
return regs - > regs [ idx ] ;
}
}
2012-03-05 11:49:33 +00:00
static int compat_gpr_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2012-03-05 11:49:33 +00:00
{
2020-05-27 19:09:44 -04:00
int i = 0 ;
2012-03-05 11:49:33 +00:00
2020-05-27 19:09:44 -04:00
while ( to . left )
membuf_store ( & to , compat_get_user_reg ( target , i + + ) ) ;
return 0 ;
2012-03-05 11:49:33 +00:00
}
static int compat_gpr_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
struct pt_regs newregs ;
int ret = 0 ;
unsigned int i , start , num_regs ;
/* Calculate the number of AArch32 registers contained in count */
num_regs = count / regset - > size ;
/* Convert pos into an register number */
start = pos / regset - > size ;
if ( start + num_regs > regset - > n )
return - EIO ;
newregs = * task_pt_regs ( target ) ;
for ( i = 0 ; i < num_regs ; + + i ) {
unsigned int idx = start + i ;
2013-11-28 12:07:22 +00:00
compat_ulong_t reg ;
2014-06-03 19:21:30 +01:00
if ( kbuf ) {
memcpy ( & reg , kbuf , sizeof ( reg ) ) ;
kbuf + = sizeof ( reg ) ;
} else {
ret = copy_from_user ( & reg , ubuf , sizeof ( reg ) ) ;
2014-08-22 14:20:24 +01:00
if ( ret ) {
ret = - EFAULT ;
break ;
}
2013-11-28 12:07:22 +00:00
2014-06-03 19:21:30 +01:00
ubuf + = sizeof ( reg ) ;
}
2012-03-05 11:49:33 +00:00
switch ( idx ) {
case 15 :
2013-11-28 12:07:22 +00:00
newregs . pc = reg ;
2012-03-05 11:49:33 +00:00
break ;
case 16 :
2018-07-05 15:16:51 +01:00
reg = compat_psr_to_pstate ( reg ) ;
2013-11-28 12:07:22 +00:00
newregs . pstate = reg ;
2012-03-05 11:49:33 +00:00
break ;
case 17 :
2013-11-28 12:07:22 +00:00
newregs . orig_x0 = reg ;
2012-03-05 11:49:33 +00:00
break ;
default :
2013-11-28 12:07:22 +00:00
newregs . regs [ idx ] = reg ;
2012-03-05 11:49:33 +00:00
}
}
2016-03-01 14:18:50 +00:00
if ( valid_user_regs ( & newregs . user_regs , target ) )
2012-03-05 11:49:33 +00:00
* task_pt_regs ( target ) = newregs ;
else
ret = - EINVAL ;
return ret ;
}
static int compat_vfp_get ( struct task_struct * target ,
const struct user_regset * regset ,
2020-05-27 19:09:44 -04:00
struct membuf to )
2012-03-05 11:49:33 +00:00
{
struct user_fpsimd_state * uregs ;
compat_ulong_t fpscr ;
2020-01-13 23:30:21 +00:00
if ( ! system_supports_fpsimd ( ) )
return - EINVAL ;
2018-03-28 10:50:49 +01:00
uregs = & target - > thread . uw . fpsimd_state ;
2012-03-05 11:49:33 +00:00
2017-06-21 16:00:43 +01:00
if ( target = = current )
fpsimd_preserve_current_state ( ) ;
2012-03-05 11:49:33 +00:00
/*
* The VFP registers are packed into the fpsimd_state , so they all sit
* nicely together for us . We just need to create the fpscr separately .
*/
2020-05-27 19:09:44 -04:00
membuf_write ( & to , uregs , VFP_STATE_SIZE - sizeof ( compat_ulong_t ) ) ;
fpscr = ( uregs - > fpsr & VFP_FPSCR_STAT_MASK ) |
( uregs - > fpcr & VFP_FPSCR_CTRL_MASK ) ;
return membuf_store ( & to , fpscr ) ;
2012-03-05 11:49:33 +00:00
}
static int compat_vfp_set ( struct task_struct * target ,
const struct user_regset * regset ,
unsigned int pos , unsigned int count ,
const void * kbuf , const void __user * ubuf )
{
struct user_fpsimd_state * uregs ;
compat_ulong_t fpscr ;
2017-06-29 15:25:49 +01:00
int ret , vregs_end_pos ;
2012-03-05 11:49:33 +00:00
2020-01-13 23:30:21 +00:00
if ( ! system_supports_fpsimd ( ) )
return - EINVAL ;
2018-03-28 10:50:49 +01:00
uregs = & target - > thread . uw . fpsimd_state ;
2012-03-05 11:49:33 +00:00
2017-06-29 15:25:49 +01:00
vregs_end_pos = VFP_STATE_SIZE - sizeof ( compat_ulong_t ) ;
2012-03-05 11:49:33 +00:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , uregs , 0 ,
2017-06-29 15:25:49 +01:00
vregs_end_pos ) ;
2012-03-05 11:49:33 +00:00
if ( count & & ! ret ) {
2017-06-29 15:25:49 +01:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & fpscr ,
vregs_end_pos , VFP_STATE_SIZE ) ;
2017-06-29 15:25:47 +01:00
if ( ! ret ) {
uregs - > fpsr = fpscr & VFP_FPSCR_STAT_MASK ;
uregs - > fpcr = fpscr & VFP_FPSCR_CTRL_MASK ;
}
2012-03-05 11:49:33 +00:00
}
2014-05-08 11:20:23 +02:00
fpsimd_flush_task_state ( target ) ;
2012-03-05 11:49:33 +00:00
return ret ;
}
2015-07-14 16:20:17 +01:00
static int compat_tls_get ( struct task_struct * target ,
2020-05-27 19:09:44 -04:00
const struct user_regset * regset ,
struct membuf to )
2015-07-14 16:20:17 +01:00
{
2020-05-27 19:09:44 -04:00
return membuf_store ( & to , ( compat_ulong_t ) target - > thread . uw . tp_value ) ;
2015-07-14 16:20:17 +01:00
}
static int compat_tls_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 ;
2018-03-28 10:50:49 +01:00
compat_ulong_t tls = target - > thread . uw . tp_value ;
2015-07-14 16:20:17 +01:00
ret = user_regset_copyin ( & pos , & count , & kbuf , & ubuf , & tls , 0 , - 1 ) ;
if ( ret )
return ret ;
2018-03-28 10:50:49 +01:00
target - > thread . uw . tp_value = tls ;
2015-07-14 16:20:17 +01:00
return ret ;
}
2012-03-05 11:49:33 +00:00
static const struct user_regset aarch32_regsets [ ] = {
[ REGSET_COMPAT_GPR ] = {
. core_note_type = NT_PRSTATUS ,
. n = COMPAT_ELF_NGREG ,
. size = sizeof ( compat_elf_greg_t ) ,
. align = sizeof ( compat_elf_greg_t ) ,
2020-05-27 19:09:44 -04:00
. regset_get = compat_gpr_get ,
2012-03-05 11:49:33 +00:00
. set = compat_gpr_set
} ,
[ REGSET_COMPAT_VFP ] = {
. core_note_type = NT_ARM_VFP ,
. n = VFP_STATE_SIZE / sizeof ( compat_ulong_t ) ,
. size = sizeof ( compat_ulong_t ) ,
. align = sizeof ( compat_ulong_t ) ,
2020-01-13 23:30:21 +00:00
. active = fpr_active ,
2020-05-27 19:09:44 -04:00
. regset_get = compat_vfp_get ,
2012-03-05 11:49:33 +00:00
. set = compat_vfp_set
} ,
} ;
static const struct user_regset_view user_aarch32_view = {
. name = " aarch32 " , . e_machine = EM_ARM ,
. regsets = aarch32_regsets , . n = ARRAY_SIZE ( aarch32_regsets )
} ;
2015-07-14 16:20:17 +01:00
static const struct user_regset aarch32_ptrace_regsets [ ] = {
[ REGSET_GPR ] = {
. core_note_type = NT_PRSTATUS ,
. n = COMPAT_ELF_NGREG ,
. size = sizeof ( compat_elf_greg_t ) ,
. align = sizeof ( compat_elf_greg_t ) ,
2020-05-27 19:09:44 -04:00
. regset_get = compat_gpr_get ,
2015-07-14 16:20:17 +01:00
. set = compat_gpr_set
} ,
[ REGSET_FPR ] = {
. core_note_type = NT_ARM_VFP ,
. n = VFP_STATE_SIZE / sizeof ( compat_ulong_t ) ,
. size = sizeof ( compat_ulong_t ) ,
. align = sizeof ( compat_ulong_t ) ,
2020-05-27 19:09:44 -04:00
. regset_get = compat_vfp_get ,
2015-07-14 16:20:17 +01:00
. set = compat_vfp_set
} ,
[ REGSET_TLS ] = {
. core_note_type = NT_ARM_TLS ,
. n = 1 ,
. size = sizeof ( compat_ulong_t ) ,
. align = sizeof ( compat_ulong_t ) ,
2020-05-27 19:09:44 -04:00
. regset_get = compat_tls_get ,
2015-07-14 16:20:17 +01:00
. set = compat_tls_set ,
} ,
# ifdef CONFIG_HAVE_HW_BREAKPOINT
[ REGSET_HW_BREAK ] = {
. core_note_type = NT_ARM_HW_BREAK ,
. n = sizeof ( struct user_hwdebug_state ) / sizeof ( u32 ) ,
. size = sizeof ( u32 ) ,
. align = sizeof ( u32 ) ,
2020-05-27 19:09:44 -04:00
. regset_get = hw_break_get ,
2015-07-14 16:20:17 +01:00
. set = hw_break_set ,
} ,
[ REGSET_HW_WATCH ] = {
. core_note_type = NT_ARM_HW_WATCH ,
. n = sizeof ( struct user_hwdebug_state ) / sizeof ( u32 ) ,
. size = sizeof ( u32 ) ,
. align = sizeof ( u32 ) ,
2020-05-27 19:09:44 -04:00
. regset_get = hw_break_get ,
2015-07-14 16:20:17 +01:00
. set = hw_break_set ,
} ,
# endif
[ REGSET_SYSTEM_CALL ] = {
. core_note_type = NT_ARM_SYSTEM_CALL ,
. n = 1 ,
. size = sizeof ( int ) ,
. align = sizeof ( int ) ,
2020-05-27 19:09:44 -04:00
. regset_get = system_call_get ,
2015-07-14 16:20:17 +01:00
. set = system_call_set ,
} ,
} ;
static const struct user_regset_view user_aarch32_ptrace_view = {
. name = " aarch32 " , . e_machine = EM_ARM ,
. regsets = aarch32_ptrace_regsets , . n = ARRAY_SIZE ( aarch32_ptrace_regsets )
} ;
2012-03-05 11:49:33 +00:00
static int compat_ptrace_read_user ( struct task_struct * tsk , compat_ulong_t off ,
compat_ulong_t __user * ret )
{
compat_ulong_t tmp ;
if ( off & 3 )
return - EIO ;
2012-10-10 15:50:03 +01:00
if ( off = = COMPAT_PT_TEXT_ADDR )
2012-03-05 11:49:33 +00:00
tmp = tsk - > mm - > start_code ;
2012-10-10 15:50:03 +01:00
else if ( off = = COMPAT_PT_DATA_ADDR )
2012-03-05 11:49:33 +00:00
tmp = tsk - > mm - > start_data ;
2012-10-10 15:50:03 +01:00
else if ( off = = COMPAT_PT_TEXT_END_ADDR )
2012-03-05 11:49:33 +00:00
tmp = tsk - > mm - > end_code ;
else if ( off < sizeof ( compat_elf_gregset_t ) )
2020-05-15 11:26:08 -04:00
tmp = compat_get_user_reg ( tsk , off > > 2 ) ;
2012-03-05 11:49:33 +00:00
else if ( off > = COMPAT_USER_SZ )
return - EIO ;
else
tmp = 0 ;
return put_user ( tmp , ret ) ;
}
static int compat_ptrace_write_user ( struct task_struct * tsk , compat_ulong_t off ,
compat_ulong_t val )
{
2020-06-06 21:19:58 -04:00
struct pt_regs newregs = * task_pt_regs ( tsk ) ;
unsigned int idx = off / 4 ;
2012-03-05 11:49:33 +00:00
if ( off & 3 | | off > = COMPAT_USER_SZ )
return - EIO ;
if ( off > = sizeof ( compat_elf_gregset_t ) )
return 0 ;
2020-06-06 21:19:58 -04:00
switch ( idx ) {
case 15 :
newregs . pc = val ;
break ;
case 16 :
newregs . pstate = compat_psr_to_pstate ( val ) ;
break ;
case 17 :
newregs . orig_x0 = val ;
break ;
default :
newregs . regs [ idx ] = val ;
}
2014-06-02 11:47:23 +01:00
2020-06-06 21:19:58 -04:00
if ( ! valid_user_regs ( & newregs . user_regs , tsk ) )
return - EINVAL ;
2014-06-02 11:47:23 +01:00
2020-06-06 21:19:58 -04:00
* task_pt_regs ( tsk ) = newregs ;
return 0 ;
2012-03-05 11:49:33 +00:00
}
# ifdef CONFIG_HAVE_HW_BREAKPOINT
/*
* Convert a virtual register number into an index for a thread_info
* breakpoint array . Breakpoints are identified using positive numbers
* whilst watchpoints are negative . The registers are laid out as pairs
* of ( address , control ) , each pair mapping to a unique hw_breakpoint struct .
* Register 0 is reserved for describing resource information .
*/
static int compat_ptrace_hbp_num_to_idx ( compat_long_t num )
{
return ( abs ( num ) - 1 ) > > 1 ;
}
static int compat_ptrace_hbp_get_resource_info ( u32 * kdata )
{
u8 num_brps , num_wrps , debug_arch , wp_len ;
u32 reg = 0 ;
num_brps = hw_breakpoint_slots ( TYPE_INST ) ;
num_wrps = hw_breakpoint_slots ( TYPE_DATA ) ;
debug_arch = debug_monitors_arch ( ) ;
wp_len = 8 ;
reg | = debug_arch ;
reg < < = 8 ;
reg | = wp_len ;
reg < < = 8 ;
reg | = num_wrps ;
reg < < = 8 ;
reg | = num_brps ;
* kdata = reg ;
return 0 ;
}
static int compat_ptrace_hbp_get ( unsigned int note_type ,
struct task_struct * tsk ,
compat_long_t num ,
u32 * kdata )
{
u64 addr = 0 ;
u32 ctrl = 0 ;
2018-02-22 10:54:55 +01:00
int err , idx = compat_ptrace_hbp_num_to_idx ( num ) ;
2012-03-05 11:49:33 +00:00
if ( num & 1 ) {
err = ptrace_hbp_get_addr ( note_type , tsk , idx , & addr ) ;
* kdata = ( u32 ) addr ;
} else {
err = ptrace_hbp_get_ctrl ( note_type , tsk , idx , & ctrl ) ;
* kdata = ctrl ;
}
return err ;
}
static int compat_ptrace_hbp_set ( unsigned int note_type ,
struct task_struct * tsk ,
compat_long_t num ,
u32 * kdata )
{
u64 addr ;
u32 ctrl ;
int err , idx = compat_ptrace_hbp_num_to_idx ( num ) ;
if ( num & 1 ) {
addr = * kdata ;
err = ptrace_hbp_set_addr ( note_type , tsk , idx , addr ) ;
} else {
ctrl = * kdata ;
err = ptrace_hbp_set_ctrl ( note_type , tsk , idx , ctrl ) ;
}
return err ;
}
static int compat_ptrace_gethbpregs ( struct task_struct * tsk , compat_long_t num ,
compat_ulong_t __user * data )
{
int ret ;
u32 kdata ;
/* Watchpoint */
if ( num < 0 ) {
ret = compat_ptrace_hbp_get ( NT_ARM_HW_WATCH , tsk , num , & kdata ) ;
/* Resource info */
} else if ( num = = 0 ) {
ret = compat_ptrace_hbp_get_resource_info ( & kdata ) ;
/* Breakpoint */
} else {
ret = compat_ptrace_hbp_get ( NT_ARM_HW_BREAK , tsk , num , & kdata ) ;
}
if ( ! ret )
ret = put_user ( kdata , data ) ;
return ret ;
}
static int compat_ptrace_sethbpregs ( struct task_struct * tsk , compat_long_t num ,
compat_ulong_t __user * data )
{
int ret ;
u32 kdata = 0 ;
if ( num = = 0 )
return 0 ;
ret = get_user ( kdata , data ) ;
if ( ret )
return ret ;
if ( num < 0 )
ret = compat_ptrace_hbp_set ( NT_ARM_HW_WATCH , tsk , num , & kdata ) ;
else
ret = compat_ptrace_hbp_set ( NT_ARM_HW_BREAK , tsk , num , & kdata ) ;
return ret ;
}
# endif /* CONFIG_HAVE_HW_BREAKPOINT */
long compat_arch_ptrace ( struct task_struct * child , compat_long_t request ,
compat_ulong_t caddr , compat_ulong_t cdata )
{
unsigned long addr = caddr ;
unsigned long data = cdata ;
void __user * datap = compat_ptr ( data ) ;
int ret ;
switch ( request ) {
case PTRACE_PEEKUSR :
ret = compat_ptrace_read_user ( child , addr , datap ) ;
break ;
case PTRACE_POKEUSR :
ret = compat_ptrace_write_user ( child , addr , data ) ;
break ;
2012-09-27 11:38:12 +01:00
case COMPAT_PTRACE_GETREGS :
2012-03-05 11:49:33 +00:00
ret = copy_regset_to_user ( child ,
& user_aarch32_view ,
REGSET_COMPAT_GPR ,
0 , sizeof ( compat_elf_gregset_t ) ,
datap ) ;
break ;
2012-09-27 11:38:12 +01:00
case COMPAT_PTRACE_SETREGS :
2012-03-05 11:49:33 +00:00
ret = copy_regset_from_user ( child ,
& user_aarch32_view ,
REGSET_COMPAT_GPR ,
0 , sizeof ( compat_elf_gregset_t ) ,
datap ) ;
break ;
2012-09-27 11:38:12 +01:00
case COMPAT_PTRACE_GET_THREAD_AREA :
2018-03-28 10:50:49 +01:00
ret = put_user ( ( compat_ulong_t ) child - > thread . uw . tp_value ,
2012-03-05 11:49:33 +00:00
( compat_ulong_t __user * ) datap ) ;
break ;
2012-09-27 11:38:12 +01:00
case COMPAT_PTRACE_SET_SYSCALL :
2012-03-05 11:49:33 +00:00
task_pt_regs ( child ) - > syscallno = data ;
ret = 0 ;
break ;
case COMPAT_PTRACE_GETVFPREGS :
ret = copy_regset_to_user ( child ,
& user_aarch32_view ,
REGSET_COMPAT_VFP ,
0 , VFP_STATE_SIZE ,
datap ) ;
break ;
case COMPAT_PTRACE_SETVFPREGS :
ret = copy_regset_from_user ( child ,
& user_aarch32_view ,
REGSET_COMPAT_VFP ,
0 , VFP_STATE_SIZE ,
datap ) ;
break ;
# ifdef CONFIG_HAVE_HW_BREAKPOINT
2012-09-27 11:38:12 +01:00
case COMPAT_PTRACE_GETHBPREGS :
2012-03-05 11:49:33 +00:00
ret = compat_ptrace_gethbpregs ( child , addr , datap ) ;
break ;
2012-09-27 11:38:12 +01:00
case COMPAT_PTRACE_SETHBPREGS :
2012-03-05 11:49:33 +00:00
ret = compat_ptrace_sethbpregs ( child , addr , datap ) ;
break ;
# endif
default :
ret = compat_ptrace_request ( child , request , addr ,
data ) ;
break ;
}
return ret ;
}
# endif /* CONFIG_COMPAT */
const struct user_regset_view * task_user_regset_view ( struct task_struct * task )
{
# ifdef CONFIG_COMPAT
2015-07-14 16:20:17 +01:00
/*
* Core dumping of 32 - bit tasks or compat ptrace requests must use the
* user_aarch32_view compatible with arm32 . Native ptrace requests on
* 32 - bit children use an extended user_aarch32_ptrace_view to allow
* access to the TLS register .
*/
if ( is_compat_task ( ) )
2012-03-05 11:49:33 +00:00
return & user_aarch32_view ;
2015-07-14 16:20:17 +01:00
else if ( is_compat_thread ( task_thread_info ( task ) ) )
return & user_aarch32_ptrace_view ;
2012-03-05 11:49:33 +00:00
# endif
return & user_aarch64_view ;
}
long arch_ptrace ( struct task_struct * child , long request ,
unsigned long addr , unsigned long data )
{
2020-03-30 10:29:38 +01:00
switch ( request ) {
case PTRACE_PEEKMTETAGS :
case PTRACE_POKEMTETAGS :
return mte_ptrace_copy_tags ( child , request , addr , data ) ;
}
2012-03-05 11:49:33 +00:00
return ptrace_request ( child , request , addr , data ) ;
}
2014-04-30 10:51:30 +01:00
enum ptrace_syscall_dir {
PTRACE_SYSCALL_ENTER = 0 ,
PTRACE_SYSCALL_EXIT ,
} ;
2022-01-27 11:27:10 -06:00
static void report_syscall ( struct pt_regs * regs , enum ptrace_syscall_dir dir )
2012-03-05 11:49:33 +00:00
{
2014-04-30 10:51:30 +01:00
int regno ;
2012-03-05 11:49:33 +00:00
unsigned long saved_reg ;
2014-04-30 10:51:30 +01:00
/*
2020-07-02 21:14:20 +01:00
* We have some ABI weirdness here in the way that we handle syscall
* exit stops because we indicate whether or not the stop has been
* signalled from syscall entry or syscall exit by clobbering a general
* purpose register ( ip / r12 for AArch32 , x7 for AArch64 ) in the tracee
* and restoring its old value after the stop . This means that :
*
* - Any writes by the tracer to this register during the stop are
* ignored / discarded .
*
* - The actual value of the register is not available during the stop ,
* so the tracer cannot save it and restore it later .
*
* - Syscall stops behave differently to seccomp and pseudo - step traps
* ( the latter do not nobble any registers ) .
2014-04-30 10:51:30 +01:00
*/
regno = ( is_compat_task ( ) ? 12 : 7 ) ;
saved_reg = regs - > regs [ regno ] ;
regs - > regs [ regno ] = dir ;
2012-03-05 11:49:33 +00:00
2020-07-02 21:16:20 +01:00
if ( dir = = PTRACE_SYSCALL_ENTER ) {
2022-01-27 11:46:37 -06:00
if ( ptrace_report_syscall_entry ( regs ) )
2020-07-02 21:16:20 +01:00
forget_syscall ( regs ) ;
regs - > regs [ regno ] = saved_reg ;
} else if ( ! test_thread_flag ( TIF_SINGLESTEP ) ) {
2022-01-27 11:46:37 -06:00
ptrace_report_syscall_exit ( regs , 0 ) ;
2020-07-02 21:16:20 +01:00
regs - > regs [ regno ] = saved_reg ;
} else {
regs - > regs [ regno ] = saved_reg ;
2012-03-05 11:49:33 +00:00
2020-07-02 21:16:20 +01:00
/*
* Signal a pseudo - step exception since we are stepping but
* tracer modifications to the registers may have rewound the
* state machine .
*/
2022-01-27 11:46:37 -06:00
ptrace_report_syscall_exit ( regs , 1 ) ;
2020-07-02 21:16:20 +01:00
}
2014-04-30 10:51:30 +01:00
}
2018-07-12 15:14:23 +01:00
int syscall_trace_enter ( struct pt_regs * regs )
2014-04-30 10:51:30 +01:00
{
2021-11-29 13:06:48 +00:00
unsigned long flags = read_thread_flags ( ) ;
2020-05-15 18:22:53 -04:00
if ( flags & ( _TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE ) ) {
2022-01-27 11:27:10 -06:00
report_syscall ( regs , PTRACE_SYSCALL_ENTER ) ;
2021-01-16 15:18:54 +00:00
if ( flags & _TIF_SYSCALL_EMU )
2020-07-10 13:20:57 +01:00
return NO_SYSCALL ;
2019-05-23 10:06:18 +01:00
}
2012-03-05 11:49:33 +00:00
2016-06-02 12:28:52 -07:00
/* Do the secure computing after ptrace; failures should be fast. */
2019-09-24 08:44:20 +02:00
if ( secure_computing ( ) = = - 1 )
2020-07-10 13:20:57 +01:00
return NO_SYSCALL ;
2016-06-02 12:28:52 -07:00
2014-04-30 10:54:36 +01:00
if ( test_thread_flag ( TIF_SYSCALL_TRACEPOINT ) )
trace_sys_enter ( regs , regs - > syscallno ) ;
2014-09-23 16:25:34 -04:00
audit_syscall_entry ( regs - > syscallno , regs - > orig_x0 , regs - > regs [ 1 ] ,
regs - > regs [ 2 ] , regs - > regs [ 3 ] ) ;
2014-07-04 08:28:31 +01:00
2012-03-05 11:49:33 +00:00
return regs - > syscallno ;
}
2014-04-30 10:51:30 +01:00
2018-07-12 15:14:23 +01:00
void syscall_trace_exit ( struct pt_regs * regs )
2014-04-30 10:51:30 +01:00
{
2021-11-29 13:06:48 +00:00
unsigned long flags = read_thread_flags ( ) ;
2020-07-02 21:16:20 +01:00
2014-07-04 08:28:31 +01:00
audit_syscall_exit ( regs ) ;
2020-07-02 21:16:20 +01:00
if ( flags & _TIF_SYSCALL_TRACEPOINT )
arm64: fix compat syscall return truncation
Due to inconsistencies in the way we manipulate compat GPRs, we have a
few issues today:
* For audit and tracing, where error codes are handled as a (native)
long, negative error codes are expected to be sign-extended to the
native 64-bits, or they may fail to be matched correctly. Thus a
syscall which fails with an error may erroneously be identified as
failing.
* For ptrace, *all* compat return values should be sign-extended for
consistency with 32-bit arm, but we currently only do this for
negative return codes.
* As we may transiently set the upper 32 bits of some compat GPRs while
in the kernel, these can be sampled by perf, which is somewhat
confusing. This means that where a syscall returns a pointer above 2G,
this will be sign-extended, but will not be mistaken for an error as
error codes are constrained to the inclusive range [-4096, -1] where
no user pointer can exist.
To fix all of these, we must consistently use helpers to get/set the
compat GPRs, ensuring that we never write the upper 32 bits of the
return code, and always sign-extend when reading the return code. This
patch does so, with the following changes:
* We re-organise syscall_get_return_value() to always sign-extend for
compat tasks, and reimplement syscall_get_error() atop. We update
syscall_trace_exit() to use syscall_get_return_value().
* We consistently use syscall_set_return_value() to set the return
value, ensureing the upper 32 bits are never set unexpectedly.
* As the core audit code currently uses regs_return_value() rather than
syscall_get_return_value(), we special-case this for
compat_user_mode(regs) such that this will do the right thing. Going
forward, we should try to move the core audit code over to
syscall_get_return_value().
Cc: <stable@vger.kernel.org>
Reported-by: He Zhe <zhe.he@windriver.com>
Reported-by: weiyuchen <weiyuchen3@huawei.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20210802104200.21390-1-mark.rutland@arm.com
Signed-off-by: Will Deacon <will@kernel.org>
2021-08-02 11:42:00 +01:00
trace_sys_exit ( regs , syscall_get_return_value ( current , regs ) ) ;
2014-04-30 10:54:36 +01:00
2020-07-02 21:16:20 +01:00
if ( flags & ( _TIF_SYSCALL_TRACE | _TIF_SINGLESTEP ) )
2022-01-27 11:27:10 -06:00
report_syscall ( regs , PTRACE_SYSCALL_EXIT ) ;
2018-06-20 14:46:50 +01:00
rseq_syscall ( regs ) ;
2014-04-30 10:51:30 +01:00
}
2016-03-01 14:18:50 +00:00
/*
2019-02-15 16:34:27 +00:00
* SPSR_ELx bits which are always architecturally RES0 per ARM DDI 04 87 D . a .
* We permit userspace to set SSBS ( AArch64 bit 12 , AArch32 bit 23 ) which is
* not described in ARM DDI 04 87 D . a .
* We treat PAN and UAO as RES0 bits , as they are meaningless at EL0 , and may
* be allocated an EL0 meaning in future .
2016-03-01 14:18:50 +00:00
* Userspace cannot use these until they have an architectural meaning .
2018-07-05 15:16:49 +01:00
* Note that this follows the SPSR_ELx format , not the AArch32 PSR format .
2016-03-01 14:18:50 +00:00
* We also reserve IL for the kernel ; SS is handled dynamically .
*/
# define SPSR_EL1_AARCH64_RES0_BITS \
2019-09-06 10:55:29 +01:00
( GENMASK_ULL ( 63 , 32 ) | GENMASK_ULL ( 27 , 26 ) | GENMASK_ULL ( 23 , 22 ) | \
2020-03-16 16:50:45 +00:00
GENMASK_ULL ( 20 , 13 ) | GENMASK_ULL ( 5 , 5 ) )
2016-03-01 14:18:50 +00:00
# define SPSR_EL1_AARCH32_RES0_BITS \
2019-02-15 16:34:27 +00:00
( GENMASK_ULL ( 63 , 32 ) | GENMASK_ULL ( 22 , 22 ) | GENMASK_ULL ( 20 , 20 ) )
2016-03-01 14:18:50 +00:00
static int valid_compat_regs ( struct user_pt_regs * regs )
{
regs - > pstate & = ~ SPSR_EL1_AARCH32_RES0_BITS ;
if ( ! system_supports_mixed_endian_el0 ( ) ) {
if ( IS_ENABLED ( CONFIG_CPU_BIG_ENDIAN ) )
2018-07-05 15:16:52 +01:00
regs - > pstate | = PSR_AA32_E_BIT ;
2016-03-01 14:18:50 +00:00
else
2018-07-05 15:16:52 +01:00
regs - > pstate & = ~ PSR_AA32_E_BIT ;
2016-03-01 14:18:50 +00:00
}
if ( user_mode ( regs ) & & ( regs - > pstate & PSR_MODE32_BIT ) & &
2018-07-05 15:16:52 +01:00
( regs - > pstate & PSR_AA32_A_BIT ) = = 0 & &
( regs - > pstate & PSR_AA32_I_BIT ) = = 0 & &
( regs - > pstate & PSR_AA32_F_BIT ) = = 0 ) {
2016-03-01 14:18:50 +00:00
return 1 ;
}
/*
* Force PSR to a valid 32 - bit EL0t , preserving the same bits as
* arch / arm .
*/
2018-07-05 15:16:52 +01:00
regs - > pstate & = PSR_AA32_N_BIT | PSR_AA32_Z_BIT |
PSR_AA32_C_BIT | PSR_AA32_V_BIT |
PSR_AA32_Q_BIT | PSR_AA32_IT_MASK |
PSR_AA32_GE_MASK | PSR_AA32_E_BIT |
PSR_AA32_T_BIT ;
2016-03-01 14:18:50 +00:00
regs - > pstate | = PSR_MODE32_BIT ;
return 0 ;
}
static int valid_native_regs ( struct user_pt_regs * regs )
{
regs - > pstate & = ~ SPSR_EL1_AARCH64_RES0_BITS ;
if ( user_mode ( regs ) & & ! ( regs - > pstate & PSR_MODE32_BIT ) & &
( regs - > pstate & PSR_D_BIT ) = = 0 & &
( regs - > pstate & PSR_A_BIT ) = = 0 & &
( regs - > pstate & PSR_I_BIT ) = = 0 & &
( regs - > pstate & PSR_F_BIT ) = = 0 ) {
return 1 ;
}
/* Force PSR to a valid 64-bit EL0t */
regs - > pstate & = PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT ;
return 0 ;
}
/*
* Are the current registers suitable for user mode ? ( used to maintain
* security in signal handlers )
*/
int valid_user_regs ( struct user_pt_regs * regs , struct task_struct * task )
{
arm64: ptrace: Override SPSR.SS when single-stepping is enabled
Luis reports that, when reverse debugging with GDB, single-step does not
function as expected on arm64:
| I've noticed, under very specific conditions, that a PTRACE_SINGLESTEP
| request by GDB won't execute the underlying instruction. As a consequence,
| the PC doesn't move, but we return a SIGTRAP just like we would for a
| regular successful PTRACE_SINGLESTEP request.
The underlying problem is that when the CPU register state is restored
as part of a reverse step, the SPSR.SS bit is cleared and so the hardware
single-step state can transition to the "active-pending" state, causing
an unexpected step exception to be taken immediately if a step operation
is attempted.
In hindsight, we probably shouldn't have exposed SPSR.SS in the pstate
accessible by the GPR regset, but it's a bit late for that now. Instead,
simply prevent userspace from configuring the bit to a value which is
inconsistent with the TIF_SINGLESTEP state for the task being traced.
Cc: <stable@vger.kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Keno Fischer <keno@juliacomputing.com>
Link: https://lore.kernel.org/r/1eed6d69-d53d-9657-1fc9-c089be07f98c@linaro.org
Reported-by: Luis Machado <luis.machado@linaro.org>
Tested-by: Luis Machado <luis.machado@linaro.org>
Signed-off-by: Will Deacon <will@kernel.org>
2020-02-13 12:06:26 +00:00
/* https://lore.kernel.org/lkml/20191118131525.GA4180@willie-the-truck */
user_regs_reset_single_step ( regs , task ) ;
2016-03-01 14:18:50 +00:00
if ( is_compat_thread ( task_thread_info ( task ) ) )
return valid_compat_regs ( regs ) ;
else
return valid_native_regs ( regs ) ;
}