aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/x86_emulate.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-03-19 14:06:18 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-03-19 14:06:18 +0000
commit7065b5e4c16be241d7182cd4fcbd316c4b14e3de (patch)
tree05a7b3755c2a5491f07b3a15ab4ab2133030dfb6 /xen/arch/x86/x86_emulate.c
parentf966bc9fc5e1f1ea04f0d7ddddc0f8e8733f3139 (diff)
downloadxen-7065b5e4c16be241d7182cd4fcbd316c4b14e3de.tar.gz
xen-7065b5e4c16be241d7182cd4fcbd316c4b14e3de.tar.bz2
xen-7065b5e4c16be241d7182cd4fcbd316c4b14e3de.zip
x86_emulate: Return X86EMUL_UNHANDLEABLE if mode_iopl() or
mode_ring0() checks cannot be carried out. Also fix handling of EFLAGS.IF in iret and popf. 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.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
index b3bb4deb52..6981f9b52d 100644
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -785,11 +785,21 @@ _mode_iopl(
struct x86_emulate_ops *ops)
{
int cpl = get_cpl(ctxt, ops);
+ if ( cpl == -1 )
+ return -1;
return ((cpl >= 0) && (cpl <= ((ctxt->regs->eflags >> 12) & 3)));
}
-#define mode_ring0() (get_cpl(ctxt, ops) == 0)
-#define mode_iopl() _mode_iopl(ctxt, ops)
+#define mode_ring0() ({ \
+ int _cpl = get_cpl(ctxt, ops); \
+ fail_if(_cpl < 0); \
+ (_cpl == 0); \
+})
+#define mode_iopl() ({ \
+ int _iopl = _mode_iopl(ctxt, ops); \
+ fail_if(_iopl < 0); \
+ _iopl; \
+})
static int
in_realmode(
@@ -2394,8 +2404,10 @@ x86_emulate(
case 0x9d: /* popf */ {
uint32_t mask = EFLG_VIP | EFLG_VIF | EFLG_VM;
- if ( !mode_iopl() )
+ if ( !mode_ring0() )
mask |= EFLG_IOPL;
+ if ( !mode_iopl() )
+ mask |= EFLG_IF;
/* 64-bit mode: POP defaults to a 64-bit operand. */
if ( mode_64bit() && (op_bytes == 4) )
op_bytes = 8;
@@ -2640,8 +2652,10 @@ x86_emulate(
case 0xcf: /* iret */ {
unsigned long cs, eip, eflags;
uint32_t mask = EFLG_VIP | EFLG_VIF | EFLG_VM;
- if ( !mode_iopl() )
+ if ( !mode_ring0() )
mask |= EFLG_IOPL;
+ if ( !mode_iopl() )
+ mask |= EFLG_IF;
fail_if(!in_realmode(ctxt, ops));
if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
&eip, op_bytes, ctxt)) ||