]>
Commit | Line | Data |
---|---|---|
c482cb11 RH |
1 | /* |
2 | * Atomic helper templates | |
3 | * Included from tcg-runtime.c and cputlb.c. | |
4 | * | |
5 | * Copyright (c) 2016 Red Hat, Inc | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | ||
21 | #if DATA_SIZE == 8 | |
22 | # define SUFFIX q | |
23 | # define DATA_TYPE uint64_t | |
24 | # define BSWAP bswap64 | |
25 | #elif DATA_SIZE == 4 | |
26 | # define SUFFIX l | |
27 | # define DATA_TYPE uint32_t | |
28 | # define BSWAP bswap32 | |
29 | #elif DATA_SIZE == 2 | |
30 | # define SUFFIX w | |
31 | # define DATA_TYPE uint16_t | |
32 | # define BSWAP bswap16 | |
33 | #elif DATA_SIZE == 1 | |
34 | # define SUFFIX b | |
35 | # define DATA_TYPE uint8_t | |
36 | # define BSWAP | |
37 | #else | |
38 | # error unsupported data size | |
39 | #endif | |
40 | ||
41 | #if DATA_SIZE >= 4 | |
42 | # define ABI_TYPE DATA_TYPE | |
43 | #else | |
44 | # define ABI_TYPE uint32_t | |
45 | #endif | |
46 | ||
47 | /* Define host-endian atomic operations. Note that END is used within | |
48 | the ATOMIC_NAME macro, and redefined below. */ | |
49 | #if DATA_SIZE == 1 | |
50 | # define END | |
51 | #elif defined(HOST_WORDS_BIGENDIAN) | |
52 | # define END _be | |
53 | #else | |
54 | # define END _le | |
55 | #endif | |
56 | ||
57 | ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, | |
58 | ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) | |
59 | { | |
60 | DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; | |
61 | return atomic_cmpxchg__nocheck(haddr, cmpv, newv); | |
62 | } | |
63 | ||
64 | ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, | |
65 | ABI_TYPE val EXTRA_ARGS) | |
66 | { | |
67 | DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; | |
68 | return atomic_xchg__nocheck(haddr, val); | |
69 | } | |
70 | ||
71 | #define GEN_ATOMIC_HELPER(X) \ | |
72 | ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ | |
73 | ABI_TYPE val EXTRA_ARGS) \ | |
74 | { \ | |
75 | DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ | |
76 | return atomic_##X(haddr, val); \ | |
77 | } \ | |
78 | ||
79 | GEN_ATOMIC_HELPER(fetch_add) | |
80 | GEN_ATOMIC_HELPER(fetch_and) | |
81 | GEN_ATOMIC_HELPER(fetch_or) | |
82 | GEN_ATOMIC_HELPER(fetch_xor) | |
83 | GEN_ATOMIC_HELPER(add_fetch) | |
84 | GEN_ATOMIC_HELPER(and_fetch) | |
85 | GEN_ATOMIC_HELPER(or_fetch) | |
86 | GEN_ATOMIC_HELPER(xor_fetch) | |
87 | ||
88 | #undef GEN_ATOMIC_HELPER | |
89 | #undef END | |
90 | ||
91 | #if DATA_SIZE > 1 | |
92 | ||
93 | /* Define reverse-host-endian atomic operations. Note that END is used | |
94 | within the ATOMIC_NAME macro. */ | |
95 | #ifdef HOST_WORDS_BIGENDIAN | |
96 | # define END _le | |
97 | #else | |
98 | # define END _be | |
99 | #endif | |
100 | ||
101 | ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, | |
102 | ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) | |
103 | { | |
104 | DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; | |
105 | return BSWAP(atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv))); | |
106 | } | |
107 | ||
108 | ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, | |
109 | ABI_TYPE val EXTRA_ARGS) | |
110 | { | |
111 | DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; | |
112 | return BSWAP(atomic_xchg__nocheck(haddr, BSWAP(val))); | |
113 | } | |
114 | ||
115 | #define GEN_ATOMIC_HELPER(X) \ | |
116 | ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ | |
117 | ABI_TYPE val EXTRA_ARGS) \ | |
118 | { \ | |
119 | DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ | |
120 | return BSWAP(atomic_##X(haddr, BSWAP(val))); \ | |
121 | } | |
122 | ||
123 | GEN_ATOMIC_HELPER(fetch_and) | |
124 | GEN_ATOMIC_HELPER(fetch_or) | |
125 | GEN_ATOMIC_HELPER(fetch_xor) | |
126 | GEN_ATOMIC_HELPER(and_fetch) | |
127 | GEN_ATOMIC_HELPER(or_fetch) | |
128 | GEN_ATOMIC_HELPER(xor_fetch) | |
129 | ||
130 | #undef GEN_ATOMIC_HELPER | |
131 | ||
132 | /* Note that for addition, we need to use a separate cmpxchg loop instead | |
133 | of bswaps for the reverse-host-endian helpers. */ | |
134 | ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr, | |
135 | ABI_TYPE val EXTRA_ARGS) | |
136 | { | |
137 | DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; | |
138 | DATA_TYPE ldo, ldn, ret, sto; | |
139 | ||
140 | ldo = atomic_read__nocheck(haddr); | |
141 | while (1) { | |
142 | ret = BSWAP(ldo); | |
143 | sto = BSWAP(ret + val); | |
144 | ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); | |
145 | if (ldn == ldo) { | |
146 | return ret; | |
147 | } | |
148 | ldo = ldn; | |
149 | } | |
150 | } | |
151 | ||
152 | ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr, | |
153 | ABI_TYPE val EXTRA_ARGS) | |
154 | { | |
155 | DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; | |
156 | DATA_TYPE ldo, ldn, ret, sto; | |
157 | ||
158 | ldo = atomic_read__nocheck(haddr); | |
159 | while (1) { | |
160 | ret = BSWAP(ldo) + val; | |
161 | sto = BSWAP(ret); | |
162 | ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); | |
163 | if (ldn == ldo) { | |
164 | return ret; | |
165 | } | |
166 | ldo = ldn; | |
167 | } | |
168 | } | |
169 | ||
170 | #undef END | |
171 | #endif /* DATA_SIZE > 1 */ | |
172 | ||
173 | #undef BSWAP | |
174 | #undef ABI_TYPE | |
175 | #undef DATA_TYPE | |
176 | #undef SUFFIX | |
177 | #undef DATA_SIZE |