1 // SPDX-License-Identifier: LGPL-2.1-only
5 * Copyright (C) 2017 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
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; only
10 * version 2.1 of the License.
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.
31 #include <rseq/cpu-op.h>
33 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
35 #define ACCESS_ONCE(x) (*(__volatile__ __typeof__(x) *)&(x))
36 #define WRITE_ONCE(x, v) __extension__ ({ ACCESS_ONCE(x) = (v); })
37 #define READ_ONCE(x) ACCESS_ONCE(x)
39 int cpu_opv(struct cpu_op
*cpu_opv
, int cpuopcnt
, int cpu
, int flags
)
41 return syscall(__NR_cpu_opv
, cpu_opv
, cpuopcnt
, cpu
, flags
);
44 int cpu_op_available(void)
48 rc
= cpu_opv(NULL
, 0, 0, CPU_OP_NR_FLAG
);
54 int cpu_op_get_current_cpu(void)
60 perror("sched_getcpu()");
66 int cpu_op_cmpxchg(void *v
, void *expect
, void *old
, void *n
, size_t len
,
69 struct cpu_op opvec
[] = {
74 .dst
= (unsigned long)old
,
75 .src
= (unsigned long)v
,
76 .expect_fault_dst
= 0,
77 .expect_fault_src
= 0,
81 .op
= CPU_COMPARE_EQ_OP
,
84 .a
= (unsigned long)v
,
85 .b
= (unsigned long)expect
,
94 .dst
= (unsigned long)v
,
95 .src
= (unsigned long)n
,
96 .expect_fault_dst
= 0,
97 .expect_fault_src
= 0,
102 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
105 int cpu_op_add(void *v
, int64_t count
, size_t len
, int cpu
)
107 struct cpu_op opvec
[] = {
112 .p
= (unsigned long)v
,
119 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
122 int cpu_op_add_release(void *v
, int64_t count
, size_t len
, int cpu
)
124 struct cpu_op opvec
[] = {
126 .op
= CPU_ADD_RELEASE_OP
,
129 .p
= (unsigned long)v
,
136 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
139 int cpu_op_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
,
142 struct cpu_op opvec
[] = {
144 .op
= CPU_COMPARE_EQ_OP
,
145 .len
= sizeof(intptr_t),
147 .a
= (unsigned long)v
,
148 .b
= (unsigned long)&expect
,
155 .len
= sizeof(intptr_t),
157 .dst
= (unsigned long)v
,
158 .src
= (unsigned long)&newv
,
159 .expect_fault_dst
= 0,
160 .expect_fault_src
= 0,
165 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
168 static int cpu_op_cmpeqv_storep_expect_fault(intptr_t *v
, intptr_t expect
,
169 intptr_t *newp
, int cpu
)
171 struct cpu_op opvec
[] = {
173 .op
= CPU_COMPARE_EQ_OP
,
174 .len
= sizeof(intptr_t),
176 .a
= (unsigned long)v
,
177 .b
= (unsigned long)&expect
,
184 .len
= sizeof(intptr_t),
186 .dst
= (unsigned long)v
,
187 .src
= (unsigned long)newp
,
188 .expect_fault_dst
= 0,
189 /* Return EAGAIN on src fault. */
190 .expect_fault_src
= 1,
195 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
198 int cpu_op_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
199 off_t voffp
, intptr_t *load
, int cpu
)
204 intptr_t oldv
= READ_ONCE(*v
);
205 intptr_t *newp
= (intptr_t *)(oldv
+ voffp
);
207 if (oldv
== expectnot
)
209 ret
= cpu_op_cmpeqv_storep_expect_fault(v
, oldv
, newp
, cpu
);
219 int cpu_op_cmpeqv_storev_storev(intptr_t *v
, intptr_t expect
,
220 intptr_t *v2
, intptr_t newv2
,
221 intptr_t newv
, int cpu
)
223 struct cpu_op opvec
[] = {
225 .op
= CPU_COMPARE_EQ_OP
,
226 .len
= sizeof(intptr_t),
228 .a
= (unsigned long)v
,
229 .b
= (unsigned long)&expect
,
236 .len
= sizeof(intptr_t),
238 .dst
= (unsigned long)v2
,
239 .src
= (unsigned long)&newv2
,
240 .expect_fault_dst
= 0,
241 .expect_fault_src
= 0,
246 .len
= sizeof(intptr_t),
248 .dst
= (unsigned long)v
,
249 .src
= (unsigned long)&newv
,
250 .expect_fault_dst
= 0,
251 .expect_fault_src
= 0,
256 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
259 int cpu_op_cmpeqv_storev_mb_storev(intptr_t *v
, intptr_t expect
,
260 intptr_t *v2
, intptr_t newv2
,
261 intptr_t newv
, int cpu
)
263 struct cpu_op opvec
[] = {
265 .op
= CPU_COMPARE_EQ_OP
,
266 .len
= sizeof(intptr_t),
268 .a
= (unsigned long)v
,
269 .b
= (unsigned long)&expect
,
276 .len
= sizeof(intptr_t),
278 .dst
= (unsigned long)v2
,
279 .src
= (unsigned long)&newv2
,
280 .expect_fault_dst
= 0,
281 .expect_fault_src
= 0,
285 .op
= CPU_MEMCPY_RELEASE_OP
,
286 .len
= sizeof(intptr_t),
288 .dst
= (unsigned long)v
,
289 .src
= (unsigned long)&newv
,
290 .expect_fault_dst
= 0,
291 .expect_fault_src
= 0,
296 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
299 int cpu_op_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
300 intptr_t *v2
, intptr_t expect2
,
301 intptr_t newv
, int cpu
)
303 struct cpu_op opvec
[] = {
305 .op
= CPU_COMPARE_EQ_OP
,
306 .len
= sizeof(intptr_t),
308 .a
= (unsigned long)v
,
309 .b
= (unsigned long)&expect
,
315 .op
= CPU_COMPARE_EQ_OP
,
316 .len
= sizeof(intptr_t),
318 .a
= (unsigned long)v2
,
319 .b
= (unsigned long)&expect2
,
326 .len
= sizeof(intptr_t),
328 .dst
= (unsigned long)v
,
329 .src
= (unsigned long)&newv
,
330 .expect_fault_dst
= 0,
331 .expect_fault_src
= 0,
336 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
339 int cpu_op_cmpeqv_memcpy_storev(intptr_t *v
, intptr_t expect
,
340 void *dst
, void *src
, size_t len
,
341 intptr_t newv
, int cpu
)
343 struct cpu_op opvec
[] = {
345 .op
= CPU_COMPARE_EQ_OP
,
346 .len
= sizeof(intptr_t),
348 .a
= (unsigned long)v
,
349 .b
= (unsigned long)&expect
,
358 .dst
= (unsigned long)dst
,
359 .src
= (unsigned long)src
,
360 .expect_fault_dst
= 0,
361 .expect_fault_src
= 0,
366 .len
= sizeof(intptr_t),
368 .dst
= (unsigned long)v
,
369 .src
= (unsigned long)&newv
,
370 .expect_fault_dst
= 0,
371 .expect_fault_src
= 0,
376 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
379 int cpu_op_cmpeqv_memcpy_mb_storev(intptr_t *v
, intptr_t expect
,
380 void *dst
, void *src
, size_t len
,
381 intptr_t newv
, int cpu
)
383 struct cpu_op opvec
[] = {
385 .op
= CPU_COMPARE_EQ_OP
,
386 .len
= sizeof(intptr_t),
388 .a
= (unsigned long)v
,
389 .b
= (unsigned long)&expect
,
398 .dst
= (unsigned long)dst
,
399 .src
= (unsigned long)src
,
400 .expect_fault_dst
= 0,
401 .expect_fault_src
= 0,
405 .op
= CPU_MEMCPY_RELEASE_OP
,
406 .len
= sizeof(intptr_t),
408 .dst
= (unsigned long)v
,
409 .src
= (unsigned long)&newv
,
410 .expect_fault_dst
= 0,
411 .expect_fault_src
= 0,
416 return cpu_opv(opvec
, ARRAY_SIZE(opvec
), cpu
, 0);
419 int cpu_op_addv(intptr_t *v
, int64_t count
, int cpu
)
421 return cpu_op_add(v
, count
, sizeof(intptr_t), cpu
);
This page took 0.037568 seconds and 4 git commands to generate.