From: Ingo Molnar Date: Mon, 6 Oct 2008 14:17:23 +0000 (+0200) Subject: Merge branch 'x86/pebs' into x86-v28-for-linus-phase1 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=19268ed7449c561694d048a34601a30e2d1aaf79;p=linux-beck.git Merge branch 'x86/pebs' into x86-v28-for-linus-phase1 Conflicts: include/asm-x86/ds.h Signed-off-by: Ingo Molnar --- 19268ed7449c561694d048a34601a30e2d1aaf79 diff --cc include/asm-x86/ds.h index 6b27c686fa10,72c5a190bf48..c3c953a45b21 --- a/include/asm-x86/ds.h +++ b/include/asm-x86/ds.h @@@ -2,71 -2,237 +2,237 @@@ * Debug Store (DS) support * * This provides a low-level interface to the hardware's Debug Store - * feature that is used for last branch recording (LBR) and + * feature that is used for branch trace store (BTS) and * precise-event based sampling (PEBS). * - * Different architectures use a different DS layout/pointer size. - * The below functions therefore work on a void*. + * It manages: + * - per-thread and per-cpu allocation of BTS and PEBS + * - buffer memory allocation (optional) + * - buffer overflow handling + * - buffer access * + * It assumes: + * - get_task_struct on all parameter tasks + * - current is allowed to trace parameter tasks * - * Since there is no user for PEBS, yet, only LBR (or branch - * trace store, BTS) is supported. * - * - * Copyright (C) 2007 Intel Corporation. - * Markus Metzger , Dec 2007 + * Copyright (C) 2007-2008 Intel Corporation. + * Markus Metzger , 2007-2008 */ -#ifndef _ASM_X86_DS_H -#define _ASM_X86_DS_H +#ifndef ASM_X86__DS_H +#define ASM_X86__DS_H + #ifdef CONFIG_X86_DS + #include #include - struct cpuinfo_x86; + struct task_struct; - /* a branch trace record entry + /* + * Request BTS or PEBS + * + * Due to alignement constraints, the actual buffer may be slightly + * smaller than the requested or provided buffer. * - * In order to unify the interface between various processor versions, - * we use the below data structure for all processors. + * Returns 0 on success; -Eerrno otherwise + * + * 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; + * NULL if buffer allocation requested + * size: the size of the requested or provided buffer + * ovfl: pointer to a function to be called on buffer overflow; + * NULL if cyclic buffer requested */ - enum bts_qualifier { - BTS_INVALID = 0, - BTS_BRANCH, - BTS_TASK_ARRIVES, - BTS_TASK_DEPARTS - }; + typedef void (*ds_ovfl_callback_t)(struct task_struct *); + extern int ds_request_bts(struct task_struct *task, void *base, size_t size, + ds_ovfl_callback_t ovfl); + extern int ds_request_pebs(struct task_struct *task, void *base, size_t size, + ds_ovfl_callback_t ovfl); + + /* + * Release BTS or PEBS resources + * + * Frees buffers allocated on ds_request. + * + * Returns 0 on success; -Eerrno otherwise + * + * task: the task to release resources for; + * NULL to release resources for the current cpu + */ + extern int ds_release_bts(struct task_struct *task); + extern int ds_release_pebs(struct task_struct *task); + + /* + * Return the (array) index of the write pointer. + * (assuming an array of BTS/PEBS records) + * + * Returns -Eerrno on error + * + * task: the task to access; + * NULL to access the current cpu + * pos (out): if not NULL, will hold the result + */ + extern int ds_get_bts_index(struct task_struct *task, size_t *pos); + extern int ds_get_pebs_index(struct task_struct *task, size_t *pos); + + /* + * Return the (array) index one record beyond the end of the array. + * (assuming an array of BTS/PEBS records) + * + * Returns -Eerrno on error + * + * task: the task to access; + * NULL to access the current cpu + * pos (out): if not NULL, will hold the result + */ + extern int ds_get_bts_end(struct task_struct *task, size_t *pos); + extern int ds_get_pebs_end(struct task_struct *task, size_t *pos); + + /* + * Provide a pointer to the BTS/PEBS record at parameter index. + * (assuming an array of BTS/PEBS records) + * + * The pointer points directly into the buffer. The user is + * responsible for copying the record. + * + * Returns the size of a single record on success; -Eerrno on error + * + * task: the task to access; + * NULL to access the current cpu + * index: the index of the requested record + * record (out): pointer to the requested record + */ + extern int ds_access_bts(struct task_struct *task, + size_t index, const void **record); + extern int ds_access_pebs(struct task_struct *task, + size_t index, const void **record); + + /* + * Write one or more BTS/PEBS records at the write pointer index and + * advance the write pointer. + * + * If size is not a multiple of the record size, trailing bytes are + * zeroed out. + * + * May result in one or more overflow notifications. + * + * If called during overflow handling, that is, with index >= + * interrupt threshold, the write will wrap around. + * + * An overflow notification is given if and when the interrupt + * threshold is reached during or after the write. + * + * Returns the number of bytes written or -Eerrno. + * + * task: the task to access; + * NULL to access the current cpu + * buffer: the buffer to write + * size: the size of the buffer + */ + extern int ds_write_bts(struct task_struct *task, + const void *buffer, size_t size); + extern int ds_write_pebs(struct task_struct *task, + const void *buffer, size_t size); + + /* + * Same as ds_write_bts/pebs, but omit ownership checks. + * + * This is needed to have some other task than the owner of the + * BTS/PEBS buffer or the parameter task itself write into the + * respective buffer. + */ + extern int ds_unchecked_write_bts(struct task_struct *task, + const void *buffer, size_t size); + extern int ds_unchecked_write_pebs(struct task_struct *task, + const void *buffer, size_t size); + + /* + * Reset the write pointer of the BTS/PEBS buffer. + * + * Returns 0 on success; -Eerrno on error + * + * task: the task to access; + * NULL to access the current cpu + */ + extern int ds_reset_bts(struct task_struct *task); + extern int ds_reset_pebs(struct task_struct *task); + + /* + * Clear the BTS/PEBS buffer and reset the write pointer. + * The entire buffer will be zeroed out. + * + * Returns 0 on success; -Eerrno on error + * + * task: the task to access; + * NULL to access the current cpu + */ + extern int ds_clear_bts(struct task_struct *task); + extern int ds_clear_pebs(struct task_struct *task); + + /* + * Provide the PEBS counter reset value. + * + * Returns 0 on success; -Eerrno on error + * + * task: the task to access; + * NULL to access the current cpu + * value (out): the counter reset value + */ + extern int ds_get_pebs_reset(struct task_struct *task, u64 *value); + + /* + * Set the PEBS counter reset value. + * + * Returns 0 on success; -Eerrno on error + * + * task: the task to access; + * NULL to access the current cpu + * value: the new counter reset value + */ + extern int ds_set_pebs_reset(struct task_struct *task, u64 value); + + /* + * Initialization + */ + struct cpuinfo_x86; + extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); + + - struct bts_struct { - u64 qualifier; - union { - /* BTS_BRANCH */ - struct { - u64 from_ip; - u64 to_ip; - } lbr; - /* BTS_TASK_ARRIVES or - BTS_TASK_DEPARTS */ - u64 jiffies; - } variant; + /* + * The DS context - part of struct thread_struct. + */ + struct ds_context { + /* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */ + unsigned char *ds; + /* the owner of the BTS and PEBS configuration, respectively */ + struct task_struct *owner[2]; + /* buffer overflow notification function for BTS and PEBS */ + ds_ovfl_callback_t callback[2]; + /* the original buffer address */ + void *buffer[2]; + /* the number of allocated pages for on-request allocated buffers */ + unsigned int pages[2]; + /* use count */ + unsigned long count; + /* a pointer to the context location inside the thread_struct + * or the per_cpu context array */ + struct ds_context **this; + /* a pointer to the task owning this context, or NULL, if the + * context is owned by a cpu */ + struct task_struct *task; }; - /* Overflow handling mechanisms */ - #define DS_O_SIGNAL 1 /* send overflow signal */ - #define DS_O_WRAP 2 /* wrap around */ - - extern int ds_allocate(void **, size_t); - extern int ds_free(void **); - extern int ds_get_bts_size(void *); - extern int ds_get_bts_end(void *); - extern int ds_get_bts_index(void *); - extern int ds_set_overflow(void *, int); - extern int ds_get_overflow(void *); - extern int ds_clear(void *); - extern int ds_read_bts(void *, int, struct bts_struct *); - extern int ds_write_bts(void *, const struct bts_struct *); - extern unsigned long ds_debugctl_mask(void); - extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *c); + /* called by exit_thread() to free leftover contexts */ + extern void ds_free(struct ds_context *context); + + #else /* CONFIG_X86_DS */ + + #define ds_init_intel(config) do {} while (0) + #endif /* CONFIG_X86_DS */ -#endif /* _ASM_X86_DS_H */ +#endif /* ASM_X86__DS_H */ diff --cc include/asm-x86/ptrace-abi.h index d0cf3344a586,3397817eded9..4298b8882a78 --- a/include/asm-x86/ptrace-abi.h +++ b/include/asm-x86/ptrace-abi.h @@@ -139,5 -140,6 +140,6 @@@ struct ptrace_bts_config BTS records are read from oldest to newest. Returns number of BTS records drained. */ + #endif /* CONFIG_X86_PTRACE_BTS */ -#endif +#endif /* ASM_X86__PTRACE_ABI_H */