brintos

brintos / linux-shallow public Read only

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