1 // SPDX-License-Identifier: GPL-2.0
2 #include "debug.h"
3 #include "evsel.h"
4 #include "kvm-stat.h"
5 #include <dwarf-regs.h>
6
kvm_exit_event(struct evsel * evsel)7 bool kvm_exit_event(struct evsel *evsel)
8 {
9 uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL);
10
11 return evsel__name_is(evsel, kvm_exit_trace(e_machine));
12 }
13
exit_event_get_key(struct evsel * evsel,struct perf_sample * sample,struct event_key * key)14 void exit_event_get_key(struct evsel *evsel,
15 struct perf_sample *sample,
16 struct event_key *key)
17 {
18 uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL);
19
20 key->info = 0;
21 key->key = evsel__intval(evsel, sample, kvm_exit_reason(e_machine));
22 }
23
24
exit_event_begin(struct evsel * evsel,struct perf_sample * sample,struct event_key * key)25 bool exit_event_begin(struct evsel *evsel,
26 struct perf_sample *sample, struct event_key *key)
27 {
28 if (kvm_exit_event(evsel)) {
29 exit_event_get_key(evsel, sample, key);
30 return true;
31 }
32
33 return false;
34 }
35
kvm_entry_event(struct evsel * evsel)36 bool kvm_entry_event(struct evsel *evsel)
37 {
38 uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL);
39
40 return evsel__name_is(evsel, kvm_entry_trace(e_machine));
41 }
42
exit_event_end(struct evsel * evsel,struct perf_sample * sample __maybe_unused,struct event_key * key __maybe_unused)43 bool exit_event_end(struct evsel *evsel,
44 struct perf_sample *sample __maybe_unused,
45 struct event_key *key __maybe_unused)
46 {
47 return kvm_entry_event(evsel);
48 }
49
get_exit_reason(struct perf_kvm_stat * kvm,struct exit_reasons_table * tbl,u64 exit_code)50 static const char *get_exit_reason(struct perf_kvm_stat *kvm,
51 struct exit_reasons_table *tbl,
52 u64 exit_code)
53 {
54 while (tbl->reason != NULL) {
55 if (tbl->exit_code == exit_code)
56 return tbl->reason;
57 tbl++;
58 }
59
60 pr_err("unknown kvm exit code:%lld on %s\n",
61 (unsigned long long)exit_code, kvm->exit_reasons_isa);
62 return "UNKNOWN";
63 }
64
exit_event_decode_key(struct perf_kvm_stat * kvm,struct event_key * key,char * decode)65 void exit_event_decode_key(struct perf_kvm_stat *kvm,
66 struct event_key *key,
67 char *decode)
68 {
69 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
70 key->key);
71
72 scnprintf(decode, KVM_EVENT_NAME_LEN, "%s", exit_reason);
73 }
74
setup_kvm_events_tp(struct perf_kvm_stat * kvm,uint16_t e_machine)75 int setup_kvm_events_tp(struct perf_kvm_stat *kvm, uint16_t e_machine)
76 {
77 switch (e_machine) {
78 case EM_PPC:
79 case EM_PPC64:
80 return __setup_kvm_events_tp_powerpc(kvm);
81 default:
82 return 0;
83 }
84 }
85
cpu_isa_init(struct perf_kvm_stat * kvm,uint16_t e_machine,const char * cpuid)86 int cpu_isa_init(struct perf_kvm_stat *kvm, uint16_t e_machine, const char *cpuid)
87 {
88 switch (e_machine) {
89 case EM_AARCH64:
90 return __cpu_isa_init_arm64(kvm);
91 case EM_LOONGARCH:
92 return __cpu_isa_init_loongarch(kvm);
93 case EM_PPC:
94 case EM_PPC64:
95 return __cpu_isa_init_powerpc(kvm);
96 case EM_RISCV:
97 return __cpu_isa_init_riscv(kvm);
98 case EM_S390:
99 return __cpu_isa_init_s390(kvm, cpuid);
100 case EM_X86_64:
101 case EM_386:
102 return __cpu_isa_init_x86(kvm, cpuid);
103 default:
104 pr_err("Unsupported kvm-stat host %d\n", e_machine);
105 return -1;
106 }
107 }
108
vcpu_id_str(uint16_t e_machine)109 const char *vcpu_id_str(uint16_t e_machine)
110 {
111 switch (e_machine) {
112 case EM_AARCH64:
113 case EM_RISCV:
114 case EM_S390:
115 return "id";
116 case EM_LOONGARCH:
117 case EM_PPC:
118 case EM_PPC64:
119 case EM_X86_64:
120 case EM_386:
121 return "vcpu_id";
122 default:
123 pr_err("Unsupported kvm-stat host %d\n", e_machine);
124 return NULL;
125 }
126 }
127
kvm_exit_reason(uint16_t e_machine)128 const char *kvm_exit_reason(uint16_t e_machine)
129 {
130 switch (e_machine) {
131 case EM_AARCH64:
132 return "ret";
133 case EM_LOONGARCH:
134 return "reason";
135 case EM_PPC:
136 case EM_PPC64:
137 return "trap";
138 case EM_RISCV:
139 return "scause";
140 case EM_S390:
141 return "icptcode";
142 case EM_X86_64:
143 case EM_386:
144 return "exit_reason";
145 default:
146 pr_err("Unsupported kvm-stat host %d\n", e_machine);
147 return NULL;
148 }
149 }
150
kvm_entry_trace(uint16_t e_machine)151 const char *kvm_entry_trace(uint16_t e_machine)
152 {
153 switch (e_machine) {
154 case EM_AARCH64:
155 case EM_RISCV:
156 case EM_X86_64:
157 case EM_386:
158 return "kvm:kvm_entry";
159 case EM_LOONGARCH:
160 return "kvm:kvm_enter";
161 case EM_PPC:
162 case EM_PPC64:
163 return "kvm_hv:kvm_guest_enter";
164 case EM_S390:
165 return "kvm:kvm_s390_sie_enter";
166 default:
167 pr_err("Unsupported kvm-stat host %d\n", e_machine);
168 return NULL;
169 }
170 }
171
kvm_exit_trace(uint16_t e_machine)172 const char *kvm_exit_trace(uint16_t e_machine)
173 {
174 switch (e_machine) {
175 case EM_AARCH64:
176 case EM_LOONGARCH:
177 case EM_RISCV:
178 case EM_X86_64:
179 case EM_386:
180 return "kvm:kvm_exit";
181 case EM_PPC:
182 case EM_PPC64:
183 return "kvm_hv:kvm_guest_exit";
184 case EM_S390:
185 return "kvm:kvm_s390_sie_exit";
186 default:
187 pr_err("Unsupported kvm-stat host %d\n", e_machine);
188 return NULL;
189 }
190 }
191
kvm_events_tp(uint16_t e_machine)192 const char * const *kvm_events_tp(uint16_t e_machine)
193 {
194 switch (e_machine) {
195 case EM_AARCH64:
196 return __kvm_events_tp_arm64();
197 case EM_LOONGARCH:
198 return __kvm_events_tp_loongarch();
199 case EM_PPC:
200 case EM_PPC64:
201 return __kvm_events_tp_powerpc();
202 case EM_RISCV:
203 return __kvm_events_tp_riscv();
204 case EM_S390:
205 return __kvm_events_tp_s390();
206 case EM_X86_64:
207 case EM_386:
208 return __kvm_events_tp_x86();
209 default:
210 pr_err("Unsupported kvm-stat host %d\n", e_machine);
211 return NULL;
212 }
213 }
214
kvm_reg_events_ops(uint16_t e_machine)215 const struct kvm_reg_events_ops *kvm_reg_events_ops(uint16_t e_machine)
216 {
217 switch (e_machine) {
218 case EM_AARCH64:
219 return __kvm_reg_events_ops_arm64();
220 case EM_LOONGARCH:
221 return __kvm_reg_events_ops_loongarch();
222 case EM_PPC:
223 case EM_PPC64:
224 return __kvm_reg_events_ops_powerpc();
225 case EM_RISCV:
226 return __kvm_reg_events_ops_riscv();
227 case EM_S390:
228 return __kvm_reg_events_ops_s390();
229 case EM_X86_64:
230 case EM_386:
231 return __kvm_reg_events_ops_x86();
232 default:
233 pr_err("Unsupported kvm-stat host %d\n", e_machine);
234 return NULL;
235 }
236 }
237
kvm_skip_events(uint16_t e_machine)238 const char * const *kvm_skip_events(uint16_t e_machine)
239 {
240 switch (e_machine) {
241 case EM_AARCH64:
242 return __kvm_skip_events_arm64();
243 case EM_LOONGARCH:
244 return __kvm_skip_events_loongarch();
245 case EM_PPC:
246 case EM_PPC64:
247 return __kvm_skip_events_powerpc();
248 case EM_RISCV:
249 return __kvm_skip_events_riscv();
250 case EM_S390:
251 return __kvm_skip_events_s390();
252 case EM_X86_64:
253 case EM_386:
254 return __kvm_skip_events_x86();
255 default:
256 pr_err("Unsupported kvm-stat host %d\n", e_machine);
257 return NULL;
258 }
259 }
260
kvm_add_default_arch_event(uint16_t e_machine,int * argc,const char ** argv)261 int kvm_add_default_arch_event(uint16_t e_machine, int *argc, const char **argv)
262 {
263 switch (e_machine) {
264 case EM_PPC:
265 case EM_PPC64:
266 return __kvm_add_default_arch_event_powerpc(argc, argv);
267 case EM_X86_64:
268 case EM_386:
269 return __kvm_add_default_arch_event_x86(argc, argv);
270 default:
271 return 0;
272 }
273 }
274