cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kvm-stat.c (5578B)


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