|
@@ -2570,6 +2570,30 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static void string_registers_quirk(struct x86_emulate_ctxt *ctxt)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Intel CPUs mask the counter and pointers in quite strange
|
|
|
+ * manner when ECX is zero due to REP-string optimizations.
|
|
|
+ */
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+ if (ctxt->ad_bytes != 4 || !vendor_intel(ctxt))
|
|
|
+ return;
|
|
|
+
|
|
|
+ *reg_write(ctxt, VCPU_REGS_RCX) = 0;
|
|
|
+
|
|
|
+ switch (ctxt->b) {
|
|
|
+ case 0xa4: /* movsb */
|
|
|
+ case 0xa5: /* movsd/w */
|
|
|
+ *reg_rmw(ctxt, VCPU_REGS_RSI) &= (u32)-1;
|
|
|
+ /* fall through */
|
|
|
+ case 0xaa: /* stosb */
|
|
|
+ case 0xab: /* stosd/w */
|
|
|
+ *reg_rmw(ctxt, VCPU_REGS_RDI) &= (u32)-1;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt,
|
|
|
struct tss_segment_16 *tss)
|
|
|
{
|
|
@@ -4910,6 +4934,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
|
|
if (ctxt->rep_prefix && (ctxt->d & String)) {
|
|
|
/* All REP prefixes have the same first termination condition */
|
|
|
if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) {
|
|
|
+ string_registers_quirk(ctxt);
|
|
|
ctxt->eip = ctxt->_eip;
|
|
|
ctxt->eflags &= ~X86_EFLAGS_RF;
|
|
|
goto done;
|