qemu/target/i386/tcg/mem_helper.c
<<
>>
Prefs
   1/*
   2 *  x86 memory access helpers
   3 *
   4 *  Copyright (c) 2003 Fabrice Bellard
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2.1 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "cpu.h"
  22#include "exec/helper-proto.h"
  23#include "exec/exec-all.h"
  24#include "exec/cpu_ldst.h"
  25#include "qemu/int128.h"
  26#include "qemu/atomic128.h"
  27#include "tcg/tcg.h"
  28#include "helper-tcg.h"
  29
  30void helper_cmpxchg8b_unlocked(CPUX86State *env, target_ulong a0)
  31{
  32    uintptr_t ra = GETPC();
  33    uint64_t oldv, cmpv, newv;
  34    int eflags;
  35
  36    eflags = cpu_cc_compute_all(env, CC_OP);
  37
  38    cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]);
  39    newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]);
  40
  41    oldv = cpu_ldq_data_ra(env, a0, ra);
  42    newv = (cmpv == oldv ? newv : oldv);
  43    /* always do the store */
  44    cpu_stq_data_ra(env, a0, newv, ra);
  45
  46    if (oldv == cmpv) {
  47        eflags |= CC_Z;
  48    } else {
  49        env->regs[R_EAX] = (uint32_t)oldv;
  50        env->regs[R_EDX] = (uint32_t)(oldv >> 32);
  51        eflags &= ~CC_Z;
  52    }
  53    CC_SRC = eflags;
  54}
  55
  56void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)
  57{
  58#ifdef CONFIG_ATOMIC64
  59    uint64_t oldv, cmpv, newv;
  60    int eflags;
  61
  62    eflags = cpu_cc_compute_all(env, CC_OP);
  63
  64    cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]);
  65    newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]);
  66
  67    {
  68        uintptr_t ra = GETPC();
  69        int mem_idx = cpu_mmu_index(env, false);
  70        MemOpIdx oi = make_memop_idx(MO_TEQ, mem_idx);
  71        oldv = cpu_atomic_cmpxchgq_le_mmu(env, a0, cmpv, newv, oi, ra);
  72    }
  73
  74    if (oldv == cmpv) {
  75        eflags |= CC_Z;
  76    } else {
  77        env->regs[R_EAX] = (uint32_t)oldv;
  78        env->regs[R_EDX] = (uint32_t)(oldv >> 32);
  79        eflags &= ~CC_Z;
  80    }
  81    CC_SRC = eflags;
  82#else
  83    cpu_loop_exit_atomic(env_cpu(env), GETPC());
  84#endif /* CONFIG_ATOMIC64 */
  85}
  86
  87#ifdef TARGET_X86_64
  88void helper_cmpxchg16b_unlocked(CPUX86State *env, target_ulong a0)
  89{
  90    uintptr_t ra = GETPC();
  91    Int128 oldv, cmpv, newv;
  92    uint64_t o0, o1;
  93    int eflags;
  94    bool success;
  95
  96    if ((a0 & 0xf) != 0) {
  97        raise_exception_ra(env, EXCP0D_GPF, GETPC());
  98    }
  99    eflags = cpu_cc_compute_all(env, CC_OP);
 100
 101    cmpv = int128_make128(env->regs[R_EAX], env->regs[R_EDX]);
 102    newv = int128_make128(env->regs[R_EBX], env->regs[R_ECX]);
 103
 104    o0 = cpu_ldq_data_ra(env, a0 + 0, ra);
 105    o1 = cpu_ldq_data_ra(env, a0 + 8, ra);
 106
 107    oldv = int128_make128(o0, o1);
 108    success = int128_eq(oldv, cmpv);
 109    if (!success) {
 110        newv = oldv;
 111    }
 112
 113    cpu_stq_data_ra(env, a0 + 0, int128_getlo(newv), ra);
 114    cpu_stq_data_ra(env, a0 + 8, int128_gethi(newv), ra);
 115
 116    if (success) {
 117        eflags |= CC_Z;
 118    } else {
 119        env->regs[R_EAX] = int128_getlo(oldv);
 120        env->regs[R_EDX] = int128_gethi(oldv);
 121        eflags &= ~CC_Z;
 122    }
 123    CC_SRC = eflags;
 124}
 125
 126void helper_cmpxchg16b(CPUX86State *env, target_ulong a0)
 127{
 128    uintptr_t ra = GETPC();
 129
 130    if ((a0 & 0xf) != 0) {
 131        raise_exception_ra(env, EXCP0D_GPF, ra);
 132    } else if (HAVE_CMPXCHG128) {
 133        int eflags = cpu_cc_compute_all(env, CC_OP);
 134
 135        Int128 cmpv = int128_make128(env->regs[R_EAX], env->regs[R_EDX]);
 136        Int128 newv = int128_make128(env->regs[R_EBX], env->regs[R_ECX]);
 137
 138        int mem_idx = cpu_mmu_index(env, false);
 139        MemOpIdx oi = make_memop_idx(MO_TE | MO_128 | MO_ALIGN, mem_idx);
 140        Int128 oldv = cpu_atomic_cmpxchgo_le_mmu(env, a0, cmpv, newv, oi, ra);
 141
 142        if (int128_eq(oldv, cmpv)) {
 143            eflags |= CC_Z;
 144        } else {
 145            env->regs[R_EAX] = int128_getlo(oldv);
 146            env->regs[R_EDX] = int128_gethi(oldv);
 147            eflags &= ~CC_Z;
 148        }
 149        CC_SRC = eflags;
 150    } else {
 151        cpu_loop_exit_atomic(env_cpu(env), ra);
 152    }
 153}
 154#endif
 155
 156void helper_boundw(CPUX86State *env, target_ulong a0, int v)
 157{
 158    int low, high;
 159
 160    low = cpu_ldsw_data_ra(env, a0, GETPC());
 161    high = cpu_ldsw_data_ra(env, a0 + 2, GETPC());
 162    v = (int16_t)v;
 163    if (v < low || v > high) {
 164        if (env->hflags & HF_MPX_EN_MASK) {
 165            env->bndcs_regs.sts = 0;
 166        }
 167        raise_exception_ra(env, EXCP05_BOUND, GETPC());
 168    }
 169}
 170
 171void helper_boundl(CPUX86State *env, target_ulong a0, int v)
 172{
 173    int low, high;
 174
 175    low = cpu_ldl_data_ra(env, a0, GETPC());
 176    high = cpu_ldl_data_ra(env, a0 + 4, GETPC());
 177    if (v < low || v > high) {
 178        if (env->hflags & HF_MPX_EN_MASK) {
 179            env->bndcs_regs.sts = 0;
 180        }
 181        raise_exception_ra(env, EXCP05_BOUND, GETPC());
 182    }
 183}
 184