2008-01-30 13:31:09 +01:00
/*
* Debug Store ( DS ) support
*
* This provides a low - level interface to the hardware ' s Debug Store
2008-04-08 11:01:58 +02:00
* feature that is used for branch trace store ( BTS ) and
2008-01-30 13:31:09 +01:00
* precise - event based sampling ( PEBS ) .
*
2008-04-08 11:01:58 +02:00
* It manages :
2008-12-11 13:49:59 +01:00
* - DS and BTS hardware configuration
2008-11-25 09:05:27 +01:00
* - buffer overflow handling ( to be done )
2008-04-08 11:01:58 +02:00
* - buffer access
2008-01-30 13:31:09 +01:00
*
2008-12-11 13:49:59 +01:00
* It does not do :
* - security checking ( is the caller allowed to trace the task )
* - buffer allocation ( memory accounting )
2008-01-30 13:31:09 +01:00
*
*
2009-04-03 16:43:40 +02:00
* Copyright ( C ) 2007 - 2009 Intel Corporation .
* Markus Metzger < markus . t . metzger @ intel . com > , 2007 - 2009
2008-01-30 13:31:09 +01:00
*/
2008-10-22 22:26:29 -07:00
# ifndef _ASM_X86_DS_H
# define _ASM_X86_DS_H
2008-01-30 13:31:09 +01:00
2008-04-08 11:01:58 +02:00
2008-01-30 13:31:09 +01:00
# include <linux/types.h>
# include <linux/init.h>
2008-11-25 09:01:25 +01:00
# include <linux/err.h>
2008-01-30 13:31:09 +01:00
2008-11-25 08:47:19 +01:00
# ifdef CONFIG_X86_DS
2008-04-08 11:01:58 +02:00
struct task_struct ;
2008-12-11 13:49:59 +01:00
struct ds_context ;
2008-11-25 09:01:25 +01:00
struct ds_tracer ;
struct bts_tracer ;
struct pebs_tracer ;
typedef void ( * bts_ovfl_callback_t ) ( struct bts_tracer * ) ;
typedef void ( * pebs_ovfl_callback_t ) ( struct pebs_tracer * ) ;
2008-01-30 13:31:09 +01:00
2008-12-11 13:49:59 +01:00
/*
* A list of features plus corresponding macros to talk about them in
* the ds_request function ' s flags parameter .
*
* We use the enum to index an array of corresponding control bits ;
* we use the macro to index a flags bit - vector .
*/
enum ds_feature {
dsf_bts = 0 ,
dsf_bts_kernel ,
# define BTS_KERNEL (1 << dsf_bts_kernel)
/* trace kernel-mode branches */
dsf_bts_user ,
# define BTS_USER (1 << dsf_bts_user)
/* trace user-mode branches */
dsf_bts_overflow ,
dsf_bts_max ,
dsf_pebs = dsf_bts_max ,
dsf_pebs_max ,
dsf_ctl_max = dsf_pebs_max ,
dsf_bts_timestamps = dsf_ctl_max ,
# define BTS_TIMESTAMPS (1 << dsf_bts_timestamps)
/* add timestamps into BTS trace */
# define BTS_USER_FLAGS (BTS_KERNEL | BTS_USER | BTS_TIMESTAMPS)
} ;
2008-04-08 11:01:58 +02:00
/*
* Request BTS or PEBS
*
* Due to alignement constraints , the actual buffer may be slightly
* smaller than the requested or provided buffer .
2008-01-30 13:31:09 +01:00
*
2008-11-25 09:01:25 +01:00
* Returns a pointer to a tracer structure on success , or
* ERR_PTR ( errcode ) on failure .
*
* The interrupt threshold is independent from the overflow callback
* to allow users to use their own overflow interrupt handling mechanism .
2008-04-08 11:01:58 +02:00
*
2009-04-03 16:43:40 +02:00
* The function might sleep .
*
* task : the task to request recording for
* cpu : the cpu to request recording for
2008-04-08 11:01:58 +02:00
* base : the base pointer for the ( non - pageable ) buffer ;
2008-11-25 09:05:27 +01:00
* size : the size of the provided buffer in bytes
2008-04-08 11:01:58 +02:00
* ovfl : pointer to a function to be called on buffer overflow ;
* NULL if cyclic buffer requested
2008-11-25 09:01:25 +01:00
* th : the interrupt threshold in records from the end of the buffer ;
* - 1 if no interrupt threshold is requested .
2008-12-11 13:49:59 +01:00
* flags : a bit - mask of the above flags
2008-01-30 13:31:09 +01:00
*/
2009-04-03 16:43:40 +02:00
extern struct bts_tracer * ds_request_bts_task ( struct task_struct * task ,
void * base , size_t size ,
bts_ovfl_callback_t ovfl ,
size_t th , unsigned int flags ) ;
extern struct bts_tracer * ds_request_bts_cpu ( int cpu , void * base , size_t size ,
bts_ovfl_callback_t ovfl ,
size_t th , unsigned int flags ) ;
extern struct pebs_tracer * ds_request_pebs_task ( struct task_struct * task ,
void * base , size_t size ,
pebs_ovfl_callback_t ovfl ,
size_t th , unsigned int flags ) ;
extern struct pebs_tracer * ds_request_pebs_cpu ( int cpu ,
void * base , size_t size ,
pebs_ovfl_callback_t ovfl ,
size_t th , unsigned int flags ) ;
2008-04-08 11:01:58 +02:00
/*
* Release BTS or PEBS resources
2008-12-11 13:49:59 +01:00
* Suspend and resume BTS or PEBS tracing
2008-04-08 11:01:58 +02:00
*
2009-04-03 16:43:40 +02:00
* Must be called with irq ' s enabled .
*
2008-11-25 09:01:25 +01:00
* tracer : the tracer handle returned from ds_request_ ~ ( )
2008-04-08 11:01:58 +02:00
*/
2008-12-11 13:49:59 +01:00
extern void ds_release_bts ( struct bts_tracer * tracer ) ;
extern void ds_suspend_bts ( struct bts_tracer * tracer ) ;
extern void ds_resume_bts ( struct bts_tracer * tracer ) ;
extern void ds_release_pebs ( struct pebs_tracer * tracer ) ;
extern void ds_suspend_pebs ( struct pebs_tracer * tracer ) ;
extern void ds_resume_pebs ( struct pebs_tracer * tracer ) ;
2009-04-03 16:43:40 +02:00
/*
* Release BTS or PEBS resources
* Suspend and resume BTS or PEBS tracing
*
* Cpu tracers must call this on the traced cpu .
* Task tracers must call ds_release_ ~ _noirq ( ) for themselves .
*
* May be called with irq ' s disabled .
*
* Returns 0 if successful ;
* - EPERM if the cpu tracer does not trace the current cpu .
* - EPERM if the task tracer does not trace itself .
*
* tracer : the tracer handle returned from ds_request_ ~ ( )
*/
extern int ds_release_bts_noirq ( struct bts_tracer * tracer ) ;
extern int ds_suspend_bts_noirq ( struct bts_tracer * tracer ) ;
extern int ds_resume_bts_noirq ( struct bts_tracer * tracer ) ;
extern int ds_release_pebs_noirq ( struct pebs_tracer * tracer ) ;
extern int ds_suspend_pebs_noirq ( struct pebs_tracer * tracer ) ;
extern int ds_resume_pebs_noirq ( struct pebs_tracer * tracer ) ;
2008-04-08 11:01:58 +02:00
/*
2008-12-11 13:49:59 +01:00
* The raw DS buffer state as it is used for BTS and PEBS recording .
2008-04-08 11:01:58 +02:00
*
2008-12-11 13:49:59 +01:00
* This is the low - level , arch - dependent interface for working
* directly on the raw trace data .
2008-04-08 11:01:58 +02:00
*/
2008-12-11 13:49:59 +01:00
struct ds_trace {
/* the number of bts/pebs records */
size_t n ;
/* the size of a bts/pebs record in bytes */
size_t size ;
/* pointers into the raw buffer:
- to the first entry */
void * begin ;
/* - one beyond the last entry */
void * end ;
/* - one beyond the newest entry */
void * top ;
/* - the interrupt threshold */
void * ith ;
/* flags given on ds_request() */
unsigned int flags ;
} ;
2008-04-08 11:01:58 +02:00
/*
2008-12-11 13:49:59 +01:00
* An arch - independent view on branch trace data .
2008-04-08 11:01:58 +02:00
*/
2008-12-11 13:49:59 +01:00
enum bts_qualifier {
bts_invalid ,
# define BTS_INVALID bts_invalid
bts_branch ,
# define BTS_BRANCH bts_branch
bts_task_arrives ,
# define BTS_TASK_ARRIVES bts_task_arrives
bts_task_departs ,
# define BTS_TASK_DEPARTS bts_task_departs
bts_qual_bit_size = 4 ,
bts_qual_max = ( 1 < < bts_qual_bit_size ) ,
} ;
struct bts_struct {
__u64 qualifier ;
union {
/* BTS_BRANCH */
struct {
__u64 from ;
__u64 to ;
} lbr ;
/* BTS_TASK_ARRIVES or BTS_TASK_DEPARTS */
struct {
2009-04-03 16:43:38 +02:00
__u64 clock ;
2008-12-11 13:49:59 +01:00
pid_t pid ;
2009-04-03 16:43:38 +02:00
} event ;
2008-12-11 13:49:59 +01:00
} variant ;
} ;
2008-04-08 11:01:58 +02:00
/*
2008-12-11 13:49:59 +01:00
* The BTS state .
2008-04-08 11:01:58 +02:00
*
2008-12-11 13:49:59 +01:00
* This gives access to the raw DS state and adds functions to provide
* an arch - independent view of the BTS data .
2008-04-08 11:01:58 +02:00
*/
2008-12-11 13:49:59 +01:00
struct bts_trace {
struct ds_trace ds ;
int ( * read ) ( struct bts_tracer * tracer , const void * at ,
struct bts_struct * out ) ;
int ( * write ) ( struct bts_tracer * tracer , const struct bts_struct * in ) ;
} ;
2008-04-08 11:01:58 +02:00
/*
2008-12-11 13:49:59 +01:00
* The PEBS state .
2008-04-08 11:01:58 +02:00
*
2008-12-11 13:49:59 +01:00
* This gives access to the raw DS state and the PEBS - specific counter
* reset value .
*/
struct pebs_trace {
struct ds_trace ds ;
2009-04-03 16:43:52 +02:00
/* the number of valid counters in the below array */
unsigned int counters ;
# define MAX_PEBS_COUNTERS 4
/* the counter reset value */
unsigned long long counter_reset [ MAX_PEBS_COUNTERS ] ;
2008-12-11 13:49:59 +01:00
} ;
/*
* Read the BTS or PEBS trace .
2008-04-08 11:01:58 +02:00
*
2008-12-11 13:49:59 +01:00
* Returns a view on the trace collected for the parameter tracer .
2008-04-08 11:01:58 +02:00
*
2008-12-11 13:49:59 +01:00
* The view remains valid as long as the traced task is not running or
* the tracer is suspended .
* Writes into the trace buffer are not reflected .
2008-04-08 11:01:58 +02:00
*
2008-11-25 09:01:25 +01:00
* tracer : the tracer handle returned from ds_request_ ~ ( )
2008-04-08 11:01:58 +02:00
*/
2008-12-11 13:49:59 +01:00
extern const struct bts_trace * ds_read_bts ( struct bts_tracer * tracer ) ;
extern const struct pebs_trace * ds_read_pebs ( struct pebs_tracer * tracer ) ;
2008-04-08 11:01:58 +02:00
/*
* Reset the write pointer of the BTS / PEBS buffer .
*
* Returns 0 on success ; - Eerrno on error
*
2008-11-25 09:01:25 +01:00
* tracer : the tracer handle returned from ds_request_ ~ ( )
2008-04-08 11:01:58 +02:00
*/
2008-11-25 09:01:25 +01:00
extern int ds_reset_bts ( struct bts_tracer * tracer ) ;
extern int ds_reset_pebs ( struct pebs_tracer * tracer ) ;
2008-04-08 11:01:58 +02:00
/*
* Set the PEBS counter reset value .
*
* Returns 0 on success ; - Eerrno on error
*
2008-11-25 09:01:25 +01:00
* tracer : the tracer handle returned from ds_request_pebs ( )
2009-04-03 16:43:52 +02:00
* counter : the index of the counter
2008-04-08 11:01:58 +02:00
* value : the new counter reset value
*/
2009-04-03 16:43:52 +02:00
extern int ds_set_pebs_reset ( struct pebs_tracer * tracer ,
unsigned int counter , u64 value ) ;
2008-04-08 11:01:58 +02:00
/*
* Initialization
*/
struct cpuinfo_x86 ;
extern void __cpuinit ds_init_intel ( struct cpuinfo_x86 * ) ;
/*
2008-12-11 13:49:59 +01:00
* Context switch work
2008-04-08 11:01:58 +02:00
*/
2008-12-11 13:49:59 +01:00
extern void ds_switch_to ( struct task_struct * prev , struct task_struct * next ) ;
2008-04-08 11:01:58 +02:00
# else /* CONFIG_X86_DS */
2008-11-25 08:47:19 +01:00
struct cpuinfo_x86 ;
static inline void __cpuinit ds_init_intel ( struct cpuinfo_x86 * ignored ) { }
2008-12-11 13:49:59 +01:00
static inline void ds_switch_to ( struct task_struct * prev ,
struct task_struct * next ) { }
2008-01-30 13:31:09 +01:00
2008-04-08 11:01:58 +02:00
# endif /* CONFIG_X86_DS */
2008-10-22 22:26:29 -07:00
# endif /* _ASM_X86_DS_H */