diff options
Diffstat (limited to 'target/i386/mpx_helper.c')
-rw-r--r-- | target/i386/mpx_helper.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/target/i386/mpx_helper.c b/target/i386/mpx_helper.c new file mode 100644 index 0000000000..7e44820659 --- /dev/null +++ b/target/i386/mpx_helper.c @@ -0,0 +1,168 @@ +/* + * 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 "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" +#include "exec/exec-all.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_MASK) + && (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; +} + +void helper_bndck(CPUX86State *env, uint32_t fail) +{ + if (unlikely(fail)) { + env->bndcs_regs.sts = 1; + raise_exception_ra(env, EXCP05_BOUND, GETPC()); + } +} + +static uint64_t lookup_bte64(CPUX86State *env, uint64_t base, uintptr_t ra) +{ + uint64_t bndcsr, bde, bt; + + if ((env->hflags & HF_CPL_MASK) == 3) { + bndcsr = env->bndcs_regs.cfgu; + } else { + bndcsr = env->msr_bndcfgs; + } + + bde = (extract64(base, 20, 28) << 3) + (extract64(bndcsr, 20, 44) << 12); + bt = cpu_ldq_data_ra(env, bde, ra); + if ((bt & 1) == 0) { + env->bndcs_regs.sts = bde | 2; + raise_exception_ra(env, EXCP05_BOUND, ra); + } + + return (extract64(base, 3, 17) << 5) + (bt & ~7); +} + +static uint32_t lookup_bte32(CPUX86State *env, uint32_t base, uintptr_t ra) +{ + uint32_t bndcsr, bde, bt; + + if ((env->hflags & HF_CPL_MASK) == 3) { + bndcsr = env->bndcs_regs.cfgu; + } else { + bndcsr = env->msr_bndcfgs; + } + + bde = (extract32(base, 12, 20) << 2) + (bndcsr & TARGET_PAGE_MASK); + bt = cpu_ldl_data_ra(env, bde, ra); + if ((bt & 1) == 0) { + env->bndcs_regs.sts = bde | 2; + raise_exception_ra(env, EXCP05_BOUND, ra); + } + + return (extract32(base, 2, 10) << 4) + (bt & ~3); +} + +uint64_t helper_bndldx64(CPUX86State *env, target_ulong base, target_ulong ptr) +{ + uintptr_t ra = GETPC(); + uint64_t bte, lb, ub, pt; + + bte = lookup_bte64(env, base, ra); + lb = cpu_ldq_data_ra(env, bte, ra); + ub = cpu_ldq_data_ra(env, bte + 8, ra); + pt = cpu_ldq_data_ra(env, bte + 16, ra); + + if (pt != ptr) { + lb = ub = 0; + } + env->mmx_t0.MMX_Q(0) = ub; + return lb; +} + +uint64_t helper_bndldx32(CPUX86State *env, target_ulong base, target_ulong ptr) +{ + uintptr_t ra = GETPC(); + uint32_t bte, lb, ub, pt; + + bte = lookup_bte32(env, base, ra); + lb = cpu_ldl_data_ra(env, bte, ra); + ub = cpu_ldl_data_ra(env, bte + 4, ra); + pt = cpu_ldl_data_ra(env, bte + 8, ra); + + if (pt != ptr) { + lb = ub = 0; + } + return ((uint64_t)ub << 32) | lb; +} + +void helper_bndstx64(CPUX86State *env, target_ulong base, target_ulong ptr, + uint64_t lb, uint64_t ub) +{ + uintptr_t ra = GETPC(); + uint64_t bte; + + bte = lookup_bte64(env, base, ra); + cpu_stq_data_ra(env, bte, lb, ra); + cpu_stq_data_ra(env, bte + 8, ub, ra); + cpu_stq_data_ra(env, bte + 16, ptr, ra); +} + +void helper_bndstx32(CPUX86State *env, target_ulong base, target_ulong ptr, + uint64_t lb, uint64_t ub) +{ + uintptr_t ra = GETPC(); + uint32_t bte; + + bte = lookup_bte32(env, base, ra); + cpu_stl_data_ra(env, bte, lb, ra); + cpu_stl_data_ra(env, bte + 4, ub, ra); + cpu_stl_data_ra(env, bte + 8, ptr, ra); +} + +void helper_bnd_jmp(CPUX86State *env) +{ + if (!(env->hflags2 & HF2_MPX_PR_MASK)) { + memset(env->bnd_regs, 0, sizeof(env->bnd_regs)); + env->hflags &= ~HF_MPX_IU_MASK; + } +} |