Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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  * For the mmio events, we treat:
0028  * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
0029  * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
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     /* MMIO read begin event in kernel. */
0046     if (kvm_exit_event(evsel))
0047         return true;
0048 
0049     /* MMIO write begin event in kernel. */
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     /* MMIO write end event in kernel. */
0063     if (kvm_entry_event(evsel))
0064         return true;
0065 
0066     /* MMIO read end event in kernel.*/
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  /* The time of emulation pio access is from kvm_pio to kvm_entry. */
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  /* The time of emulation msr is from kvm_msr to kvm_entry. */
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 }