diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2007-11-25 18:06:30 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2007-11-25 18:06:30 +0000 |
commit | 4abb21480a434074fa0db3d9e5799a7fc3712a1e (patch) | |
tree | e4fe8a73787a0067d578c0486557c27d95deb0b5 /xen/arch/x86/x86_emulate.c | |
parent | f96485f0106b462f8e19921d6a63a07e709a6e19 (diff) | |
download | xen-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.c | 29 |
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; |