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