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

[Xen-devel] [PATCH 5/7] fuzz/x86emul: update fuzzer



Provide the fuzzer with more ops, and more sophisticated input
structure.

Based on a patch originally written by Andrew and George.

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxx>
Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
---
 .../x86-insn-emulator-fuzzer.c                     | 653 +++++++++++++++++++--
 1 file changed, 595 insertions(+), 58 deletions(-)

diff --git a/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c 
b/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c
index 7d7f731677..8ca0421f60 100644
--- a/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c
+++ b/tools/fuzz/x86_instruction_emulator/x86-insn-emulator-fuzzer.c
@@ -16,26 +16,75 @@
 
 #include "x86_emulate.h"
 
-static unsigned char data[4096];
+#include "../../../xen/include/asm-x86/msr-index.h"
+
+#ifndef offsetof
+#define offsetof(t,m) ((size_t)&(((t *)0)->m))
+#endif
+
+#define MSR_INDEX_MAX 16
+
+#define SEG_MAX x86_seg_none
+
+struct input_struct {
+    unsigned cr[5];
+    uint64_t msr[MSR_INDEX_MAX];
+    struct cpu_user_regs regs;
+    struct segment_register segments[SEG_MAX+1];
+    unsigned long options;
+    unsigned char data[4096];
+} input;
+#define DATA_OFFSET offsetof(struct input_struct, data)
 static unsigned int data_index;
 static unsigned int data_max;
 
+int maybe_fail(const char *why, bool exception)
+{
+    int rc;
+
+    if ( data_index + 1 > data_max )
+        return X86EMUL_EXCEPTION;
+    else
+    {
+        if ( input.data[data_index] > 0xc )
+            rc = X86EMUL_EXCEPTION;
+        else if ( input.data[data_index] > 0x8 )
+            rc = X86EMUL_UNHANDLEABLE;
+        else
+            rc = X86EMUL_OKAY;
+        data_index++;
+    }
+
+    if ( rc == X86EMUL_EXCEPTION && !exception )
+        rc = X86EMUL_OKAY;
+
+    printf("maybe_fail %s: %d\n", why, rc);
+
+    return rc;
+}
+
 static int data_read(const char *why, void *dst, unsigned int bytes)
 {
     unsigned int i;
+    int rc;
 
     if ( data_index + bytes > data_max )
         return X86EMUL_EXCEPTION;
+    else
+        rc = maybe_fail(why, true);
 
-    memcpy(dst,  data + data_index, bytes);
-    data_index += bytes;
+    if ( rc == X86EMUL_OKAY )
+    {
+        memcpy(dst,  input.data + data_index, bytes);
+        data_index += bytes;
 
-    printf("%s: ", why);
-    for ( i = 0; i < bytes; i++ )
-        printf(" %02x", *(unsigned char *)(dst + i));
-    printf("\n");
+        printf("%s: ", why);
+        for ( i = 0; i < bytes; i++ )
+            printf(" %02x", *(unsigned char *)(dst + i));
+        printf("\n");
+    }
 
-    return X86EMUL_OKAY;
+    return rc;
 }
 
 static int fuzz_read(
@@ -48,14 +97,71 @@ static int fuzz_read(
     return data_read("read", p_data, bytes);
 }
 
-static int fuzz_fetch(
+static int fuzz_read_io(
+    unsigned int port,
+    unsigned int bytes,
+    unsigned long *val,
+    struct x86_emulate_ctxt *ctxt)
+{
+    return data_read("read_io", val, bytes);
+}
+
+static int fuzz_insn_fetch(
     unsigned int seg,
     unsigned long offset,
     void *p_data,
     unsigned int bytes,
     struct x86_emulate_ctxt *ctxt)
 {
-    return data_read("fetch", p_data, bytes);
+    return data_read("insn_fetch", p_data, bytes);
+}
+
+static int fuzz_rep_ins(
+    uint16_t src_port,
+    enum x86_segment dst_seg,
+    unsigned long dst_offset,
+    unsigned int bytes_per_rep,
+    unsigned long *reps,
+    struct x86_emulate_ctxt *ctxt)
+{
+    int rc;
+    unsigned long bytes_read;
+
+    rc = data_read("rep_ins", &bytes_read, sizeof(bytes_read));
+
+    if ( rc != X86EMUL_OKAY )
+        return rc;
+
+    if ( bytes_read < *reps )
+        *reps -= bytes_read;
+    else
+        *reps = 0;
+
+    return rc;
+}
+
+static int fuzz_rep_movs(
+    enum x86_segment src_seg,
+    unsigned long src_offset,
+    enum x86_segment dst_seg,
+    unsigned long dst_offset,
+    unsigned int bytes_per_rep,
+    unsigned long *reps,
+    struct x86_emulate_ctxt *ctxt)
+{
+    int rc;
+    unsigned long bytes_read;
+    rc = data_read("rep_ins", &bytes_read, sizeof(bytes_read));
+
+    if ( rc != X86EMUL_OKAY )
+        return rc;
+
+    if ( bytes_read < *reps )
+        *reps -= bytes_read;
+    else
+        *reps = 0;
+
+    return rc;
 }
 
 static int fuzz_write(
@@ -65,7 +171,7 @@ static int fuzz_write(
     unsigned int bytes,
     struct x86_emulate_ctxt *ctxt)
 {
-    return X86EMUL_OKAY;
+    return maybe_fail("write", true);
 }
 
 static int fuzz_cmpxchg(
@@ -76,18 +182,323 @@ static int fuzz_cmpxchg(
     unsigned int bytes,
     struct x86_emulate_ctxt *ctxt)
 {
-    return X86EMUL_OKAY;
+    return maybe_fail("cmpxchg", true);
+}
+
+static int fuzz_invlpg(
+    enum x86_segment seg,
+    unsigned long offset,
+    struct x86_emulate_ctxt *ctxt)
+{
+    return maybe_fail("invlpg", false);
+}
+
+static int fuzz_wbinvd(
+    struct x86_emulate_ctxt *ctxt)
+{
+    return maybe_fail("wbinvd", true);
+}
+
+static int fuzz_write_io(
+    unsigned int port,
+    unsigned int bytes,
+    unsigned long val,
+    struct x86_emulate_ctxt *ctxt)
+{
+    return maybe_fail("write_io", true);
+}
+
+static int fuzz_rep_stos(
+    void *p_data,
+    enum x86_segment seg,
+    unsigned long offset,
+    unsigned int bytes_per_rep,
+    unsigned long *reps,
+    struct x86_emulate_ctxt *ctxt)
+{
+    return maybe_fail("rep_stos", true);
 }
 
+static int fuzz_rep_outs(
+    enum x86_segment src_seg,
+    unsigned long src_offset,
+    uint16_t dst_port,
+    unsigned int bytes_per_rep,
+    unsigned long *reps,
+    struct x86_emulate_ctxt *ctxt)
+{
+    return maybe_fail("rep_outs", true);
+}
+
+static int fuzz_cpuid(
+    uint32_t leaf,
+    uint32_t subleaf,
+    struct cpuid_leaf *res,
+    struct x86_emulate_ctxt *ctxt)
+{
+    int rc;
+
+    rc = maybe_fail("cpuid", true);
+
+    if ( rc == X86EMUL_OKAY )
+        emul_test_cpuid(leaf, subleaf, res, ctxt);
+
+    return rc;
+}
+
+static int fuzz_read_segment(
+    enum x86_segment seg,
+    struct segment_register *reg,
+    struct x86_emulate_ctxt *ctxt)
+{
+    int rc;
+
+    if ( seg > SEG_MAX )
+        return X86EMUL_UNHANDLEABLE;
+
+    rc = maybe_fail("read_segment", true);
+
+    if ( rc == X86EMUL_OKAY )
+        memcpy(reg, input.segments+seg, sizeof(struct segment_register));
+
+    return rc;
+}
+
+static int fuzz_write_segment(
+    enum x86_segment seg,
+    const struct segment_register *reg,
+    struct x86_emulate_ctxt *ctxt)
+{
+    int rc;
+
+    if ( seg > SEG_MAX )
+        return X86EMUL_UNHANDLEABLE;
+
+    rc = maybe_fail("write_segment", true);
+
+    if ( rc == X86EMUL_OKAY )
+        memcpy(input.segments+seg, reg, sizeof(struct segment_register));
+
+    return rc;
+}
+
+static int fuzz_read_cr(
+    unsigned int reg,
+    unsigned long *val,
+    struct x86_emulate_ctxt *ctxt)
+{
+    int rc;
+
+    if ( reg > 5 )
+        return X86EMUL_UNHANDLEABLE;
+
+    rc = maybe_fail("read_cr", true);
+
+    if ( rc == X86EMUL_OKAY )
+        *val = input.cr[reg];
+
+    return rc;
+}
+
+static int fuzz_write_cr(
+    unsigned int reg,
+    unsigned long val,
+    struct x86_emulate_ctxt *ctxt)
+{
+    int rc;
+
+    if ( reg > 5 )
+        return X86EMUL_UNHANDLEABLE;
+
+    rc = maybe_fail("write_cr", true);
+
+    if ( rc == X86EMUL_OKAY )
+        input.cr[reg] = val;
+
+    return rc;
+}
+
+enum {
+    MSRI_IA32_SYSENTER_CS,
+    MSRI_IA32_SYSENTER_ESP,
+    MSRI_IA32_SYSENTER_EIP,
+    MSRI_EFER,
+    MSRI_STAR,
+    MSRI_LSTAR,
+    MSRI_CSTAR,
+    MSRI_SYSCALL_MASK
+};
+
+int msr_index[MSR_INDEX_MAX] = {
+    [MSRI_IA32_SYSENTER_CS] = MSR_IA32_SYSENTER_CS,
+    [MSRI_IA32_SYSENTER_ESP] = MSR_IA32_SYSENTER_ESP,
+    [MSRI_IA32_SYSENTER_EIP] = MSR_IA32_SYSENTER_EIP,
+    [MSRI_EFER] = MSR_EFER,
+    [MSRI_STAR] = MSR_STAR,
+    [MSRI_LSTAR] = MSR_LSTAR,
+    [MSRI_CSTAR] = MSR_CSTAR,
+    [MSRI_SYSCALL_MASK] = MSR_SYSCALL_MASK
+};
+
+static int fuzz_read_msr_(
+    unsigned int reg,
+    uint64_t *val,
+    struct x86_emulate_ctxt *ctxt)
+{
+    unsigned int idx;
+
+    switch ( reg )
+    {
+    case MSR_TSC_AUX:
+    case MSR_TSC:
+        return data_read("read_msr", val, sizeof(*val));
+    case MSR_EFER:
+        *val = input.msr[MSRI_EFER];
+        *val &= ~EFER_LMA;
+        if ( (*val & EFER_LME) && (input.cr[4] & X86_CR4_PAE) &&
+             (input.cr[0] & X86_CR0_PG) )
+        {
+            printf("Setting EFER_LMA\n");
+            *val |= EFER_LMA;
+        }
+        return X86EMUL_OKAY;
+    }
+
+    for ( idx = 0; idx < MSR_INDEX_MAX; idx++ )
+    {
+        if ( msr_index[idx] == reg )
+        {
+            *val = input.msr[idx];
+            return X86EMUL_OKAY;
+        }
+    }
+
+    return X86EMUL_EXCEPTION;
+}
+
+static int fuzz_read_msr(
+    unsigned int reg,
+    uint64_t *val,
+    struct x86_emulate_ctxt *ctxt) {
+    int rc;
+
+    rc = maybe_fail("read_msr", true);
+    if ( rc != X86EMUL_OKAY )
+        return rc;
+    else
+        return fuzz_read_msr_(reg, val, ctxt);
+}
+
+static int fuzz_write_msr(
+    unsigned int reg,
+    uint64_t val,
+    struct x86_emulate_ctxt *ctxt)
+{
+    unsigned int idx;
+    int rc;
+
+    rc = maybe_fail("write_ms", true);
+    if ( rc != X86EMUL_OKAY )
+        return rc;
+
+    switch ( reg )
+    {
+    case MSR_TSC_AUX:
+    case MSR_TSC:
+        return X86EMUL_OKAY;
+    }
+
+    for ( idx = 0; idx < MSR_INDEX_MAX; idx++ )
+    {
+        if ( msr_index[idx] == reg )
+        {
+            input.msr[idx] = val;
+            return X86EMUL_OKAY;
+        }
+    }
+
+    return X86EMUL_EXCEPTION;
+}
+
+#define SET(h) .h = fuzz_##h
 static struct x86_emulate_ops fuzz_emulops = {
-    .read       = fuzz_read,
-    .insn_fetch = fuzz_fetch,
-    .write      = fuzz_write,
-    .cmpxchg    = fuzz_cmpxchg,
-    .cpuid      = emul_test_cpuid,
-    .read_cr    = emul_test_read_cr,
+    SET(read),
+    SET(insn_fetch),
+    SET(write),
+    SET(cmpxchg),
+    SET(rep_ins),
+    SET(rep_outs),
+    SET(rep_movs),
+    SET(rep_stos),
+    SET(read_segment),
+    SET(write_segment),
+    SET(read_io),
+    SET(write_io),
+    SET(read_cr),
+    SET(write_cr),
+    SET(read_msr),
+    SET(write_msr),
+    SET(wbinvd),
+    SET(cpuid),
+    SET(invlpg),
     .get_fpu    = emul_test_get_fpu,
 };
+#undef SET
+
+static void setup_fpu_exception_handler(void)
+{
+    /* FIXME - just disable exceptions for now */
+    unsigned long a;
+
+    asm volatile ( "fnclex");
+    a=0x3f;
+    asm volatile ( "fldcw %0" :: "m" (a));
+    a=0x1f80;
+    asm volatile ( "ldmxcsr %0" :: "m" (a) );
+}
+
+static void dump_state(struct x86_emulate_ctxt *ctxt)
+{
+    struct cpu_user_regs *regs = ctxt->regs;
+    uint64_t val;
+
+    printf(" -- State -- \n");
+    printf("addr / sp size: %d / %d\n", ctxt->addr_size, ctxt->sp_size);
+    printf(" cr0: %x\n", input.cr[0]);
+    printf(" cr3: %x\n", input.cr[3]);
+    printf(" cr4: %x\n", input.cr[4]);
+
+    printf(" rip: %"PRIx64"\n", regs->rip);
+
+    fuzz_read_msr_(MSR_EFER, &val, ctxt);
+    printf("EFER: %"PRIx64"\n", val);
+}
+
+static bool long_mode_active(struct x86_emulate_ctxt *ctxt)
+{
+    uint64_t val;
+
+    if ( fuzz_read_msr_(MSR_EFER, &val, ctxt) != X86EMUL_OKAY )
+        return false;
+
+    return !!(val & EFER_LMA);
+}
+
+static bool in_longmode(struct x86_emulate_ctxt *ctxt)
+{
+    return long_mode_active(ctxt) && input.segments[x86_seg_cs].attr.fields.l;
+}
+
+static void set_sizes(struct x86_emulate_ctxt *ctxt)
+{
+    if ( in_longmode(ctxt) )
+        ctxt->addr_size = ctxt->sp_size = 64;
+    else
+    {
+        ctxt->addr_size = input.segments[x86_seg_cs].attr.fields.db ? 32 : 16;
+        ctxt->sp_size   = input.segments[x86_seg_ss].attr.fields.db ? 32 : 16;
+    }
+}
 
 #define CANONICALIZE(x)                                   \
     do {                                                  \
@@ -100,10 +511,152 @@ static struct x86_emulate_ops fuzz_emulops = {
         (x) = _y;                                       \
     } while( 0 )
 
-#define ADDR_SIZE_SHIFT 60
-#define ADDR_SIZE_64 (2ULL << ADDR_SIZE_SHIFT)
-#define ADDR_SIZE_32 (1ULL << ADDR_SIZE_SHIFT)
-#define ADDR_SIZE_16 (0)
+/* Expects bitmap and regs to be defined */
+#define CANONICALIZE_MAYBE(reg)                       \
+    if ( !(bitmap & (1 << CANONICALIZE_##reg)) )      \
+        CANONICALIZE(regs->reg);                      \
+
+enum {
+    HOOK_read,
+    HOOK_insn_fetch,
+    HOOK_write,
+    HOOK_cmpxchg,
+    HOOK_rep_ins,
+    HOOK_rep_outs,
+    HOOK_rep_movs,
+    HOOK_rep_stos,
+    HOOK_read_segment,
+    HOOK_write_segment,
+    HOOK_read_io,
+    HOOK_write_io,
+    HOOK_read_cr,
+    HOOK_write_cr,
+    HOOK_read_dr,
+    HOOK_write_dr,
+    HOOK_read_msr,
+    HOOK_write_msr,
+    HOOK_wbinvd,
+    HOOK_cpuid,
+    HOOK_inject_hw_exception,
+    HOOK_inject_sw_interrupt,
+    HOOK_get_fpu,
+    HOOK_put_fpu,
+    HOOK_invlpg,
+    HOOK_vmfunc, /* 26 */
+    OPTION_swint_emulation = 27, /* Two bits */
+    CANONICALIZE_rip = 29,
+    CANONICALIZE_rsp,
+    CANONICALIZE_rbp
+};
+
+/* Expects bitmap to be defined */
+#define MAYBE_DISABLE_HOOK(h)                          \
+    if ( bitmap & (1 << HOOK_##h) )                    \
+    {                                                  \
+        fuzz_emulops.h = NULL;                         \
+        printf("Disabling hook "#h"\n");               \
+    }
+
+static void disable_hooks(void)
+{
+    unsigned long bitmap = input.options;
+
+    MAYBE_DISABLE_HOOK(read);
+    MAYBE_DISABLE_HOOK(insn_fetch);
+    MAYBE_DISABLE_HOOK(write);
+    MAYBE_DISABLE_HOOK(cmpxchg);
+    MAYBE_DISABLE_HOOK(rep_ins);
+    MAYBE_DISABLE_HOOK(rep_outs);
+    MAYBE_DISABLE_HOOK(rep_movs);
+    MAYBE_DISABLE_HOOK(rep_stos);
+    MAYBE_DISABLE_HOOK(read_segment);
+    MAYBE_DISABLE_HOOK(write_segment);
+    MAYBE_DISABLE_HOOK(read_io);
+    MAYBE_DISABLE_HOOK(write_io);
+    MAYBE_DISABLE_HOOK(read_cr);
+    MAYBE_DISABLE_HOOK(write_cr);
+    MAYBE_DISABLE_HOOK(read_msr);
+    MAYBE_DISABLE_HOOK(write_msr);
+    MAYBE_DISABLE_HOOK(wbinvd);
+    MAYBE_DISABLE_HOOK(cpuid);
+    MAYBE_DISABLE_HOOK(get_fpu);
+    MAYBE_DISABLE_HOOK(invlpg);
+}
+
+static void set_swint_support(struct x86_emulate_ctxt *ctxt)
+{
+    int swint_opt = (input.options >> OPTION_swint_emulation) & 3;
+
+    int map[4] = {
+        x86_swint_emulate_none,
+        x86_swint_emulate_none,
+        x86_swint_emulate_icebp,
+        x86_swint_emulate_all };
+
+    ctxt->swint_emulate = map[swint_opt];
+}
+
+/*
+ * Constrain input to architecturally-possible states where
+ * the emulator relies on these
+ *
+ * In general we want the emulator to be as absolutely robust as
+ * possible; which means that we want to minimize the number of things
+ * it assumes about the input state.  Tesing this means minimizing and
+ * removing as much of the input constraints as possible.
+ *
+ * So we only add constraints that (in general) have been proven to
+ * cause crashes in the emulator.
+ *
+ * For future reference: other constraints which might be necessary at
+ * some point:
+ *
+ * - EFER.LMA => !EFLAGS.NT
+ * - In VM86 mode (and real mode?), force segment...
+ *  - ...access rights to 0xf3
+ *  - ...limits to 0xffff
+ *  - ...bases to below 1Mb, 16-byte aligned
+ *  - ...selectors to (base >> 4)
+ */
+void sanitize_input(struct x86_emulate_ctxt *ctxt) {
+    struct cpu_user_regs *regs = &input.regs;
+    unsigned long bitmap = input.options;
+
+    input.options &=
+        ~((1<<HOOK_read)|
+          (1<<HOOK_write)|
+          (1<<HOOK_cmpxchg)|
+          (1<<HOOK_insn_fetch));
+
+    /* Zero 'private' entries */
+    regs->error_code = 0;
+    regs->entry_vector = 0;
+
+    CANONICALIZE_MAYBE(rip);
+    CANONICALIZE_MAYBE(rsp);
+    CANONICALIZE_MAYBE(rbp);
+
+    /*
+     * CR0.PG can't be set if CR0.PE isn't set.  Set is more interesting, so
+     * set PE if PG is set.
+     */
+    if ( input.cr[0] & X86_CR0_PG )
+        input.cr[0] |= X86_CR0_PE;
+
+    /*
+     * EFLAGS.VM not available in long mode
+     */
+    if ( long_mode_active(ctxt) )
+        regs->rflags &= ~EFLG_VM;
+
+    /*
+     * EFLAGS.VM implies 16-bit mode
+     */
+    if ( regs->rflags & EFLG_VM ) {
+        input.segments[x86_seg_cs].attr.fields.db = 0;
+        input.segments[x86_seg_ss].attr.fields.db = 0;
+    }
+}
 
 int LLVMFuzzerTestOneInput(const uint8_t *data_p, size_t size)
 {
@@ -114,10 +667,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data_p, size_t 
size)
         .addr_size = 8 * sizeof(void *),
         .sp_size = 8 * sizeof(void *),
     };
-    unsigned int nr = 0;
     int rc;
-    unsigned int x;
-    const uint8_t *p = data_p;
 
     stack_exec = emul_test_make_stack_executable();
     if ( !stack_exec )
@@ -127,52 +677,39 @@ int LLVMFuzzerTestOneInput(const uint8_t *data_p, size_t 
size)
     }
 
     /* Reset all global state variables */
-    memset(data, 0, sizeof(data));
+    memset(&input, 0, sizeof(input));
     data_index = 0;
     data_max = 0;
 
-    nr = size < sizeof(regs) ? size : sizeof(regs);
-
-    memcpy(&regs, p, nr);
-    p += sizeof(regs);
+    if ( size <= DATA_OFFSET )
+    {
+        printf("Input too small\n");
+        return 1;
+    }
 
-    if ( nr < size )
+    if ( size > sizeof(input) )
     {
-        memcpy(data, p, size - nr);
-        data_max = size - nr;
+        printf("Input too large\n");
+        return 1;
     }
 
-    ctxt.force_writeback = false;
+    memcpy(&input, data_p, size);
 
-    /* Zero 'private' fields */
-    regs.error_code = 0;
-    regs.entry_vector = 0;
+    data_max = size - DATA_OFFSET;
 
-    /* Use the upper bits of regs.eip to determine addr_size */
-    x = (regs.rip >> ADDR_SIZE_SHIFT) & 0x3;
-    if ( x == 3 )
-        x = 2;
-    ctxt.addr_size = 16 << x;
-    printf("addr_size: %d\n", ctxt.addr_size);
+    sanitize_input(&ctxt);
 
-    /* Use the upper bit of regs.rsp to determine sp_size (if appropriate) */
-    if ( ctxt.addr_size == 64 )
-        ctxt.sp_size = 64;
-    else
-    {
-        /* If addr_size isn't 64-bits, sp_size can only be 16 or 32 bits */
-        x = (regs.rsp >> ADDR_SIZE_SHIFT) & 0x1;
-        ctxt.sp_size = 16 << x;
-    }
-    printf("sp_size: %d\n", ctxt.sp_size);
-    CANONICALIZE(regs.rip);
-    CANONICALIZE(regs.rsp);
-    CANONICALIZE(regs.rbp);
+    disable_hooks();
 
-    /* Zero all segments for now */
-    regs.cs = regs.ss = regs.es = regs.ds = regs.fs = regs.gs = 0;
+    set_swint_support(&ctxt);
 
     do {
+        /* FIXME: Until we actually implement SIGFPE handling properly */
+        setup_fpu_exception_handler();
+
+        set_sizes(&ctxt);
+        dump_state(&ctxt);
+
         rc = x86_emulate(&ctxt, &fuzz_emulops);
         printf("Emulation result: %d\n", rc);
     } while ( rc == X86EMUL_OKAY );
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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