#define MSR_SYSENTER_EIP 0x00000176
#define MSR_DEBUGCTL 0x000001d9
#define DEBUGCTL_BTF (1 << 1)
+#define MSR_BNDCFGS 0x00000d90
+#define BNDCFG_ENABLE (1 << 0)
+#define BNDCFG_PRESERVE (1 << 1)
#define MSR_EFER 0xc0000080
#define MSR_STAR 0xc0000081
#define MSR_LSTAR 0xc0000082
#define vcpu_has_bmi1() vcpu_has( 7, EBX, 3, ctxt, ops)
#define vcpu_has_hle() vcpu_has( 7, EBX, 4, ctxt, ops)
#define vcpu_has_rtm() vcpu_has( 7, EBX, 11, ctxt, ops)
+#define vcpu_has_mpx() vcpu_has( 7, EBX, 14, ctxt, ops)
#define vcpu_has_smap() vcpu_has( 7, EBX, 20, ctxt, ops)
#define vcpu_has_clflushopt() vcpu_has( 7, EBX, 23, ctxt, ops)
#define vcpu_has_clwb() vcpu_has( 7, EBX, 24, ctxt, ops)
generate_exception(fault_type, error_code);
}
+static void adjust_bnd(struct x86_emulate_ctxt *ctxt,
+ const struct x86_emulate_ops *ops, enum vex_pfx pfx)
+{
+ uint64_t bndcfg;
+ int rc;
+
+ if ( pfx == vex_f2 || !cpu_has_mpx || !vcpu_has_mpx() )
+ return;
+
+ if ( !mode_ring0() )
+ bndcfg = read_bndcfgu();
+ else if ( !ops->read_msr ||
+ ops->read_msr(MSR_BNDCFGS, &bndcfg, ctxt) != X86EMUL_OKAY )
+ return;
+ if ( (bndcfg & BNDCFG_ENABLE) && !(bndcfg & BNDCFG_PRESERVE) )
+ {
+ /*
+ * Using BNDMK or any other MPX instruction here is pointless, as
+ * we run with MPX disabled ourselves, and hence they're all no-ops.
+ * Therefore we have two ways to clear BNDn: Enable MPX temporarily
+ * (in which case executing any suitable non-prefixed branch
+ * instruction would do), or use XRSTOR.
+ */
+ xstate_set_init(XSTATE_BNDREGS);
+ }
+ done:;
+}
+
int x86emul_unhandleable_rw(
enum x86_segment seg,
unsigned long offset,
case 0x70 ... 0x7f: /* jcc (short) */
if ( test_cc(b, _regs._eflags) )
jmp_rel((int32_t)src.val);
+ adjust_bnd(ctxt, ops, vex.pfx);
break;
case 0x82: /* Grp1 (x86/32 only) */
(rc = ops->insn_fetch(x86_seg_cs, dst.val, NULL, 0, ctxt)) )
goto done;
_regs.r(ip) = dst.val;
+ adjust_bnd(ctxt, ops, vex.pfx);
break;
case 0xc4: /* les */
op_bytes = ((op_bytes == 4) && mode_64bit()) ? 8 : op_bytes;
src.val = _regs.r(ip);
jmp_rel(rel);
+ adjust_bnd(ctxt, ops, vex.pfx);
goto push;
}
case 0xe9: /* jmp (near) */
case 0xeb: /* jmp (short) */
jmp_rel((int32_t)src.val);
+ if ( !(b & 2) )
+ adjust_bnd(ctxt, ops, vex.pfx);
break;
case 0xea: /* jmp (far, absolute) */
goto done;
_regs.r(ip) = src.val;
src.val = dst.val;
+ adjust_bnd(ctxt, ops, vex.pfx);
goto push;
case 4: /* jmp (near) */
if ( (rc = ops->insn_fetch(x86_seg_cs, src.val, NULL, 0, ctxt)) )
goto done;
_regs.r(ip) = src.val;
dst.type = OP_NONE;
+ adjust_bnd(ctxt, ops, vex.pfx);
break;
case 3: /* call (far, absolute indirect) */
case 5: /* jmp (far, absolute indirect) */
case X86EMUL_OPC(0x0f, 0x80) ... X86EMUL_OPC(0x0f, 0x8f): /* jcc (near) */
if ( test_cc(b, _regs._eflags) )
jmp_rel((int32_t)src.val);
+ adjust_bnd(ctxt, ops, vex.pfx);
break;
case X86EMUL_OPC(0x0f, 0x90) ... X86EMUL_OPC(0x0f, 0x9f): /* setcc */
int xstate_alloc_save_area(struct vcpu *v)
{
struct xsave_struct *save_area;
+ unsigned int size;
- if ( !cpu_has_xsave || is_idle_vcpu(v) )
+ if ( !cpu_has_xsave )
return 0;
- BUG_ON(xsave_cntxt_size < XSTATE_AREA_MIN_SIZE);
+ if ( !is_idle_vcpu(v) || !cpu_has_xsavec )
+ {
+ size = xsave_cntxt_size;
+ BUG_ON(size < XSTATE_AREA_MIN_SIZE);
+ }
+ else
+ {
+ /*
+ * For idle vcpus on XSAVEC-capable CPUs allocate an area large
+ * enough to save any individual extended state.
+ */
+ unsigned int i;
+
+ for ( size = 0, i = 2; i < xstate_features; ++i )
+ if ( size < xstate_sizes[i] )
+ size = xstate_sizes[i];
+ size += XSTATE_AREA_MIN_SIZE;
+ }
/* XSAVE/XRSTOR requires the save area be 64-byte-boundary aligned. */
BUILD_BUG_ON(__alignof(*save_area) < 64);
- save_area = _xzalloc(xsave_cntxt_size, __alignof(*save_area));
+ save_area = _xzalloc(size, __alignof(*save_area));
if ( save_area == NULL )
return -ENOMEM;
return 0;
}
+uint64_t read_bndcfgu(void)
+{
+ unsigned long cr0 = read_cr0();
+ struct xsave_struct *xstate
+ = idle_vcpu[smp_processor_id()]->arch.xsave_area;
+ const struct xstate_bndcsr *bndcsr;
+
+ ASSERT(cpu_has_mpx);
+ clts();
+
+ if ( cpu_has_xsavec )
+ {
+ asm ( ".byte 0x0f,0xc7,0x27\n" /* xsavec */
+ : "=m" (*xstate)
+ : "a" (XSTATE_BNDCSR), "d" (0), "D" (xstate) );
+
+ bndcsr = (void *)(xstate + 1);
+ }
+ else
+ {
+ asm ( ".byte 0x0f,0xae,0x27\n" /* xsave */
+ : "=m" (*xstate)
+ : "a" (XSTATE_BNDCSR), "d" (0), "D" (xstate) );
+
+ bndcsr = (void *)xstate + xstate_offsets[_XSTATE_BNDCSR];
+ }
+
+ if ( cr0 & X86_CR0_TS )
+ write_cr0(cr0);
+
+ return xstate->xsave_hdr.xstate_bv & XSTATE_BNDCSR ? bndcsr->bndcfgu : 0;
+}
+
+void xstate_set_init(uint64_t mask)
+{
+ unsigned long cr0 = read_cr0();
+ unsigned long xcr0 = this_cpu(xcr0);
+ struct vcpu *v = idle_vcpu[smp_processor_id()];
+ struct xsave_struct *xstate = v->arch.xsave_area;
+
+ if ( ~xfeature_mask & mask )
+ {
+ ASSERT_UNREACHABLE();
+ return;
+ }
+
+ if ( (~xcr0 & mask) && !set_xcr0(xcr0 | mask) )
+ return;
+
+ clts();
+
+ memset(&xstate->xsave_hdr, 0, sizeof(xstate->xsave_hdr));
+ xrstor(v, mask);
+
+ if ( cr0 & X86_CR0_TS )
+ write_cr0(cr0);
+
+ if ( (~xcr0 & mask) && !set_xcr0(xcr0) )
+ BUG();
+}
+
/*
* Local variables:
* mode: C