1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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_TEUQ, 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
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