aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/x86_emulate.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2007-11-25 18:06:30 +0000
committerKeir Fraser <keir.fraser@citrix.com>2007-11-25 18:06:30 +0000
commit4abb21480a434074fa0db3d9e5799a7fc3712a1e (patch)
treee4fe8a73787a0067d578c0486557c27d95deb0b5 /xen/arch/x86/x86_emulate.c
parentf96485f0106b462f8e19921d6a63a07e709a6e19 (diff)
downloadxen-4abb21480a434074fa0db3d9e5799a7fc3712a1e.tar.gz
xen-4abb21480a434074fa0db3d9e5799a7fc3712a1e.tar.bz2
xen-4abb21480a434074fa0db3d9e5799a7fc3712a1e.zip
x86_emulate: Emulate IRET.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/x86_emulate.c')
-rw-r--r--xen/arch/x86/x86_emulate.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
index 9d89e8e652..c6262243ac 100644
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -149,7 +149,7 @@ static uint8_t opcode_table[256] = {
ImplicitOps, ImplicitOps,
0, 0, ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov,
/* 0xC8 - 0xCF */
- 0, 0, 0, 0, ImplicitOps, ImplicitOps, ImplicitOps, 0,
+ 0, 0, 0, 0, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0xD0 - 0xD7 */
ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
@@ -2214,6 +2214,33 @@ x86_emulate(
src.val = EXC_OF;
goto swint;
+ case 0xcf: /* iret */ {
+ unsigned long cs, eip, eflags;
+ uint32_t mask = EFLG_VIP | EFLG_VIF | EFLG_VM;
+ if ( !mode_iopl() )
+ mask |= EFLG_IOPL;
+ fail_if(!in_realmode(ctxt, ops));
+ fail_if(ops->write_rflags == NULL);
+ if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
+ &eip, op_bytes, ctxt)) ||
+ (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
+ &cs, op_bytes, ctxt)) ||
+ (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
+ &eflags, op_bytes, ctxt)) )
+ goto done;
+ if ( op_bytes == 2 )
+ eflags = (uint16_t)eflags | (_regs.eflags & 0xffff0000u);
+ eflags &= 0x257fd5;
+ _regs.eflags &= mask;
+ _regs.eflags |= (uint32_t)(eflags & ~mask) | 0x02;
+ if ( (rc = ops->write_rflags(_regs.eflags, ctxt)) != 0 )
+ goto done;
+ _regs.eip = eip;
+ if ( (rc = load_seg(x86_seg_cs, (uint16_t)cs, ctxt, ops)) != 0 )
+ goto done;
+ break;
+ }
+
case 0xd4: /* aam */ {
unsigned int base = insn_fetch_type(uint8_t);
uint8_t al = _regs.eax;