Merge branch 'x86/pebs' into x86-v28-for-linus-phase1
authorIngo Molnar <mingo@elte.hu>
Mon, 6 Oct 2008 14:17:23 +0000 (16:17 +0200)
committerIngo Molnar <mingo@elte.hu>
Mon, 6 Oct 2008 14:17:23 +0000 (16:17 +0200)
Conflicts:
include/asm-x86/ds.h

Signed-off-by: Ingo Molnar <mingo@elte.hu>
1  2 
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
include/asm-x86/ds.h
include/asm-x86/processor.h
include/asm-x86/ptrace-abi.h
include/asm-x86/ptrace.h

Simple merge
Simple merge
index 6b27c686fa10f43046cd3fa123a365f408941080,72c5a190bf48076d8b99b9f42f8a6f7a16a0e009..c3c953a45b215ba24b3c4216f4ee9def2e1f7c08
   * 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 <markus.t.metzger@intel.com>, Dec 2007
+  * 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
 +#ifndef ASM_X86__DS_H
 +#define ASM_X86__DS_H
  
+ #ifdef CONFIG_X86_DS
  #include <linux/types.h>
  #include <linux/init.h>
  
- 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 /* _ASM_X86_DS_H */
+ #endif /* CONFIG_X86_DS */
 +#endif /* ASM_X86__DS_H */
Simple merge
index d0cf3344a586ccedc403472fa179039049b737c4,3397817eded997c054286ea00a2081f9051f26ba..4298b8882a782ab23ac101fcf48322eb78ea2cbb
@@@ -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 */
Simple merge