x86emul: support UMIP

To make this complete, also add support for SLDT and STR. Note that by
just looking at the guest CR4 bit, this is independent of actually
making available the UMIP feature to guests.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Jan Beulich committed 2016-09-30 15:37:00 +02:00
1 parent 412ddc726c
commit 8c14e5f97f
1 file changed
+61 -10
+61 -10
View File
@@ -182,7 +182,7 @@ static const opcode_desc_t opcode_table[256] = {
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,
@@ -419,6 +419,7 @@ typedef union {
/* 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)
@@ -1489,6 +1490,17 @@ static bool is_aligned(enum x86_segment seg, unsigned long offs,
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,
@@ -2041,10 +2053,20 @@ x86_decode(
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:
@@ -2060,6 +2082,12 @@ x86_decode(
}
break;
case ext_0f3a:
case ext_8f08:
case ext_8f09:
case ext_8f0a:
break;
default:
ASSERT_UNREACHABLE();
}
@@ -4156,13 +4184,34 @@ x86_emulate(
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;
@@ -4261,6 +4310,7 @@ x86_emulate(
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,
@@ -4295,6 +4345,7 @@ x86_emulate(
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);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.