1 // SPDX-License-Identifier: GPL-2.0
4 #include "../../../util/kvm-stat.h"
5 #include "../../../util/evsel.h"
10 define_exit_reasons_table(vmx_exit_reasons
, VMX_EXIT_REASONS
);
11 define_exit_reasons_table(svm_exit_reasons
, SVM_EXIT_REASONS
);
13 static struct kvm_events_ops exit_events
= {
14 .is_begin_event
= exit_event_begin
,
15 .is_end_event
= exit_event_end
,
16 .decode_key
= exit_event_decode_key
,
20 const char *vcpu_id_str
= "vcpu_id";
21 const char *kvm_exit_reason
= "exit_reason";
22 const char *kvm_entry_trace
= "kvm:kvm_entry";
23 const char *kvm_exit_trace
= "kvm:kvm_exit";
26 * For the mmio events, we treat:
27 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
28 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
30 static void mmio_event_get_key(struct evsel
*evsel
, struct perf_sample
*sample
,
31 struct event_key
*key
)
33 key
->key
= evsel__intval(evsel
, sample
, "gpa");
34 key
->info
= evsel__intval(evsel
, sample
, "type");
37 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
38 #define KVM_TRACE_MMIO_READ 1
39 #define KVM_TRACE_MMIO_WRITE 2
41 static bool mmio_event_begin(struct evsel
*evsel
,
42 struct perf_sample
*sample
, struct event_key
*key
)
44 /* MMIO read begin event in kernel. */
45 if (kvm_exit_event(evsel
))
48 /* MMIO write begin event in kernel. */
49 if (evsel__name_is(evsel
, "kvm:kvm_mmio") &&
50 evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_WRITE
) {
51 mmio_event_get_key(evsel
, sample
, key
);
58 static bool mmio_event_end(struct evsel
*evsel
, struct perf_sample
*sample
,
59 struct event_key
*key
)
61 /* MMIO write end event in kernel. */
62 if (kvm_entry_event(evsel
))
65 /* MMIO read end event in kernel.*/
66 if (evsel__name_is(evsel
, "kvm:kvm_mmio") &&
67 evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_READ
) {
68 mmio_event_get_key(evsel
, sample
, key
);
75 static void mmio_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
76 struct event_key
*key
,
79 scnprintf(decode
, KVM_EVENT_NAME_LEN
, "%#lx:%s",
80 (unsigned long)key
->key
,
81 key
->info
== KVM_TRACE_MMIO_WRITE
? "W" : "R");
84 static struct kvm_events_ops mmio_events
= {
85 .is_begin_event
= mmio_event_begin
,
86 .is_end_event
= mmio_event_end
,
87 .decode_key
= mmio_event_decode_key
,
91 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
92 static void ioport_event_get_key(struct evsel
*evsel
,
93 struct perf_sample
*sample
,
94 struct event_key
*key
)
96 key
->key
= evsel__intval(evsel
, sample
, "port");
97 key
->info
= evsel__intval(evsel
, sample
, "rw");
100 static bool ioport_event_begin(struct evsel
*evsel
,
101 struct perf_sample
*sample
,
102 struct event_key
*key
)
104 if (evsel__name_is(evsel
, "kvm:kvm_pio")) {
105 ioport_event_get_key(evsel
, sample
, key
);
112 static bool ioport_event_end(struct evsel
*evsel
,
113 struct perf_sample
*sample __maybe_unused
,
114 struct event_key
*key __maybe_unused
)
116 return kvm_entry_event(evsel
);
119 static void ioport_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
120 struct event_key
*key
,
123 scnprintf(decode
, KVM_EVENT_NAME_LEN
, "%#llx:%s",
124 (unsigned long long)key
->key
,
125 key
->info
? "POUT" : "PIN");
128 static struct kvm_events_ops ioport_events
= {
129 .is_begin_event
= ioport_event_begin
,
130 .is_end_event
= ioport_event_end
,
131 .decode_key
= ioport_event_decode_key
,
132 .name
= "IO Port Access"
135 /* The time of emulation msr is from kvm_msr to kvm_entry. */
136 static void msr_event_get_key(struct evsel
*evsel
,
137 struct perf_sample
*sample
,
138 struct event_key
*key
)
140 key
->key
= evsel__intval(evsel
, sample
, "ecx");
141 key
->info
= evsel__intval(evsel
, sample
, "write");
144 static bool msr_event_begin(struct evsel
*evsel
,
145 struct perf_sample
*sample
,
146 struct event_key
*key
)
148 if (evsel__name_is(evsel
, "kvm:kvm_msr")) {
149 msr_event_get_key(evsel
, sample
, key
);
156 static bool msr_event_end(struct evsel
*evsel
,
157 struct perf_sample
*sample __maybe_unused
,
158 struct event_key
*key __maybe_unused
)
160 return kvm_entry_event(evsel
);
163 static void msr_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
164 struct event_key
*key
,
167 scnprintf(decode
, KVM_EVENT_NAME_LEN
, "%#llx:%s",
168 (unsigned long long)key
->key
,
169 key
->info
? "W" : "R");
172 static struct kvm_events_ops msr_events
= {
173 .is_begin_event
= msr_event_begin
,
174 .is_end_event
= msr_event_end
,
175 .decode_key
= msr_event_decode_key
,
179 const char *kvm_events_tp
[] = {
188 struct kvm_reg_events_ops kvm_reg_events_ops
[] = {
189 { .name
= "vmexit", .ops
= &exit_events
},
190 { .name
= "mmio", .ops
= &mmio_events
},
191 { .name
= "ioport", .ops
= &ioport_events
},
192 { .name
= "msr", .ops
= &msr_events
},
196 const char * const kvm_skip_events
[] = {
201 int cpu_isa_init(struct perf_kvm_stat
*kvm
, const char *cpuid
)
203 if (strstr(cpuid
, "Intel")) {
204 kvm
->exit_reasons
= vmx_exit_reasons
;
205 kvm
->exit_reasons_isa
= "VMX";
206 } else if (strstr(cpuid
, "AMD") || strstr(cpuid
, "Hygon")) {
207 kvm
->exit_reasons
= svm_exit_reasons
;
208 kvm
->exit_reasons_isa
= "SVM";