]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/lib/traceevent/plugin_kvm.c
9e0e8c61b43b8341fc19ceabfee8e894d38f8bfa
[karo-tx-linux.git] / tools / lib / traceevent / plugin_kvm.c
1 /*
2  * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3  *
4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation;
8  * version 2.1 of the License (not later!)
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not,  see <http://www.gnu.org/licenses>
17  *
18  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdint.h>
24
25 #include "event-parse.h"
26
27 #ifdef HAVE_UDIS86
28
29 #include <udis86.h>
30
31 static ud_t ud;
32
33 static void init_disassembler(void)
34 {
35         ud_init(&ud);
36         ud_set_syntax(&ud, UD_SYN_ATT);
37 }
38
39 static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
40                                int cr0_pe, int eflags_vm,
41                                int cs_d, int cs_l)
42 {
43         int mode;
44
45         if (!cr0_pe)
46                 mode = 16;
47         else if (eflags_vm)
48                 mode = 16;
49         else if (cs_l)
50                 mode = 64;
51         else if (cs_d)
52                 mode = 32;
53         else
54                 mode = 16;
55
56         ud_set_pc(&ud, rip);
57         ud_set_mode(&ud, mode);
58         ud_set_input_buffer(&ud, insn, len);
59         ud_disassemble(&ud);
60         return ud_insn_asm(&ud);
61 }
62
63 #else
64
65 static void init_disassembler(void)
66 {
67 }
68
69 static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
70                                int cr0_pe, int eflags_vm,
71                                int cs_d, int cs_l)
72 {
73         static char out[15*3+1];
74         int i;
75
76         for (i = 0; i < len; ++i)
77                 sprintf(out + i * 3, "%02x ", insn[i]);
78         out[len*3-1] = '\0';
79         return out;
80 }
81
82 #endif
83
84
85 #define VMX_EXIT_REASONS                        \
86         _ER(EXCEPTION_NMI,       0)             \
87         _ER(EXTERNAL_INTERRUPT,  1)             \
88         _ER(TRIPLE_FAULT,        2)             \
89         _ER(PENDING_INTERRUPT,   7)             \
90         _ER(NMI_WINDOW,          8)             \
91         _ER(TASK_SWITCH,         9)             \
92         _ER(CPUID,               10)            \
93         _ER(HLT,                 12)            \
94         _ER(INVD,                13)            \
95         _ER(INVLPG,              14)            \
96         _ER(RDPMC,               15)            \
97         _ER(RDTSC,               16)            \
98         _ER(VMCALL,              18)            \
99         _ER(VMCLEAR,             19)            \
100         _ER(VMLAUNCH,            20)            \
101         _ER(VMPTRLD,             21)            \
102         _ER(VMPTRST,             22)            \
103         _ER(VMREAD,              23)            \
104         _ER(VMRESUME,            24)            \
105         _ER(VMWRITE,             25)            \
106         _ER(VMOFF,               26)            \
107         _ER(VMON,                27)            \
108         _ER(CR_ACCESS,           28)            \
109         _ER(DR_ACCESS,           29)            \
110         _ER(IO_INSTRUCTION,      30)            \
111         _ER(MSR_READ,            31)            \
112         _ER(MSR_WRITE,           32)            \
113         _ER(MWAIT_INSTRUCTION,   36)            \
114         _ER(MONITOR_INSTRUCTION, 39)            \
115         _ER(PAUSE_INSTRUCTION,   40)            \
116         _ER(MCE_DURING_VMENTRY,  41)            \
117         _ER(TPR_BELOW_THRESHOLD, 43)            \
118         _ER(APIC_ACCESS,         44)            \
119         _ER(EOI_INDUCED,         45)            \
120         _ER(EPT_VIOLATION,       48)            \
121         _ER(EPT_MISCONFIG,       49)            \
122         _ER(INVEPT,              50)            \
123         _ER(PREEMPTION_TIMER,    52)            \
124         _ER(WBINVD,              54)            \
125         _ER(XSETBV,              55)            \
126         _ER(APIC_WRITE,          56)            \
127         _ER(INVPCID,             58)
128
129 #define SVM_EXIT_REASONS \
130         _ER(EXIT_READ_CR0,      0x000)          \
131         _ER(EXIT_READ_CR3,      0x003)          \
132         _ER(EXIT_READ_CR4,      0x004)          \
133         _ER(EXIT_READ_CR8,      0x008)          \
134         _ER(EXIT_WRITE_CR0,     0x010)          \
135         _ER(EXIT_WRITE_CR3,     0x013)          \
136         _ER(EXIT_WRITE_CR4,     0x014)          \
137         _ER(EXIT_WRITE_CR8,     0x018)          \
138         _ER(EXIT_READ_DR0,      0x020)          \
139         _ER(EXIT_READ_DR1,      0x021)          \
140         _ER(EXIT_READ_DR2,      0x022)          \
141         _ER(EXIT_READ_DR3,      0x023)          \
142         _ER(EXIT_READ_DR4,      0x024)          \
143         _ER(EXIT_READ_DR5,      0x025)          \
144         _ER(EXIT_READ_DR6,      0x026)          \
145         _ER(EXIT_READ_DR7,      0x027)          \
146         _ER(EXIT_WRITE_DR0,     0x030)          \
147         _ER(EXIT_WRITE_DR1,     0x031)          \
148         _ER(EXIT_WRITE_DR2,     0x032)          \
149         _ER(EXIT_WRITE_DR3,     0x033)          \
150         _ER(EXIT_WRITE_DR4,     0x034)          \
151         _ER(EXIT_WRITE_DR5,     0x035)          \
152         _ER(EXIT_WRITE_DR6,     0x036)          \
153         _ER(EXIT_WRITE_DR7,     0x037)          \
154         _ER(EXIT_EXCP_BASE,     0x040)          \
155         _ER(EXIT_INTR,          0x060)          \
156         _ER(EXIT_NMI,           0x061)          \
157         _ER(EXIT_SMI,           0x062)          \
158         _ER(EXIT_INIT,          0x063)          \
159         _ER(EXIT_VINTR,         0x064)          \
160         _ER(EXIT_CR0_SEL_WRITE, 0x065)          \
161         _ER(EXIT_IDTR_READ,     0x066)          \
162         _ER(EXIT_GDTR_READ,     0x067)          \
163         _ER(EXIT_LDTR_READ,     0x068)          \
164         _ER(EXIT_TR_READ,       0x069)          \
165         _ER(EXIT_IDTR_WRITE,    0x06a)          \
166         _ER(EXIT_GDTR_WRITE,    0x06b)          \
167         _ER(EXIT_LDTR_WRITE,    0x06c)          \
168         _ER(EXIT_TR_WRITE,      0x06d)          \
169         _ER(EXIT_RDTSC,         0x06e)          \
170         _ER(EXIT_RDPMC,         0x06f)          \
171         _ER(EXIT_PUSHF,         0x070)          \
172         _ER(EXIT_POPF,          0x071)          \
173         _ER(EXIT_CPUID,         0x072)          \
174         _ER(EXIT_RSM,           0x073)          \
175         _ER(EXIT_IRET,          0x074)          \
176         _ER(EXIT_SWINT,         0x075)          \
177         _ER(EXIT_INVD,          0x076)          \
178         _ER(EXIT_PAUSE,         0x077)          \
179         _ER(EXIT_HLT,           0x078)          \
180         _ER(EXIT_INVLPG,        0x079)          \
181         _ER(EXIT_INVLPGA,       0x07a)          \
182         _ER(EXIT_IOIO,          0x07b)          \
183         _ER(EXIT_MSR,           0x07c)          \
184         _ER(EXIT_TASK_SWITCH,   0x07d)          \
185         _ER(EXIT_FERR_FREEZE,   0x07e)          \
186         _ER(EXIT_SHUTDOWN,      0x07f)          \
187         _ER(EXIT_VMRUN,         0x080)          \
188         _ER(EXIT_VMMCALL,       0x081)          \
189         _ER(EXIT_VMLOAD,        0x082)          \
190         _ER(EXIT_VMSAVE,        0x083)          \
191         _ER(EXIT_STGI,          0x084)          \
192         _ER(EXIT_CLGI,          0x085)          \
193         _ER(EXIT_SKINIT,        0x086)          \
194         _ER(EXIT_RDTSCP,        0x087)          \
195         _ER(EXIT_ICEBP,         0x088)          \
196         _ER(EXIT_WBINVD,        0x089)          \
197         _ER(EXIT_MONITOR,       0x08a)          \
198         _ER(EXIT_MWAIT,         0x08b)          \
199         _ER(EXIT_MWAIT_COND,    0x08c)          \
200         _ER(EXIT_NPF,           0x400)          \
201         _ER(EXIT_ERR,           -1)
202
203 #define _ER(reason, val)        { #reason, val },
204 struct str_values {
205         const char      *str;
206         int             val;
207 };
208
209 static struct str_values vmx_exit_reasons[] = {
210         VMX_EXIT_REASONS
211         { NULL, -1}
212 };
213
214 static struct str_values svm_exit_reasons[] = {
215         SVM_EXIT_REASONS
216         { NULL, -1}
217 };
218
219 static struct isa_exit_reasons {
220         unsigned isa;
221         struct str_values *strings;
222 } isa_exit_reasons[] = {
223         { .isa = 1, .strings = vmx_exit_reasons },
224         { .isa = 2, .strings = svm_exit_reasons },
225         { }
226 };
227
228 static const char *find_exit_reason(unsigned isa, int val)
229 {
230         struct str_values *strings = NULL;
231         int i;
232
233         for (i = 0; isa_exit_reasons[i].strings; ++i)
234                 if (isa_exit_reasons[i].isa == isa) {
235                         strings = isa_exit_reasons[i].strings;
236                         break;
237                 }
238         if (!strings)
239                 return "UNKNOWN-ISA";
240         for (i = 0; strings[i].val >= 0; i++)
241                 if (strings[i].val == val)
242                         break;
243         if (strings[i].str)
244                 return strings[i].str;
245         return "UNKNOWN";
246 }
247
248 static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
249                             struct event_format *event, void *context)
250 {
251         unsigned long long isa;
252         unsigned long long val;
253         unsigned long long info1 = 0, info2 = 0;
254
255         if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0)
256                 return -1;
257
258         if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0)
259                 isa = 1;
260
261         trace_seq_printf(s, "reason %s", find_exit_reason(isa, val));
262
263         pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
264
265         if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0
266             && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
267                 trace_seq_printf(s, " info %llx %llx", info1, info2);
268
269         return 0;
270 }
271
272 #define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
273 #define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
274 #define KVM_EMUL_INSN_F_CS_D   (1 << 2)
275 #define KVM_EMUL_INSN_F_CS_L   (1 << 3)
276
277 static int kvm_emulate_insn_handler(struct trace_seq *s,
278                                     struct pevent_record *record,
279                                     struct event_format *event, void *context)
280 {
281         unsigned long long rip, csbase, len, flags, failed;
282         int llen;
283         uint8_t *insn;
284         const char *disasm;
285
286         if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0)
287                 return -1;
288
289         if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
290                 return -1;
291
292         if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0)
293                 return -1;
294
295         if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0)
296                 return -1;
297
298         if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0)
299                 return -1;
300
301         insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1);
302         if (!insn)
303                 return -1;
304
305         disasm = disassemble(insn, len, rip,
306                              flags & KVM_EMUL_INSN_F_CR0_PE,
307                              flags & KVM_EMUL_INSN_F_EFL_VM,
308                              flags & KVM_EMUL_INSN_F_CS_D,
309                              flags & KVM_EMUL_INSN_F_CS_L);
310
311         trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
312                          failed ? " FAIL" : "");
313         return 0;
314 }
315
316 union kvm_mmu_page_role {
317         unsigned word;
318         struct {
319                 unsigned glevels:4;
320                 unsigned level:4;
321                 unsigned quadrant:2;
322                 unsigned pad_for_nice_hex_output:6;
323                 unsigned direct:1;
324                 unsigned access:3;
325                 unsigned invalid:1;
326                 unsigned cr4_pge:1;
327                 unsigned nxe:1;
328         };
329 };
330
331 static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
332                               struct event_format *event, void *context)
333 {
334         unsigned long long val;
335         static const char *access_str[] = {
336                 "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
337         };
338         union kvm_mmu_page_role role;
339
340         if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0)
341                 return -1;
342
343         role.word = (int)val;
344
345         /*
346          * We can only use the structure if file is of the same
347          * endianess.
348          */
349         if (pevent_is_file_bigendian(event->pevent) ==
350             pevent_is_host_bigendian(event->pevent)) {
351
352                 trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe",
353                                  role.level,
354                                  role.glevels,
355                                  role.quadrant,
356                                  role.direct ? " direct" : "",
357                                  access_str[role.access],
358                                  role.invalid ? " invalid" : "",
359                                  role.cr4_pge ? "" : "!",
360                                  role.nxe ? "" : "!");
361         } else
362                 trace_seq_printf(s, "WORD: %08x", role.word);
363
364         pevent_print_num_field(s, " root %u ",  event,
365                                "root_count", record, 1);
366
367         if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0)
368                 return -1;
369
370         trace_seq_printf(s, "%s%c",  val ? "unsync" : "sync", 0);
371         return 0;
372 }
373
374 static int kvm_mmu_get_page_handler(struct trace_seq *s,
375                                     struct pevent_record *record,
376                                     struct event_format *event, void *context)
377 {
378         unsigned long long val;
379
380         if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0)
381                 return -1;
382
383         trace_seq_printf(s, "%s ", val ? "new" : "existing");
384
385         if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0)
386                 return -1;
387
388         trace_seq_printf(s, "sp gfn %llx ", val);
389         return kvm_mmu_print_role(s, record, event, context);
390 }
391
392 #define PT_WRITABLE_SHIFT 1
393 #define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
394
395 static unsigned long long
396 process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
397 {
398         unsigned long pte = args[0];
399         return pte & PT_WRITABLE_MASK;
400 }
401
402 int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
403 {
404         init_disassembler();
405
406         pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit",
407                                       kvm_exit_handler, NULL);
408
409         pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
410                                       kvm_emulate_insn_handler, NULL);
411
412         pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
413                                       kvm_mmu_get_page_handler, NULL);
414
415         pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
416                                       kvm_mmu_print_role, NULL);
417
418         pevent_register_event_handler(pevent, -1,
419                                       "kvmmmu", "kvm_mmu_unsync_page",
420                                       kvm_mmu_print_role, NULL);
421
422         pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
423                                       kvm_mmu_print_role, NULL);
424
425         pevent_register_event_handler(pevent, -1, "kvmmmu",
426                         "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
427                         NULL);
428
429         pevent_register_print_function(pevent,
430                                        process_is_writable_pte,
431                                        PEVENT_FUNC_ARG_INT,
432                                        "is_writable_pte",
433                                        PEVENT_FUNC_ARG_LONG,
434                                        PEVENT_FUNC_ARG_VOID);
435         return 0;
436 }
437
438 void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
439 {
440         pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit",
441                                         kvm_exit_handler, NULL);
442
443         pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
444                                         kvm_emulate_insn_handler, NULL);
445
446         pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
447                                         kvm_mmu_get_page_handler, NULL);
448
449         pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
450                                         kvm_mmu_print_role, NULL);
451
452         pevent_unregister_event_handler(pevent, -1,
453                                         "kvmmmu", "kvm_mmu_unsync_page",
454                                         kvm_mmu_print_role, NULL);
455
456         pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
457                                         kvm_mmu_print_role, NULL);
458
459         pevent_unregister_event_handler(pevent, -1, "kvmmmu",
460                         "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
461                         NULL);
462
463         pevent_unregister_print_function(pevent, process_is_writable_pte,
464                                          "is_writable_pte");
465 }