1 #include "../../util/kvm-stat.h" 2 #include <asm/svm.h> 3 #include <asm/vmx.h> 4 #include <asm/kvm.h> 5 6 define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); 7 define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); 8 9 static struct kvm_events_ops exit_events = { 10 .is_begin_event = exit_event_begin, 11 .is_end_event = exit_event_end, 12 .decode_key = exit_event_decode_key, 13 .name = "VM-EXIT" 14 }; 15 16 const char *vcpu_id_str = "vcpu_id"; 17 const int decode_str_len = 20; 18 const char *kvm_exit_reason = "exit_reason"; 19 const char *kvm_entry_trace = "kvm:kvm_entry"; 20 const char *kvm_exit_trace = "kvm:kvm_exit"; 21 22 /* 23 * For the mmio events, we treat: 24 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry 25 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). 26 */ 27 static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, 28 struct event_key *key) 29 { 30 key->key = perf_evsel__intval(evsel, sample, "gpa"); 31 key->info = perf_evsel__intval(evsel, sample, "type"); 32 } 33 34 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 35 #define KVM_TRACE_MMIO_READ 1 36 #define KVM_TRACE_MMIO_WRITE 2 37 38 static bool mmio_event_begin(struct perf_evsel *evsel, 39 struct perf_sample *sample, struct event_key *key) 40 { 41 /* MMIO read begin event in kernel. */ 42 if (kvm_exit_event(evsel)) 43 return true; 44 45 /* MMIO write begin event in kernel. */ 46 if (!strcmp(evsel->name, "kvm:kvm_mmio") && 47 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { 48 mmio_event_get_key(evsel, sample, key); 49 return true; 50 } 51 52 return false; 53 } 54 55 static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, 56 struct event_key *key) 57 { 58 /* MMIO write end event in kernel. */ 59 if (kvm_entry_event(evsel)) 60 return true; 61 62 /* MMIO read end event in kernel.*/ 63 if (!strcmp(evsel->name, "kvm:kvm_mmio") && 64 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { 65 mmio_event_get_key(evsel, sample, key); 66 return true; 67 } 68 69 return false; 70 } 71 72 static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, 73 struct event_key *key, 74 char *decode) 75 { 76 scnprintf(decode, decode_str_len, "%#lx:%s", 77 (unsigned long)key->key, 78 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); 79 } 80 81 static struct kvm_events_ops mmio_events = { 82 .is_begin_event = mmio_event_begin, 83 .is_end_event = mmio_event_end, 84 .decode_key = mmio_event_decode_key, 85 .name = "MMIO Access" 86 }; 87 88 /* The time of emulation pio access is from kvm_pio to kvm_entry. */ 89 static void ioport_event_get_key(struct perf_evsel *evsel, 90 struct perf_sample *sample, 91 struct event_key *key) 92 { 93 key->key = perf_evsel__intval(evsel, sample, "port"); 94 key->info = perf_evsel__intval(evsel, sample, "rw"); 95 } 96 97 static bool ioport_event_begin(struct perf_evsel *evsel, 98 struct perf_sample *sample, 99 struct event_key *key) 100 { 101 if (!strcmp(evsel->name, "kvm:kvm_pio")) { 102 ioport_event_get_key(evsel, sample, key); 103 return true; 104 } 105 106 return false; 107 } 108 109 static bool ioport_event_end(struct perf_evsel *evsel, 110 struct perf_sample *sample __maybe_unused, 111 struct event_key *key __maybe_unused) 112 { 113 return kvm_entry_event(evsel); 114 } 115 116 static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, 117 struct event_key *key, 118 char *decode) 119 { 120 scnprintf(decode, decode_str_len, "%#llx:%s", 121 (unsigned long long)key->key, 122 key->info ? "POUT" : "PIN"); 123 } 124 125 static struct kvm_events_ops ioport_events = { 126 .is_begin_event = ioport_event_begin, 127 .is_end_event = ioport_event_end, 128 .decode_key = ioport_event_decode_key, 129 .name = "IO Port Access" 130 }; 131 132 const char *kvm_events_tp[] = { 133 "kvm:kvm_entry", 134 "kvm:kvm_exit", 135 "kvm:kvm_mmio", 136 "kvm:kvm_pio", 137 NULL, 138 }; 139 140 struct kvm_reg_events_ops kvm_reg_events_ops[] = { 141 { .name = "vmexit", .ops = &exit_events }, 142 { .name = "mmio", .ops = &mmio_events }, 143 { .name = "ioport", .ops = &ioport_events }, 144 { NULL, NULL }, 145 }; 146 147 const char * const kvm_skip_events[] = { 148 "HLT", 149 NULL, 150 }; 151 152 int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) 153 { 154 if (strstr(cpuid, "Intel")) { 155 kvm->exit_reasons = vmx_exit_reasons; 156 kvm->exit_reasons_isa = "VMX"; 157 } else if (strstr(cpuid, "AMD")) { 158 kvm->exit_reasons = svm_exit_reasons; 159 kvm->exit_reasons_isa = "SVM"; 160 } else 161 return -ENOTSUP; 162 163 return 0; 164 } 165