KVM: x86 emulator: fix pusha instruction emulation
emulate pusha instruction only writeback the last EDI register, but the other registers which need to be writeback is ignored. This patch fixed it. Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
parent
bd371396b3
commit
c37eda1384
@ -1553,6 +1553,64 @@ exception:
|
|||||||
return X86EMUL_PROPAGATE_FAULT;
|
return X86EMUL_PROPAGATE_FAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int writeback(struct x86_emulate_ctxt *ctxt,
|
||||||
|
struct x86_emulate_ops *ops)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct decode_cache *c = &ctxt->decode;
|
||||||
|
u32 err;
|
||||||
|
|
||||||
|
switch (c->dst.type) {
|
||||||
|
case OP_REG:
|
||||||
|
/* The 4-byte case *is* correct:
|
||||||
|
* in 64-bit mode we zero-extend.
|
||||||
|
*/
|
||||||
|
switch (c->dst.bytes) {
|
||||||
|
case 1:
|
||||||
|
*(u8 *)c->dst.ptr = (u8)c->dst.val;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*(u16 *)c->dst.ptr = (u16)c->dst.val;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*c->dst.ptr = (u32)c->dst.val;
|
||||||
|
break; /* 64b: zero-ext */
|
||||||
|
case 8:
|
||||||
|
*c->dst.ptr = c->dst.val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_MEM:
|
||||||
|
if (c->lock_prefix)
|
||||||
|
rc = ops->cmpxchg_emulated(
|
||||||
|
(unsigned long)c->dst.ptr,
|
||||||
|
&c->dst.orig_val,
|
||||||
|
&c->dst.val,
|
||||||
|
c->dst.bytes,
|
||||||
|
&err,
|
||||||
|
ctxt->vcpu);
|
||||||
|
else
|
||||||
|
rc = ops->write_emulated(
|
||||||
|
(unsigned long)c->dst.ptr,
|
||||||
|
&c->dst.val,
|
||||||
|
c->dst.bytes,
|
||||||
|
&err,
|
||||||
|
ctxt->vcpu);
|
||||||
|
if (rc == X86EMUL_PROPAGATE_FAULT)
|
||||||
|
emulate_pf(ctxt,
|
||||||
|
(unsigned long)c->dst.ptr, err);
|
||||||
|
if (rc != X86EMUL_CONTINUE)
|
||||||
|
return rc;
|
||||||
|
break;
|
||||||
|
case OP_NONE:
|
||||||
|
/* no writeback */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return X86EMUL_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void emulate_push(struct x86_emulate_ctxt *ctxt,
|
static inline void emulate_push(struct x86_emulate_ctxt *ctxt,
|
||||||
struct x86_emulate_ops *ops)
|
struct x86_emulate_ops *ops)
|
||||||
{
|
{
|
||||||
@ -1651,11 +1709,12 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emulate_pusha(struct x86_emulate_ctxt *ctxt,
|
static int emulate_pusha(struct x86_emulate_ctxt *ctxt,
|
||||||
struct x86_emulate_ops *ops)
|
struct x86_emulate_ops *ops)
|
||||||
{
|
{
|
||||||
struct decode_cache *c = &ctxt->decode;
|
struct decode_cache *c = &ctxt->decode;
|
||||||
unsigned long old_esp = c->regs[VCPU_REGS_RSP];
|
unsigned long old_esp = c->regs[VCPU_REGS_RSP];
|
||||||
|
int rc = X86EMUL_CONTINUE;
|
||||||
int reg = VCPU_REGS_RAX;
|
int reg = VCPU_REGS_RAX;
|
||||||
|
|
||||||
while (reg <= VCPU_REGS_RDI) {
|
while (reg <= VCPU_REGS_RDI) {
|
||||||
@ -1663,8 +1722,18 @@ static void emulate_pusha(struct x86_emulate_ctxt *ctxt,
|
|||||||
(c->src.val = old_esp) : (c->src.val = c->regs[reg]);
|
(c->src.val = old_esp) : (c->src.val = c->regs[reg]);
|
||||||
|
|
||||||
emulate_push(ctxt, ops);
|
emulate_push(ctxt, ops);
|
||||||
|
|
||||||
|
rc = writeback(ctxt, ops);
|
||||||
|
if (rc != X86EMUL_CONTINUE)
|
||||||
|
return rc;
|
||||||
|
|
||||||
++reg;
|
++reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disable writeback. */
|
||||||
|
c->dst.type = OP_NONE;
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int emulate_popa(struct x86_emulate_ctxt *ctxt,
|
static int emulate_popa(struct x86_emulate_ctxt *ctxt,
|
||||||
@ -1817,64 +1886,6 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int writeback(struct x86_emulate_ctxt *ctxt,
|
|
||||||
struct x86_emulate_ops *ops)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct decode_cache *c = &ctxt->decode;
|
|
||||||
u32 err;
|
|
||||||
|
|
||||||
switch (c->dst.type) {
|
|
||||||
case OP_REG:
|
|
||||||
/* The 4-byte case *is* correct:
|
|
||||||
* in 64-bit mode we zero-extend.
|
|
||||||
*/
|
|
||||||
switch (c->dst.bytes) {
|
|
||||||
case 1:
|
|
||||||
*(u8 *)c->dst.ptr = (u8)c->dst.val;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
*(u16 *)c->dst.ptr = (u16)c->dst.val;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
*c->dst.ptr = (u32)c->dst.val;
|
|
||||||
break; /* 64b: zero-ext */
|
|
||||||
case 8:
|
|
||||||
*c->dst.ptr = c->dst.val;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OP_MEM:
|
|
||||||
if (c->lock_prefix)
|
|
||||||
rc = ops->cmpxchg_emulated(
|
|
||||||
(unsigned long)c->dst.ptr,
|
|
||||||
&c->dst.orig_val,
|
|
||||||
&c->dst.val,
|
|
||||||
c->dst.bytes,
|
|
||||||
&err,
|
|
||||||
ctxt->vcpu);
|
|
||||||
else
|
|
||||||
rc = ops->write_emulated(
|
|
||||||
(unsigned long)c->dst.ptr,
|
|
||||||
&c->dst.val,
|
|
||||||
c->dst.bytes,
|
|
||||||
&err,
|
|
||||||
ctxt->vcpu);
|
|
||||||
if (rc == X86EMUL_PROPAGATE_FAULT)
|
|
||||||
emulate_pf(ctxt,
|
|
||||||
(unsigned long)c->dst.ptr, err);
|
|
||||||
if (rc != X86EMUL_CONTINUE)
|
|
||||||
return rc;
|
|
||||||
break;
|
|
||||||
case OP_NONE:
|
|
||||||
/* no writeback */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return X86EMUL_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
|
setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
|
||||||
struct x86_emulate_ops *ops, struct desc_struct *cs,
|
struct x86_emulate_ops *ops, struct desc_struct *cs,
|
||||||
@ -2689,7 +2700,9 @@ special_insn:
|
|||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case 0x60: /* pusha */
|
case 0x60: /* pusha */
|
||||||
emulate_pusha(ctxt, ops);
|
rc = emulate_pusha(ctxt, ops);
|
||||||
|
if (rc != X86EMUL_CONTINUE)
|
||||||
|
goto done;
|
||||||
break;
|
break;
|
||||||
case 0x61: /* popa */
|
case 0x61: /* popa */
|
||||||
rc = emulate_popa(ctxt, ops);
|
rc = emulate_popa(ctxt, ops);
|
||||||
|
Loading…
Reference in New Issue
Block a user