xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] x86emul: support clzero
@ 2015-09-22 13:06 Jan Beulich
  2015-09-23 17:37 ` Andrew Cooper
  2016-01-11 15:55 ` Aravind Gopalakrishnan
  0 siblings, 2 replies; 8+ messages in thread
From: Jan Beulich @ 2015-09-22 13:06 UTC (permalink / raw)
  To: xen-devel
  Cc: Andrew Cooper, Keir Fraser, Aravind Gopalakrishnan,
	suravee.suthikulpanit

[-- Attachment #1: Type: text/plain, Size: 4407 bytes --]

... 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@suse.com>

--- 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__)
--- 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)
 
@@ -3841,6 +3842,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 )



[-- Attachment #2: x86emul-clzero.patch --]
[-- Type: text/plain, Size: 4430 bytes --]

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@suse.com>

--- 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__)
--- 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)
 
@@ -3841,6 +3842,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 )

[-- Attachment #3: Type: text/plain, Size: 126 bytes --]

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

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-01-13 15:11 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-22 13:06 [PATCH] x86emul: support clzero Jan Beulich
2015-09-23 17:37 ` Andrew Cooper
2015-09-24  8:02   ` Jan Beulich
2015-09-24 11:59     ` Andrew Cooper
2015-09-24 12:13       ` Jan Beulich
2015-10-08 10:26     ` Jan Beulich
2016-01-11 15:55 ` Aravind Gopalakrishnan
2016-01-13 15:10   ` Andrew Cooper

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).