]>
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 | |
d9ff33ad | 9 | * version 2.1 of the License, or (at your option) any later version. |
10774999 BS |
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" |
ed69e831 | 28 | #include "helper-tcg.h" |
10774999 | 29 | |
ae03f8de EC |
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 | ||
92fc4b58 | 56 | void helper_cmpxchg8b(CPUX86State *env, target_ulong a0) |
10774999 | 57 | { |
ae03f8de EC |
58 | #ifdef CONFIG_ATOMIC64 |
59 | uint64_t oldv, cmpv, newv; | |
10774999 BS |
60 | int eflags; |
61 | ||
f0967a1a | 62 | eflags = cpu_cc_compute_all(env, CC_OP); |
ae03f8de EC |
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 | ||
ae03f8de EC |
67 | { |
68 | uintptr_t ra = GETPC(); | |
69 | int mem_idx = cpu_mmu_index(env, false); | |
fc313c64 | 70 | MemOpIdx oi = make_memop_idx(MO_TEUQ, mem_idx); |
be9568b4 | 71 | oldv = cpu_atomic_cmpxchgq_le_mmu(env, a0, cmpv, newv, oi, ra); |
ae03f8de | 72 | } |
ae03f8de EC |
73 | |
74 | if (oldv == cmpv) { | |
10774999 BS |
75 | eflags |= CC_Z; |
76 | } else { | |
ae03f8de EC |
77 | env->regs[R_EAX] = (uint32_t)oldv; |
78 | env->regs[R_EDX] = (uint32_t)(oldv >> 32); | |
10774999 BS |
79 | eflags &= ~CC_Z; |
80 | } | |
81 | CC_SRC = eflags; | |
ae03f8de | 82 | #else |
29a0af61 | 83 | cpu_loop_exit_atomic(env_cpu(env), GETPC()); |
ae03f8de | 84 | #endif /* CONFIG_ATOMIC64 */ |
10774999 BS |
85 | } |
86 | ||
87 | #ifdef TARGET_X86_64 | |
ae03f8de | 88 | void helper_cmpxchg16b_unlocked(CPUX86State *env, target_ulong a0) |
10774999 | 89 | { |
ae03f8de EC |
90 | uintptr_t ra = GETPC(); |
91 | Int128 oldv, cmpv, newv; | |
92 | uint64_t o0, o1; | |
10774999 | 93 | int eflags; |
ae03f8de | 94 | bool success; |
10774999 BS |
95 | |
96 | if ((a0 & 0xf) != 0) { | |
2afbdf84 | 97 | raise_exception_ra(env, EXCP0D_GPF, GETPC()); |
10774999 | 98 | } |
f0967a1a | 99 | eflags = cpu_cc_compute_all(env, CC_OP); |
ae03f8de EC |
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) { | |
10774999 BS |
117 | eflags |= CC_Z; |
118 | } else { | |
ae03f8de EC |
119 | env->regs[R_EAX] = int128_getlo(oldv); |
120 | env->regs[R_EDX] = int128_gethi(oldv); | |
10774999 BS |
121 | eflags &= ~CC_Z; |
122 | } | |
123 | CC_SRC = eflags; | |
124 | } | |
ae03f8de EC |
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); | |
e1ed709f | 132 | } else if (HAVE_CMPXCHG128) { |
ae03f8de EC |
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); | |
26b14640 | 139 | MemOpIdx oi = make_memop_idx(MO_TE | MO_128 | MO_ALIGN, mem_idx); |
be9568b4 | 140 | Int128 oldv = cpu_atomic_cmpxchgo_le_mmu(env, a0, cmpv, newv, oi, ra); |
ae03f8de EC |
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; | |
e1ed709f | 150 | } else { |
29a0af61 | 151 | cpu_loop_exit_atomic(env_cpu(env), ra); |
ae03f8de EC |
152 | } |
153 | } | |
10774999 BS |
154 | #endif |
155 | ||
92fc4b58 | 156 | void helper_boundw(CPUX86State *env, target_ulong a0, int v) |
10774999 BS |
157 | { |
158 | int low, high; | |
159 | ||
2afbdf84 PD |
160 | low = cpu_ldsw_data_ra(env, a0, GETPC()); |
161 | high = cpu_ldsw_data_ra(env, a0 + 2, GETPC()); | |
10774999 BS |
162 | v = (int16_t)v; |
163 | if (v < low || v > high) { | |
75d14edc RH |
164 | if (env->hflags & HF_MPX_EN_MASK) { |
165 | env->bndcs_regs.sts = 0; | |
166 | } | |
2afbdf84 | 167 | raise_exception_ra(env, EXCP05_BOUND, GETPC()); |
10774999 BS |
168 | } |
169 | } | |
170 | ||
92fc4b58 | 171 | void helper_boundl(CPUX86State *env, target_ulong a0, int v) |
10774999 BS |
172 | { |
173 | int low, high; | |
174 | ||
2afbdf84 PD |
175 | low = cpu_ldl_data_ra(env, a0, GETPC()); |
176 | high = cpu_ldl_data_ra(env, a0 + 4, GETPC()); | |
10774999 | 177 | if (v < low || v > high) { |
75d14edc RH |
178 | if (env->hflags & HF_MPX_EN_MASK) { |
179 | env->bndcs_regs.sts = 0; | |
180 | } | |
2afbdf84 | 181 | raise_exception_ra(env, EXCP05_BOUND, GETPC()); |
10774999 BS |
182 | } |
183 | } |