89 lines
2.7 KiB
Diff
89 lines
2.7 KiB
Diff
|
# HG changeset patch
|
||
|
# User Jan Beulich <jbeulich@suse.com>
|
||
|
# Date 1322725849 -3600
|
||
|
# Node ID 76ea126f21724b72c120aff59460f7bbe9e6960d
|
||
|
# Parent 07cf778d517fdf661a34027af653a489489bf222
|
||
|
x86/emulator: properly handle lzcnt and tzcnt
|
||
|
|
||
|
These instructions are prefix selected flavors of bsf and bsr
|
||
|
respectively, and hence the presences of the F3 prefix must be handled
|
||
|
in the emulation code in order to avoid running into problems on newer
|
||
|
CPUs.
|
||
|
|
||
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||
|
|
||
|
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
|
||
|
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
|
||
|
@@ -990,6 +990,9 @@ static bool_t vcpu_has(
|
||
|
return rc == X86EMUL_OKAY;
|
||
|
}
|
||
|
|
||
|
+#define vcpu_has_lzcnt() vcpu_has(0x80000001, ECX, 5, ctxt, ops)
|
||
|
+#define vcpu_has_bmi1() vcpu_has(0x00000007, EBX, 3, ctxt, ops)
|
||
|
+
|
||
|
#define vcpu_must_have(leaf, reg, bit) \
|
||
|
generate_exception_if(!vcpu_has(leaf, reg, bit, ctxt, ops), EXC_UD, -1)
|
||
|
#define vcpu_must_have_sse2() vcpu_must_have(0x00000001, EDX, 26)
|
||
|
@@ -4114,13 +4117,24 @@ x86_emulate(
|
||
|
dst.val = (uint8_t)src.val;
|
||
|
break;
|
||
|
|
||
|
- case 0xbc: /* bsf */ {
|
||
|
- int zf;
|
||
|
+ case 0xbc: /* bsf or tzcnt */ {
|
||
|
+ bool_t zf;
|
||
|
asm ( "bsf %2,%0; setz %b1"
|
||
|
: "=r" (dst.val), "=q" (zf)
|
||
|
- : "r" (src.val), "1" (0) );
|
||
|
+ : "r" (src.val) );
|
||
|
_regs.eflags &= ~EFLG_ZF;
|
||
|
- if ( zf )
|
||
|
+ if ( (rep_prefix == REPE_PREFIX) && vcpu_has_bmi1() )
|
||
|
+ {
|
||
|
+ _regs.eflags &= ~EFLG_CF;
|
||
|
+ if ( zf )
|
||
|
+ {
|
||
|
+ _regs.eflags |= EFLG_CF;
|
||
|
+ dst.val = op_bytes * 8;
|
||
|
+ }
|
||
|
+ else if ( !dst.val )
|
||
|
+ _regs.eflags |= EFLG_ZF;
|
||
|
+ }
|
||
|
+ else if ( zf )
|
||
|
{
|
||
|
_regs.eflags |= EFLG_ZF;
|
||
|
dst.type = OP_NONE;
|
||
|
@@ -4128,13 +4142,28 @@ x86_emulate(
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
- case 0xbd: /* bsr */ {
|
||
|
- int zf;
|
||
|
+ case 0xbd: /* bsr or lzcnt */ {
|
||
|
+ bool_t zf;
|
||
|
asm ( "bsr %2,%0; setz %b1"
|
||
|
: "=r" (dst.val), "=q" (zf)
|
||
|
- : "r" (src.val), "1" (0) );
|
||
|
+ : "r" (src.val) );
|
||
|
_regs.eflags &= ~EFLG_ZF;
|
||
|
- if ( zf )
|
||
|
+ if ( (rep_prefix == REPE_PREFIX) && vcpu_has_lzcnt() )
|
||
|
+ {
|
||
|
+ _regs.eflags &= ~EFLG_CF;
|
||
|
+ if ( zf )
|
||
|
+ {
|
||
|
+ _regs.eflags |= EFLG_CF;
|
||
|
+ dst.val = op_bytes * 8;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ dst.val = op_bytes * 8 - 1 - dst.val;
|
||
|
+ if ( !dst.val )
|
||
|
+ _regs.eflags |= EFLG_ZF;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else if ( zf )
|
||
|
{
|
||
|
_regs.eflags |= EFLG_ZF;
|
||
|
dst.type = OP_NONE;
|