mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00:00
target-i386: Enable control registers for MPX
Enable and disable at CPL changes, MSR changes, and XRSTOR changes. Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
c9cfe8f9fb
commit
f4f1110e4b
@ -1,6 +1,6 @@
|
||||
obj-y += translate.o helper.o cpu.o bpt_helper.o
|
||||
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
|
||||
obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
|
||||
obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o mpx_helper.o
|
||||
obj-y += gdbstub.o
|
||||
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o monitor.o
|
||||
obj-$(CONFIG_KVM) += kvm.o hyperv.o
|
||||
|
@ -358,7 +358,7 @@ static const char *cpuid_6_feature_name[] = {
|
||||
#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP | \
|
||||
CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \
|
||||
CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \
|
||||
CPUID_7_0_EBX_CLWB)
|
||||
CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX)
|
||||
/* missing:
|
||||
CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
|
||||
CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
|
||||
@ -472,12 +472,7 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
|
||||
};
|
||||
#undef REGISTER
|
||||
|
||||
typedef struct ExtSaveArea {
|
||||
uint32_t feature, bits;
|
||||
uint32_t offset, size;
|
||||
} ExtSaveArea;
|
||||
|
||||
static const ExtSaveArea ext_save_areas[] = {
|
||||
const ExtSaveArea x86_ext_save_areas[] = {
|
||||
[2] = { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
|
||||
.offset = 0x240, .size = 0x100 },
|
||||
[3] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
|
||||
@ -2476,8 +2471,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
|
||||
if (count == 0) {
|
||||
*ecx = 0x240;
|
||||
for (i = 2; i < ARRAY_SIZE(ext_save_areas); i++) {
|
||||
const ExtSaveArea *esa = &ext_save_areas[i];
|
||||
for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
|
||||
const ExtSaveArea *esa = &x86_ext_save_areas[i];
|
||||
if ((env->features[esa->feature] & esa->bits) == esa->bits
|
||||
&& ((ena_mask >> i) & 1) != 0) {
|
||||
if (i < 32) {
|
||||
@ -2492,8 +2487,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
*ebx = *ecx;
|
||||
} else if (count == 1) {
|
||||
*eax = env->features[FEAT_XSAVE];
|
||||
} else if (count < ARRAY_SIZE(ext_save_areas)) {
|
||||
const ExtSaveArea *esa = &ext_save_areas[count];
|
||||
} else if (count < ARRAY_SIZE(x86_ext_save_areas)) {
|
||||
const ExtSaveArea *esa = &x86_ext_save_areas[count];
|
||||
if ((env->features[esa->feature] & esa->bits) == esa->bits
|
||||
&& ((ena_mask >> count) & 1) != 0) {
|
||||
*eax = esa->size;
|
||||
|
@ -156,6 +156,8 @@
|
||||
#define HF_OSFXSR_SHIFT 22 /* CR4.OSFXSR */
|
||||
#define HF_SMAP_SHIFT 23 /* CR4.SMAP */
|
||||
#define HF_IOBPT_SHIFT 24 /* an io breakpoint enabled */
|
||||
#define HF_MPX_EN_SHIFT 25 /* MPX Enabled (CR4+XCR0+BNDCFGx) */
|
||||
#define HF_MPX_IU_SHIFT 26 /* BND registers in-use */
|
||||
|
||||
#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
|
||||
#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
|
||||
@ -180,6 +182,8 @@
|
||||
#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)
|
||||
#define HF_SMAP_MASK (1 << HF_SMAP_SHIFT)
|
||||
#define HF_IOBPT_MASK (1 << HF_IOBPT_SHIFT)
|
||||
#define HF_MPX_EN_MASK (1 << HF_MPX_EN_SHIFT)
|
||||
#define HF_MPX_IU_MASK (1 << HF_MPX_IU_SHIFT)
|
||||
|
||||
/* hflags2 */
|
||||
|
||||
@ -188,12 +192,14 @@
|
||||
#define HF2_NMI_SHIFT 2 /* CPU serving NMI */
|
||||
#define HF2_VINTR_SHIFT 3 /* value of V_INTR_MASKING bit */
|
||||
#define HF2_SMM_INSIDE_NMI_SHIFT 4 /* CPU serving SMI nested inside NMI */
|
||||
#define HF2_MPX_PR_SHIFT 5 /* BNDCFGx.BNDPRESERVE */
|
||||
|
||||
#define HF2_GIF_MASK (1 << HF2_GIF_SHIFT)
|
||||
#define HF2_HIF_MASK (1 << HF2_HIF_SHIFT)
|
||||
#define HF2_NMI_MASK (1 << HF2_NMI_SHIFT)
|
||||
#define HF2_VINTR_MASK (1 << HF2_VINTR_SHIFT)
|
||||
#define HF2_SMM_INSIDE_NMI_MASK (1 << HF2_SMM_INSIDE_NMI_SHIFT)
|
||||
#define HF2_MPX_PR_MASK (1 << HF2_MPX_PR_SHIFT)
|
||||
|
||||
#define CR0_PE_SHIFT 0
|
||||
#define CR0_MP_SHIFT 1
|
||||
@ -753,6 +759,10 @@ typedef struct BNDCSReg {
|
||||
uint64_t sts;
|
||||
} BNDCSReg;
|
||||
|
||||
#define BNDCFG_ENABLE 1ULL
|
||||
#define BNDCFG_BNDPRESERVE 2ULL
|
||||
#define BNDCFG_BDIR_MASK TARGET_PAGE_MASK
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
#define ZMM_B(n) _b_ZMMReg[63 - (n)]
|
||||
#define ZMM_W(n) _w_ZMMReg[31 - (n)]
|
||||
@ -1121,7 +1131,14 @@ void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32);
|
||||
int cpu_x86_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc);
|
||||
|
||||
/* cpuid.c */
|
||||
/* cpu.c */
|
||||
typedef struct ExtSaveArea {
|
||||
uint32_t feature, bits;
|
||||
uint32_t offset, size;
|
||||
} ExtSaveArea;
|
||||
|
||||
extern const ExtSaveArea x86_ext_save_areas[];
|
||||
|
||||
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
uint32_t *eax, uint32_t *ebx,
|
||||
uint32_t *ecx, uint32_t *edx);
|
||||
@ -1342,6 +1359,8 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
|
||||
*/
|
||||
void x86_cpu_change_kvm_default(const char *prop, const char *value);
|
||||
|
||||
/* mpx_helper.c */
|
||||
void cpu_sync_bndcs_hflags(CPUX86State *env);
|
||||
|
||||
/* Return name of 32-bit register, from a R_* constant */
|
||||
const char *get_register_name_32(unsigned int reg);
|
||||
|
@ -1168,6 +1168,22 @@ static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
|
||||
}
|
||||
}
|
||||
|
||||
static void do_xsave_bndregs(CPUX86State *env, target_ulong addr, uintptr_t ra)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++, addr += 16) {
|
||||
cpu_stq_data_ra(env, addr, env->bnd_regs[i].lb, ra);
|
||||
cpu_stq_data_ra(env, addr + 8, env->bnd_regs[i].ub, ra);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_xsave_bndcsr(CPUX86State *env, target_ulong addr, uintptr_t ra)
|
||||
{
|
||||
cpu_stq_data_ra(env, addr, env->bndcs_regs.cfgu, ra);
|
||||
cpu_stq_data_ra(env, addr + 8, env->bndcs_regs.sts, ra);
|
||||
}
|
||||
|
||||
void helper_fxsave(CPUX86State *env, target_ulong ptr)
|
||||
{
|
||||
uintptr_t ra = GETPC();
|
||||
@ -1192,9 +1208,16 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr)
|
||||
|
||||
static uint64_t get_xinuse(CPUX86State *env)
|
||||
{
|
||||
/* We don't track XINUSE. We could calculate it here, but it's
|
||||
probably less work to simply indicate all components in use. */
|
||||
return -1;
|
||||
uint64_t inuse = -1;
|
||||
|
||||
/* For the most part, we don't track XINUSE. We could calculate it
|
||||
here for all components, but it's probably less work to simply
|
||||
indicate in use. That said, the state of BNDREGS is important
|
||||
enough to track in HFLAGS, so we might as well use that here. */
|
||||
if ((env->hflags & HF_MPX_IU_MASK) == 0) {
|
||||
inuse &= ~XSTATE_BNDREGS;
|
||||
}
|
||||
return inuse;
|
||||
}
|
||||
|
||||
static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
|
||||
@ -1226,6 +1249,14 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
|
||||
if (opt & XSTATE_SSE) {
|
||||
do_xsave_sse(env, ptr, ra);
|
||||
}
|
||||
if (opt & XSTATE_BNDREGS) {
|
||||
target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset;
|
||||
do_xsave_bndregs(env, ptr + off, ra);
|
||||
}
|
||||
if (opt & XSTATE_BNDCSR) {
|
||||
target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset;
|
||||
do_xsave_bndcsr(env, ptr + off, ra);
|
||||
}
|
||||
|
||||
/* Update the XSTATE_BV field. */
|
||||
old_bv = cpu_ldq_data_ra(env, ptr + 512, ra);
|
||||
@ -1291,6 +1322,23 @@ static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
|
||||
}
|
||||
}
|
||||
|
||||
static void do_xrstor_bndregs(CPUX86State *env, target_ulong addr, uintptr_t ra)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++, addr += 16) {
|
||||
env->bnd_regs[i].lb = cpu_ldq_data_ra(env, addr, ra);
|
||||
env->bnd_regs[i].ub = cpu_ldq_data_ra(env, addr + 8, ra);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_xrstor_bndcsr(CPUX86State *env, target_ulong addr, uintptr_t ra)
|
||||
{
|
||||
/* FIXME: Extend highest implemented bit of linear address. */
|
||||
env->bndcs_regs.cfgu = cpu_ldq_data_ra(env, addr, ra);
|
||||
env->bndcs_regs.sts = cpu_ldq_data_ra(env, addr + 8, ra);
|
||||
}
|
||||
|
||||
void helper_fxrstor(CPUX86State *env, target_ulong ptr)
|
||||
{
|
||||
uintptr_t ra = GETPC();
|
||||
@ -1371,6 +1419,25 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
|
||||
memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
|
||||
}
|
||||
}
|
||||
if (rfbm & XSTATE_BNDREGS) {
|
||||
if (xstate_bv & XSTATE_BNDREGS) {
|
||||
target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset;
|
||||
do_xrstor_bndregs(env, ptr + off, ra);
|
||||
env->hflags |= HF_MPX_IU_MASK;
|
||||
} else {
|
||||
memset(env->bnd_regs, 0, sizeof(env->bnd_regs));
|
||||
env->hflags &= ~HF_MPX_IU_MASK;
|
||||
}
|
||||
}
|
||||
if (rfbm & XSTATE_BNDCSR) {
|
||||
if (xstate_bv & XSTATE_BNDCSR) {
|
||||
target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset;
|
||||
do_xrstor_bndcsr(env, ptr + off, ra);
|
||||
} else {
|
||||
memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs));
|
||||
}
|
||||
cpu_sync_bndcs_hflags(env);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx)
|
||||
@ -1414,7 +1481,13 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
|
||||
goto do_gpf;
|
||||
}
|
||||
|
||||
/* Disallow enabling only half of MPX. */
|
||||
if ((mask ^ (mask * (XSTATE_BNDCSR / XSTATE_BNDREGS))) & XSTATE_BNDCSR) {
|
||||
goto do_gpf;
|
||||
}
|
||||
|
||||
env->xcr0 = mask;
|
||||
cpu_sync_bndcs_hflags(env);
|
||||
return;
|
||||
|
||||
do_gpf:
|
||||
|
@ -678,6 +678,8 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
|
||||
|
||||
env->cr[4] = new_cr4;
|
||||
env->hflags = hflags;
|
||||
|
||||
cpu_sync_bndcs_hflags(env);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
@ -2588,41 +2588,44 @@ int kvm_arch_get_registers(CPUState *cs)
|
||||
|
||||
ret = kvm_getput_regs(cpu, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_xsave(cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_xcrs(cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_sregs(cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_msrs(cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_mp_state(cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_apic(cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_vcpu_events(cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_debugregs(cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
ret = 0;
|
||||
out:
|
||||
cpu_sync_bndcs_hflags(&cpu->env);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
|
||||
|
@ -361,6 +361,12 @@ void helper_wrmsr(CPUX86State *env)
|
||||
case MSR_IA32_MISC_ENABLE:
|
||||
env->msr_ia32_misc_enable = val;
|
||||
break;
|
||||
case MSR_IA32_BNDCFGS:
|
||||
/* FIXME: #GP if reserved bits are set. */
|
||||
/* FIXME: Extend highest implemented bit of linear address. */
|
||||
env->msr_bndcfgs = val;
|
||||
cpu_sync_bndcs_hflags(env);
|
||||
break;
|
||||
default:
|
||||
if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
|
||||
&& (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
|
||||
@ -506,6 +512,9 @@ void helper_rdmsr(CPUX86State *env)
|
||||
case MSR_IA32_MISC_ENABLE:
|
||||
val = env->msr_ia32_misc_enable;
|
||||
break;
|
||||
case MSR_IA32_BNDCFGS:
|
||||
val = env->msr_bndcfgs;
|
||||
break;
|
||||
default:
|
||||
if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
|
||||
&& (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
|
||||
|
53
target-i386/mpx_helper.c
Normal file
53
target-i386/mpx_helper.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* x86 MPX helpers
|
||||
*
|
||||
* Copyright (c) 2015 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
|
||||
void cpu_sync_bndcs_hflags(CPUX86State *env)
|
||||
{
|
||||
uint32_t hflags = env->hflags;
|
||||
uint32_t hflags2 = env->hflags2;
|
||||
uint32_t bndcsr;
|
||||
|
||||
if ((hflags & HF_CPL_MASK) == 3) {
|
||||
bndcsr = env->bndcs_regs.cfgu;
|
||||
} else {
|
||||
bndcsr = env->msr_bndcfgs;
|
||||
}
|
||||
|
||||
if ((env->cr[4] & CR4_OSXSAVE_MASK)
|
||||
&& (env->xcr0 & XSTATE_BNDCSR)
|
||||
&& (bndcsr & BNDCFG_ENABLE)) {
|
||||
hflags |= HF_MPX_EN_MASK;
|
||||
} else {
|
||||
hflags &= ~HF_MPX_EN_MASK;
|
||||
}
|
||||
|
||||
if (bndcsr & BNDCFG_BNDPRESERVE) {
|
||||
hflags2 |= HF2_MPX_PR_MASK;
|
||||
} else {
|
||||
hflags2 &= ~HF2_MPX_PR_MASK;
|
||||
}
|
||||
|
||||
env->hflags = hflags;
|
||||
env->hflags2 = hflags2;
|
||||
}
|
@ -99,6 +99,10 @@ void do_smm_enter(X86CPU *cpu)
|
||||
x86_stl_phys(cs, sm_state + 0x7e94, env->tr.limit);
|
||||
x86_stw_phys(cs, sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
|
||||
|
||||
/* ??? Vol 1, 16.5.6 Intel MPX and SMM says that IA32_BNDCFGS
|
||||
is saved at offset 7ED0. Vol 3, 34.4.1.1, Table 32-2, has
|
||||
7EA0-7ED7 as "reserved". What's this, and what's really
|
||||
supposed to happen? */
|
||||
x86_stq_phys(cs, sm_state + 0x7ed0, env->efer);
|
||||
|
||||
x86_stq_phys(cs, sm_state + 0x7ff8, env->regs[R_EAX]);
|
||||
|
@ -7633,6 +7633,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||
tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
|
||||
cpu_regs[R_EDX]);
|
||||
gen_helper_xrstor(cpu_env, cpu_A0, cpu_tmp1_i64);
|
||||
/* XRSTOR is how MPX is enabled, which changes how
|
||||
we translate. Thus we need to end the TB. */
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
break;
|
||||
|
||||
CASE_MEM_OP(6): /* xsaveopt / clwb */
|
||||
|
Loading…
Reference in New Issue
Block a user