static const opcode_desc_t twobyte_table[256] = {
/* 0x00 - 0x07 */
- SrcMem16|ModRM, ImplicitOps|ModRM, ModRM, ModRM,
+ ModRM, ImplicitOps|ModRM, ModRM, ModRM,
0, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x08 - 0x0F */
ImplicitOps, ImplicitOps, 0, ImplicitOps,
/* Control register flags. */
#define CR0_PE (1<<0)
#define CR4_TSD (1<<2)
+#define CR4_UMIP (1<<11)
/* EFLAGS bit definitions. */
#define EFLG_VIP (1<<20)
return !((reg.base + offs) & (size - 1));
}
+static bool umip_active(struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops)
+{
+ unsigned long cr4;
+
+ /* Intentionally not using mode_ring0() here to avoid its fail_if(). */
+ return get_cpl(ctxt, ops) > 0 &&
+ ops->read_cr && ops->read_cr(4, &cr4, ctxt) == X86EMUL_OKAY &&
+ (cr4 & CR4_UMIP);
+}
+
/* Inject a software interrupt/exception, emulating if needed. */
static int inject_swint(enum x86_swint_type type,
uint8_t vector, uint8_t insn_len,
break;
case ext_0f:
- case ext_0f3a:
- case ext_8f08:
- case ext_8f09:
- case ext_8f0a:
+ switch ( b )
+ {
+ case 0x00: /* Grp6 */
+ switch ( modrm_reg & 6 )
+ {
+ case 0:
+ d |= DstMem | SrcImplicit | Mov;
+ break;
+ case 2: case 4:
+ d |= SrcMem16;
+ break;
+ }
+ break;
+ }
break;
case ext_0f38:
}
break;
+ case ext_0f3a:
+ case ext_8f08:
+ case ext_8f09:
+ case ext_8f0a:
+ break;
+
default:
ASSERT_UNREACHABLE();
}
break;
case X86EMUL_OPC(0x0f, 0x00): /* Grp6 */
- fail_if((modrm_reg & 6) != 2);
+ {
+ enum x86_segment seg = (modrm_reg & 1) ? x86_seg_tr : x86_seg_ldtr;
+
generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);
- generate_exception_if(!mode_ring0(), EXC_GP, 0);
- if ( (rc = load_seg((modrm_reg & 1) ? x86_seg_tr : x86_seg_ldtr,
- src.val, 0, NULL, ctxt, ops)) != 0 )
- goto done;
+ switch ( modrm_reg & 6 )
+ {
+ struct segment_register sreg;
+
+ case 0: /* sldt / str */
+ generate_exception_if(umip_active(ctxt, ops), EXC_GP, 0);
+ fail_if(!ops->read_segment);
+ if ( (rc = ops->read_segment(seg, &sreg, ctxt)) != 0 )
+ goto done;
+ dst.val = sreg.sel;
+ if ( dst.type == OP_MEM )
+ dst.bytes = 2;
+ break;
+ case 2: /* lldt / ltr */
+ generate_exception_if(!mode_ring0(), EXC_GP, 0);
+ if ( (rc = load_seg(seg, src.val, 0, NULL, ctxt, ops)) != 0 )
+ goto done;
+ break;
+ default:
+ generate_exception_if(true, EXC_UD, -1);
+ break;
+ }
break;
+ }
case X86EMUL_OPC(0x0f, 0x01): /* Grp7 */ {
struct segment_register reg;
case 0: /* sgdt */
case 1: /* sidt */
generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
+ generate_exception_if(umip_active(ctxt, ops), EXC_GP, 0);
fail_if(ops->read_segment == NULL);
if ( (rc = ops->read_segment((modrm_reg & 1) ?
x86_seg_idtr : x86_seg_gdtr,
goto done;
break;
case 4: /* smsw */
+ generate_exception_if(umip_active(ctxt, ops), EXC_GP, 0);
ea.bytes = (ea.type == OP_MEM) ? 2 : op_bytes;
dst = ea;
fail_if(ops->read_cr == NULL);