11218838dSSergey Senozhatsky // SPDX-License-Identifier: GPL-2.0 21218838dSSergey Senozhatsky #include <errno.h> 31218838dSSergey Senozhatsky #include <memory.h> 4b96da02bSIan Rogers #include "../../../util/evsel.h" 5b96da02bSIan Rogers #include "../../../util/kvm-stat.h" 61218838dSSergey Senozhatsky #include "arm64_exception_types.h" 71218838dSSergey Senozhatsky #include "debug.h" 81218838dSSergey Senozhatsky 91218838dSSergey Senozhatsky define_exit_reasons_table(arm64_exit_reasons, kvm_arm_exception_type); 101218838dSSergey Senozhatsky define_exit_reasons_table(arm64_trap_exit_reasons, kvm_arm_exception_class); 111218838dSSergey Senozhatsky 121218838dSSergey Senozhatsky const char *kvm_trap_exit_reason = "esr_ec"; 131218838dSSergey Senozhatsky const char *vcpu_id_str = "id"; 141218838dSSergey Senozhatsky const int decode_str_len = 20; 151218838dSSergey Senozhatsky const char *kvm_exit_reason = "ret"; 161218838dSSergey Senozhatsky const char *kvm_entry_trace = "kvm:kvm_entry"; 171218838dSSergey Senozhatsky const char *kvm_exit_trace = "kvm:kvm_exit"; 181218838dSSergey Senozhatsky 191218838dSSergey Senozhatsky const char *kvm_events_tp[] = { 201218838dSSergey Senozhatsky "kvm:kvm_entry", 211218838dSSergey Senozhatsky "kvm:kvm_exit", 221218838dSSergey Senozhatsky NULL, 231218838dSSergey Senozhatsky }; 241218838dSSergey Senozhatsky 251218838dSSergey Senozhatsky static void event_get_key(struct evsel *evsel, 261218838dSSergey Senozhatsky struct perf_sample *sample, 271218838dSSergey Senozhatsky struct event_key *key) 281218838dSSergey Senozhatsky { 291218838dSSergey Senozhatsky key->info = 0; 301218838dSSergey Senozhatsky key->key = evsel__intval(evsel, sample, kvm_exit_reason); 311218838dSSergey Senozhatsky key->exit_reasons = arm64_exit_reasons; 321218838dSSergey Senozhatsky 331218838dSSergey Senozhatsky /* 341218838dSSergey Senozhatsky * TRAP exceptions carry exception class info in esr_ec field 351218838dSSergey Senozhatsky * and, hence, we need to use a different exit_reasons table to 361218838dSSergey Senozhatsky * properly decode event's est_ec. 371218838dSSergey Senozhatsky */ 381218838dSSergey Senozhatsky if (key->key == ARM_EXCEPTION_TRAP) { 391218838dSSergey Senozhatsky key->key = evsel__intval(evsel, sample, kvm_trap_exit_reason); 401218838dSSergey Senozhatsky key->exit_reasons = arm64_trap_exit_reasons; 411218838dSSergey Senozhatsky } 421218838dSSergey Senozhatsky } 431218838dSSergey Senozhatsky 441218838dSSergey Senozhatsky static bool event_begin(struct evsel *evsel, 451218838dSSergey Senozhatsky struct perf_sample *sample __maybe_unused, 461218838dSSergey Senozhatsky struct event_key *key __maybe_unused) 471218838dSSergey Senozhatsky { 481218838dSSergey Senozhatsky return !strcmp(evsel->name, kvm_entry_trace); 491218838dSSergey Senozhatsky } 501218838dSSergey Senozhatsky 511218838dSSergey Senozhatsky static bool event_end(struct evsel *evsel, 521218838dSSergey Senozhatsky struct perf_sample *sample, 531218838dSSergey Senozhatsky struct event_key *key) 541218838dSSergey Senozhatsky { 551218838dSSergey Senozhatsky if (!strcmp(evsel->name, kvm_exit_trace)) { 561218838dSSergey Senozhatsky event_get_key(evsel, sample, key); 571218838dSSergey Senozhatsky return true; 581218838dSSergey Senozhatsky } 591218838dSSergey Senozhatsky return false; 601218838dSSergey Senozhatsky } 611218838dSSergey Senozhatsky 621218838dSSergey Senozhatsky static struct kvm_events_ops exit_events = { 631218838dSSergey Senozhatsky .is_begin_event = event_begin, 641218838dSSergey Senozhatsky .is_end_event = event_end, 651218838dSSergey Senozhatsky .decode_key = exit_event_decode_key, 661218838dSSergey Senozhatsky .name = "VM-EXIT" 671218838dSSergey Senozhatsky }; 681218838dSSergey Senozhatsky 691218838dSSergey Senozhatsky struct kvm_reg_events_ops kvm_reg_events_ops[] = { 701218838dSSergey Senozhatsky { 711218838dSSergey Senozhatsky .name = "vmexit", 721218838dSSergey Senozhatsky .ops = &exit_events, 731218838dSSergey Senozhatsky }, 74*a00b7e39SMasami Hiramatsu { NULL, NULL }, 751218838dSSergey Senozhatsky }; 761218838dSSergey Senozhatsky 771218838dSSergey Senozhatsky const char * const kvm_skip_events[] = { 781218838dSSergey Senozhatsky NULL, 791218838dSSergey Senozhatsky }; 801218838dSSergey Senozhatsky 811218838dSSergey Senozhatsky int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused) 821218838dSSergey Senozhatsky { 831218838dSSergey Senozhatsky kvm->exit_reasons_isa = "arm64"; 841218838dSSergey Senozhatsky return 0; 851218838dSSergey Senozhatsky } 86