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

[Xen-changelog] [xen-unstable] x86: Extend emulator return codes.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1172087938 0
# Node ID b010e556fe2c1e7cf73d3f279113ba1f4eac6a11
# Parent  ad3ee81cc8c4bf44edc01404782c7a197f8764fc
x86: Extend emulator return codes.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 tools/tests/test_x86_emulator.c   |   48 +++++++++++++++++++-------------------
 xen/arch/x86/mm.c                 |   17 +++++++------
 xen/arch/x86/mm/shadow/common.c   |   16 ++++++------
 xen/arch/x86/mm/shadow/multi.c    |   19 ++++++++-------
 xen/arch/x86/x86_emulate.c        |   16 ++++++------
 xen/include/asm-x86/x86_emulate.h |   24 +++++++++++--------
 6 files changed, 76 insertions(+), 64 deletions(-)

diff -r ad3ee81cc8c4 -r b010e556fe2c tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c   Wed Feb 21 11:42:04 2007 -0800
+++ b/tools/tests/test_x86_emulator.c   Wed Feb 21 19:58:58 2007 +0000
@@ -43,7 +43,7 @@ static int read(
     case 4: *val = *(u32 *)addr; break;
     case 8: *val = *(unsigned long *)addr; break;
     }
-    return X86EMUL_CONTINUE;
+    return X86EMUL_OKAY;
 }
 
 static int write(
@@ -61,7 +61,7 @@ static int write(
     case 4: *(u32 *)addr = (u32)val; break;
     case 8: *(unsigned long *)addr = val; break;
     }
-    return X86EMUL_CONTINUE;
+    return X86EMUL_OKAY;
 }
 
 static int cmpxchg(
@@ -80,7 +80,7 @@ static int cmpxchg(
     case 4: *(u32 *)addr = (u32)new; break;
     case 8: *(unsigned long *)addr = new; break;
     }
-    return X86EMUL_CONTINUE;
+    return X86EMUL_OKAY;
 }
 
 static int cmpxchg8b(
@@ -95,7 +95,7 @@ static int cmpxchg8b(
     unsigned long addr = offset;
     ((unsigned long *)addr)[0] = new_lo;
     ((unsigned long *)addr)[1] = new_hi;
-    return X86EMUL_CONTINUE;
+    return X86EMUL_OKAY;
 }
 
 static struct x86_emulate_ops emulops = {
@@ -138,7 +138,7 @@ int main(int argc, char **argv)
     regs.eax    = (unsigned long)res;
     *res        = 0x7FFFFFFF;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (*res != 0x92345677) || 
          (regs.eflags != 0xa94) ||
          (regs.eip != (unsigned long)&instr[2]) )
@@ -152,7 +152,7 @@ int main(int argc, char **argv)
     regs.ecx    = 0x12345678;
     regs.eax    = 0x7FFFFFFF;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (regs.ecx != 0x12345678) ||
          (regs.eax != 0x92345677) ||
          (regs.eflags != 0xa94) ||
@@ -171,7 +171,7 @@ int main(int argc, char **argv)
 #endif
     regs.eax    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (*res != 0x92345677) || 
          (regs.ecx != 0x8000000FUL) ||
          (regs.eip != (unsigned long)&instr[2]) )
@@ -185,7 +185,7 @@ int main(int argc, char **argv)
     regs.ecx    = ~0UL;
     regs.eax    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (*res != 0x92345677) || 
          (regs.ecx != 0x92345677UL) ||
          (regs.eip != (unsigned long)&instr[2]) )
@@ -200,7 +200,7 @@ int main(int argc, char **argv)
     regs.ecx    = 0xAA;
     regs.ebx    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (*res != 0x923456AA) || 
          (regs.eflags != 0x244) ||
          (regs.eax != 0x92345677UL) ||
@@ -216,7 +216,7 @@ int main(int argc, char **argv)
     regs.ecx    = 0xFF;
     regs.ebx    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (*res != 0x923456AA) || 
          ((regs.eflags&0x240) != 0x200) ||
          (regs.eax != 0xAABBCCAA) ||
@@ -232,7 +232,7 @@ int main(int argc, char **argv)
     regs.ecx    = 0x12345678;
     regs.eax    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (*res != 0x12345678) || 
          (regs.eflags != 0x200) ||
          (regs.ecx != 0x923456AA) ||
@@ -249,7 +249,7 @@ int main(int argc, char **argv)
     regs.ecx    = 0xDDEEFF00L;
     regs.ebx    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (*res != 0xDDEEFF00) || 
          (regs.eflags != 0x244) ||
          (regs.eax != 0x923456AAUL) ||
@@ -266,7 +266,7 @@ int main(int argc, char **argv)
     regs.esi    = (unsigned long)res + 0;
     regs.edi    = (unsigned long)res + 2;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (*res != 0x44554455) ||
          (regs.eflags != 0x200) ||
          (regs.ecx != 22) || 
@@ -283,7 +283,7 @@ int main(int argc, char **argv)
     regs.eip    = (unsigned long)&instr[0];
     regs.edi    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) ||
+    if ( (rc != X86EMUL_OKAY) ||
          (*res != 0x2233445D) ||
          ((regs.eflags&0x201) != 0x201) ||
          (regs.eip != (unsigned long)&instr[4]) )
@@ -298,7 +298,7 @@ int main(int argc, char **argv)
     regs.eax    = -32;
     regs.edi    = (unsigned long)(res+1);
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) ||
+    if ( (rc != X86EMUL_OKAY) ||
          (*res != 0x2233445E) ||
          ((regs.eflags&0x201) != 0x201) ||
          (regs.eip != (unsigned long)&instr[3]) )
@@ -318,7 +318,7 @@ int main(int argc, char **argv)
     regs.eip    = (unsigned long)&instr[0];
     regs.edi    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) ||
+    if ( (rc != X86EMUL_OKAY) ||
          (res[0] != 0x9999AAAA) ||
          (res[1] != 0xCCCCFFFF) ||
          ((regs.eflags&0x240) != 0x240) ||
@@ -332,7 +332,7 @@ int main(int argc, char **argv)
     regs.eip    = (unsigned long)&instr[0];
     regs.edi    = (unsigned long)res;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) || 
+    if ( (rc != X86EMUL_OKAY) || 
          (res[0] != 0x9999AAAA) ||
          (res[1] != 0xCCCCFFFF) ||
          (regs.eax != 0x9999AAAA) ||
@@ -350,7 +350,7 @@ int main(int argc, char **argv)
     regs.eax    = (unsigned long)res;
     *res        = 0x82;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) ||
+    if ( (rc != X86EMUL_OKAY) ||
          (*res != 0x82) ||
          (regs.ecx != 0xFFFFFF82) ||
          ((regs.eflags&0x240) != 0x200) ||
@@ -366,7 +366,7 @@ int main(int argc, char **argv)
     regs.eax    = (unsigned long)res;
     *res        = 0x1234aa82;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) ||
+    if ( (rc != X86EMUL_OKAY) ||
          (*res != 0x1234aa82) ||
          (regs.ecx != 0xaa82) ||
          ((regs.eflags&0x240) != 0x200) ||
@@ -382,7 +382,7 @@ int main(int argc, char **argv)
     regs.eax    = 0x12345678;
     *res        = 0x11111111;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) ||
+    if ( (rc != X86EMUL_OKAY) ||
          (*res != 0x11116789) ||
          (regs.eax != 0x12341111) ||
          ((regs.eflags&0x240) != 0x200) ||
@@ -396,7 +396,7 @@ int main(int argc, char **argv)
     regs.eip    = (unsigned long)&instr[0];
     regs.eax    = 0x00000000;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) ||
+    if ( (rc != X86EMUL_OKAY) ||
          (regs.eax != 0x0000ffff) ||
          ((regs.eflags&0x240) != 0x200) ||
          (regs.eip != (unsigned long)&instr[2]) )
@@ -410,7 +410,7 @@ int main(int argc, char **argv)
     regs.eax    = 0x12345678;
     regs.ebp    = 0xaaaaaaaa;
     rc = x86_emulate(&ctxt, &emulops);
-    if ( (rc != 0) ||
+    if ( (rc != X86EMUL_OKAY) ||
          (regs.eax != 0xaaaaaab2) ||
          ((regs.eflags&0x240) != 0x200) ||
          (regs.eip != (unsigned long)&instr[3]) )
@@ -454,7 +454,7 @@ int main(int argc, char **argv)
         bcdres_emul |= (regs.eflags & EFLG_SF) ? 0x400 : 0;
         bcdres_emul |= (regs.eflags & EFLG_CF) ? 0x200 : 0;
         bcdres_emul |= (regs.eflags & EFLG_AF) ? 0x100 : 0;
-        if ( (rc != 0) || (regs.eax > 255) ||
+        if ( (rc != X86EMUL_OKAY) || (regs.eax > 255) ||
              (regs.eip != (unsigned long)&instr[1]) )
             goto fail;
 
@@ -501,7 +501,7 @@ int main(int argc, char **argv)
         if ( (i++ & 8191) == 0 )
             printf(".");
         rc = x86_emulate(&ctxt, &emulops);
-        if ( rc != 0 )
+        if ( rc != X86EMUL_OKAY )
         {
             printf("failed at %%eip == %08x\n", (unsigned int)regs.eip);
             return 1;
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/arch/x86/mm.c Wed Feb 21 19:58:58 2007 +0000
@@ -3151,10 +3151,10 @@ static int ptwr_emulated_read(
     if ( (rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0 )
     {
         propagate_page_fault(addr + bytes - rc, 0); /* read fault */
-        return X86EMUL_PROPAGATE_FAULT;
-    }
-
-    return X86EMUL_CONTINUE;
+        return X86EMUL_EXCEPTION;
+    }
+
+    return X86EMUL_OKAY;
 }
 
 static int ptwr_emulated_update(
@@ -3190,7 +3190,7 @@ static int ptwr_emulated_update(
         if ( (rc = copy_from_user(&full, (void *)addr, sizeof(paddr_t))) != 0 )
         {
             propagate_page_fault(addr+sizeof(paddr_t)-rc, 0); /* read fault */
-            return X86EMUL_PROPAGATE_FAULT;
+            return X86EMUL_EXCEPTION;
         }
         /* Mask out bits provided by caller. */
         full &= ~((((paddr_t)1 << (bytes*8)) - 1) << (offset*8));
@@ -3273,7 +3273,7 @@ static int ptwr_emulated_update(
     /* Finally, drop the old PTE. */
     put_page_from_l1e(gl1e_to_ml1e(d, ol1e), d);
 
-    return X86EMUL_CONTINUE;
+    return X86EMUL_OKAY;
 }
 
 static int ptwr_emulated_write(
@@ -3333,6 +3333,7 @@ int ptwr_do_page_fault(struct vcpu *v, u
     struct page_info *page;
     l1_pgentry_t      pte;
     struct ptwr_emulate_ctxt ptwr_ctxt;
+    int rc;
 
     LOCK_BIGLOCK(d);
 
@@ -3357,7 +3358,9 @@ int ptwr_do_page_fault(struct vcpu *v, u
         IS_COMPAT(d) ? 32 : BITS_PER_LONG;
     ptwr_ctxt.cr2 = addr;
     ptwr_ctxt.pte = pte;
-    if ( x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops) )
+
+    rc = x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops);
+    if ( rc == X86EMUL_UNHANDLEABLE )
         goto bail;
 
     UNLOCK_BIGLOCK(d);
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c   Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/arch/x86/mm/shadow/common.c   Wed Feb 21 19:58:58 2007 +0000
@@ -191,7 +191,7 @@ static int hvm_translate_linear_addr(
  gpf:
     /* Inject #GP(0). */
     hvm_inject_exception(TRAP_gp_fault, 0, 0);
-    return X86EMUL_PROPAGATE_FAULT;
+    return X86EMUL_EXCEPTION;
 }
 
 static int
@@ -216,7 +216,7 @@ hvm_read(enum x86_segment seg,
     //        In this case, that is only a user vs supervisor access check.
     //
     if ( (rc = hvm_copy_from_guest_virt(val, addr, bytes)) == 0 )
-        return X86EMUL_CONTINUE;
+        return X86EMUL_OKAY;
 
     /* If we got here, there was nothing mapped here, or a bad GFN 
      * was mapped here.  This should never happen: we're here because
@@ -226,7 +226,7 @@ hvm_read(enum x86_segment seg,
     if ( access_type == hvm_access_insn_fetch )
         errcode |= PFEC_insn_fetch;
     hvm_inject_exception(TRAP_page_fault, errcode, addr + bytes - rc);
-    return X86EMUL_PROPAGATE_FAULT;
+    return X86EMUL_EXCEPTION;
 }
 
 static int
@@ -259,7 +259,7 @@ hvm_emulate_insn_fetch(enum x86_segment 
     /* Hit the cache. Simple memcpy. */
     *val = 0;
     memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes);
-    return X86EMUL_CONTINUE;
+    return X86EMUL_OKAY;
 }
 
 static int
@@ -352,10 +352,10 @@ pv_emulate_read(enum x86_segment seg,
     if ( (rc = copy_from_user((void *)val, (void *)offset, bytes)) != 0 )
     {
         propagate_page_fault(offset + bytes - rc, 0); /* read fault */
-        return X86EMUL_PROPAGATE_FAULT;
-    }
-
-    return X86EMUL_CONTINUE;
+        return X86EMUL_EXCEPTION;
+    }
+
+    return X86EMUL_OKAY;
 }
 
 static int
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c    Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/arch/x86/mm/shadow/multi.c    Wed Feb 21 19:58:58 2007 +0000
@@ -2911,8 +2911,11 @@ static int sh_page_fault(struct vcpu *v,
      * page is no longer a page table. This behaviour differs from native, but
      * it seems very unlikely that any OS grants user access to page tables.
      */
-    if ( (regs->error_code & PFEC_user_mode) ||
-         x86_emulate(&emul_ctxt.ctxt, emul_ops) )
+    r = X86EMUL_UNHANDLEABLE;
+    if ( !(regs->error_code & PFEC_user_mode) )
+        r = x86_emulate(&emul_ctxt.ctxt, emul_ops);
+
+    if ( (r == X86EMUL_UNHANDLEABLE) || (r == X86EMUL_EXCEPTION) )
     {
         SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n", 
                        mfn_x(gmfn));
@@ -3956,7 +3959,7 @@ sh_x86_emulate_write(struct vcpu *v, uns
     ASSERT(((vaddr & ~PAGE_MASK) + bytes) <= PAGE_SIZE);
 
     if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
-        return X86EMUL_PROPAGATE_FAULT;
+        return X86EMUL_EXCEPTION;
 
     skip = safe_not_to_verify_write(mfn, addr, src, bytes);
     memcpy(addr, src, bytes);
@@ -3968,7 +3971,7 @@ sh_x86_emulate_write(struct vcpu *v, uns
 
     sh_unmap_domain_page(addr);
     shadow_audit_tables(v);
-    return X86EMUL_CONTINUE;
+    return X86EMUL_OKAY;
 }
 
 int
@@ -3979,7 +3982,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u
     mfn_t mfn;
     void *addr;
     unsigned long prev;
-    int rv = X86EMUL_CONTINUE, skip;
+    int rv = X86EMUL_OKAY, skip;
 
     ASSERT(shadow_locked_by_me(v->domain));
     ASSERT(bytes <= sizeof(unsigned long));
@@ -3988,7 +3991,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u
         return X86EMUL_UNHANDLEABLE;
 
     if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
-        return X86EMUL_PROPAGATE_FAULT;
+        return X86EMUL_EXCEPTION;
 
     skip = safe_not_to_verify_write(mfn, &new, &old, bytes);
 
@@ -4032,7 +4035,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v,
     mfn_t mfn;
     void *addr;
     u64 old, new, prev;
-    int rv = X86EMUL_CONTINUE, skip;
+    int rv = X86EMUL_OKAY, skip;
 
     ASSERT(shadow_locked_by_me(v->domain));
 
@@ -4040,7 +4043,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v,
         return X86EMUL_UNHANDLEABLE;
 
     if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
-        return X86EMUL_PROPAGATE_FAULT;
+        return X86EMUL_EXCEPTION;
 
     old = (((u64) old_hi) << 32) | (u64) old_lo;
     new = (((u64) new_hi) << 32) | (u64) new_lo;
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c        Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/arch/x86/x86_emulate.c        Wed Feb 21 19:58:58 2007 +0000
@@ -464,10 +464,10 @@ do{ __asm__ __volatile__ (              
 
 #define mode_64bit() (def_ad_bytes == 8)
 
-#define fail_if(p)                              \
-do {                                            \
-    rc = (p) ? X86EMUL_UNHANDLEABLE : 0;        \
-    if ( rc ) goto done;                        \
+#define fail_if(p)                                      \
+do {                                                    \
+    rc = (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY;     \
+    if ( rc ) goto done;                                \
 } while (0)
 
 /* In future we will be able to generate arbitrary exceptions. */
@@ -726,7 +726,7 @@ x86_emulate(
     uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
     unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes;
     unsigned int lock_prefix = 0, rep_prefix = 0;
-    int rc = 0;
+    int rc = X86EMUL_OKAY;
     struct operand src, dst;
 
     /* Data operand effective address (usually computed from ModRM). */
@@ -742,7 +742,7 @@ x86_emulate(
     {
         op_bytes = def_op_bytes = 4;
 #ifndef __x86_64__
-        return -1;
+        return X86EMUL_UNHANDLEABLE;
 #endif
     }
 
@@ -1593,7 +1593,7 @@ x86_emulate(
     *ctxt->regs = _regs;
 
  done:
-    return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+    return rc;
 
  special_insn:
     dst.type = OP_NONE;
@@ -2383,5 +2383,5 @@ x86_emulate(
     }
     printk("\n");
 #endif
-    return -1;
+    return X86EMUL_UNHANDLEABLE;
 }
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/include/asm-x86/x86_emulate.h
--- a/xen/include/asm-x86/x86_emulate.h Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/include/asm-x86/x86_emulate.h Wed Feb 21 19:58:58 2007 +0000
@@ -46,26 +46,32 @@ enum x86_segment {
 };
 
 /*
+ * Return codes from state-accessor functions and from x86_emulate().
+ */
+ /* Completed successfully. State modified appropriately. */
+#define X86EMUL_OKAY           0
+ /* Unhandleable access or emulation. No state modified. */
+#define X86EMUL_UNHANDLEABLE   1
+ /* Exception raised and requires delivery. */
+#define X86EMUL_EXCEPTION      2
+ /* Retry the emulation for some reason. No state modified. */
+#define X86EMUL_RETRY          3
+ /* (cmpxchg accessor): CMPXCHG failed. Maps to X86EMUL_RETRY in caller. */
+#define X86EMUL_CMPXCHG_FAILED 3
+
+/*
  * These operations represent the instruction emulator's interface to memory.
  * 
  * NOTES:
  *  1. If the access fails (cannot emulate, or a standard access faults) then
  *     it is up to the memop to propagate the fault to the guest VM via
  *     some out-of-band mechanism, unknown to the emulator. The memop signals
- *     failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will
+ *     failure by returning X86EMUL_EXCEPTION to the emulator, which will
  *     then immediately bail.
  *  2. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
  *     cmpxchg8b_emulated need support 8-byte accesses.
  *  3. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
  */
-/* Access completed successfully: continue emulation as normal. */
-#define X86EMUL_CONTINUE        0
-/* Access is unhandleable: bail from emulation and return error to caller. */
-#define X86EMUL_UNHANDLEABLE    1
-/* Terminate emulation but return success to the caller. */
-#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
-#define X86EMUL_RETRY_INSTR     2 /* retry the instruction for some reason */
-#define X86EMUL_CMPXCHG_FAILED  2 /* cmpxchg did not see expected value */
 struct x86_emulate_ops
 {
     /*

_______________________________________________
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®.