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); \
#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__)
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)
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 )