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 <[email protected]>

----

Changes from v1:
- Corrected handling of eflags
---
 arch/x86/kvm/emulate.c |   69 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index b38bd8b..e45fd28 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1778,6 +1778,69 @@ 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 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;
+       }
+
+       c->eip = temp_eip;
+
+       rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_CS);
+
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
+
+       rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes);
+
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
+
+       if (c->op_bytes == 4) {
+               temp_eflags = ((temp_eflags & mask) | (ctxt->eflags & 
vm86_mask));
+               ctxt->eflags = temp_eflags;
+       } else if (c->op_bytes == 2) {
+               temp_eflags &= ~0xfffd; /* Do not clear reserved bit 1 */
+               ctxt->eflags |= temp_eflags;
+       }
+
+       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)
 {
@@ -2910,6 +2973,12 @@ special_insn:
                if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
+       case 0xcf:              /* iret */
+               rc = emulate_iret(ctxt, ops);
+
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
+               break;
        case 0xd0 ... 0xd1:     /* Grp2 */
                c->src.val = 1;
                emulate_grp2(ctxt);
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to