Skip to content

Commit

Permalink
KVM: x86 emulator: Add IRET instruction
Browse files Browse the repository at this point in the history
Ths patch adds IRET instruction (opcode 0xcf).
Currently, only IRET in real mode is emulated. Protected mode support is to be added later if needed.

Signed-off-by: Mohammed Gamal <m.gamal005@gmail.com>
Reviewed-by: Avi Kivity <avi@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
  • Loading branch information
Mohammed Gamal authored and Avi Kivity committed Oct 24, 2010
1 parent 7a19066 commit 62bd430
Showing 1 changed file with 81 additions and 0 deletions.
81 changes: 81 additions & 0 deletions 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 62bd430

Please sign in to comment.