diff options
author | Keir Fraser <keir@xensource.com> | 2007-10-12 13:06:02 +0100 |
---|---|---|
committer | Keir Fraser <keir@xensource.com> | 2007-10-12 13:06:02 +0100 |
commit | 06a73c9f9380bba455cbf1a5502b902d01a5dc3f (patch) | |
tree | 56e70068152a5fb6d4a893a15c3cf4449549d919 /xen/arch/x86/trace.c | |
parent | 70c2e55854116bee937026175e54985a73f159fa (diff) | |
download | xen-06a73c9f9380bba455cbf1a5502b902d01a5dc3f.tar.gz xen-06a73c9f9380bba455cbf1a5502b902d01a5dc3f.tar.bz2 xen-06a73c9f9380bba455cbf1a5502b902d01a5dc3f.zip |
xentrace/x86: PV guest tracing extensions.
From: George Dunlap <gdunlap@xensource.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'xen/arch/x86/trace.c')
-rw-r--r-- | xen/arch/x86/trace.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/xen/arch/x86/trace.c b/xen/arch/x86/trace.c new file mode 100644 index 0000000000..ddb32202bd --- /dev/null +++ b/xen/arch/x86/trace.c @@ -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); + } +} |