return (!rc && !(cr0 & CR0_PE));
}
+static int
+in_protmode(
+ struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+ return !(in_realmode(ctxt, ops) || (ctxt->regs->eflags & EFLG_VM));
+}
+
static int
realmode_load_seg(
enum x86_segment seg,
struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
- struct segment_register desctab, cs, segr;
+ struct segment_register desctab, ss, segr;
struct { uint32_t a, b; } desc;
unsigned long val;
uint8_t dpl, rpl, cpl;
if ( (seg == x86_seg_ldtr) && (sel & 4) )
goto raise_exn;
- if ( (rc = ops->read_segment(x86_seg_cs, &cs, ctxt)) ||
+ if ( (rc = ops->read_segment(x86_seg_ss, &ss, ctxt)) ||
(rc = ops->read_segment((sel & 4) ? x86_seg_ldtr : x86_seg_gdtr,
&desctab, ctxt)) )
return rc;
dpl = (desc.b >> 13) & 3;
rpl = sel & 3;
- cpl = cs.sel & 3;
+ cpl = ss.attr.fields.dpl;
switch ( seg )
{
if ( !(desc.b & (1u<<11)) )
goto raise_exn;
/* Non-conforming segment: check DPL against RPL. */
- if ( ((desc.b & (6u<<9)) != 6) && (dpl != rpl) )
+ if ( ((desc.b & (6u<<9)) != (6u<<9)) && (dpl != rpl) )
goto raise_exn;
break;
case x86_seg_ss:
if ( (desc.b & (5u<<9)) == (4u<<9) )
goto raise_exn;
/* Non-conforming segment: check DPL against RPL and CPL. */
- if ( ((desc.b & (6u<<9)) != 6) && ((dpl < cpl) || (dpl < rpl)) )
+ if ( ((desc.b & (6u<<9)) != (6u<<9)) && ((dpl < cpl) || (dpl < rpl)) )
goto raise_exn;
break;
}
(ops->write_segment == NULL) )
return X86EMUL_UNHANDLEABLE;
- if ( in_realmode(ctxt, ops) )
- return realmode_load_seg(seg, sel, ctxt, ops);
+ if ( in_protmode(ctxt, ops) )
+ return protmode_load_seg(seg, sel, ctxt, ops);
- return protmode_load_seg(seg, sel, ctxt, ops);
+ return realmode_load_seg(seg, sel, ctxt, ops);
}
void *
dst.val = (dst.val & ~3) | (src_val & 3);
else
dst.type = OP_NONE;
- generate_exception_if(in_realmode(ctxt, ops), EXC_UD, -1);
+ generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);
}
break;
if ( modrm == 0xdf ) /* invlpga */
{
- generate_exception_if(in_realmode(ctxt, ops), EXC_UD, -1);
+ generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);
generate_exception_if(!mode_ring0(), EXC_GP, 0);
fail_if(ops->invlpg == NULL);
if ( (rc = ops->invlpg(x86_seg_none, truncate_ea(_regs.eax),