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

plugin_kvm.c (13594B)


      1// SPDX-License-Identifier: LGPL-2.1
      2/*
      3 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
      4 */
      5#include <stdio.h>
      6#include <stdlib.h>
      7#include <string.h>
      8#include <stdint.h>
      9
     10#include "event-parse.h"
     11#include "trace-seq.h"
     12
     13#ifdef HAVE_UDIS86
     14
     15#include <udis86.h>
     16
     17static ud_t ud;
     18
     19static void init_disassembler(void)
     20{
     21	ud_init(&ud);
     22	ud_set_syntax(&ud, UD_SYN_ATT);
     23}
     24
     25static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
     26			       int cr0_pe, int eflags_vm,
     27			       int cs_d, int cs_l)
     28{
     29	int mode;
     30
     31	if (!cr0_pe)
     32		mode = 16;
     33	else if (eflags_vm)
     34		mode = 16;
     35	else if (cs_l)
     36		mode = 64;
     37	else if (cs_d)
     38		mode = 32;
     39	else
     40		mode = 16;
     41
     42	ud_set_pc(&ud, rip);
     43	ud_set_mode(&ud, mode);
     44	ud_set_input_buffer(&ud, insn, len);
     45	ud_disassemble(&ud);
     46	return ud_insn_asm(&ud);
     47}
     48
     49#else
     50
     51static void init_disassembler(void)
     52{
     53}
     54
     55static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
     56			       int cr0_pe, int eflags_vm,
     57			       int cs_d, int cs_l)
     58{
     59	static char out[15*3+1];
     60	int i;
     61
     62	for (i = 0; i < len; ++i)
     63		sprintf(out + i * 3, "%02x ", insn[i]);
     64	out[len*3-1] = '\0';
     65	return out;
     66}
     67
     68#endif
     69
     70
     71#define VMX_EXIT_REASONS			\
     72	_ER(EXCEPTION_NMI,	 0)		\
     73	_ER(EXTERNAL_INTERRUPT,	 1)		\
     74	_ER(TRIPLE_FAULT,	 2)		\
     75	_ER(PENDING_INTERRUPT,	 7)		\
     76	_ER(NMI_WINDOW,		 8)		\
     77	_ER(TASK_SWITCH,	 9)		\
     78	_ER(CPUID,		 10)		\
     79	_ER(HLT,		 12)		\
     80	_ER(INVD,		 13)		\
     81	_ER(INVLPG,		 14)		\
     82	_ER(RDPMC,		 15)		\
     83	_ER(RDTSC,		 16)		\
     84	_ER(VMCALL,		 18)		\
     85	_ER(VMCLEAR,		 19)		\
     86	_ER(VMLAUNCH,		 20)		\
     87	_ER(VMPTRLD,		 21)		\
     88	_ER(VMPTRST,		 22)		\
     89	_ER(VMREAD,		 23)		\
     90	_ER(VMRESUME,		 24)		\
     91	_ER(VMWRITE,		 25)		\
     92	_ER(VMOFF,		 26)		\
     93	_ER(VMON,		 27)		\
     94	_ER(CR_ACCESS,		 28)		\
     95	_ER(DR_ACCESS,		 29)		\
     96	_ER(IO_INSTRUCTION,	 30)		\
     97	_ER(MSR_READ,		 31)		\
     98	_ER(MSR_WRITE,		 32)		\
     99	_ER(MWAIT_INSTRUCTION,	 36)		\
    100	_ER(MONITOR_INSTRUCTION, 39)		\
    101	_ER(PAUSE_INSTRUCTION,	 40)		\
    102	_ER(MCE_DURING_VMENTRY,	 41)		\
    103	_ER(TPR_BELOW_THRESHOLD, 43)		\
    104	_ER(APIC_ACCESS,	 44)		\
    105	_ER(EOI_INDUCED,	 45)		\
    106	_ER(EPT_VIOLATION,	 48)		\
    107	_ER(EPT_MISCONFIG,	 49)		\
    108	_ER(INVEPT,		 50)		\
    109	_ER(PREEMPTION_TIMER,	 52)		\
    110	_ER(WBINVD,		 54)		\
    111	_ER(XSETBV,		 55)		\
    112	_ER(APIC_WRITE,		 56)		\
    113	_ER(INVPCID,		 58)		\
    114	_ER(PML_FULL,		 62)		\
    115	_ER(XSAVES,		 63)		\
    116	_ER(XRSTORS,		 64)
    117
    118#define SVM_EXIT_REASONS \
    119	_ER(EXIT_READ_CR0,	0x000)		\
    120	_ER(EXIT_READ_CR3,	0x003)		\
    121	_ER(EXIT_READ_CR4,	0x004)		\
    122	_ER(EXIT_READ_CR8,	0x008)		\
    123	_ER(EXIT_WRITE_CR0,	0x010)		\
    124	_ER(EXIT_WRITE_CR3,	0x013)		\
    125	_ER(EXIT_WRITE_CR4,	0x014)		\
    126	_ER(EXIT_WRITE_CR8,	0x018)		\
    127	_ER(EXIT_READ_DR0,	0x020)		\
    128	_ER(EXIT_READ_DR1,	0x021)		\
    129	_ER(EXIT_READ_DR2,	0x022)		\
    130	_ER(EXIT_READ_DR3,	0x023)		\
    131	_ER(EXIT_READ_DR4,	0x024)		\
    132	_ER(EXIT_READ_DR5,	0x025)		\
    133	_ER(EXIT_READ_DR6,	0x026)		\
    134	_ER(EXIT_READ_DR7,	0x027)		\
    135	_ER(EXIT_WRITE_DR0,	0x030)		\
    136	_ER(EXIT_WRITE_DR1,	0x031)		\
    137	_ER(EXIT_WRITE_DR2,	0x032)		\
    138	_ER(EXIT_WRITE_DR3,	0x033)		\
    139	_ER(EXIT_WRITE_DR4,	0x034)		\
    140	_ER(EXIT_WRITE_DR5,	0x035)		\
    141	_ER(EXIT_WRITE_DR6,	0x036)		\
    142	_ER(EXIT_WRITE_DR7,	0x037)		\
    143	_ER(EXIT_EXCP_DE,	0x040)		\
    144	_ER(EXIT_EXCP_DB,	0x041)		\
    145	_ER(EXIT_EXCP_BP,	0x043)		\
    146	_ER(EXIT_EXCP_OF,	0x044)		\
    147	_ER(EXIT_EXCP_BR,	0x045)		\
    148	_ER(EXIT_EXCP_UD,	0x046)		\
    149	_ER(EXIT_EXCP_NM,	0x047)		\
    150	_ER(EXIT_EXCP_DF,	0x048)		\
    151	_ER(EXIT_EXCP_TS,	0x04a)		\
    152	_ER(EXIT_EXCP_NP,	0x04b)		\
    153	_ER(EXIT_EXCP_SS,	0x04c)		\
    154	_ER(EXIT_EXCP_GP,	0x04d)		\
    155	_ER(EXIT_EXCP_PF,	0x04e)		\
    156	_ER(EXIT_EXCP_MF,	0x050)		\
    157	_ER(EXIT_EXCP_AC,	0x051)		\
    158	_ER(EXIT_EXCP_MC,	0x052)		\
    159	_ER(EXIT_EXCP_XF,	0x053)		\
    160	_ER(EXIT_INTR,		0x060)		\
    161	_ER(EXIT_NMI,		0x061)		\
    162	_ER(EXIT_SMI,		0x062)		\
    163	_ER(EXIT_INIT,		0x063)		\
    164	_ER(EXIT_VINTR,		0x064)		\
    165	_ER(EXIT_CR0_SEL_WRITE,	0x065)		\
    166	_ER(EXIT_IDTR_READ,	0x066)		\
    167	_ER(EXIT_GDTR_READ,	0x067)		\
    168	_ER(EXIT_LDTR_READ,	0x068)		\
    169	_ER(EXIT_TR_READ,	0x069)		\
    170	_ER(EXIT_IDTR_WRITE,	0x06a)		\
    171	_ER(EXIT_GDTR_WRITE,	0x06b)		\
    172	_ER(EXIT_LDTR_WRITE,	0x06c)		\
    173	_ER(EXIT_TR_WRITE,	0x06d)		\
    174	_ER(EXIT_RDTSC,		0x06e)		\
    175	_ER(EXIT_RDPMC,		0x06f)		\
    176	_ER(EXIT_PUSHF,		0x070)		\
    177	_ER(EXIT_POPF,		0x071)		\
    178	_ER(EXIT_CPUID,		0x072)		\
    179	_ER(EXIT_RSM,		0x073)		\
    180	_ER(EXIT_IRET,		0x074)		\
    181	_ER(EXIT_SWINT,		0x075)		\
    182	_ER(EXIT_INVD,		0x076)		\
    183	_ER(EXIT_PAUSE,		0x077)		\
    184	_ER(EXIT_HLT,		0x078)		\
    185	_ER(EXIT_INVLPG,	0x079)		\
    186	_ER(EXIT_INVLPGA,	0x07a)		\
    187	_ER(EXIT_IOIO,		0x07b)		\
    188	_ER(EXIT_MSR,		0x07c)		\
    189	_ER(EXIT_TASK_SWITCH,	0x07d)		\
    190	_ER(EXIT_FERR_FREEZE,	0x07e)		\
    191	_ER(EXIT_SHUTDOWN,	0x07f)		\
    192	_ER(EXIT_VMRUN,		0x080)		\
    193	_ER(EXIT_VMMCALL,	0x081)		\
    194	_ER(EXIT_VMLOAD,	0x082)		\
    195	_ER(EXIT_VMSAVE,	0x083)		\
    196	_ER(EXIT_STGI,		0x084)		\
    197	_ER(EXIT_CLGI,		0x085)		\
    198	_ER(EXIT_SKINIT,	0x086)		\
    199	_ER(EXIT_RDTSCP,	0x087)		\
    200	_ER(EXIT_ICEBP,		0x088)		\
    201	_ER(EXIT_WBINVD,	0x089)		\
    202	_ER(EXIT_MONITOR,	0x08a)		\
    203	_ER(EXIT_MWAIT,		0x08b)		\
    204	_ER(EXIT_MWAIT_COND,	0x08c)		\
    205	_ER(EXIT_XSETBV,	0x08d)		\
    206	_ER(EXIT_NPF, 		0x400)		\
    207	_ER(EXIT_AVIC_INCOMPLETE_IPI,		0x401)	\
    208	_ER(EXIT_AVIC_UNACCELERATED_ACCESS,	0x402)	\
    209	_ER(EXIT_ERR,		-1)
    210
    211#define _ER(reason, val)	{ #reason, val },
    212struct str_values {
    213	const char	*str;
    214	int		val;
    215};
    216
    217static struct str_values vmx_exit_reasons[] = {
    218	VMX_EXIT_REASONS
    219	{ NULL, -1}
    220};
    221
    222static struct str_values svm_exit_reasons[] = {
    223	SVM_EXIT_REASONS
    224	{ NULL, -1}
    225};
    226
    227static struct isa_exit_reasons {
    228	unsigned isa;
    229	struct str_values *strings;
    230} isa_exit_reasons[] = {
    231	{ .isa = 1, .strings = vmx_exit_reasons },
    232	{ .isa = 2, .strings = svm_exit_reasons },
    233	{ }
    234};
    235
    236static const char *find_exit_reason(unsigned isa, int val)
    237{
    238	struct str_values *strings = NULL;
    239	int i;
    240
    241	for (i = 0; isa_exit_reasons[i].strings; ++i)
    242		if (isa_exit_reasons[i].isa == isa) {
    243			strings = isa_exit_reasons[i].strings;
    244			break;
    245		}
    246	if (!strings)
    247		return "UNKNOWN-ISA";
    248	for (i = 0; strings[i].str; i++)
    249		if (strings[i].val == val)
    250			break;
    251
    252	return strings[i].str;
    253}
    254
    255static int print_exit_reason(struct trace_seq *s, struct tep_record *record,
    256			     struct tep_event *event, const char *field)
    257{
    258	unsigned long long isa;
    259	unsigned long long val;
    260	const char *reason;
    261
    262	if (tep_get_field_val(s, event, field, record, &val, 1) < 0)
    263		return -1;
    264
    265	if (tep_get_field_val(s, event, "isa", record, &isa, 0) < 0)
    266		isa = 1;
    267
    268	reason = find_exit_reason(isa, val);
    269	if (reason)
    270		trace_seq_printf(s, "reason %s", reason);
    271	else
    272		trace_seq_printf(s, "reason UNKNOWN (%llu)", val);
    273	return 0;
    274}
    275
    276static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record,
    277			    struct tep_event *event, void *context)
    278{
    279	unsigned long long info1 = 0, info2 = 0;
    280
    281	if (print_exit_reason(s, record, event, "exit_reason") < 0)
    282		return -1;
    283
    284	tep_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
    285
    286	if (tep_get_field_val(s, event, "info1", record, &info1, 0) >= 0
    287	    && tep_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
    288		trace_seq_printf(s, " info %llx %llx", info1, info2);
    289
    290	return 0;
    291}
    292
    293#define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
    294#define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
    295#define KVM_EMUL_INSN_F_CS_D   (1 << 2)
    296#define KVM_EMUL_INSN_F_CS_L   (1 << 3)
    297
    298static int kvm_emulate_insn_handler(struct trace_seq *s,
    299				    struct tep_record *record,
    300				    struct tep_event *event, void *context)
    301{
    302	unsigned long long rip, csbase, len, flags, failed;
    303	int llen;
    304	uint8_t *insn;
    305	const char *disasm;
    306
    307	if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0)
    308		return -1;
    309
    310	if (tep_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
    311		return -1;
    312
    313	if (tep_get_field_val(s, event, "len", record, &len, 1) < 0)
    314		return -1;
    315
    316	if (tep_get_field_val(s, event, "flags", record, &flags, 1) < 0)
    317		return -1;
    318
    319	if (tep_get_field_val(s, event, "failed", record, &failed, 1) < 0)
    320		return -1;
    321
    322	insn = tep_get_field_raw(s, event, "insn", record, &llen, 1);
    323	if (!insn)
    324		return -1;
    325
    326	disasm = disassemble(insn, len, rip,
    327			     flags & KVM_EMUL_INSN_F_CR0_PE,
    328			     flags & KVM_EMUL_INSN_F_EFL_VM,
    329			     flags & KVM_EMUL_INSN_F_CS_D,
    330			     flags & KVM_EMUL_INSN_F_CS_L);
    331
    332	trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
    333			 failed ? " FAIL" : "");
    334	return 0;
    335}
    336
    337
    338static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record,
    339					    struct tep_event *event, void *context)
    340{
    341	if (print_exit_reason(s, record, event, "exit_code") < 0)
    342		return -1;
    343
    344	tep_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1);
    345	tep_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1);
    346	tep_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1);
    347	tep_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1);
    348
    349	return 0;
    350}
    351
    352static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record,
    353				     struct tep_event *event, void *context)
    354{
    355	tep_print_num_field(s, "rip %llx ", event, "rip", record, 1);
    356
    357	return kvm_nested_vmexit_inject_handler(s, record, event, context);
    358}
    359
    360union kvm_mmu_page_role {
    361	unsigned word;
    362	struct {
    363		unsigned level:4;
    364		unsigned cr4_pae:1;
    365		unsigned quadrant:2;
    366		unsigned direct:1;
    367		unsigned access:3;
    368		unsigned invalid:1;
    369		unsigned efer_nx:1;
    370		unsigned cr0_wp:1;
    371		unsigned smep_and_not_wp:1;
    372		unsigned smap_and_not_wp:1;
    373		unsigned pad_for_nice_hex_output:8;
    374		unsigned smm:8;
    375	};
    376};
    377
    378static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record,
    379			      struct tep_event *event, void *context)
    380{
    381	unsigned long long val;
    382	static const char *access_str[] = {
    383		"---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
    384	};
    385	union kvm_mmu_page_role role;
    386
    387	if (tep_get_field_val(s, event, "role", record, &val, 1) < 0)
    388		return -1;
    389
    390	role.word = (int)val;
    391
    392	/*
    393	 * We can only use the structure if file is of the same
    394	 * endianness.
    395	 */
    396	if (tep_is_file_bigendian(event->tep) ==
    397	    tep_is_local_bigendian(event->tep)) {
    398
    399		trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s",
    400				 role.level,
    401				 role.quadrant,
    402				 role.direct ? " direct" : "",
    403				 access_str[role.access],
    404				 role.invalid ? " invalid" : "",
    405				 role.cr4_pae ? "" : "!",
    406				 role.efer_nx ? "" : "!",
    407				 role.cr0_wp ? "" : "!",
    408				 role.smep_and_not_wp ? " smep" : "",
    409				 role.smap_and_not_wp ? " smap" : "",
    410				 role.smm ? " smm" : "");
    411	} else
    412		trace_seq_printf(s, "WORD: %08x", role.word);
    413
    414	tep_print_num_field(s, " root %u ",  event,
    415			    "root_count", record, 1);
    416
    417	if (tep_get_field_val(s, event, "unsync", record, &val, 1) < 0)
    418		return -1;
    419
    420	trace_seq_printf(s, "%s%c",  val ? "unsync" : "sync", 0);
    421	return 0;
    422}
    423
    424static int kvm_mmu_get_page_handler(struct trace_seq *s,
    425				    struct tep_record *record,
    426				    struct tep_event *event, void *context)
    427{
    428	unsigned long long val;
    429
    430	if (tep_get_field_val(s, event, "created", record, &val, 1) < 0)
    431		return -1;
    432
    433	trace_seq_printf(s, "%s ", val ? "new" : "existing");
    434
    435	if (tep_get_field_val(s, event, "gfn", record, &val, 1) < 0)
    436		return -1;
    437
    438	trace_seq_printf(s, "sp gfn %llx ", val);
    439	return kvm_mmu_print_role(s, record, event, context);
    440}
    441
    442#define PT_WRITABLE_SHIFT 1
    443#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
    444
    445static unsigned long long
    446process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
    447{
    448	unsigned long pte = args[0];
    449	return pte & PT_WRITABLE_MASK;
    450}
    451
    452int TEP_PLUGIN_LOADER(struct tep_handle *tep)
    453{
    454	init_disassembler();
    455
    456	tep_register_event_handler(tep, -1, "kvm", "kvm_exit",
    457				   kvm_exit_handler, NULL);
    458
    459	tep_register_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
    460				   kvm_emulate_insn_handler, NULL);
    461
    462	tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit",
    463				   kvm_nested_vmexit_handler, NULL);
    464
    465	tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject",
    466				   kvm_nested_vmexit_inject_handler, NULL);
    467
    468	tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page",
    469				   kvm_mmu_get_page_handler, NULL);
    470
    471	tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page",
    472				   kvm_mmu_print_role, NULL);
    473
    474	tep_register_event_handler(tep, -1,
    475				   "kvmmmu", "kvm_mmu_unsync_page",
    476				   kvm_mmu_print_role, NULL);
    477
    478	tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page",
    479				   kvm_mmu_print_role, NULL);
    480
    481	tep_register_event_handler(tep, -1, "kvmmmu",
    482			"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
    483			NULL);
    484
    485	tep_register_print_function(tep,
    486				    process_is_writable_pte,
    487				    TEP_FUNC_ARG_INT,
    488				    "is_writable_pte",
    489				    TEP_FUNC_ARG_LONG,
    490				    TEP_FUNC_ARG_VOID);
    491	return 0;
    492}
    493
    494void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
    495{
    496	tep_unregister_event_handler(tep, -1, "kvm", "kvm_exit",
    497				     kvm_exit_handler, NULL);
    498
    499	tep_unregister_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
    500				     kvm_emulate_insn_handler, NULL);
    501
    502	tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit",
    503				     kvm_nested_vmexit_handler, NULL);
    504
    505	tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject",
    506				     kvm_nested_vmexit_inject_handler, NULL);
    507
    508	tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page",
    509				     kvm_mmu_get_page_handler, NULL);
    510
    511	tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page",
    512				     kvm_mmu_print_role, NULL);
    513
    514	tep_unregister_event_handler(tep, -1,
    515				     "kvmmmu", "kvm_mmu_unsync_page",
    516				     kvm_mmu_print_role, NULL);
    517
    518	tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page",
    519				     kvm_mmu_print_role, NULL);
    520
    521	tep_unregister_event_handler(tep, -1, "kvmmmu",
    522			"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
    523			NULL);
    524
    525	tep_unregister_print_function(tep, process_is_writable_pte,
    526				      "is_writable_pte");
    527}