Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 215629
b: refs/heads/master
c: 62bd430
h: refs/heads/master
i:
  215627: b6d11cb
v: v3
  • Loading branch information
Mohammed Gamal authored and Avi Kivity committed Oct 24, 2010
1 parent 2138672 commit 0c094c0
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7a190667bb316653cbb782fff95cfdfcf51ded45
refs/heads/master: 62bd430e6d41ac84ff2fb719f5783c3692718f47
81 changes: 81 additions & 0 deletions trunk/arch/x86/kvm/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ static u32 group2_table[] = {
#define EFLG_PF (1<<2)
#define EFLG_CF (1<<0)

#define EFLG_RESERVED_ZEROS_MASK 0xffc0802a
#define EFLG_RESERVED_ONE_MASK 2

/*
* Instruction emulation:
* Most instructions are emulated directly via a fragment of inline assembly
Expand Down Expand Up @@ -1729,6 +1732,78 @@ static int emulate_popa(struct x86_emulate_ctxt *ctxt,
return rc;
}

static int emulate_iret_real(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
int rc = X86EMUL_CONTINUE;
unsigned long temp_eip = 0;
unsigned long temp_eflags = 0;
unsigned long cs = 0;
unsigned long mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_TF |
EFLG_IF | EFLG_DF | EFLG_OF | EFLG_IOPL | EFLG_NT | EFLG_RF |
EFLG_AC | EFLG_ID | (1 << 1); /* Last one is the reserved bit */
unsigned long vm86_mask = EFLG_VM | EFLG_VIF | EFLG_VIP;

/* TODO: Add stack limit check */

rc = emulate_pop(ctxt, ops, &temp_eip, c->op_bytes);

if (rc != X86EMUL_CONTINUE)
return rc;

if (temp_eip & ~0xffff) {
emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}

rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);

if (rc != X86EMUL_CONTINUE)
return rc;

rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes);

if (rc != X86EMUL_CONTINUE)
return rc;

rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS);

if (rc != X86EMUL_CONTINUE)
return rc;

c->eip = temp_eip;


if (c->op_bytes == 4)
ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask));
else if (c->op_bytes == 2) {
ctxt->eflags &= ~0xffff;
ctxt->eflags |= temp_eflags;
}

ctxt->eflags &= ~EFLG_RESERVED_ZEROS_MASK; /* Clear reserved zeros */
ctxt->eflags |= EFLG_RESERVED_ONE_MASK;

return rc;
}

static inline int emulate_iret(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops* ops)
{
switch(ctxt->mode) {
case X86EMUL_MODE_REAL:
return emulate_iret_real(ctxt, ops);
case X86EMUL_MODE_VM86:
case X86EMUL_MODE_PROT16:
case X86EMUL_MODE_PROT32:
case X86EMUL_MODE_PROT64:
default:
/* iret from protected mode unimplemented yet */
return X86EMUL_UNHANDLEABLE;
}
}

static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
Expand Down Expand Up @@ -2857,6 +2932,12 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
break;
case 0xcb: /* ret far */
rc = emulate_ret_far(ctxt, ops);
if (rc != X86EMUL_CONTINUE)
goto done;
break;
case 0xcf: /* iret */
rc = emulate_iret(ctxt, ops);

if (rc != X86EMUL_CONTINUE)
goto done;
break;
Expand Down

0 comments on commit 0c094c0

Please sign in to comment.