[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] xentrace/x86: PV guest tracing extensions.



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.