# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1192190762 -3600
# Node ID a330276d8c9095cbf9a39e21d945ab1cc32b7a5c
# Parent ef4119637f52648c096e899801f1ca82dbbc04d2
xentrace/x86: PV guest tracing extensions.
From: George Dunlap <gdunlap@xxxxxxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/Makefile | 1
xen/arch/x86/mm.c | 3
xen/arch/x86/trace.c | 231 +++++++++++++++++++++++++++++++++++++
xen/arch/x86/traps.c | 37 +++++
xen/arch/x86/x86_32/entry.S | 6
xen/arch/x86/x86_64/compat/entry.S | 12 +
xen/arch/x86/x86_64/entry.S | 12 +
xen/include/asm-ia64/trace.h | 4
xen/include/asm-powerpc/trace.h | 4
xen/include/asm-x86/trace.h | 46 +++++++
xen/include/public/trace.h | 15 ++
xen/include/xen/domain.h | 2
xen/include/xen/trace.h | 5
13 files changed, 373 insertions(+), 5 deletions(-)
diff -r ef4119637f52 -r a330276d8c90 xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/arch/x86/Makefile Fri Oct 12 13:06:02 2007 +0100
@@ -40,6 +40,7 @@ obj-y += string.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
diff -r ef4119637f52 -r a330276d8c90 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/arch/x86/mm.c Fri Oct 12 13:06:02 2007 +0100
@@ -111,6 +111,7 @@
#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 -r ef4119637f52 -r a330276d8c90 xen/arch/x86/trace.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/trace.c Fri Oct 12 13:06:02 2007 +0100
@@ -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);
+ }
+}
diff -r ef4119637f52 -r a330276d8c90 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/arch/x86/traps.c Fri Oct 12 13:06:02 2007 +0100
@@ -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(str
regs->eip = eip;
regs->eflags &= ~X86_EFLAGS_RF;
+ trace_trap_one_addr(TRC_PV_FORCED_INVALID_OP, regs->eip);
+
return EXCRET_fault_fixed;
}
@@ -751,6 +756,8 @@ void propagate_page_fault(unsigned long
error_code &= ~PFEC_user_mode;
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;
@@ -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 lon
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 lon
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(str
/* 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(s
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;
}
diff -r ef4119637f52 -r a330276d8c90 xen/arch/x86/x86_32/entry.S
--- a/xen/arch/x86/x86_32/entry.S Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/arch/x86/x86_32/entry.S Fri Oct 12 13:06:02 2007 +0100
@@ -194,6 +194,12 @@ 1: sti
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
diff -r ef4119637f52 -r a330276d8c90 xen/arch/x86/x86_64/compat/entry.S
--- a/xen/arch/x86/x86_64/compat/entry.S Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/arch/x86/x86_64/compat/entry.S Fri Oct 12 13:06:02 2007 +0100
@@ -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)
diff -r ef4119637f52 -r a330276d8c90 xen/arch/x86/x86_64/entry.S
--- a/xen/arch/x86/x86_64/entry.S Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/arch/x86/x86_64/entry.S Fri Oct 12 13:06:02 2007 +0100
@@ -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 -r ef4119637f52 -r a330276d8c90 xen/include/asm-ia64/trace.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/asm-ia64/trace.h Fri Oct 12 13:06:02 2007 +0100
@@ -0,0 +1,4 @@
+#ifndef __ASM_TRACE_H__
+#define __ASM_TRACE_H__
+
+#endif /* __ASM_TRACE_H__ */
diff -r ef4119637f52 -r a330276d8c90 xen/include/asm-powerpc/trace.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/asm-powerpc/trace.h Fri Oct 12 13:06:02 2007 +0100
@@ -0,0 +1,4 @@
+#ifndef __ASM_TRACE_H__
+#define __ASM_TRACE_H__
+
+#endif /* __ASM_TRACE_H__ */
diff -r ef4119637f52 -r a330276d8c90 xen/include/asm-x86/trace.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/asm-x86/trace.h Fri Oct 12 13:06:02 2007 +0100
@@ -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__ */
diff -r ef4119637f52 -r a330276d8c90 xen/include/public/trace.h
--- a/xen/include/public/trace.h Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/include/public/trace.h Fri Oct 12 13:06:02 2007 +0100
@@ -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)
@@ -73,6 +74,20 @@
#define TRC_MEM_PAGE_GRANT_MAP (TRC_MEM + 1)
#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)
diff -r ef4119637f52 -r a330276d8c90 xen/include/xen/domain.h
--- a/xen/include/xen/domain.h Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/include/xen/domain.h Fri Oct 12 13:06:02 2007 +0100
@@ -1,6 +1,8 @@
#ifndef __XEN_DOMAIN_H__
#define __XEN_DOMAIN_H__
+
+#include <public/xen.h>
typedef union {
struct vcpu_guest_context *nat;
diff -r ef4119637f52 -r a330276d8c90 xen/include/xen/trace.h
--- a/xen/include/xen/trace.h Fri Oct 12 11:55:41 2007 +0100
+++ b/xen/include/xen/trace.h Fri Oct 12 13:06:02 2007 +0100
@@ -21,11 +21,12 @@
#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);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|