]>
Commit | Line | Data |
---|---|---|
10774999 BS |
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 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 | ||
b6a0aa05 | 20 | #include "qemu/osdep.h" |
10774999 | 21 | #include "cpu.h" |
2ef6175a | 22 | #include "exec/helper-proto.h" |
63c91552 | 23 | #include "exec/exec-all.h" |
f08b6170 | 24 | #include "exec/cpu_ldst.h" |
ae03f8de | 25 | #include "qemu/int128.h" |
e1ed709f | 26 | #include "qemu/atomic128.h" |
dcb32f1d | 27 | #include "tcg/tcg.h" |
10774999 | 28 | |
ae03f8de EC |
29 | void helper_cmpxchg8b_unlocked(CPUX86State *env, target_ulong a0) |
30 | { | |
31 | uintptr_t ra = GETPC(); | |
32 | uint64_t oldv, cmpv, newv; | |
33 | int eflags; | |
34 | ||
35 | eflags = cpu_cc_compute_all(env, CC_OP); | |
36 | ||
37 | cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]); | |
38 | newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]); | |
39 | ||
40 | oldv = cpu_ldq_data_ra(env, a0, ra); | |
41 | newv = (cmpv == oldv ? newv : oldv); | |
42 | /* always do the store */ | |
43 | cpu_stq_data_ra(env, a0, newv, ra); | |
44 | ||
45 | if (oldv == cmpv) { | |
46 | eflags |= CC_Z; | |
47 | } else { | |
48 | env->regs[R_EAX] = (uint32_t)oldv; | |
49 | env->regs[R_EDX] = (uint32_t)(oldv >> 32); | |
50 | eflags &= ~CC_Z; | |
51 | } | |
52 | CC_SRC = eflags; | |
53 | } | |
54 | ||
92fc4b58 | 55 | void helper_cmpxchg8b(CPUX86State *env, target_ulong a0) |
10774999 | 56 | { |
ae03f8de EC |
57 | #ifdef CONFIG_ATOMIC64 |
58 | uint64_t oldv, cmpv, newv; | |
10774999 BS |
59 | int eflags; |
60 | ||
f0967a1a | 61 | eflags = cpu_cc_compute_all(env, CC_OP); |
ae03f8de EC |
62 | |
63 | cmpv = deposit64(env->regs[R_EAX], 32, 32, env->regs[R_EDX]); | |
64 | newv = deposit64(env->regs[R_EBX], 32, 32, env->regs[R_ECX]); | |
65 | ||
66 | #ifdef CONFIG_USER_ONLY | |
67 | { | |
68 | uint64_t *haddr = g2h(a0); | |
69 | cmpv = cpu_to_le64(cmpv); | |
70 | newv = cpu_to_le64(newv); | |
71 | oldv = atomic_cmpxchg__nocheck(haddr, cmpv, newv); | |
72 | oldv = le64_to_cpu(oldv); | |
73 | } | |
74 | #else | |
75 | { | |
76 | uintptr_t ra = GETPC(); | |
77 | int mem_idx = cpu_mmu_index(env, false); | |
78 | TCGMemOpIdx oi = make_memop_idx(MO_TEQ, mem_idx); | |
79 | oldv = helper_atomic_cmpxchgq_le_mmu(env, a0, cmpv, newv, oi, ra); | |
80 | } | |
81 | #endif | |
82 | ||
83 | if (oldv == cmpv) { | |
10774999 BS |
84 | eflags |= CC_Z; |
85 | } else { | |
ae03f8de EC |
86 | env->regs[R_EAX] = (uint32_t)oldv; |
87 | env->regs[R_EDX] = (uint32_t)(oldv >> 32); | |
10774999 BS |
88 | eflags &= ~CC_Z; |
89 | } | |
90 | CC_SRC = eflags; | |
ae03f8de | 91 | #else |
29a0af61 | 92 | cpu_loop_exit_atomic(env_cpu(env), GETPC()); |
ae03f8de | 93 | #endif /* CONFIG_ATOMIC64 */ |
10774999 BS |
94 | } |
95 | ||
96 | #ifdef TARGET_X86_64 | |
ae03f8de | 97 | void helper_cmpxchg16b_unlocked(CPUX86State *env, target_ulong a0) |
10774999 | 98 | { |
ae03f8de EC |
99 | uintptr_t ra = GETPC(); |
100 | Int128 oldv, cmpv, newv; | |
101 | uint64_t o0, o1; | |
10774999 | 102 | int eflags; |
ae03f8de | 103 | bool success; |
10774999 BS |
104 | |
105 | if ((a0 & 0xf) != 0) { | |
2afbdf84 | 106 | raise_exception_ra(env, EXCP0D_GPF, GETPC()); |
10774999 | 107 | } |
f0967a1a | 108 | eflags = cpu_cc_compute_all(env, CC_OP); |
ae03f8de EC |
109 | |
110 | cmpv = int128_make128(env->regs[R_EAX], env->regs[R_EDX]); | |
111 | newv = int128_make128(env->regs[R_EBX], env->regs[R_ECX]); | |
112 | ||
113 | o0 = cpu_ldq_data_ra(env, a0 + 0, ra); | |
114 | o1 = cpu_ldq_data_ra(env, a0 + 8, ra); | |
115 | ||
116 | oldv = int128_make128(o0, o1); | |
117 | success = int128_eq(oldv, cmpv); | |
118 | if (!success) { | |
119 | newv = oldv; | |
120 | } | |
121 | ||
122 | cpu_stq_data_ra(env, a0 + 0, int128_getlo(newv), ra); | |
123 | cpu_stq_data_ra(env, a0 + 8, int128_gethi(newv), ra); | |
124 | ||
125 | if (success) { | |
10774999 BS |
126 | eflags |= CC_Z; |
127 | } else { | |
ae03f8de EC |
128 | env->regs[R_EAX] = int128_getlo(oldv); |
129 | env->regs[R_EDX] = int128_gethi(oldv); | |
10774999 BS |
130 | eflags &= ~CC_Z; |
131 | } | |
132 | CC_SRC = eflags; | |
133 | } | |
ae03f8de EC |
134 | |
135 | void helper_cmpxchg16b(CPUX86State *env, target_ulong a0) | |
136 | { | |
137 | uintptr_t ra = GETPC(); | |
138 | ||
139 | if ((a0 & 0xf) != 0) { | |
140 | raise_exception_ra(env, EXCP0D_GPF, ra); | |
e1ed709f | 141 | } else if (HAVE_CMPXCHG128) { |
ae03f8de EC |
142 | int eflags = cpu_cc_compute_all(env, CC_OP); |
143 | ||
144 | Int128 cmpv = int128_make128(env->regs[R_EAX], env->regs[R_EDX]); | |
145 | Int128 newv = int128_make128(env->regs[R_EBX], env->regs[R_ECX]); | |
146 | ||
147 | int mem_idx = cpu_mmu_index(env, false); | |
148 | TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); | |
149 | Int128 oldv = helper_atomic_cmpxchgo_le_mmu(env, a0, cmpv, | |
150 | newv, oi, ra); | |
151 | ||
152 | if (int128_eq(oldv, cmpv)) { | |
153 | eflags |= CC_Z; | |
154 | } else { | |
155 | env->regs[R_EAX] = int128_getlo(oldv); | |
156 | env->regs[R_EDX] = int128_gethi(oldv); | |
157 | eflags &= ~CC_Z; | |
158 | } | |
159 | CC_SRC = eflags; | |
e1ed709f | 160 | } else { |
29a0af61 | 161 | cpu_loop_exit_atomic(env_cpu(env), ra); |
ae03f8de EC |
162 | } |
163 | } | |
10774999 BS |
164 | #endif |
165 | ||
92fc4b58 | 166 | void helper_boundw(CPUX86State *env, target_ulong a0, int v) |
10774999 BS |
167 | { |
168 | int low, high; | |
169 | ||
2afbdf84 PD |
170 | low = cpu_ldsw_data_ra(env, a0, GETPC()); |
171 | high = cpu_ldsw_data_ra(env, a0 + 2, GETPC()); | |
10774999 BS |
172 | v = (int16_t)v; |
173 | if (v < low || v > high) { | |
75d14edc RH |
174 | if (env->hflags & HF_MPX_EN_MASK) { |
175 | env->bndcs_regs.sts = 0; | |
176 | } | |
2afbdf84 | 177 | raise_exception_ra(env, EXCP05_BOUND, GETPC()); |
10774999 BS |
178 | } |
179 | } | |
180 | ||
92fc4b58 | 181 | void helper_boundl(CPUX86State *env, target_ulong a0, int v) |
10774999 BS |
182 | { |
183 | int low, high; | |
184 | ||
2afbdf84 PD |
185 | low = cpu_ldl_data_ra(env, a0, GETPC()); |
186 | high = cpu_ldl_data_ra(env, a0 + 4, GETPC()); | |
10774999 | 187 | if (v < low || v > high) { |
75d14edc RH |
188 | if (env->hflags & HF_MPX_EN_MASK) { |
189 | env->bndcs_regs.sts = 0; | |
190 | } | |
2afbdf84 | 191 | raise_exception_ra(env, EXCP05_BOUND, GETPC()); |
10774999 BS |
192 | } |
193 | } |