0001
0002 #include <errno.h>
0003 #include <string.h>
0004 #include "../../../util/kvm-stat.h"
0005 #include "../../../util/evsel.h"
0006 #include <asm/svm.h>
0007 #include <asm/vmx.h>
0008 #include <asm/kvm.h>
0009
0010 define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
0011 define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
0012
0013 static struct kvm_events_ops exit_events = {
0014 .is_begin_event = exit_event_begin,
0015 .is_end_event = exit_event_end,
0016 .decode_key = exit_event_decode_key,
0017 .name = "VM-EXIT"
0018 };
0019
0020 const char *vcpu_id_str = "vcpu_id";
0021 const int decode_str_len = 20;
0022 const char *kvm_exit_reason = "exit_reason";
0023 const char *kvm_entry_trace = "kvm:kvm_entry";
0024 const char *kvm_exit_trace = "kvm:kvm_exit";
0025
0026
0027
0028
0029
0030
0031 static void mmio_event_get_key(struct evsel *evsel, struct perf_sample *sample,
0032 struct event_key *key)
0033 {
0034 key->key = evsel__intval(evsel, sample, "gpa");
0035 key->info = evsel__intval(evsel, sample, "type");
0036 }
0037
0038 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
0039 #define KVM_TRACE_MMIO_READ 1
0040 #define KVM_TRACE_MMIO_WRITE 2
0041
0042 static bool mmio_event_begin(struct evsel *evsel,
0043 struct perf_sample *sample, struct event_key *key)
0044 {
0045
0046 if (kvm_exit_event(evsel))
0047 return true;
0048
0049
0050 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
0051 evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
0052 mmio_event_get_key(evsel, sample, key);
0053 return true;
0054 }
0055
0056 return false;
0057 }
0058
0059 static bool mmio_event_end(struct evsel *evsel, struct perf_sample *sample,
0060 struct event_key *key)
0061 {
0062
0063 if (kvm_entry_event(evsel))
0064 return true;
0065
0066
0067 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
0068 evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
0069 mmio_event_get_key(evsel, sample, key);
0070 return true;
0071 }
0072
0073 return false;
0074 }
0075
0076 static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
0077 struct event_key *key,
0078 char *decode)
0079 {
0080 scnprintf(decode, decode_str_len, "%#lx:%s",
0081 (unsigned long)key->key,
0082 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
0083 }
0084
0085 static struct kvm_events_ops mmio_events = {
0086 .is_begin_event = mmio_event_begin,
0087 .is_end_event = mmio_event_end,
0088 .decode_key = mmio_event_decode_key,
0089 .name = "MMIO Access"
0090 };
0091
0092
0093 static void ioport_event_get_key(struct evsel *evsel,
0094 struct perf_sample *sample,
0095 struct event_key *key)
0096 {
0097 key->key = evsel__intval(evsel, sample, "port");
0098 key->info = evsel__intval(evsel, sample, "rw");
0099 }
0100
0101 static bool ioport_event_begin(struct evsel *evsel,
0102 struct perf_sample *sample,
0103 struct event_key *key)
0104 {
0105 if (!strcmp(evsel->name, "kvm:kvm_pio")) {
0106 ioport_event_get_key(evsel, sample, key);
0107 return true;
0108 }
0109
0110 return false;
0111 }
0112
0113 static bool ioport_event_end(struct evsel *evsel,
0114 struct perf_sample *sample __maybe_unused,
0115 struct event_key *key __maybe_unused)
0116 {
0117 return kvm_entry_event(evsel);
0118 }
0119
0120 static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
0121 struct event_key *key,
0122 char *decode)
0123 {
0124 scnprintf(decode, decode_str_len, "%#llx:%s",
0125 (unsigned long long)key->key,
0126 key->info ? "POUT" : "PIN");
0127 }
0128
0129 static struct kvm_events_ops ioport_events = {
0130 .is_begin_event = ioport_event_begin,
0131 .is_end_event = ioport_event_end,
0132 .decode_key = ioport_event_decode_key,
0133 .name = "IO Port Access"
0134 };
0135
0136
0137 static void msr_event_get_key(struct evsel *evsel,
0138 struct perf_sample *sample,
0139 struct event_key *key)
0140 {
0141 key->key = evsel__intval(evsel, sample, "ecx");
0142 key->info = evsel__intval(evsel, sample, "write");
0143 }
0144
0145 static bool msr_event_begin(struct evsel *evsel,
0146 struct perf_sample *sample,
0147 struct event_key *key)
0148 {
0149 if (!strcmp(evsel->name, "kvm:kvm_msr")) {
0150 msr_event_get_key(evsel, sample, key);
0151 return true;
0152 }
0153
0154 return false;
0155 }
0156
0157 static bool msr_event_end(struct evsel *evsel,
0158 struct perf_sample *sample __maybe_unused,
0159 struct event_key *key __maybe_unused)
0160 {
0161 return kvm_entry_event(evsel);
0162 }
0163
0164 static void msr_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
0165 struct event_key *key,
0166 char *decode)
0167 {
0168 scnprintf(decode, decode_str_len, "%#llx:%s",
0169 (unsigned long long)key->key,
0170 key->info ? "W" : "R");
0171 }
0172
0173 static struct kvm_events_ops msr_events = {
0174 .is_begin_event = msr_event_begin,
0175 .is_end_event = msr_event_end,
0176 .decode_key = msr_event_decode_key,
0177 .name = "MSR Access"
0178 };
0179
0180 const char *kvm_events_tp[] = {
0181 "kvm:kvm_entry",
0182 "kvm:kvm_exit",
0183 "kvm:kvm_mmio",
0184 "kvm:kvm_pio",
0185 "kvm:kvm_msr",
0186 NULL,
0187 };
0188
0189 struct kvm_reg_events_ops kvm_reg_events_ops[] = {
0190 { .name = "vmexit", .ops = &exit_events },
0191 { .name = "mmio", .ops = &mmio_events },
0192 { .name = "ioport", .ops = &ioport_events },
0193 { .name = "msr", .ops = &msr_events },
0194 { NULL, NULL },
0195 };
0196
0197 const char * const kvm_skip_events[] = {
0198 "HLT",
0199 NULL,
0200 };
0201
0202 int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
0203 {
0204 if (strstr(cpuid, "Intel")) {
0205 kvm->exit_reasons = vmx_exit_reasons;
0206 kvm->exit_reasons_isa = "VMX";
0207 } else if (strstr(cpuid, "AMD") || strstr(cpuid, "Hygon")) {
0208 kvm->exit_reasons = svm_exit_reasons;
0209 kvm->exit_reasons_isa = "SVM";
0210 } else
0211 return -ENOTSUP;
0212
0213 return 0;
0214 }