1 // SPDX-License-Identifier: GPL-2.0
3 #include "../../util/kvm-stat.h"
8 define_exit_reasons_table(vmx_exit_reasons
, VMX_EXIT_REASONS
);
9 define_exit_reasons_table(svm_exit_reasons
, SVM_EXIT_REASONS
);
11 static struct kvm_events_ops exit_events
= {
12 .is_begin_event
= exit_event_begin
,
13 .is_end_event
= exit_event_end
,
14 .decode_key
= exit_event_decode_key
,
18 const char *vcpu_id_str
= "vcpu_id";
19 const int decode_str_len
= 20;
20 const char *kvm_exit_reason
= "exit_reason";
21 const char *kvm_entry_trace
= "kvm:kvm_entry";
22 const char *kvm_exit_trace
= "kvm:kvm_exit";
25 * For the mmio events, we treat:
26 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
27 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
29 static void mmio_event_get_key(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
30 struct event_key
*key
)
32 key
->key
= perf_evsel__intval(evsel
, sample
, "gpa");
33 key
->info
= perf_evsel__intval(evsel
, sample
, "type");
36 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
37 #define KVM_TRACE_MMIO_READ 1
38 #define KVM_TRACE_MMIO_WRITE 2
40 static bool mmio_event_begin(struct perf_evsel
*evsel
,
41 struct perf_sample
*sample
, struct event_key
*key
)
43 /* MMIO read begin event in kernel. */
44 if (kvm_exit_event(evsel
))
47 /* MMIO write begin event in kernel. */
48 if (!strcmp(evsel
->name
, "kvm:kvm_mmio") &&
49 perf_evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_WRITE
) {
50 mmio_event_get_key(evsel
, sample
, key
);
57 static bool mmio_event_end(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
58 struct event_key
*key
)
60 /* MMIO write end event in kernel. */
61 if (kvm_entry_event(evsel
))
64 /* MMIO read end event in kernel.*/
65 if (!strcmp(evsel
->name
, "kvm:kvm_mmio") &&
66 perf_evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_READ
) {
67 mmio_event_get_key(evsel
, sample
, key
);
74 static void mmio_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
75 struct event_key
*key
,
78 scnprintf(decode
, decode_str_len
, "%#lx:%s",
79 (unsigned long)key
->key
,
80 key
->info
== KVM_TRACE_MMIO_WRITE
? "W" : "R");
83 static struct kvm_events_ops mmio_events
= {
84 .is_begin_event
= mmio_event_begin
,
85 .is_end_event
= mmio_event_end
,
86 .decode_key
= mmio_event_decode_key
,
90 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
91 static void ioport_event_get_key(struct perf_evsel
*evsel
,
92 struct perf_sample
*sample
,
93 struct event_key
*key
)
95 key
->key
= perf_evsel__intval(evsel
, sample
, "port");
96 key
->info
= perf_evsel__intval(evsel
, sample
, "rw");
99 static bool ioport_event_begin(struct perf_evsel
*evsel
,
100 struct perf_sample
*sample
,
101 struct event_key
*key
)
103 if (!strcmp(evsel
->name
, "kvm:kvm_pio")) {
104 ioport_event_get_key(evsel
, sample
, key
);
111 static bool ioport_event_end(struct perf_evsel
*evsel
,
112 struct perf_sample
*sample __maybe_unused
,
113 struct event_key
*key __maybe_unused
)
115 return kvm_entry_event(evsel
);
118 static void ioport_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
119 struct event_key
*key
,
122 scnprintf(decode
, decode_str_len
, "%#llx:%s",
123 (unsigned long long)key
->key
,
124 key
->info
? "POUT" : "PIN");
127 static struct kvm_events_ops ioport_events
= {
128 .is_begin_event
= ioport_event_begin
,
129 .is_end_event
= ioport_event_end
,
130 .decode_key
= ioport_event_decode_key
,
131 .name
= "IO Port Access"
134 const char *kvm_events_tp
[] = {
142 struct kvm_reg_events_ops kvm_reg_events_ops
[] = {
143 { .name
= "vmexit", .ops
= &exit_events
},
144 { .name
= "mmio", .ops
= &mmio_events
},
145 { .name
= "ioport", .ops
= &ioport_events
},
149 const char * const kvm_skip_events
[] = {
154 int cpu_isa_init(struct perf_kvm_stat
*kvm
, const char *cpuid
)
156 if (strstr(cpuid
, "Intel")) {
157 kvm
->exit_reasons
= vmx_exit_reasons
;
158 kvm
->exit_reasons_isa
= "VMX";
159 } else if (strstr(cpuid
, "AMD")) {
160 kvm
->exit_reasons
= svm_exit_reasons
;
161 kvm
->exit_reasons_isa
= "SVM";