0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 #ifdef __ARMEB__
0058 #define RSEQ_SIG 0xf3def5e7
0059 #else
0060 #define RSEQ_SIG 0xe7f5def3
0061 #endif
0062
0063 #define rseq_smp_mb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
0064 #define rseq_smp_rmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
0065 #define rseq_smp_wmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
0066
0067 #define rseq_smp_load_acquire(p) \
0068 __extension__ ({ \
0069 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
0070 rseq_smp_mb(); \
0071 ____p1; \
0072 })
0073
0074 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
0075
0076 #define rseq_smp_store_release(p, v) \
0077 do { \
0078 rseq_smp_mb(); \
0079 RSEQ_WRITE_ONCE(*p, v); \
0080 } while (0)
0081
0082 #ifdef RSEQ_SKIP_FASTPATH
0083 #include "rseq-skip.h"
0084 #else
0085
0086 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
0087 post_commit_offset, abort_ip) \
0088 ".pushsection __rseq_cs, \"aw\"\n\t" \
0089 ".balign 32\n\t" \
0090 __rseq_str(label) ":\n\t" \
0091 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
0092 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
0093 ".popsection\n\t" \
0094 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
0095 ".word " __rseq_str(label) "b, 0x0\n\t" \
0096 ".popsection\n\t"
0097
0098 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
0099 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
0100 (post_commit_ip - start_ip), abort_ip)
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
0111 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
0112 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
0113 ".popsection\n\t"
0114
0115 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
0116 RSEQ_INJECT_ASM(1) \
0117 "adr r0, " __rseq_str(cs_label) "\n\t" \
0118 "str r0, %[" __rseq_str(rseq_cs) "]\n\t" \
0119 __rseq_str(label) ":\n\t"
0120
0121 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
0122 RSEQ_INJECT_ASM(2) \
0123 "ldr r0, %[" __rseq_str(current_cpu_id) "]\n\t" \
0124 "cmp %[" __rseq_str(cpu_id) "], r0\n\t" \
0125 "bne " __rseq_str(label) "\n\t"
0126
0127 #define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
0128 abort_label, version, flags, \
0129 start_ip, post_commit_offset, abort_ip) \
0130 ".balign 32\n\t" \
0131 __rseq_str(table_label) ":\n\t" \
0132 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
0133 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
0134 ".word " __rseq_str(RSEQ_SIG) "\n\t" \
0135 __rseq_str(label) ":\n\t" \
0136 teardown \
0137 "b %l[" __rseq_str(abort_label) "]\n\t"
0138
0139 #define RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, abort_label, \
0140 start_ip, post_commit_ip, abort_ip) \
0141 __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
0142 abort_label, 0x0, 0x0, start_ip, \
0143 (post_commit_ip - start_ip), abort_ip)
0144
0145 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
0146 __rseq_str(label) ":\n\t" \
0147 teardown \
0148 "b %l[" __rseq_str(cmpfail_label) "]\n\t"
0149
0150 static inline __attribute__((always_inline))
0151 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
0152 {
0153 RSEQ_INJECT_C(9)
0154
0155 __asm__ __volatile__ goto (
0156 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
0157 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0158 #ifdef RSEQ_COMPARE_TWICE
0159 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0160 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0161 #endif
0162
0163 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
0164 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
0165 RSEQ_INJECT_ASM(3)
0166 "ldr r0, %[v]\n\t"
0167 "cmp %[expect], r0\n\t"
0168 "bne %l[cmpfail]\n\t"
0169 RSEQ_INJECT_ASM(4)
0170 #ifdef RSEQ_COMPARE_TWICE
0171 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
0172 "ldr r0, %[v]\n\t"
0173 "cmp %[expect], r0\n\t"
0174 "bne %l[error2]\n\t"
0175 #endif
0176
0177 "str %[newv], %[v]\n\t"
0178 "2:\n\t"
0179 RSEQ_INJECT_ASM(5)
0180 "b 5f\n\t"
0181 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
0182 "5:\n\t"
0183 :
0184 : [cpu_id] "r" (cpu),
0185 [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
0186 [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
0187 [v] "m" (*v),
0188 [expect] "r" (expect),
0189 [newv] "r" (newv)
0190 RSEQ_INJECT_INPUT
0191 : "r0", "memory", "cc"
0192 RSEQ_INJECT_CLOBBER
0193 : abort, cmpfail
0194 #ifdef RSEQ_COMPARE_TWICE
0195 , error1, error2
0196 #endif
0197 );
0198 rseq_after_asm_goto();
0199 return 0;
0200 abort:
0201 rseq_after_asm_goto();
0202 RSEQ_INJECT_FAILED
0203 return -1;
0204 cmpfail:
0205 rseq_after_asm_goto();
0206 return 1;
0207 #ifdef RSEQ_COMPARE_TWICE
0208 error1:
0209 rseq_after_asm_goto();
0210 rseq_bug("cpu_id comparison failed");
0211 error2:
0212 rseq_after_asm_goto();
0213 rseq_bug("expected value comparison failed");
0214 #endif
0215 }
0216
0217 static inline __attribute__((always_inline))
0218 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
0219 long voffp, intptr_t *load, int cpu)
0220 {
0221 RSEQ_INJECT_C(9)
0222
0223 __asm__ __volatile__ goto (
0224 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
0225 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0226 #ifdef RSEQ_COMPARE_TWICE
0227 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0228 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0229 #endif
0230
0231 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
0232 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
0233 RSEQ_INJECT_ASM(3)
0234 "ldr r0, %[v]\n\t"
0235 "cmp %[expectnot], r0\n\t"
0236 "beq %l[cmpfail]\n\t"
0237 RSEQ_INJECT_ASM(4)
0238 #ifdef RSEQ_COMPARE_TWICE
0239 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
0240 "ldr r0, %[v]\n\t"
0241 "cmp %[expectnot], r0\n\t"
0242 "beq %l[error2]\n\t"
0243 #endif
0244 "str r0, %[load]\n\t"
0245 "add r0, %[voffp]\n\t"
0246 "ldr r0, [r0]\n\t"
0247
0248 "str r0, %[v]\n\t"
0249 "2:\n\t"
0250 RSEQ_INJECT_ASM(5)
0251 "b 5f\n\t"
0252 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
0253 "5:\n\t"
0254 :
0255 : [cpu_id] "r" (cpu),
0256 [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
0257 [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
0258
0259 [v] "m" (*v),
0260 [expectnot] "r" (expectnot),
0261 [voffp] "Ir" (voffp),
0262 [load] "m" (*load)
0263 RSEQ_INJECT_INPUT
0264 : "r0", "memory", "cc"
0265 RSEQ_INJECT_CLOBBER
0266 : abort, cmpfail
0267 #ifdef RSEQ_COMPARE_TWICE
0268 , error1, error2
0269 #endif
0270 );
0271 rseq_after_asm_goto();
0272 return 0;
0273 abort:
0274 rseq_after_asm_goto();
0275 RSEQ_INJECT_FAILED
0276 return -1;
0277 cmpfail:
0278 rseq_after_asm_goto();
0279 return 1;
0280 #ifdef RSEQ_COMPARE_TWICE
0281 error1:
0282 rseq_after_asm_goto();
0283 rseq_bug("cpu_id comparison failed");
0284 error2:
0285 rseq_after_asm_goto();
0286 rseq_bug("expected value comparison failed");
0287 #endif
0288 }
0289
0290 static inline __attribute__((always_inline))
0291 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
0292 {
0293 RSEQ_INJECT_C(9)
0294
0295 __asm__ __volatile__ goto (
0296 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
0297 #ifdef RSEQ_COMPARE_TWICE
0298 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0299 #endif
0300
0301 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
0302 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
0303 RSEQ_INJECT_ASM(3)
0304 #ifdef RSEQ_COMPARE_TWICE
0305 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
0306 #endif
0307 "ldr r0, %[v]\n\t"
0308 "add r0, %[count]\n\t"
0309
0310 "str r0, %[v]\n\t"
0311 "2:\n\t"
0312 RSEQ_INJECT_ASM(4)
0313 "b 5f\n\t"
0314 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
0315 "5:\n\t"
0316 :
0317 : [cpu_id] "r" (cpu),
0318 [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
0319 [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
0320 [v] "m" (*v),
0321 [count] "Ir" (count)
0322 RSEQ_INJECT_INPUT
0323 : "r0", "memory", "cc"
0324 RSEQ_INJECT_CLOBBER
0325 : abort
0326 #ifdef RSEQ_COMPARE_TWICE
0327 , error1
0328 #endif
0329 );
0330 rseq_after_asm_goto();
0331 return 0;
0332 abort:
0333 rseq_after_asm_goto();
0334 RSEQ_INJECT_FAILED
0335 return -1;
0336 #ifdef RSEQ_COMPARE_TWICE
0337 error1:
0338 rseq_after_asm_goto();
0339 rseq_bug("cpu_id comparison failed");
0340 #endif
0341 }
0342
0343 static inline __attribute__((always_inline))
0344 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
0345 intptr_t *v2, intptr_t newv2,
0346 intptr_t newv, int cpu)
0347 {
0348 RSEQ_INJECT_C(9)
0349
0350 __asm__ __volatile__ goto (
0351 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
0352 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0353 #ifdef RSEQ_COMPARE_TWICE
0354 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0355 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0356 #endif
0357
0358 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
0359 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
0360 RSEQ_INJECT_ASM(3)
0361 "ldr r0, %[v]\n\t"
0362 "cmp %[expect], r0\n\t"
0363 "bne %l[cmpfail]\n\t"
0364 RSEQ_INJECT_ASM(4)
0365 #ifdef RSEQ_COMPARE_TWICE
0366 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
0367 "ldr r0, %[v]\n\t"
0368 "cmp %[expect], r0\n\t"
0369 "bne %l[error2]\n\t"
0370 #endif
0371
0372 "str %[newv2], %[v2]\n\t"
0373 RSEQ_INJECT_ASM(5)
0374
0375 "str %[newv], %[v]\n\t"
0376 "2:\n\t"
0377 RSEQ_INJECT_ASM(6)
0378 "b 5f\n\t"
0379 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
0380 "5:\n\t"
0381 :
0382 : [cpu_id] "r" (cpu),
0383 [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
0384 [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
0385
0386 [v2] "m" (*v2),
0387 [newv2] "r" (newv2),
0388
0389 [v] "m" (*v),
0390 [expect] "r" (expect),
0391 [newv] "r" (newv)
0392 RSEQ_INJECT_INPUT
0393 : "r0", "memory", "cc"
0394 RSEQ_INJECT_CLOBBER
0395 : abort, cmpfail
0396 #ifdef RSEQ_COMPARE_TWICE
0397 , error1, error2
0398 #endif
0399 );
0400 rseq_after_asm_goto();
0401 return 0;
0402 abort:
0403 rseq_after_asm_goto();
0404 RSEQ_INJECT_FAILED
0405 return -1;
0406 cmpfail:
0407 rseq_after_asm_goto();
0408 return 1;
0409 #ifdef RSEQ_COMPARE_TWICE
0410 error1:
0411 rseq_after_asm_goto();
0412 rseq_bug("cpu_id comparison failed");
0413 error2:
0414 rseq_after_asm_goto();
0415 rseq_bug("expected value comparison failed");
0416 #endif
0417 }
0418
0419 static inline __attribute__((always_inline))
0420 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
0421 intptr_t *v2, intptr_t newv2,
0422 intptr_t newv, int cpu)
0423 {
0424 RSEQ_INJECT_C(9)
0425
0426 __asm__ __volatile__ goto (
0427 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
0428 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0429 #ifdef RSEQ_COMPARE_TWICE
0430 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0431 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0432 #endif
0433
0434 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
0435 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
0436 RSEQ_INJECT_ASM(3)
0437 "ldr r0, %[v]\n\t"
0438 "cmp %[expect], r0\n\t"
0439 "bne %l[cmpfail]\n\t"
0440 RSEQ_INJECT_ASM(4)
0441 #ifdef RSEQ_COMPARE_TWICE
0442 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
0443 "ldr r0, %[v]\n\t"
0444 "cmp %[expect], r0\n\t"
0445 "bne %l[error2]\n\t"
0446 #endif
0447
0448 "str %[newv2], %[v2]\n\t"
0449 RSEQ_INJECT_ASM(5)
0450 "dmb\n\t"
0451
0452 "str %[newv], %[v]\n\t"
0453 "2:\n\t"
0454 RSEQ_INJECT_ASM(6)
0455 "b 5f\n\t"
0456 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
0457 "5:\n\t"
0458 :
0459 : [cpu_id] "r" (cpu),
0460 [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
0461 [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
0462
0463 [v2] "m" (*v2),
0464 [newv2] "r" (newv2),
0465
0466 [v] "m" (*v),
0467 [expect] "r" (expect),
0468 [newv] "r" (newv)
0469 RSEQ_INJECT_INPUT
0470 : "r0", "memory", "cc"
0471 RSEQ_INJECT_CLOBBER
0472 : abort, cmpfail
0473 #ifdef RSEQ_COMPARE_TWICE
0474 , error1, error2
0475 #endif
0476 );
0477 rseq_after_asm_goto();
0478 return 0;
0479 abort:
0480 rseq_after_asm_goto();
0481 RSEQ_INJECT_FAILED
0482 return -1;
0483 cmpfail:
0484 rseq_after_asm_goto();
0485 return 1;
0486 #ifdef RSEQ_COMPARE_TWICE
0487 error1:
0488 rseq_after_asm_goto();
0489 rseq_bug("cpu_id comparison failed");
0490 error2:
0491 rseq_after_asm_goto();
0492 rseq_bug("expected value comparison failed");
0493 #endif
0494 }
0495
0496 static inline __attribute__((always_inline))
0497 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
0498 intptr_t *v2, intptr_t expect2,
0499 intptr_t newv, int cpu)
0500 {
0501 RSEQ_INJECT_C(9)
0502
0503 __asm__ __volatile__ goto (
0504 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
0505 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0506 #ifdef RSEQ_COMPARE_TWICE
0507 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0508 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0509 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
0510 #endif
0511
0512 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
0513 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
0514 RSEQ_INJECT_ASM(3)
0515 "ldr r0, %[v]\n\t"
0516 "cmp %[expect], r0\n\t"
0517 "bne %l[cmpfail]\n\t"
0518 RSEQ_INJECT_ASM(4)
0519 "ldr r0, %[v2]\n\t"
0520 "cmp %[expect2], r0\n\t"
0521 "bne %l[cmpfail]\n\t"
0522 RSEQ_INJECT_ASM(5)
0523 #ifdef RSEQ_COMPARE_TWICE
0524 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
0525 "ldr r0, %[v]\n\t"
0526 "cmp %[expect], r0\n\t"
0527 "bne %l[error2]\n\t"
0528 "ldr r0, %[v2]\n\t"
0529 "cmp %[expect2], r0\n\t"
0530 "bne %l[error3]\n\t"
0531 #endif
0532
0533 "str %[newv], %[v]\n\t"
0534 "2:\n\t"
0535 RSEQ_INJECT_ASM(6)
0536 "b 5f\n\t"
0537 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
0538 "5:\n\t"
0539 :
0540 : [cpu_id] "r" (cpu),
0541 [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
0542 [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
0543
0544 [v2] "m" (*v2),
0545 [expect2] "r" (expect2),
0546
0547 [v] "m" (*v),
0548 [expect] "r" (expect),
0549 [newv] "r" (newv)
0550 RSEQ_INJECT_INPUT
0551 : "r0", "memory", "cc"
0552 RSEQ_INJECT_CLOBBER
0553 : abort, cmpfail
0554 #ifdef RSEQ_COMPARE_TWICE
0555 , error1, error2, error3
0556 #endif
0557 );
0558 rseq_after_asm_goto();
0559 return 0;
0560 abort:
0561 rseq_after_asm_goto();
0562 RSEQ_INJECT_FAILED
0563 return -1;
0564 cmpfail:
0565 rseq_after_asm_goto();
0566 return 1;
0567 #ifdef RSEQ_COMPARE_TWICE
0568 error1:
0569 rseq_after_asm_goto();
0570 rseq_bug("cpu_id comparison failed");
0571 error2:
0572 rseq_after_asm_goto();
0573 rseq_bug("1st expected value comparison failed");
0574 error3:
0575 rseq_after_asm_goto();
0576 rseq_bug("2nd expected value comparison failed");
0577 #endif
0578 }
0579
0580 static inline __attribute__((always_inline))
0581 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
0582 void *dst, void *src, size_t len,
0583 intptr_t newv, int cpu)
0584 {
0585 uint32_t rseq_scratch[3];
0586
0587 RSEQ_INJECT_C(9)
0588
0589 __asm__ __volatile__ goto (
0590 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
0591 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0592 #ifdef RSEQ_COMPARE_TWICE
0593 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0594 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0595 #endif
0596 "str %[src], %[rseq_scratch0]\n\t"
0597 "str %[dst], %[rseq_scratch1]\n\t"
0598 "str %[len], %[rseq_scratch2]\n\t"
0599
0600 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
0601 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
0602 RSEQ_INJECT_ASM(3)
0603 "ldr r0, %[v]\n\t"
0604 "cmp %[expect], r0\n\t"
0605 "bne 5f\n\t"
0606 RSEQ_INJECT_ASM(4)
0607 #ifdef RSEQ_COMPARE_TWICE
0608 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
0609 "ldr r0, %[v]\n\t"
0610 "cmp %[expect], r0\n\t"
0611 "bne 7f\n\t"
0612 #endif
0613
0614 "cmp %[len], #0\n\t" \
0615 "beq 333f\n\t" \
0616 "222:\n\t" \
0617 "ldrb %%r0, [%[src]]\n\t" \
0618 "strb %%r0, [%[dst]]\n\t" \
0619 "adds %[src], #1\n\t" \
0620 "adds %[dst], #1\n\t" \
0621 "subs %[len], #1\n\t" \
0622 "bne 222b\n\t" \
0623 "333:\n\t" \
0624 RSEQ_INJECT_ASM(5)
0625
0626 "str %[newv], %[v]\n\t"
0627 "2:\n\t"
0628 RSEQ_INJECT_ASM(6)
0629
0630 "ldr %[len], %[rseq_scratch2]\n\t"
0631 "ldr %[dst], %[rseq_scratch1]\n\t"
0632 "ldr %[src], %[rseq_scratch0]\n\t"
0633 "b 8f\n\t"
0634 RSEQ_ASM_DEFINE_ABORT(3, 4,
0635
0636 "ldr %[len], %[rseq_scratch2]\n\t"
0637 "ldr %[dst], %[rseq_scratch1]\n\t"
0638 "ldr %[src], %[rseq_scratch0]\n\t",
0639 abort, 1b, 2b, 4f)
0640 RSEQ_ASM_DEFINE_CMPFAIL(5,
0641
0642 "ldr %[len], %[rseq_scratch2]\n\t"
0643 "ldr %[dst], %[rseq_scratch1]\n\t"
0644 "ldr %[src], %[rseq_scratch0]\n\t",
0645 cmpfail)
0646 #ifdef RSEQ_COMPARE_TWICE
0647 RSEQ_ASM_DEFINE_CMPFAIL(6,
0648
0649 "ldr %[len], %[rseq_scratch2]\n\t"
0650 "ldr %[dst], %[rseq_scratch1]\n\t"
0651 "ldr %[src], %[rseq_scratch0]\n\t",
0652 error1)
0653 RSEQ_ASM_DEFINE_CMPFAIL(7,
0654
0655 "ldr %[len], %[rseq_scratch2]\n\t"
0656 "ldr %[dst], %[rseq_scratch1]\n\t"
0657 "ldr %[src], %[rseq_scratch0]\n\t",
0658 error2)
0659 #endif
0660 "8:\n\t"
0661 :
0662 : [cpu_id] "r" (cpu),
0663 [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
0664 [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
0665
0666 [v] "m" (*v),
0667 [expect] "r" (expect),
0668 [newv] "r" (newv),
0669
0670 [dst] "r" (dst),
0671 [src] "r" (src),
0672 [len] "r" (len),
0673 [rseq_scratch0] "m" (rseq_scratch[0]),
0674 [rseq_scratch1] "m" (rseq_scratch[1]),
0675 [rseq_scratch2] "m" (rseq_scratch[2])
0676 RSEQ_INJECT_INPUT
0677 : "r0", "memory", "cc"
0678 RSEQ_INJECT_CLOBBER
0679 : abort, cmpfail
0680 #ifdef RSEQ_COMPARE_TWICE
0681 , error1, error2
0682 #endif
0683 );
0684 rseq_after_asm_goto();
0685 return 0;
0686 abort:
0687 rseq_after_asm_goto();
0688 RSEQ_INJECT_FAILED
0689 return -1;
0690 cmpfail:
0691 rseq_after_asm_goto();
0692 return 1;
0693 #ifdef RSEQ_COMPARE_TWICE
0694 error1:
0695 rseq_after_asm_goto();
0696 rseq_bug("cpu_id comparison failed");
0697 error2:
0698 rseq_after_asm_goto();
0699 rseq_bug("expected value comparison failed");
0700 #endif
0701 }
0702
0703 static inline __attribute__((always_inline))
0704 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
0705 void *dst, void *src, size_t len,
0706 intptr_t newv, int cpu)
0707 {
0708 uint32_t rseq_scratch[3];
0709
0710 RSEQ_INJECT_C(9)
0711
0712 __asm__ __volatile__ goto (
0713 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
0714 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
0715 #ifdef RSEQ_COMPARE_TWICE
0716 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
0717 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
0718 #endif
0719 "str %[src], %[rseq_scratch0]\n\t"
0720 "str %[dst], %[rseq_scratch1]\n\t"
0721 "str %[len], %[rseq_scratch2]\n\t"
0722
0723 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
0724 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
0725 RSEQ_INJECT_ASM(3)
0726 "ldr r0, %[v]\n\t"
0727 "cmp %[expect], r0\n\t"
0728 "bne 5f\n\t"
0729 RSEQ_INJECT_ASM(4)
0730 #ifdef RSEQ_COMPARE_TWICE
0731 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
0732 "ldr r0, %[v]\n\t"
0733 "cmp %[expect], r0\n\t"
0734 "bne 7f\n\t"
0735 #endif
0736
0737 "cmp %[len], #0\n\t" \
0738 "beq 333f\n\t" \
0739 "222:\n\t" \
0740 "ldrb %%r0, [%[src]]\n\t" \
0741 "strb %%r0, [%[dst]]\n\t" \
0742 "adds %[src], #1\n\t" \
0743 "adds %[dst], #1\n\t" \
0744 "subs %[len], #1\n\t" \
0745 "bne 222b\n\t" \
0746 "333:\n\t" \
0747 RSEQ_INJECT_ASM(5)
0748 "dmb\n\t"
0749
0750 "str %[newv], %[v]\n\t"
0751 "2:\n\t"
0752 RSEQ_INJECT_ASM(6)
0753
0754 "ldr %[len], %[rseq_scratch2]\n\t"
0755 "ldr %[dst], %[rseq_scratch1]\n\t"
0756 "ldr %[src], %[rseq_scratch0]\n\t"
0757 "b 8f\n\t"
0758 RSEQ_ASM_DEFINE_ABORT(3, 4,
0759
0760 "ldr %[len], %[rseq_scratch2]\n\t"
0761 "ldr %[dst], %[rseq_scratch1]\n\t"
0762 "ldr %[src], %[rseq_scratch0]\n\t",
0763 abort, 1b, 2b, 4f)
0764 RSEQ_ASM_DEFINE_CMPFAIL(5,
0765
0766 "ldr %[len], %[rseq_scratch2]\n\t"
0767 "ldr %[dst], %[rseq_scratch1]\n\t"
0768 "ldr %[src], %[rseq_scratch0]\n\t",
0769 cmpfail)
0770 #ifdef RSEQ_COMPARE_TWICE
0771 RSEQ_ASM_DEFINE_CMPFAIL(6,
0772
0773 "ldr %[len], %[rseq_scratch2]\n\t"
0774 "ldr %[dst], %[rseq_scratch1]\n\t"
0775 "ldr %[src], %[rseq_scratch0]\n\t",
0776 error1)
0777 RSEQ_ASM_DEFINE_CMPFAIL(7,
0778
0779 "ldr %[len], %[rseq_scratch2]\n\t"
0780 "ldr %[dst], %[rseq_scratch1]\n\t"
0781 "ldr %[src], %[rseq_scratch0]\n\t",
0782 error2)
0783 #endif
0784 "8:\n\t"
0785 :
0786 : [cpu_id] "r" (cpu),
0787 [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
0788 [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
0789
0790 [v] "m" (*v),
0791 [expect] "r" (expect),
0792 [newv] "r" (newv),
0793
0794 [dst] "r" (dst),
0795 [src] "r" (src),
0796 [len] "r" (len),
0797 [rseq_scratch0] "m" (rseq_scratch[0]),
0798 [rseq_scratch1] "m" (rseq_scratch[1]),
0799 [rseq_scratch2] "m" (rseq_scratch[2])
0800 RSEQ_INJECT_INPUT
0801 : "r0", "memory", "cc"
0802 RSEQ_INJECT_CLOBBER
0803 : abort, cmpfail
0804 #ifdef RSEQ_COMPARE_TWICE
0805 , error1, error2
0806 #endif
0807 );
0808 rseq_after_asm_goto();
0809 return 0;
0810 abort:
0811 rseq_after_asm_goto();
0812 RSEQ_INJECT_FAILED
0813 return -1;
0814 cmpfail:
0815 rseq_after_asm_goto();
0816 return 1;
0817 #ifdef RSEQ_COMPARE_TWICE
0818 error1:
0819 rseq_after_asm_goto();
0820 rseq_bug("cpu_id comparison failed");
0821 error2:
0822 rseq_after_asm_goto();
0823 rseq_bug("expected value comparison failed");
0824 #endif
0825 }
0826
0827 #endif