projects/linux·blob master · refs

311 lines · 6.4 KiB

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
9bool 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
16void 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
26bool 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
36bool 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
43bool exit_event_end(struct perf_sample *sample,
44 struct event_key *key __maybe_unused)
45{
46 return kvm_entry_event(sample->evsel);
47}
48
49static 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
64void 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
74int 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
85int 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
108const 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
127const 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
150const 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
171const 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
191const 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
214const 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
237const 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
260int 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
274bool 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}