1 /* SPDX-License-Identifier: MIT */
2 /* SPDX-FileCopyrightText: 2016-2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> */
8 #include "rseq/arch/templates/bits.h"
11 * Refer to rseq/pseudocode.h for pseudo-code of the rseq critical
14 #include "rseq/pseudocode.h"
18 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
19 (defined(RSEQ_TEMPLATE_INDEX_CPU_ID) || defined(RSEQ_TEMPLATE_INDEX_MM_CID))
21 static inline __attribute__((always_inline
))
22 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_store__ptr
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
26 __asm__ __volatile__
goto (
27 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
28 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[ne
])
29 #ifdef RSEQ_COMPARE_TWICE
30 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
31 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
33 /* Start rseq by storing table entry pointer into rseq_cs. */
34 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]))
35 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
37 "cmpq %[v], %[expect]\n\t"
40 #ifdef RSEQ_COMPARE_TWICE
41 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
42 "cmpq %[v], %[expect]\n\t"
46 "movq %[newv], %[v]\n\t"
49 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
50 : /* gcc asm goto does not allow outputs */
52 [rseq_offset
] "r" (rseq_offset
),
54 [expect
] "r" (expect
),
56 : "memory", "cc", "rax"
59 #ifdef RSEQ_COMPARE_TWICE
63 rseq_after_asm_goto();
66 rseq_after_asm_goto();
70 rseq_after_asm_goto();
72 #ifdef RSEQ_COMPARE_TWICE
74 rseq_after_asm_goto();
75 rseq_bug("cpu_id comparison failed");
77 rseq_after_asm_goto();
78 rseq_bug("expected value comparison failed");
82 static inline __attribute__((always_inline
))
83 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbeq_store_add_load_store__ptr
)(intptr_t *v
, intptr_t expectnot
,
84 long voffp
, intptr_t *load
, int cpu
)
88 __asm__ __volatile__
goto (
89 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
90 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[eq
])
91 #ifdef RSEQ_COMPARE_TWICE
92 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
93 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
95 /* Start rseq by storing table entry pointer into rseq_cs. */
96 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]))
97 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
99 "movq %[v], %%rbx\n\t"
100 "cmpq %%rbx, %[expectnot]\n\t"
103 #ifdef RSEQ_COMPARE_TWICE
104 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
105 "movq %[v], %%rbx\n\t"
106 "cmpq %%rbx, %[expectnot]\n\t"
109 "movq %%rbx, %[load]\n\t"
110 "addq %[voffp], %%rbx\n\t"
111 "movq (%%rbx), %%rbx\n\t"
113 "movq %%rbx, %[v]\n\t"
116 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
117 : /* gcc asm goto does not allow outputs */
118 : [cpu_id
] "r" (cpu
),
119 [rseq_offset
] "r" (rseq_offset
),
120 /* final store input */
122 [expectnot
] "r" (expectnot
),
123 [voffp
] "er" (voffp
),
125 : "memory", "cc", "rax", "rbx"
128 #ifdef RSEQ_COMPARE_TWICE
132 rseq_after_asm_goto();
135 rseq_after_asm_goto();
139 rseq_after_asm_goto();
141 #ifdef RSEQ_COMPARE_TWICE
143 rseq_after_asm_goto();
144 rseq_bug("cpu_id comparison failed");
146 rseq_after_asm_goto();
147 rseq_bug("expected value comparison failed");
151 static inline __attribute__((always_inline
))
152 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_add_store__ptr
)(intptr_t *v
, intptr_t count
, int cpu
)
156 __asm__ __volatile__
goto (
157 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
158 #ifdef RSEQ_COMPARE_TWICE
159 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
161 /* Start rseq by storing table entry pointer into rseq_cs. */
162 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]))
163 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
165 #ifdef RSEQ_COMPARE_TWICE
166 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
169 "addq %[count], %[v]\n\t"
172 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
173 : /* gcc asm goto does not allow outputs */
174 : [cpu_id
] "r" (cpu
),
175 [rseq_offset
] "r" (rseq_offset
),
176 /* final store input */
179 : "memory", "cc", "rax"
182 #ifdef RSEQ_COMPARE_TWICE
186 rseq_after_asm_goto();
189 rseq_after_asm_goto();
192 #ifdef RSEQ_COMPARE_TWICE
194 rseq_after_asm_goto();
195 rseq_bug("cpu_id comparison failed");
199 #define rseq_arch_has_load_cbne_load_add_load_add_store
201 static inline __attribute__((always_inline
))
203 RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_load_add_load_add_store__ptr
)(intptr_t *ptr
,
204 intptr_t expect
, intptr_t *ptr2
, ptrdiff_t offset
,
205 intptr_t inc
, int cpu
)
209 __asm__ __volatile__
goto (
210 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
211 #ifdef RSEQ_COMPARE_TWICE
212 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
214 /* Start rseq by storing table entry pointer into rseq_cs. */
215 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]))
216 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
218 #ifdef RSEQ_COMPARE_TWICE
219 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
221 "movq %[ptr], %%rbx\n\t"
222 "cmpq %%rbx, %[expect]\n\t"
225 "movq %[ptr2], %%rbx\n\t"
226 "addq %[offset], %%rbx\n\t"
227 "addq %[inc], (%%rbx)\n\t"
230 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
231 : /* gcc asm goto does not allow outputs */
232 : [cpu_id
] "r" (cpu
),
233 [rseq_offset
] "r" (rseq_offset
),
234 /* final store input */
236 [expect
] "r" (expect
),
238 [offset
] "er" (offset
),
240 : "memory", "cc", "rax", "rbx"
243 #ifdef RSEQ_COMPARE_TWICE
247 rseq_after_asm_goto();
250 rseq_after_asm_goto();
254 rseq_after_asm_goto();
256 #ifdef RSEQ_COMPARE_TWICE
258 rseq_after_asm_goto();
259 rseq_bug("cpu_id comparison failed");
263 static inline __attribute__((always_inline
))
264 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_load_cbne_store__ptr
)(intptr_t *v
, intptr_t expect
,
265 intptr_t *v2
, intptr_t expect2
,
266 intptr_t newv
, int cpu
)
270 __asm__ __volatile__
goto (
271 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
272 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[ne
])
273 #ifdef RSEQ_COMPARE_TWICE
274 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
275 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
276 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
278 /* Start rseq by storing table entry pointer into rseq_cs. */
279 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]))
280 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
282 "cmpq %[v], %[expect]\n\t"
285 "cmpq %[v2], %[expect2]\n\t"
288 #ifdef RSEQ_COMPARE_TWICE
289 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
290 "cmpq %[v], %[expect]\n\t"
292 "cmpq %[v2], %[expect2]\n\t"
296 "movq %[newv], %[v]\n\t"
299 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
300 : /* gcc asm goto does not allow outputs */
301 : [cpu_id
] "r" (cpu
),
302 [rseq_offset
] "r" (rseq_offset
),
305 [expect2
] "r" (expect2
),
306 /* final store input */
308 [expect
] "r" (expect
),
310 : "memory", "cc", "rax"
313 #ifdef RSEQ_COMPARE_TWICE
314 , error1
, error2
, error3
317 rseq_after_asm_goto();
320 rseq_after_asm_goto();
324 rseq_after_asm_goto();
326 #ifdef RSEQ_COMPARE_TWICE
328 rseq_after_asm_goto();
329 rseq_bug("cpu_id comparison failed");
331 rseq_after_asm_goto();
332 rseq_bug("1st expected value comparison failed");
334 rseq_after_asm_goto();
335 rseq_bug("2nd expected value comparison failed");
339 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
340 (defined(RSEQ_TEMPLATE_INDEX_CPU_ID) || defined(RSEQ_TEMPLATE_INDEX_MM_CID)) */
342 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
343 (defined(RSEQ_TEMPLATE_INDEX_CPU_ID) || defined(RSEQ_TEMPLATE_INDEX_MM_CID))
345 static inline __attribute__((always_inline
))
346 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_store_store__ptr
)(intptr_t *v
, intptr_t expect
,
347 intptr_t *v2
, intptr_t newv2
,
348 intptr_t newv
, int cpu
)
352 __asm__ __volatile__
goto (
353 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
354 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[ne
])
355 #ifdef RSEQ_COMPARE_TWICE
356 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
357 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
359 /* Start rseq by storing table entry pointer into rseq_cs. */
360 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]))
361 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
363 "cmpq %[v], %[expect]\n\t"
366 #ifdef RSEQ_COMPARE_TWICE
367 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
368 "cmpq %[v], %[expect]\n\t"
372 "movq %[newv2], %[v2]\n\t"
375 "movq %[newv], %[v]\n\t"
378 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
379 : /* gcc asm goto does not allow outputs */
380 : [cpu_id
] "r" (cpu
),
381 [rseq_offset
] "r" (rseq_offset
),
382 /* try store input */
385 /* final store input */
387 [expect
] "r" (expect
),
389 : "memory", "cc", "rax"
392 #ifdef RSEQ_COMPARE_TWICE
396 rseq_after_asm_goto();
399 rseq_after_asm_goto();
403 rseq_after_asm_goto();
405 #ifdef RSEQ_COMPARE_TWICE
407 rseq_after_asm_goto();
408 rseq_bug("cpu_id comparison failed");
410 rseq_after_asm_goto();
411 rseq_bug("expected value comparison failed");
415 static inline __attribute__((always_inline
))
416 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_memcpy_store__ptr
)(intptr_t *v
, intptr_t expect
,
417 void *dst
, void *src
, size_t len
,
418 intptr_t newv
, int cpu
)
420 uint64_t rseq_scratch
[3];
424 __asm__ __volatile__
goto (
425 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
426 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[ne
])
427 #ifdef RSEQ_COMPARE_TWICE
428 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
429 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
431 "movq %[src], %[rseq_scratch0]\n\t"
432 "movq %[dst], %[rseq_scratch1]\n\t"
433 "movq %[len], %[rseq_scratch2]\n\t"
434 /* Start rseq by storing table entry pointer into rseq_cs. */
435 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]))
436 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
438 "cmpq %[v], %[expect]\n\t"
441 #ifdef RSEQ_COMPARE_TWICE
442 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 6f
)
443 "cmpq %[v], %[expect]\n\t"
447 "test %[len], %[len]\n\t" \
450 "movb (%[src]), %%al\n\t" \
451 "movb %%al, (%[dst])\n\t" \
459 "movq %[newv], %[v]\n\t"
463 "movq %[rseq_scratch2], %[len]\n\t"
464 "movq %[rseq_scratch1], %[dst]\n\t"
465 "movq %[rseq_scratch0], %[src]\n\t"
466 RSEQ_ASM_DEFINE_ABORT(4,
467 "movq %[rseq_scratch2], %[len]\n\t"
468 "movq %[rseq_scratch1], %[dst]\n\t"
469 "movq %[rseq_scratch0], %[src]\n\t",
471 RSEQ_ASM_DEFINE_TEARDOWN(5,
472 "movq %[rseq_scratch2], %[len]\n\t"
473 "movq %[rseq_scratch1], %[dst]\n\t"
474 "movq %[rseq_scratch0], %[src]\n\t",
476 #ifdef RSEQ_COMPARE_TWICE
477 RSEQ_ASM_DEFINE_TEARDOWN(6,
478 "movq %[rseq_scratch2], %[len]\n\t"
479 "movq %[rseq_scratch1], %[dst]\n\t"
480 "movq %[rseq_scratch0], %[src]\n\t",
482 RSEQ_ASM_DEFINE_TEARDOWN(7,
483 "movq %[rseq_scratch2], %[len]\n\t"
484 "movq %[rseq_scratch1], %[dst]\n\t"
485 "movq %[rseq_scratch0], %[src]\n\t",
488 : /* gcc asm goto does not allow outputs */
489 : [cpu_id
] "r" (cpu
),
490 [rseq_offset
] "r" (rseq_offset
),
491 /* final store input */
493 [expect
] "r" (expect
),
495 /* try memcpy input */
499 [rseq_scratch0
] "m" (rseq_scratch
[0]),
500 [rseq_scratch1
] "m" (rseq_scratch
[1]),
501 [rseq_scratch2
] "m" (rseq_scratch
[2])
502 : "memory", "cc", "rax"
505 #ifdef RSEQ_COMPARE_TWICE
509 rseq_after_asm_goto();
512 rseq_after_asm_goto();
516 rseq_after_asm_goto();
518 #ifdef RSEQ_COMPARE_TWICE
520 rseq_after_asm_goto();
521 rseq_bug("cpu_id comparison failed");
523 rseq_after_asm_goto();
524 rseq_bug("expected value comparison failed");
528 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
529 (defined(RSEQ_TEMPLATE_INDEX_CPU_ID) || defined(RSEQ_TEMPLATE_INDEX_MM_CID)) */
531 #elif defined(__i386__)
534 * On x86-32, use eax as scratch register and take memory operands as
535 * input to lessen register pressure. Especially needed when compiling
539 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
540 (defined(RSEQ_TEMPLATE_INDEX_CPU_ID) || defined(RSEQ_TEMPLATE_INDEX_MM_CID))
542 static inline __attribute__((always_inline
))
543 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_store__ptr
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
546 * ref_ip is used to store a reference instruction pointer
547 * for ip-relative addressing.
555 __asm__ __volatile__
goto (
556 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
557 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[ne
])
558 #ifdef RSEQ_COMPARE_TWICE
559 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
560 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
562 /* Start rseq by storing table entry pointer into rseq_cs. */
563 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]), %[ref_ip
], RSEQ_ASM_REF_LABEL
)
564 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
566 "cmpl %[v], %[expect]\n\t"
569 #ifdef RSEQ_COMPARE_TWICE
570 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
571 "cmpl %[v], %[expect]\n\t"
575 "movl %[newv], %[v]\n\t"
578 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
579 : /* gcc asm goto does not allow outputs */
580 : [cpu_id
] "r" (cpu
),
581 [rseq_offset
] "r" (rseq_offset
),
583 [expect
] "r" (expect
),
585 [ref_ip
] "m" (rseq_local
.ref_ip
)
586 : "memory", "cc", "eax"
589 #ifdef RSEQ_COMPARE_TWICE
593 rseq_after_asm_goto();
596 rseq_after_asm_goto();
600 rseq_after_asm_goto();
602 #ifdef RSEQ_COMPARE_TWICE
604 rseq_after_asm_goto();
605 rseq_bug("cpu_id comparison failed");
607 rseq_after_asm_goto();
608 rseq_bug("expected value comparison failed");
612 static inline __attribute__((always_inline
))
613 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbeq_store_add_load_store__ptr
)(intptr_t *v
, intptr_t expectnot
,
614 long voffp
, intptr_t *load
, int cpu
)
617 * ref_ip is used to store a reference instruction pointer
618 * for ip-relative addressing.
626 __asm__ __volatile__
goto (
627 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
628 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[eq
])
629 #ifdef RSEQ_COMPARE_TWICE
630 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
631 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
633 /* Start rseq by storing table entry pointer into rseq_cs. */
634 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]), %[ref_ip
], RSEQ_ASM_REF_LABEL
)
635 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
637 "movl %[v], %%ebx\n\t"
638 "cmpl %%ebx, %[expectnot]\n\t"
641 #ifdef RSEQ_COMPARE_TWICE
642 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
643 "movl %[v], %%ebx\n\t"
644 "cmpl %%ebx, %[expectnot]\n\t"
647 "movl %%ebx, %[load]\n\t"
648 "addl %[voffp], %%ebx\n\t"
649 "movl (%%ebx), %%ebx\n\t"
651 "movl %%ebx, %[v]\n\t"
654 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
655 : /* gcc asm goto does not allow outputs */
656 : [cpu_id
] "r" (cpu
),
657 [rseq_offset
] "r" (rseq_offset
),
658 /* final store input */
660 [expectnot
] "r" (expectnot
),
661 [voffp
] "ir" (voffp
),
663 [ref_ip
] "m" (rseq_local
.ref_ip
)
664 : "memory", "cc", "eax", "ebx"
667 #ifdef RSEQ_COMPARE_TWICE
671 rseq_after_asm_goto();
674 rseq_after_asm_goto();
678 rseq_after_asm_goto();
680 #ifdef RSEQ_COMPARE_TWICE
682 rseq_after_asm_goto();
683 rseq_bug("cpu_id comparison failed");
685 rseq_after_asm_goto();
686 rseq_bug("expected value comparison failed");
690 static inline __attribute__((always_inline
))
691 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_add_store__ptr
)(intptr_t *v
, intptr_t count
, int cpu
)
694 * ref_ip is used to store a reference instruction pointer
695 * for ip-relative addressing.
703 __asm__ __volatile__
goto (
704 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
705 #ifdef RSEQ_COMPARE_TWICE
706 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
708 /* Start rseq by storing table entry pointer into rseq_cs. */
709 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]), %[ref_ip
], RSEQ_ASM_REF_LABEL
)
710 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
712 #ifdef RSEQ_COMPARE_TWICE
713 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
716 "addl %[count], %[v]\n\t"
719 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
720 : /* gcc asm goto does not allow outputs */
721 : [cpu_id
] "r" (cpu
),
722 [rseq_offset
] "r" (rseq_offset
),
723 /* final store input */
725 [count
] "ir" (count
),
726 [ref_ip
] "m" (rseq_local
.ref_ip
)
727 : "memory", "cc", "eax"
730 #ifdef RSEQ_COMPARE_TWICE
734 rseq_after_asm_goto();
737 rseq_after_asm_goto();
740 #ifdef RSEQ_COMPARE_TWICE
742 rseq_after_asm_goto();
743 rseq_bug("cpu_id comparison failed");
747 static inline __attribute__((always_inline
))
748 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_load_cbne_store__ptr
)(intptr_t *v
, intptr_t expect
,
749 intptr_t *v2
, intptr_t expect2
,
750 intptr_t newv
, int cpu
)
753 * ref_ip is used to store a reference instruction pointer
754 * for ip-relative addressing.
762 __asm__ __volatile__
goto (
763 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
764 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[ne
])
765 #ifdef RSEQ_COMPARE_TWICE
766 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
767 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
768 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
770 /* Start rseq by storing table entry pointer into rseq_cs. */
771 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]), %[ref_ip
], RSEQ_ASM_REF_LABEL
)
772 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
774 "cmpl %[v], %[expect]\n\t"
777 "cmpl %[expect2], %[v2]\n\t"
780 #ifdef RSEQ_COMPARE_TWICE
781 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
782 "cmpl %[v], %[expect]\n\t"
784 "cmpl %[expect2], %[v2]\n\t"
787 "movl %[newv], %%eax\n\t"
789 "movl %%eax, %[v]\n\t"
792 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
793 : /* gcc asm goto does not allow outputs */
794 : [cpu_id
] "r" (cpu
),
795 [rseq_offset
] "r" (rseq_offset
),
798 [expect2
] "r" (expect2
),
799 /* final store input */
801 [expect
] "r" (expect
),
803 [ref_ip
] "m" (rseq_local
.ref_ip
)
804 : "memory", "cc", "eax"
807 #ifdef RSEQ_COMPARE_TWICE
808 , error1
, error2
, error3
811 rseq_after_asm_goto();
814 rseq_after_asm_goto();
818 rseq_after_asm_goto();
820 #ifdef RSEQ_COMPARE_TWICE
822 rseq_after_asm_goto();
823 rseq_bug("cpu_id comparison failed");
825 rseq_after_asm_goto();
826 rseq_bug("1st expected value comparison failed");
828 rseq_after_asm_goto();
829 rseq_bug("2nd expected value comparison failed");
833 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
834 (defined(RSEQ_TEMPLATE_INDEX_CPU_ID) || defined(RSEQ_TEMPLATE_INDEX_MM_CID)) */
836 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
837 (defined(RSEQ_TEMPLATE_INDEX_CPU_ID) || defined(RSEQ_TEMPLATE_INDEX_MM_CID))
839 static inline __attribute__((always_inline
))
840 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_store_store__ptr
)(intptr_t *v
, intptr_t expect
,
841 intptr_t *v2
, intptr_t newv2
,
842 intptr_t newv
, int cpu
)
845 * ref_ip is used to store a reference instruction pointer
846 * for ip-relative addressing.
854 __asm__ __volatile__
goto (
855 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
856 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[ne
])
857 #ifdef RSEQ_COMPARE_TWICE
858 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
859 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
861 /* Start rseq by storing table entry pointer into rseq_cs. */
862 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]), %[ref_ip
], RSEQ_ASM_REF_LABEL
)
863 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
865 "movl %[expect], %%eax\n\t"
866 "cmpl %[v], %%eax\n\t"
869 #ifdef RSEQ_COMPARE_TWICE
870 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
871 "movl %[expect], %%eax\n\t"
872 "cmpl %[v], %%eax\n\t"
876 "movl %[newv2], %[v2]\n\t"
878 #ifdef RSEQ_TEMPLATE_MO_RELEASE
879 "lock; addl $0,-128(%%esp)\n\t"
882 "movl %[newv], %[v]\n\t"
885 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
886 : /* gcc asm goto does not allow outputs */
887 : [cpu_id
] "r" (cpu
),
888 [rseq_offset
] "r" (rseq_offset
),
889 /* try store input */
892 /* final store input */
894 [expect
] "m" (expect
),
896 [ref_ip
] "m" (rseq_local
.ref_ip
)
897 : "memory", "cc", "eax"
900 #ifdef RSEQ_COMPARE_TWICE
904 rseq_after_asm_goto();
907 rseq_after_asm_goto();
911 rseq_after_asm_goto();
913 #ifdef RSEQ_COMPARE_TWICE
915 rseq_after_asm_goto();
916 rseq_bug("cpu_id comparison failed");
918 rseq_after_asm_goto();
919 rseq_bug("expected value comparison failed");
924 /* TODO: implement a faster memcpy. */
925 static inline __attribute__((always_inline
))
926 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_memcpy_store__ptr
)(intptr_t *v
, intptr_t expect
,
927 void *dst
, void *src
, size_t len
,
928 intptr_t newv
, int cpu
)
931 * Work-around register pressure limitations.
932 * Old gcc does not support output operands for asm goto, so
933 * input registers cannot simply be re-used as output registers.
934 * This is why clobbered registers are used.
935 * ref_ip is used to store a reference instruction pointer
936 * for ip-relative addressing.
939 uint32_t expect
, dst
, src
, len
, newv
, ref_ip
;
941 .expect
= (uint32_t) expect
,
942 .dst
= (uint32_t) dst
,
943 .src
= (uint32_t) src
,
944 .len
= (uint32_t) len
,
945 .newv
= (uint32_t) newv
,
951 __asm__ __volatile__
goto (
952 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
953 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[ne
])
954 #ifdef RSEQ_COMPARE_TWICE
955 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
956 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
958 /* Start rseq by storing table entry pointer into rseq_cs. */
959 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, RSEQ_ASM_TP_SEGMENT
:RSEQ_ASM_CS_OFFSET(%[rseq_offset
]), %[ref_ip
], RSEQ_ASM_REF_LABEL
)
960 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), 4f
)
962 /* load expect into ebx */
963 "movl %[expect], %%ebx\n\t"
964 "cmpl %%ebx, %[v]\n\t"
967 #ifdef RSEQ_COMPARE_TWICE
968 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, RSEQ_ASM_TP_SEGMENT
:RSEQ_TEMPLATE_INDEX_CPU_ID_OFFSET(%[rseq_offset
]), %l
[error1
])
969 "cmpl %%ebx, %[v]\n\t"
973 /* load dst into ebx */
974 "movl %[dst], %%ebx\n\t"
975 /* load src into ecx */
976 "movl %[src], %%ecx\n\t"
977 /* load len into edx */
978 "movl %[len], %%edx\n\t"
979 "test %%edx, %%edx\n\t"
982 "movb (%%ecx), %%al\n\t"
983 "movb %%al, (%%ebx)\n\t"
990 #ifdef RSEQ_TEMPLATE_MO_RELEASE
991 "lock; addl $0,-128(%%esp)\n\t"
993 /* load newv into ebx */
994 "movl %[newv], %%ebx\n\t"
996 "movl %%ebx, %[v]\n\t"
999 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
1000 : /* gcc asm goto does not allow outputs */
1001 : [cpu_id
] "r" (cpu
),
1002 [rseq_offset
] "r" (rseq_offset
),
1003 /* final store input */
1005 /* try memcpy input */
1006 [expect
] "m" (rseq_local
.expect
), /* ebx */
1007 [dst
] "m" (rseq_local
.dst
), /* ebx */
1008 [src
] "m" (rseq_local
.src
), /* ecx */
1009 [len
] "m" (rseq_local
.len
), /* edx */
1010 [newv
] "m" (rseq_local
.newv
), /* ebx */
1011 [ref_ip
] "m" (rseq_local
.ref_ip
)
1012 : "memory", "cc", "eax", "ebx", "ecx", "edx"
1015 #ifdef RSEQ_COMPARE_TWICE
1019 rseq_after_asm_goto();
1022 rseq_after_asm_goto();
1026 rseq_after_asm_goto();
1028 #ifdef RSEQ_COMPARE_TWICE
1030 rseq_after_asm_goto();
1031 rseq_bug("cpu_id comparison failed");
1033 rseq_after_asm_goto();
1034 rseq_bug("expected value comparison failed");
1038 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
1039 (defined(RSEQ_TEMPLATE_INDEX_CPU_ID) || defined(RSEQ_TEMPLATE_INDEX_MM_CID)) */
1043 #include "rseq/arch/templates/bits-reset.h"