/* * Debug Store (DS) support * * This provides a low-level interface to the hardware's Debug Store * feature that is used for branch trace store (BTS) and * precise-event based sampling (PEBS). * * It manages: * - DS and BTS hardware configuration * - buffer overflow handling (to be done) * - buffer access * * It does not do: * - security checking (is the caller allowed to trace the task) * - buffer allocation (memory accounting) * * * Copyright (C) 2007-2008 Intel Corporation. * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008 */ #ifndef _ASM_X86_DS_H #define _ASM_X86_DS_H #include <linux/types.h> #include <linux/init.h> #include <linux/err.h> #ifdef CONFIG_X86_DS struct task_struct; struct ds_context; 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 *); /* * 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) }; /* * Request BTS or PEBS * * Due to alignement constraints, the actual buffer may be slightly * smaller than the requested or provided buffer. * * 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. * * task: the task to request recording for; * NULL for per-cpu recording on the current cpu * base: the base pointer for the (non-pageable) buffer; * size: the size of the provided buffer in bytes * ovfl: pointer to a function to be called on buffer overflow; * NULL if cyclic buffer requested * th: the interrupt threshold in records from the end of the buffer; * -1 if no interrupt threshold is requested. * flags: a bit-mask of the above flags */ extern struct bts_tracer *ds_request_bts(struct task_struct *task, void *base, size_t size, bts_ovfl_callback_t ovfl, size_t th, unsigned int flags); extern struct pebs_tracer *ds_request_pebs(struct task_struct *task, void *base, size_t size, pebs_ovfl_callback_t ovfl, size_t th, unsigned int flags); /* * Release BTS or PEBS resources * Suspend and resume BTS or PEBS tracing * * tracer: the tracer handle returned from ds_request_~() */ 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); /* * The raw DS buffer state as it is used for BTS and PEBS recording. * * This is the low-level, arch-dependent interface for working * directly on the raw trace data. */ 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; }; /* * An arch-independent view on branch trace data. */ 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 { __u64 jiffies; pid_t pid; } timestamp; } variant; }; /* * The BTS state. * * This gives access to the raw DS state and adds functions to provide * an arch-independent view of the BTS data. */ 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); }; /* * The PEBS state. * * This gives access to the raw DS state and the PEBS-specific counter * reset value. */ struct pebs_trace { struct ds_trace ds; /* the PEBS reset value */ unsigned long long reset_value; }; /* * Read the BTS or PEBS trace. * * Returns a view on the trace collected for the parameter tracer. * * 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. * * tracer: the tracer handle returned from ds_request_~() */ extern const struct bts_trace *ds_read_bts(struct bts_tracer *tracer); extern const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer); /* * Reset the write pointer of the BTS/PEBS buffer. * * Returns 0 on success; -Eerrno on error * * tracer: the tracer handle returned from ds_request_~() */ extern int ds_reset_bts(struct bts_tracer *tracer); extern int ds_reset_pebs(struct pebs_tracer *tracer); /* * Set the PEBS counter reset value. * * Returns 0 on success; -Eerrno on error * * tracer: the tracer handle returned from ds_request_pebs() * value: the new counter reset value */ extern int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value); /* * Initialization */ struct cpuinfo_x86; extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); /* * Context switch work */ extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); /* * Task clone/init and cleanup work */ extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father); extern void ds_exit_thread(struct task_struct *tsk); #else /* CONFIG_X86_DS */ struct cpuinfo_x86; static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} static inline void ds_switch_to(struct task_struct *prev, struct task_struct *next) {} static inline void ds_copy_thread(struct task_struct *tsk, struct task_struct *father) {} static inline void ds_exit_thread(struct task_struct *tsk) {} #endif /* CONFIG_X86_DS */ #endif /* _ASM_X86_DS_H */