diff options
-rw-r--r-- | Documentation/trace/events-msr.txt | 37 | ||||
-rw-r--r-- | Documentation/trace/postprocess/decode_msr.py | 37 | ||||
-rw-r--r-- | arch/x86/include/asm/msr-trace.h | 57 | ||||
-rw-r--r-- | arch/x86/include/asm/msr.h | 31 | ||||
-rw-r--r-- | arch/x86/lib/msr.c | 26 |
5 files changed, 188 insertions, 0 deletions
diff --git a/Documentation/trace/events-msr.txt b/Documentation/trace/events-msr.txt new file mode 100644 index 000000000000..78c383bf06aa --- /dev/null +++ b/Documentation/trace/events-msr.txt | |||
@@ -0,0 +1,37 @@ | |||
1 | |||
2 | The x86 kernel supports tracing most MSR (Model Specific Register) accesses. | ||
3 | To see the definition of the MSRs on Intel systems please see the SDM | ||
4 | at http://www.intel.com/sdm (Volume 3) | ||
5 | |||
6 | Available trace points: | ||
7 | |||
8 | /sys/kernel/debug/tracing/events/msr/ | ||
9 | |||
10 | Trace MSR reads | ||
11 | |||
12 | read_msr | ||
13 | |||
14 | msr: MSR number | ||
15 | val: Value written | ||
16 | failed: 1 if the access failed, otherwise 0 | ||
17 | |||
18 | |||
19 | Trace MSR writes | ||
20 | |||
21 | write_msr | ||
22 | |||
23 | msr: MSR number | ||
24 | val: Value written | ||
25 | failed: 1 if the access failed, otherwise 0 | ||
26 | |||
27 | |||
28 | Trace RDPMC in kernel | ||
29 | |||
30 | rdpmc | ||
31 | |||
32 | The trace data can be post processed with the postprocess/decode_msr.py script | ||
33 | |||
34 | cat /sys/kernel/debug/tracing/trace | decode_msr.py /usr/src/linux/include/asm/msr-index.h | ||
35 | |||
36 | to add symbolic MSR names. | ||
37 | |||
diff --git a/Documentation/trace/postprocess/decode_msr.py b/Documentation/trace/postprocess/decode_msr.py new file mode 100644 index 000000000000..0ab40e0db580 --- /dev/null +++ b/Documentation/trace/postprocess/decode_msr.py | |||
@@ -0,0 +1,37 @@ | |||
1 | #!/usr/bin/python | ||
2 | # add symbolic names to read_msr / write_msr in trace | ||
3 | # decode_msr msr-index.h < trace | ||
4 | import sys | ||
5 | import re | ||
6 | |||
7 | msrs = dict() | ||
8 | |||
9 | with open(sys.argv[1] if len(sys.argv) > 1 else "msr-index.h", "r") as f: | ||
10 | for j in f: | ||
11 | m = re.match(r'#define (MSR_\w+)\s+(0x[0-9a-fA-F]+)', j) | ||
12 | if m: | ||
13 | msrs[int(m.group(2), 16)] = m.group(1) | ||
14 | |||
15 | extra_ranges = ( | ||
16 | ( "MSR_LASTBRANCH_%d_FROM_IP", 0x680, 0x69F ), | ||
17 | ( "MSR_LASTBRANCH_%d_TO_IP", 0x6C0, 0x6DF ), | ||
18 | ( "LBR_INFO_%d", 0xdc0, 0xddf ), | ||
19 | ) | ||
20 | |||
21 | for j in sys.stdin: | ||
22 | m = re.search(r'(read|write)_msr:\s+([0-9a-f]+)', j) | ||
23 | if m: | ||
24 | r = None | ||
25 | num = int(m.group(2), 16) | ||
26 | if num in msrs: | ||
27 | r = msrs[num] | ||
28 | else: | ||
29 | for er in extra_ranges: | ||
30 | if er[1] <= num <= er[2]: | ||
31 | r = er[0] % (num - er[1],) | ||
32 | break | ||
33 | if r: | ||
34 | j = j.replace(" " + m.group(2), " " + r + "(" + m.group(2) + ")") | ||
35 | print j, | ||
36 | |||
37 | |||
diff --git a/arch/x86/include/asm/msr-trace.h b/arch/x86/include/asm/msr-trace.h new file mode 100644 index 000000000000..7567225747d8 --- /dev/null +++ b/arch/x86/include/asm/msr-trace.h | |||
@@ -0,0 +1,57 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM msr | ||
3 | |||
4 | #undef TRACE_INCLUDE_FILE | ||
5 | #define TRACE_INCLUDE_FILE msr-trace | ||
6 | |||
7 | #undef TRACE_INCLUDE_PATH | ||
8 | #define TRACE_INCLUDE_PATH asm/ | ||
9 | |||
10 | #if !defined(_TRACE_MSR_H) || defined(TRACE_HEADER_MULTI_READ) | ||
11 | #define _TRACE_MSR_H | ||
12 | |||
13 | #include <linux/tracepoint.h> | ||
14 | |||
15 | /* | ||
16 | * Tracing for x86 model specific registers. Directly maps to the | ||
17 | * RDMSR/WRMSR instructions. | ||
18 | */ | ||
19 | |||
20 | DECLARE_EVENT_CLASS(msr_trace_class, | ||
21 | TP_PROTO(unsigned msr, u64 val, int failed), | ||
22 | TP_ARGS(msr, val, failed), | ||
23 | TP_STRUCT__entry( | ||
24 | __field( unsigned, msr ) | ||
25 | __field( u64, val ) | ||
26 | __field( int, failed ) | ||
27 | ), | ||
28 | TP_fast_assign( | ||
29 | __entry->msr = msr; | ||
30 | __entry->val = val; | ||
31 | __entry->failed = failed; | ||
32 | ), | ||
33 | TP_printk("%x, value %llx%s", | ||
34 | __entry->msr, | ||
35 | __entry->val, | ||
36 | __entry->failed ? " #GP" : "") | ||
37 | ); | ||
38 | |||
39 | DEFINE_EVENT(msr_trace_class, read_msr, | ||
40 | TP_PROTO(unsigned msr, u64 val, int failed), | ||
41 | TP_ARGS(msr, val, failed) | ||
42 | ); | ||
43 | |||
44 | DEFINE_EVENT(msr_trace_class, write_msr, | ||
45 | TP_PROTO(unsigned msr, u64 val, int failed), | ||
46 | TP_ARGS(msr, val, failed) | ||
47 | ); | ||
48 | |||
49 | DEFINE_EVENT(msr_trace_class, rdpmc, | ||
50 | TP_PROTO(unsigned msr, u64 val, int failed), | ||
51 | TP_ARGS(msr, val, failed) | ||
52 | ); | ||
53 | |||
54 | #endif /* _TRACE_MSR_H */ | ||
55 | |||
56 | /* This part must be outside protection */ | ||
57 | #include <trace/define_trace.h> | ||
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 77d8b284e4a7..fedd6e6d1e43 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h | |||
@@ -57,11 +57,34 @@ static inline unsigned long long native_read_tscp(unsigned int *aux) | |||
57 | #define EAX_EDX_RET(val, low, high) "=A" (val) | 57 | #define EAX_EDX_RET(val, low, high) "=A" (val) |
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | #ifdef CONFIG_TRACEPOINTS | ||
61 | /* | ||
62 | * Be very careful with includes. This header is prone to include loops. | ||
63 | */ | ||
64 | #include <asm/atomic.h> | ||
65 | #include <linux/tracepoint-defs.h> | ||
66 | |||
67 | extern struct tracepoint __tracepoint_read_msr; | ||
68 | extern struct tracepoint __tracepoint_write_msr; | ||
69 | extern struct tracepoint __tracepoint_rdpmc; | ||
70 | #define msr_tracepoint_active(t) static_key_false(&(t).key) | ||
71 | extern void do_trace_write_msr(unsigned msr, u64 val, int failed); | ||
72 | extern void do_trace_read_msr(unsigned msr, u64 val, int failed); | ||
73 | extern void do_trace_rdpmc(unsigned msr, u64 val, int failed); | ||
74 | #else | ||
75 | #define msr_tracepoint_active(t) false | ||
76 | static inline void do_trace_write_msr(unsigned msr, u64 val, int failed) {} | ||
77 | static inline void do_trace_read_msr(unsigned msr, u64 val, int failed) {} | ||
78 | static inline void do_trace_rdpmc(unsigned msr, u64 val, int failed) {} | ||
79 | #endif | ||
80 | |||
60 | static inline unsigned long long native_read_msr(unsigned int msr) | 81 | static inline unsigned long long native_read_msr(unsigned int msr) |
61 | { | 82 | { |
62 | DECLARE_ARGS(val, low, high); | 83 | DECLARE_ARGS(val, low, high); |
63 | 84 | ||
64 | asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr)); | 85 | asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr)); |
86 | if (msr_tracepoint_active(__tracepoint_read_msr)) | ||
87 | do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), 0); | ||
65 | return EAX_EDX_VAL(val, low, high); | 88 | return EAX_EDX_VAL(val, low, high); |
66 | } | 89 | } |
67 | 90 | ||
@@ -78,6 +101,8 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr, | |||
78 | _ASM_EXTABLE(2b, 3b) | 101 | _ASM_EXTABLE(2b, 3b) |
79 | : [err] "=r" (*err), EAX_EDX_RET(val, low, high) | 102 | : [err] "=r" (*err), EAX_EDX_RET(val, low, high) |
80 | : "c" (msr), [fault] "i" (-EIO)); | 103 | : "c" (msr), [fault] "i" (-EIO)); |
104 | if (msr_tracepoint_active(__tracepoint_read_msr)) | ||
105 | do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), *err); | ||
81 | return EAX_EDX_VAL(val, low, high); | 106 | return EAX_EDX_VAL(val, low, high); |
82 | } | 107 | } |
83 | 108 | ||
@@ -85,6 +110,8 @@ static inline void native_write_msr(unsigned int msr, | |||
85 | unsigned low, unsigned high) | 110 | unsigned low, unsigned high) |
86 | { | 111 | { |
87 | asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory"); | 112 | asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory"); |
113 | if (msr_tracepoint_active(__tracepoint_read_msr)) | ||
114 | do_trace_write_msr(msr, ((u64)high << 32 | low), 0); | ||
88 | } | 115 | } |
89 | 116 | ||
90 | /* Can be uninlined because referenced by paravirt */ | 117 | /* Can be uninlined because referenced by paravirt */ |
@@ -102,6 +129,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr, | |||
102 | : "c" (msr), "0" (low), "d" (high), | 129 | : "c" (msr), "0" (low), "d" (high), |
103 | [fault] "i" (-EIO) | 130 | [fault] "i" (-EIO) |
104 | : "memory"); | 131 | : "memory"); |
132 | if (msr_tracepoint_active(__tracepoint_read_msr)) | ||
133 | do_trace_write_msr(msr, ((u64)high << 32 | low), err); | ||
105 | return err; | 134 | return err; |
106 | } | 135 | } |
107 | 136 | ||
@@ -160,6 +189,8 @@ static inline unsigned long long native_read_pmc(int counter) | |||
160 | DECLARE_ARGS(val, low, high); | 189 | DECLARE_ARGS(val, low, high); |
161 | 190 | ||
162 | asm volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter)); | 191 | asm volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter)); |
192 | if (msr_tracepoint_active(__tracepoint_rdpmc)) | ||
193 | do_trace_rdpmc(counter, EAX_EDX_VAL(val, low, high), 0); | ||
163 | return EAX_EDX_VAL(val, low, high); | 194 | return EAX_EDX_VAL(val, low, high); |
164 | } | 195 | } |
165 | 196 | ||
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c index 43623739c7cf..004c861b1648 100644 --- a/arch/x86/lib/msr.c +++ b/arch/x86/lib/msr.c | |||
@@ -1,6 +1,8 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include <linux/preempt.h> | 2 | #include <linux/preempt.h> |
3 | #include <asm/msr.h> | 3 | #include <asm/msr.h> |
4 | #define CREATE_TRACE_POINTS | ||
5 | #include <asm/msr-trace.h> | ||
4 | 6 | ||
5 | struct msr *msrs_alloc(void) | 7 | struct msr *msrs_alloc(void) |
6 | { | 8 | { |
@@ -108,3 +110,27 @@ int msr_clear_bit(u32 msr, u8 bit) | |||
108 | { | 110 | { |
109 | return __flip_bit(msr, bit, false); | 111 | return __flip_bit(msr, bit, false); |
110 | } | 112 | } |
113 | |||
114 | #ifdef CONFIG_TRACEPOINTS | ||
115 | void do_trace_write_msr(unsigned msr, u64 val, int failed) | ||
116 | { | ||
117 | trace_write_msr(msr, val, failed); | ||
118 | } | ||
119 | EXPORT_SYMBOL(do_trace_write_msr); | ||
120 | EXPORT_TRACEPOINT_SYMBOL(write_msr); | ||
121 | |||
122 | void do_trace_read_msr(unsigned msr, u64 val, int failed) | ||
123 | { | ||
124 | trace_read_msr(msr, val, failed); | ||
125 | } | ||
126 | EXPORT_SYMBOL(do_trace_read_msr); | ||
127 | EXPORT_TRACEPOINT_SYMBOL(read_msr); | ||
128 | |||
129 | void do_trace_rdpmc(unsigned counter, u64 val, int failed) | ||
130 | { | ||
131 | trace_rdpmc(counter, val, failed); | ||
132 | } | ||
133 | EXPORT_SYMBOL(do_trace_rdpmc); | ||
134 | EXPORT_TRACEPOINT_SYMBOL(rdpmc); | ||
135 | |||
136 | #endif | ||