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

[Xen-changelog] [xen master] x86emul: support clzero



commit 892d196360d65dfa87f5fd7210cd5bca927aa455
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Thu Jan 14 10:32:35 2016 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Jan 14 10:32:35 2016 +0100

    x86emul: support clzero
    
    ... in anticipation of this possibly going to get used by guests for
    basic thinks like memset() or clearing or pages.
    
    Since the emulation doesn't use clzero itself, checking the guest's
    CPUID for the feature to be exposed is (intentionally) being avoided
    here. All that's required is sensible guest side data for the clflush
    line size.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Aravind Gopalakrishnan <aravind.gopalakrishnan@xxxxxxx>
    Acked-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
 tools/tests/x86_emulator/test_x86_emulator.c |   35 ++++++++++++++++++++++
 xen/arch/x86/x86_emulate/x86_emulate.c       |   40 ++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/tools/tests/x86_emulator/test_x86_emulator.c 
b/tools/tests/x86_emulator/test_x86_emulator.c
index 1b78bf7..86e298f 100644
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -82,6 +82,12 @@ static int cpuid(
     return X86EMUL_OKAY;
 }
 
+#define cache_line_size() ({ \
+    unsigned int eax = 1, ebx, ecx = 0, edx; \
+    cpuid(&eax, &ebx, &ecx, &edx, NULL); \
+    edx & (1U << 19) ? (ebx >> 5) & 0x7f8 : 0; \
+})
+
 #define cpu_has_mmx ({ \
     unsigned int eax = 1, ecx = 0, edx; \
     cpuid(&eax, &ecx, &ecx, &edx, NULL); \
@@ -873,6 +879,35 @@ int main(int argc, char **argv)
 #undef set_insn
 #undef check_eip
 
+    j = cache_line_size();
+    snprintf(instr, (char *)res + MMAP_SZ - instr,
+             "Testing clzero (%u-byte line)...", j);
+    printf("%-40s", instr);
+    if ( j >= sizeof(*res) && j <= MMAP_SZ / 4 )
+    {
+        instr[0] = 0x0f; instr[1] = 0x01; instr[2] = 0xfc;
+        regs.eflags = 0x200;
+        regs.eip    = (unsigned long)&instr[0];
+        regs.eax    = (unsigned long)res + MMAP_SZ / 2 + j - 1;
+        memset((void *)res + MMAP_SZ / 4, ~0, 3 * MMAP_SZ / 4);
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) ||
+             (regs.eax != (unsigned long)res + MMAP_SZ / 2 + j - 1) ||
+             (regs.eflags != 0x200) ||
+             (regs.eip != (unsigned long)&instr[3]) ||
+             (res[MMAP_SZ / 2 / sizeof(*res) - 1] != ~0U) ||
+             (res[(MMAP_SZ / 2 + j) / sizeof(*res)] != ~0U) )
+            goto fail;
+        for ( i = 0; i < j; i += sizeof(*res) )
+            if ( res[(MMAP_SZ / 2 + i) / sizeof(*res)] )
+                break;
+        if ( i < j )
+            goto fail;
+        printf("okay\n");
+    }
+    else
+        printf("skipped\n");
+
     for ( j = 1; j <= 2; j++ )
     {
 #if defined(__i386__)
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c 
b/xen/arch/x86/x86_emulate/x86_emulate.c
index 56aef3e..c3672e7 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -1069,6 +1069,7 @@ static bool_t vcpu_has(
     return rc == X86EMUL_OKAY;
 }
 
+#define vcpu_has_clflush() vcpu_has(       1, EDX, 19, ctxt, ops)
 #define vcpu_has_lzcnt() vcpu_has(0x80000001, ECX,  5, ctxt, ops)
 #define vcpu_has_bmi1()  vcpu_has(0x00000007, EBX,  3, ctxt, ops)
 
@@ -3851,6 +3852,45 @@ x86_emulate(
             if ( (rc = ops->vmfunc(ctxt) != X86EMUL_OKAY) )
                 goto done;
             goto no_writeback;
+       case 0xfc: /* clzero */ {
+            unsigned int eax = 1, ebx = 0, dummy = 0;
+            unsigned long zero = 0;
+
+            base = ad_bytes == 8 ? _regs.eax :
+                   ad_bytes == 4 ? (uint32_t)_regs.eax : (uint16_t)_regs.eax;
+            limit = 0;
+            if ( vcpu_has_clflush() &&
+                 ops->cpuid(&eax, &ebx, &dummy, &dummy, ctxt) == X86EMUL_OKAY )
+                limit = ((ebx >> 8) & 0xff) * 8;
+            generate_exception_if(limit < sizeof(long) ||
+                                  (limit & (limit - 1)), EXC_UD, -1);
+            base &= ~(limit - 1);
+            if ( override_seg == -1 )
+                override_seg = x86_seg_ds;
+            if ( ops->rep_stos )
+            {
+                unsigned long nr_reps = limit / sizeof(zero);
+
+                rc = ops->rep_stos(&zero, override_seg, base, sizeof(zero),
+                                   &nr_reps, ctxt);
+                if ( rc == X86EMUL_OKAY )
+                {
+                    base += nr_reps * sizeof(zero);
+                    limit -= nr_reps * sizeof(zero);
+                }
+                else if ( rc != X86EMUL_UNHANDLEABLE )
+                    goto done;
+            }
+            while ( limit )
+            {
+                rc = ops->write(override_seg, base, &zero, sizeof(zero), ctxt);
+                if ( rc != X86EMUL_OKAY )
+                    goto done;
+                base += sizeof(zero);
+                limit -= sizeof(zero);
+            }
+            goto no_writeback;
+        }
         }
 
         switch ( modrm_reg & 7 )
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
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®.