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 30 void 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 56 void 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 TCGMemOpIdx 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 88 void 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 126 void 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 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, 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 156 void 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 171 void 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