xentrace/x86: PV guest tracing extensions.
authorKeir Fraser <keir@xensource.com>
Fri, 12 Oct 2007 12:06:02 +0000 (13:06 +0100)
committerKeir Fraser <keir@xensource.com>
Fri, 12 Oct 2007 12:06:02 +0000 (13:06 +0100)
From: George Dunlap <gdunlap@xensource.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
13 files changed:
xen/arch/x86/Makefile
xen/arch/x86/mm.c
xen/arch/x86/trace.c [new file with mode: 0644]
xen/arch/x86/traps.c
xen/arch/x86/x86_32/entry.S
xen/arch/x86/x86_64/compat/entry.S
xen/arch/x86/x86_64/entry.S
xen/include/asm-ia64/trace.h [new file with mode: 0644]
xen/include/asm-powerpc/trace.h [new file with mode: 0644]
xen/include/asm-x86/trace.h [new file with mode: 0644]
xen/include/public/trace.h
xen/include/xen/domain.h
xen/include/xen/trace.h

index 3899874714aecdf3ce974d6e51ecc036a58114a6..aa4f42ffd19dadd0c7a03edc44df087fe07bf70a 100644 (file)
@@ -40,6 +40,7 @@ obj-y += srat.o
 obj-y += string.o
 obj-y += sysctl.o
 obj-y += time.o
+obj-y += trace.o
 obj-y += traps.o
 obj-y += usercopy.o
 obj-y += x86_emulate.o
index ecd41cf4a64e644069d02137c1a1a597da5026cf..94f8f891827f2c9e86bc76cd1c07563cc9398fc6 100644 (file)
 #include <asm/shared.h>
 #include <public/memory.h>
 #include <xsm/xsm.h>
+#include <xen/trace.h>
 
 #define MEM_LOG(_f, _a...) gdprintk(XENLOG_WARNING , _f "\n" , ## _a)
 
@@ -3402,6 +3403,8 @@ static int ptwr_emulated_update(
             BUG();
     }
 
+    trace_ptwr_emulation(addr, nl1e);
+
     unmap_domain_page(pl1e);
 
     /* Finally, drop the old PTE. */
diff --git a/xen/arch/x86/trace.c b/xen/arch/x86/trace.c
new file mode 100644 (file)
index 0000000..ddb3220
--- /dev/null
@@ -0,0 +1,231 @@
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/kernel.h>
+#include <xen/lib.h>
+#include <xen/domain.h>
+#include <xen/sched.h>
+#include <xen/trace.h>
+
+#ifndef __x86_64__
+#undef TRC_PV_64_FLAG
+#define TRC_PV_64_FLAG 0
+#endif
+
+asmlinkage void trace_hypercall(void)
+{
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+
+    if ( !tb_init_done )
+        return;
+
+#ifdef __x86_64__
+    if ( is_pv_32on64_vcpu(current) )
+    {
+        struct {
+            u32 eip,eax;
+        } __attribute__((packed)) d;
+            
+        d.eip = regs->eip;
+        d.eax = regs->eax;
+
+        __trace_var(TRC_PV_HYPERCALL, 1,
+                    sizeof(d), (unsigned char *)&d);
+    }
+    else
+#endif
+    {
+        struct {
+            unsigned long eip;
+            u32 eax;
+        } __attribute__((packed)) d;
+        u32 event;
+
+        event = TRC_PV_HYPERCALL;
+        event |= TRC_PV_64_FLAG;
+        d.eip = regs->eip;
+        d.eax = regs->eax;
+
+        __trace_var(event, 1/*tsc*/, sizeof(d), (unsigned char*)&d);
+    }
+}
+
+void __trace_pv_trap(int trapnr, unsigned long eip,
+                     int use_error_code, unsigned error_code)
+{
+    if ( !tb_init_done )
+        return;
+
+#ifdef __x86_64__
+    if ( is_pv_32on64_vcpu(current) )
+    {
+        struct {
+            unsigned eip:32,
+                trapnr:15,
+                use_error_code:1,
+                error_code:16;
+        } __attribute__((packed)) d;
+
+        d.eip = eip;
+        d.trapnr = trapnr;
+        d.error_code = error_code;
+        d.use_error_code=!!use_error_code;
+                
+        __trace_var(TRC_PV_TRAP, 1,
+                    sizeof(d), (unsigned char *)&d);
+    }
+    else
+#endif        
+    {
+        struct {
+            unsigned long eip;
+            unsigned trapnr:15,
+                use_error_code:1,
+                error_code:16;
+        } __attribute__((packed)) d;
+        unsigned event;
+
+        d.eip = eip;
+        d.trapnr = trapnr;
+        d.error_code = error_code;
+        d.use_error_code=!!use_error_code;
+                
+        event = TRC_PV_TRAP;
+        event |= TRC_PV_64_FLAG;
+        __trace_var(event, 1, sizeof(d), (unsigned char *)&d);
+    }
+}
+
+void __trace_pv_page_fault(unsigned long addr, unsigned error_code)
+{
+    unsigned long eip = guest_cpu_user_regs()->eip;
+
+    if ( !tb_init_done )
+        return;
+
+#ifdef __x86_64__
+    if ( is_pv_32on64_vcpu(current) )
+    {
+        struct {
+            u32 eip, addr, error_code;
+        } __attribute__((packed)) d;
+
+        d.eip = eip;
+        d.addr = addr;
+        d.error_code = error_code;
+                
+        __trace_var(TRC_PV_PAGE_FAULT, 1, sizeof(d), (unsigned char *)&d);
+    }
+    else
+#endif        
+    {
+        struct {
+            unsigned long eip, addr;
+            u32 error_code;
+        } __attribute__((packed)) d;
+        unsigned event;
+
+        d.eip = eip;
+        d.addr = addr;
+        d.error_code = error_code;
+        event = TRC_PV_PAGE_FAULT;
+        event |= TRC_PV_64_FLAG;
+        __trace_var(event, 1, sizeof(d), (unsigned char *)&d);
+    }
+}
+
+void __trace_trap_one_addr(unsigned event, unsigned long va)
+{
+    if ( !tb_init_done )
+        return;
+
+#ifdef __x86_64__
+    if ( is_pv_32on64_vcpu(current) )
+    {
+        u32 d = va;
+        __trace_var(event, 1, sizeof(d), (unsigned char *)&d);
+    }
+    else
+#endif        
+    {
+        event |= TRC_PV_64_FLAG;
+        __trace_var(event, 1, sizeof(va), (unsigned char *)&va);
+    }
+}
+
+void __trace_trap_two_addr(unsigned event, unsigned long va1,
+                           unsigned long va2)
+{
+    if ( !tb_init_done )
+        return;
+
+#ifdef __x86_64__
+    if ( is_pv_32on64_vcpu(current) )
+    {
+        struct {
+            u32 va1, va2;
+        } __attribute__((packed)) d;
+        d.va1=va1;
+        d.va2=va2;
+        __trace_var(event, 1, sizeof(d), (unsigned char *)&d);
+    }
+    else
+#endif        
+    {
+        struct {
+            unsigned long va1, va2;
+        } __attribute__((packed)) d;
+        d.va1=va1;
+        d.va2=va2;
+        event |= TRC_PV_64_FLAG;
+        __trace_var(event, 1, sizeof(d), (unsigned char *)&d);
+    }
+}
+
+void __trace_ptwr_emulation(unsigned long addr, l1_pgentry_t npte)
+{
+    unsigned long eip = guest_cpu_user_regs()->eip;
+
+    if ( !tb_init_done )
+        return;
+
+    /* We have a couple of different modes to worry about:
+     * - 32-on-32: 32-bit pte, 32-bit virtual addresses
+     * - pae-on-pae, pae-on-64: 64-bit pte, 32-bit virtual addresses
+     * - 64-on-64: 64-bit pte, 64-bit virtual addresses
+     * pae-on-64 is the only one that requires extra code; in all other
+     * cases, "unsigned long" is the size of a guest virtual address.
+     */
+
+#ifdef __x86_64__
+    if ( is_pv_32on64_vcpu(current) )
+    {
+        struct {
+            l1_pgentry_t pte;
+            u32 addr, eip;
+        } __attribute__((packed)) d;
+        d.addr = addr;
+        d.eip = eip;
+        d.pte = npte;
+
+        __trace_var(TRC_PV_PTWR_EMULATION_PAE, 1,
+                    sizeof(d), (unsigned char *)&d);
+    }
+    else
+#endif        
+    {
+        struct {
+            l1_pgentry_t pte;
+            unsigned long addr, eip;
+        } d;
+        unsigned event;
+
+        d.addr = addr;
+        d.eip = eip;
+        d.pte = npte;
+
+        event = ((CONFIG_PAGING_LEVELS == 3) ?
+                 TRC_PV_PTWR_EMULATION_PAE : TRC_PV_PTWR_EMULATION);
+        event |= TRC_PV_64_FLAG;
+        __trace_var(event, 1/*tsc*/, sizeof(d), (unsigned char *)&d);
+    }
+}
index 4d4fdffca74f0f65d08586533b622e5959fde65e..51d84739e941a15428f6741939a527730efbb483 100644 (file)
@@ -46,6 +46,7 @@
 #include <xen/nmi.h>
 #include <xen/version.h>
 #include <xen/kexec.h>
+#include <xen/trace.h>
 #include <asm/paging.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -380,6 +381,8 @@ static int do_guest_trap(
     struct trap_bounce *tb;
     const struct trap_info *ti;
 
+    trace_pv_trap(trapnr, regs->eip, use_error_code, regs->error_code);
+
     tb = &v->arch.trap_bounce;
     ti = &v->arch.guest_context.trap_ctxt[trapnr];
 
@@ -633,6 +636,8 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs)
     regs->eip = eip;
     regs->eflags &= ~X86_EFLAGS_RF;
 
+    trace_trap_one_addr(TRC_PV_FORCED_INVALID_OP, regs->eip);
+
     return EXCRET_fault_fixed;
 }
 
@@ -752,6 +757,8 @@ void propagate_page_fault(unsigned long addr, u16 error_code)
     if ( !guest_kernel_mode(v, guest_cpu_user_regs()) )
         error_code |= PFEC_user_mode;
 
+    trace_pv_page_fault(addr, error_code);
+
     ti = &v->arch.guest_context.trap_ctxt[TRAP_page_fault];
     tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
     tb->error_code = error_code;
@@ -783,7 +790,13 @@ static int handle_gdt_ldt_mapping_fault(
     if ( likely(is_ldt_area) )
     {
         /* LDT fault: Copy a mapping from the guest's LDT, if it is valid. */
-        if ( unlikely(map_ldt_shadow_page(offset >> PAGE_SHIFT) == 0) )
+        if ( likely(map_ldt_shadow_page(offset >> PAGE_SHIFT)) )
+        {
+            if ( guest_mode(regs) )
+                trace_trap_two_addr(TRC_PV_GDT_LDT_MAPPING_FAULT,
+                                    regs->eip, offset);
+        }
+        else
         {
             /* In hypervisor mode? Leave it to the #PF handler to fix up. */
             if ( !guest_mode(regs) )
@@ -939,7 +952,12 @@ static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs)
     if ( unlikely(IN_HYPERVISOR_RANGE(addr)) )
     {
         if ( paging_mode_external(d) && guest_mode(regs) )
-            return paging_fault(addr, regs);
+        {
+            int ret = paging_fault(addr, regs);
+            if ( ret == EXCRET_fault_fixed )
+                trace_trap_two_addr(TRC_PV_PAGING_FIXUP, regs->eip, addr);
+            return ret;
+        }
         if ( (addr >= GDT_LDT_VIRT_START) && (addr < GDT_LDT_VIRT_END) )
             return handle_gdt_ldt_mapping_fault(
                 addr - GDT_LDT_VIRT_START, regs);
@@ -955,7 +973,12 @@ static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs)
         return EXCRET_fault_fixed;
 
     if ( paging_mode_enabled(d) )
-        return paging_fault(addr, regs);
+    {
+        int ret = paging_fault(addr, regs);
+        if ( ret == EXCRET_fault_fixed )
+            trace_trap_two_addr(TRC_PV_PAGING_FIXUP, regs->eip, addr);
+        return ret;
+    }
 
     return 0;
 }
@@ -1872,13 +1895,19 @@ asmlinkage int do_general_protection(struct cpu_user_regs *regs)
     /* Emulate some simple privileged and I/O instructions. */
     if ( (regs->error_code == 0) &&
          emulate_privileged_op(regs) )
+    {
+        trace_trap_one_addr(TRC_PV_EMULATE_PRIVOP, regs->eip);
         return 0;
+    }
 
 #if defined(__i386__)
     if ( VM_ASSIST(v->domain, VMASST_TYPE_4gb_segments) && 
          (regs->error_code == 0) && 
          gpf_emulate_4gb(regs) )
+    {
+        TRACE_1D(TRC_PV_EMULATE_4GB, regs->eip);
         return 0;
+    }
 #endif
 
     /* Pass on GPF as is. */
@@ -2030,6 +2059,8 @@ asmlinkage int do_device_not_available(struct cpu_user_regs *regs)
         do_guest_trap(TRAP_no_device, regs, 0);
         current->arch.guest_context.ctrlreg[0] &= ~X86_CR0_TS;
     }
+    else
+        TRACE_0D(TRC_PV_MATH_STATE_RESTORE);
 
     return EXCRET_fault_fixed;
 }
index 0ccfb8edc73a2903da0b213b0bb6c2893539080d..37ed92d6125aabceb41447b849ede9a4103d0b1b 100644 (file)
@@ -194,6 +194,12 @@ ENTRY(hypercall)
         pushl 20(%esp) # ECX
         pushl 20(%esp) # EBX
 #endif
+        cmpb  $0,tb_init_done
+        je    tracing_off
+        call  trace_hypercall
+        /* Now restore all the registers that trace_hypercall clobbered */
+        movl  UREGS_eax+24(%esp),%eax /* Hypercall # */
+tracing_off:
         call *hypercall_table(,%eax,4)
         addl  $24,%esp     # Discard the shadow parameters
 #ifndef NDEBUG
index 8bf2dd010bc84d8348ea689019348baf11507827..3504e2605881e467f9ffe5927559eb7f6258410a 100644 (file)
@@ -56,6 +56,18 @@ ENTRY(compat_hypercall)
         movl  %ebp,%r9d              /* Arg 6        */
         movl  UREGS_rbx(%rsp),%edi   /* Arg 1        */
 #endif
+        cmpb  $0,tb_init_done(%rip)
+        je    compat_tracing_off
+        call  trace_hypercall
+        /* Now restore all the registers that trace_hypercall clobbered */
+        movl  UREGS_rax(%rsp),%eax   /* Hypercall #  */
+        movl  UREGS_rbx(%rsp),%edi   /* Arg 1        */
+        movl  UREGS_rcx(%rsp),%esi   /* Arg 2        */
+        movl  UREGS_rdx(%rsp),%edx   /* Arg 3        */
+        movl  UREGS_rsi(%rsp),%ecx   /* Arg 4        */
+        movl  UREGS_rdi(%rsp),%r8d   /* Arg 5        */
+        movl  UREGS_rbp(%rsp),%r9d   /* Arg 6        */
+compat_tracing_off:
         leaq  compat_hypercall_table(%rip),%r10
         PERFC_INCR(PERFC_hypercalls, %rax, %rbx)
         callq *(%r10,%rax,8)
index 30d3bf38cea622fdce454baff8aa4d242bb35b02..ad9e9ceebc276eda492a635986d791dccfc2d7c4 100644 (file)
@@ -148,6 +148,18 @@ ENTRY(syscall_enter)
         pushq %rax
         pushq UREGS_rip+8(%rsp)
 #endif
+        cmpb  $0,tb_init_done(%rip)
+        je    tracing_off
+        call  trace_hypercall
+        /* Now restore all the registers that trace_hypercall clobbered */
+        movq  UREGS_rax(%rsp),%rax   /* Hypercall #  */
+        movq  UREGS_rdi(%rsp),%rdi   /* Arg 1        */
+        movq  UREGS_rsi(%rsp),%rsi   /* Arg 2        */
+        movq  UREGS_rdx(%rsp),%rdx   /* Arg 3        */
+        movq  UREGS_r10(%rsp),%rcx   /* Arg 4        */
+        movq  UREGS_rdi(%rsp),%r8    /* Arg 5        */
+        movq  UREGS_rbp(%rsp),%r9    /* Arg 6        */
+tracing_off:
         leaq  hypercall_table(%rip),%r10
         PERFC_INCR(PERFC_hypercalls, %rax, %rbx)
         callq *(%r10,%rax,8)
diff --git a/xen/include/asm-ia64/trace.h b/xen/include/asm-ia64/trace.h
new file mode 100644 (file)
index 0000000..edef1bb
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASM_TRACE_H__
+#define __ASM_TRACE_H__
+
+#endif /* __ASM_TRACE_H__ */
diff --git a/xen/include/asm-powerpc/trace.h b/xen/include/asm-powerpc/trace.h
new file mode 100644 (file)
index 0000000..edef1bb
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ASM_TRACE_H__
+#define __ASM_TRACE_H__
+
+#endif /* __ASM_TRACE_H__ */
diff --git a/xen/include/asm-x86/trace.h b/xen/include/asm-x86/trace.h
new file mode 100644 (file)
index 0000000..c8b13c4
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __ASM_TRACE_H__
+#define __ASM_TRACE_H__
+
+#include <asm/page.h>
+
+void __trace_pv_trap(int trapnr, unsigned long eip,
+                     int use_error_code, unsigned error_code);
+static inline void trace_pv_trap(int trapnr, unsigned long eip,
+                                 int use_error_code, unsigned error_code)
+{
+    if ( tb_init_done )
+        __trace_pv_trap(trapnr, eip, use_error_code, error_code);
+}
+
+void __trace_pv_page_fault(unsigned long addr, unsigned error_code);
+static inline void trace_pv_page_fault(unsigned long addr,
+                                       unsigned error_code)
+{
+    if ( tb_init_done )
+        __trace_pv_page_fault(addr, error_code);
+}
+
+void __trace_trap_one_addr(unsigned event, unsigned long va);
+static inline void trace_trap_one_addr(unsigned event, unsigned long va)
+{
+    if ( tb_init_done )
+        __trace_trap_one_addr(event, va);
+}
+
+void __trace_trap_two_addr(unsigned event, unsigned long va1,
+                           unsigned long va2);
+static inline void trace_trap_two_addr(unsigned event, unsigned long va1,
+                                       unsigned long va2)
+{
+    if ( tb_init_done )
+        __trace_trap_two_addr(event, va1, va2);
+}
+
+void __trace_ptwr_emulation(unsigned long addr, l1_pgentry_t npte);
+static inline void trace_ptwr_emulation(unsigned long addr, l1_pgentry_t npte)
+{
+    if ( tb_init_done )
+        __trace_ptwr_emulation(addr, npte);
+}
+
+#endif /* __ASM_TRACE_H__ */
index a2d75ba2f2324622ac0e921b0dce6f2237f01ec9..4cbb8963422322c79a06b89f5a240636daba1616 100644 (file)
@@ -36,6 +36,7 @@
 #define TRC_DOM0OP   0x0004f000    /* Xen DOM0 operation trace */
 #define TRC_HVM      0x0008f000    /* Xen HVM trace            */
 #define TRC_MEM      0x0010f000    /* Xen memory trace         */
+#define TRC_PV       0x0020f000    /* Xen PV traces            */
 #define TRC_ALL      0x0ffff000
 #define TRC_HD_TO_EVENT(x) ((x)&0x0fffffff)
 #define TRC_HD_CYCLE_FLAG (1UL<<31)
 #define TRC_MEM_PAGE_GRANT_UNMAP    (TRC_MEM + 2)
 #define TRC_MEM_PAGE_GRANT_TRANSFER (TRC_MEM + 3)
 
+#define TRC_PV_HYPERCALL             (TRC_PV +  1)
+#define TRC_PV_TRAP                  (TRC_PV +  3)
+#define TRC_PV_PAGE_FAULT            (TRC_PV +  4)
+#define TRC_PV_FORCED_INVALID_OP     (TRC_PV +  5)
+#define TRC_PV_EMULATE_PRIVOP        (TRC_PV +  6)
+#define TRC_PV_EMULATE_4GB           (TRC_PV +  7)
+#define TRC_PV_MATH_STATE_RESTORE    (TRC_PV +  8)
+#define TRC_PV_PAGING_FIXUP          (TRC_PV +  9)
+#define TRC_PV_GDT_LDT_MAPPING_FAULT (TRC_PV + 10)
+#define TRC_PV_PTWR_EMULATION        (TRC_PV + 11)
+#define TRC_PV_PTWR_EMULATION_PAE    (TRC_PV + 12)
+  /* Indicates that addresses in trace record are 64 bits */
+#define TRC_PV_64_FLAG               (0x100) 
+
 /* trace events per subclass */
 #define TRC_HVM_VMENTRY         (TRC_HVM_ENTRYEXIT + 0x01)
 #define TRC_HVM_VMEXIT          (TRC_HVM_ENTRYEXIT + 0x02)
index aa8c72f0ac42a2e7ac07cb46fdb969e428e55835..2b3a24cb2dec48b8685c1d8fe42f455ee2faee70 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __XEN_DOMAIN_H__
 #define __XEN_DOMAIN_H__
 
+#include <public/xen.h>
+
 typedef union {
     struct vcpu_guest_context *nat;
     struct compat_vcpu_guest_context *cmp;
index 41db3f7dc6fe8e6696fbcc317882ba58cc16d549..7635f2dbf604368c482728d0c49a5ea068bd3f3e 100644 (file)
 #ifndef __XEN_TRACE_H__
 #define __XEN_TRACE_H__
 
+extern int tb_init_done;
+
 #include <xen/config.h>
 #include <public/sysctl.h>
 #include <public/trace.h>
-
-extern int tb_init_done;
+#include <asm/trace.h>
 
 /* Used to initialise trace buffer functionality */
 void init_trace_bufs(void);