1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * rseq-ppc.h 4 * 5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> 6 * (C) Copyright 2016-2018 - Boqun Feng <boqun.feng@gmail.com> 7 */ 8 9 #define RSEQ_SIG 0x53053053 10 11 #define rseq_smp_mb() __asm__ __volatile__ ("sync" ::: "memory", "cc") 12 #define rseq_smp_lwsync() __asm__ __volatile__ ("lwsync" ::: "memory", "cc") 13 #define rseq_smp_rmb() rseq_smp_lwsync() 14 #define rseq_smp_wmb() rseq_smp_lwsync() 15 16 #define rseq_smp_load_acquire(p) \ 17 __extension__ ({ \ 18 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ 19 rseq_smp_lwsync(); \ 20 ____p1; \ 21 }) 22 23 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_lwsync() 24 25 #define rseq_smp_store_release(p, v) \ 26 do { \ 27 rseq_smp_lwsync(); \ 28 RSEQ_WRITE_ONCE(*p, v); \ 29 } while (0) 30 31 #ifdef RSEQ_SKIP_FASTPATH 32 #include "rseq-skip.h" 33 #else /* !RSEQ_SKIP_FASTPATH */ 34 35 /* 36 * The __rseq_table section can be used by debuggers to better handle 37 * single-stepping through the restartable critical sections. 38 */ 39 40 #ifdef __PPC64__ 41 42 #define STORE_WORD "std " 43 #define LOAD_WORD "ld " 44 #define LOADX_WORD "ldx " 45 #define CMP_WORD "cmpd " 46 47 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ 48 start_ip, post_commit_offset, abort_ip) \ 49 ".pushsection __rseq_table, \"aw\"\n\t" \ 50 ".balign 32\n\t" \ 51 __rseq_str(label) ":\n\t" \ 52 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ 53 ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \ 54 ".popsection\n\t" 55 56 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ 57 RSEQ_INJECT_ASM(1) \ 58 "lis %%r17, (" __rseq_str(cs_label) ")@highest\n\t" \ 59 "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@higher\n\t" \ 60 "rldicr %%r17, %%r17, 32, 31\n\t" \ 61 "oris %%r17, %%r17, (" __rseq_str(cs_label) ")@high\n\t" \ 62 "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \ 63 "std %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \ 64 __rseq_str(label) ":\n\t" 65 66 #else /* #ifdef __PPC64__ */ 67 68 #define STORE_WORD "stw " 69 #define LOAD_WORD "lwz " 70 #define LOADX_WORD "lwzx " 71 #define CMP_WORD "cmpw " 72 73 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ 74 start_ip, post_commit_offset, abort_ip) \ 75 ".pushsection __rseq_table, \"aw\"\n\t" \ 76 ".balign 32\n\t" \ 77 __rseq_str(label) ":\n\t" \ 78 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ 79 /* 32-bit only supported on BE */ \ 80 ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \ 81 ".popsection\n\t" 82 83 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ 84 RSEQ_INJECT_ASM(1) \ 85 "lis %%r17, (" __rseq_str(cs_label) ")@ha\n\t" \ 86 "addi %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \ 87 "stw %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \ 88 __rseq_str(label) ":\n\t" 89 90 #endif /* #ifdef __PPC64__ */ 91 92 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \ 93 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \ 94 (post_commit_ip - start_ip), abort_ip) 95 96 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ 97 RSEQ_INJECT_ASM(2) \ 98 "lwz %%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \ 99 "cmpw cr7, %[" __rseq_str(cpu_id) "], %%r17\n\t" \ 100 "bne- cr7, " __rseq_str(label) "\n\t" 101 102 #define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \ 103 ".pushsection __rseq_failure, \"ax\"\n\t" \ 104 ".long " __rseq_str(RSEQ_SIG) "\n\t" \ 105 __rseq_str(label) ":\n\t" \ 106 "b %l[" __rseq_str(abort_label) "]\n\t" \ 107 ".popsection\n\t" 108 109 /* 110 * RSEQ_ASM_OPs: asm operations for rseq 111 * RSEQ_ASM_OP_R_*: has hard-code registers in it 112 * RSEQ_ASM_OP_* (else): doesn't have hard-code registers(unless cr7) 113 */ 114 #define RSEQ_ASM_OP_CMPEQ(var, expect, label) \ 115 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ 116 CMP_WORD "cr7, %%r17, %[" __rseq_str(expect) "]\n\t" \ 117 "bne- cr7, " __rseq_str(label) "\n\t" 118 119 #define RSEQ_ASM_OP_CMPNE(var, expectnot, label) \ 120 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ 121 CMP_WORD "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t" \ 122 "beq- cr7, " __rseq_str(label) "\n\t" 123 124 #define RSEQ_ASM_OP_STORE(value, var) \ 125 STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" 126 127 /* Load @var to r17 */ 128 #define RSEQ_ASM_OP_R_LOAD(var) \ 129 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" 130 131 /* Store r17 to @var */ 132 #define RSEQ_ASM_OP_R_STORE(var) \ 133 STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t" 134 135 /* Add @count to r17 */ 136 #define RSEQ_ASM_OP_R_ADD(count) \ 137 "add %%r17, %[" __rseq_str(count) "], %%r17\n\t" 138 139 /* Load (r17 + voffp) to r17 */ 140 #define RSEQ_ASM_OP_R_LOADX(voffp) \ 141 LOADX_WORD "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t" 142 143 /* TODO: implement a faster memcpy. */ 144 #define RSEQ_ASM_OP_R_MEMCPY() \ 145 "cmpdi %%r19, 0\n\t" \ 146 "beq 333f\n\t" \ 147 "addi %%r20, %%r20, -1\n\t" \ 148 "addi %%r21, %%r21, -1\n\t" \ 149 "222:\n\t" \ 150 "lbzu %%r18, 1(%%r20)\n\t" \ 151 "stbu %%r18, 1(%%r21)\n\t" \ 152 "addi %%r19, %%r19, -1\n\t" \ 153 "cmpdi %%r19, 0\n\t" \ 154 "bne 222b\n\t" \ 155 "333:\n\t" \ 156 157 #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \ 158 STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ 159 __rseq_str(post_commit_label) ":\n\t" 160 161 #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \ 162 STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \ 163 __rseq_str(post_commit_label) ":\n\t" 164 165 static inline __attribute__((always_inline)) 166 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) 167 { 168 RSEQ_INJECT_C(9) 169 170 __asm__ __volatile__ goto ( 171 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ 172 /* Start rseq by storing table entry pointer into rseq_cs. */ 173 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) 174 /* cmp cpuid */ 175 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 176 RSEQ_INJECT_ASM(3) 177 /* cmp @v equal to @expect */ 178 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) 179 RSEQ_INJECT_ASM(4) 180 #ifdef RSEQ_COMPARE_TWICE 181 /* cmp cpuid */ 182 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 183 /* cmp @v equal to @expect */ 184 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) 185 #endif 186 /* final store */ 187 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) 188 RSEQ_INJECT_ASM(5) 189 RSEQ_ASM_DEFINE_ABORT(4, abort) 190 : /* gcc asm goto does not allow outputs */ 191 : [cpu_id] "r" (cpu), 192 [current_cpu_id] "m" (__rseq_abi.cpu_id), 193 [rseq_cs] "m" (__rseq_abi.rseq_cs), 194 [v] "m" (*v), 195 [expect] "r" (expect), 196 [newv] "r" (newv) 197 RSEQ_INJECT_INPUT 198 : "memory", "cc", "r17" 199 RSEQ_INJECT_CLOBBER 200 : abort, cmpfail 201 #ifdef RSEQ_COMPARE_TWICE 202 , error1, error2 203 #endif 204 ); 205 return 0; 206 abort: 207 RSEQ_INJECT_FAILED 208 return -1; 209 cmpfail: 210 return 1; 211 #ifdef RSEQ_COMPARE_TWICE 212 error1: 213 rseq_bug("cpu_id comparison failed"); 214 error2: 215 rseq_bug("expected value comparison failed"); 216 #endif 217 } 218 219 static inline __attribute__((always_inline)) 220 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, 221 off_t voffp, intptr_t *load, int cpu) 222 { 223 RSEQ_INJECT_C(9) 224 225 __asm__ __volatile__ goto ( 226 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ 227 /* Start rseq by storing table entry pointer into rseq_cs. */ 228 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) 229 /* cmp cpuid */ 230 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 231 RSEQ_INJECT_ASM(3) 232 /* cmp @v not equal to @expectnot */ 233 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail]) 234 RSEQ_INJECT_ASM(4) 235 #ifdef RSEQ_COMPARE_TWICE 236 /* cmp cpuid */ 237 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 238 /* cmp @v not equal to @expectnot */ 239 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2]) 240 #endif 241 /* load the value of @v */ 242 RSEQ_ASM_OP_R_LOAD(v) 243 /* store it in @load */ 244 RSEQ_ASM_OP_R_STORE(load) 245 /* dereference voffp(v) */ 246 RSEQ_ASM_OP_R_LOADX(voffp) 247 /* final store the value at voffp(v) */ 248 RSEQ_ASM_OP_R_FINAL_STORE(v, 2) 249 RSEQ_INJECT_ASM(5) 250 RSEQ_ASM_DEFINE_ABORT(4, abort) 251 : /* gcc asm goto does not allow outputs */ 252 : [cpu_id] "r" (cpu), 253 [current_cpu_id] "m" (__rseq_abi.cpu_id), 254 [rseq_cs] "m" (__rseq_abi.rseq_cs), 255 /* final store input */ 256 [v] "m" (*v), 257 [expectnot] "r" (expectnot), 258 [voffp] "b" (voffp), 259 [load] "m" (*load) 260 RSEQ_INJECT_INPUT 261 : "memory", "cc", "r17" 262 RSEQ_INJECT_CLOBBER 263 : abort, cmpfail 264 #ifdef RSEQ_COMPARE_TWICE 265 , error1, error2 266 #endif 267 ); 268 return 0; 269 abort: 270 RSEQ_INJECT_FAILED 271 return -1; 272 cmpfail: 273 return 1; 274 #ifdef RSEQ_COMPARE_TWICE 275 error1: 276 rseq_bug("cpu_id comparison failed"); 277 error2: 278 rseq_bug("expected value comparison failed"); 279 #endif 280 } 281 282 static inline __attribute__((always_inline)) 283 int rseq_addv(intptr_t *v, intptr_t count, int cpu) 284 { 285 RSEQ_INJECT_C(9) 286 287 __asm__ __volatile__ goto ( 288 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ 289 /* Start rseq by storing table entry pointer into rseq_cs. */ 290 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) 291 /* cmp cpuid */ 292 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 293 RSEQ_INJECT_ASM(3) 294 #ifdef RSEQ_COMPARE_TWICE 295 /* cmp cpuid */ 296 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 297 #endif 298 /* load the value of @v */ 299 RSEQ_ASM_OP_R_LOAD(v) 300 /* add @count to it */ 301 RSEQ_ASM_OP_R_ADD(count) 302 /* final store */ 303 RSEQ_ASM_OP_R_FINAL_STORE(v, 2) 304 RSEQ_INJECT_ASM(4) 305 RSEQ_ASM_DEFINE_ABORT(4, abort) 306 : /* gcc asm goto does not allow outputs */ 307 : [cpu_id] "r" (cpu), 308 [current_cpu_id] "m" (__rseq_abi.cpu_id), 309 [rseq_cs] "m" (__rseq_abi.rseq_cs), 310 /* final store input */ 311 [v] "m" (*v), 312 [count] "r" (count) 313 RSEQ_INJECT_INPUT 314 : "memory", "cc", "r17" 315 RSEQ_INJECT_CLOBBER 316 : abort 317 #ifdef RSEQ_COMPARE_TWICE 318 , error1 319 #endif 320 ); 321 return 0; 322 abort: 323 RSEQ_INJECT_FAILED 324 return -1; 325 #ifdef RSEQ_COMPARE_TWICE 326 error1: 327 rseq_bug("cpu_id comparison failed"); 328 #endif 329 } 330 331 static inline __attribute__((always_inline)) 332 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, 333 intptr_t *v2, intptr_t newv2, 334 intptr_t newv, int cpu) 335 { 336 RSEQ_INJECT_C(9) 337 338 __asm__ __volatile__ goto ( 339 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ 340 /* Start rseq by storing table entry pointer into rseq_cs. */ 341 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) 342 /* cmp cpuid */ 343 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 344 RSEQ_INJECT_ASM(3) 345 /* cmp @v equal to @expect */ 346 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) 347 RSEQ_INJECT_ASM(4) 348 #ifdef RSEQ_COMPARE_TWICE 349 /* cmp cpuid */ 350 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 351 /* cmp @v equal to @expect */ 352 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) 353 #endif 354 /* try store */ 355 RSEQ_ASM_OP_STORE(newv2, v2) 356 RSEQ_INJECT_ASM(5) 357 /* final store */ 358 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) 359 RSEQ_INJECT_ASM(6) 360 RSEQ_ASM_DEFINE_ABORT(4, abort) 361 : /* gcc asm goto does not allow outputs */ 362 : [cpu_id] "r" (cpu), 363 [current_cpu_id] "m" (__rseq_abi.cpu_id), 364 [rseq_cs] "m" (__rseq_abi.rseq_cs), 365 /* try store input */ 366 [v2] "m" (*v2), 367 [newv2] "r" (newv2), 368 /* final store input */ 369 [v] "m" (*v), 370 [expect] "r" (expect), 371 [newv] "r" (newv) 372 RSEQ_INJECT_INPUT 373 : "memory", "cc", "r17" 374 RSEQ_INJECT_CLOBBER 375 : abort, cmpfail 376 #ifdef RSEQ_COMPARE_TWICE 377 , error1, error2 378 #endif 379 ); 380 return 0; 381 abort: 382 RSEQ_INJECT_FAILED 383 return -1; 384 cmpfail: 385 return 1; 386 #ifdef RSEQ_COMPARE_TWICE 387 error1: 388 rseq_bug("cpu_id comparison failed"); 389 error2: 390 rseq_bug("expected value comparison failed"); 391 #endif 392 } 393 394 static inline __attribute__((always_inline)) 395 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, 396 intptr_t *v2, intptr_t newv2, 397 intptr_t newv, int cpu) 398 { 399 RSEQ_INJECT_C(9) 400 401 __asm__ __volatile__ goto ( 402 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ 403 /* Start rseq by storing table entry pointer into rseq_cs. */ 404 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) 405 /* cmp cpuid */ 406 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 407 RSEQ_INJECT_ASM(3) 408 /* cmp @v equal to @expect */ 409 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) 410 RSEQ_INJECT_ASM(4) 411 #ifdef RSEQ_COMPARE_TWICE 412 /* cmp cpuid */ 413 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 414 /* cmp @v equal to @expect */ 415 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) 416 #endif 417 /* try store */ 418 RSEQ_ASM_OP_STORE(newv2, v2) 419 RSEQ_INJECT_ASM(5) 420 /* for 'release' */ 421 "lwsync\n\t" 422 /* final store */ 423 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) 424 RSEQ_INJECT_ASM(6) 425 RSEQ_ASM_DEFINE_ABORT(4, abort) 426 : /* gcc asm goto does not allow outputs */ 427 : [cpu_id] "r" (cpu), 428 [current_cpu_id] "m" (__rseq_abi.cpu_id), 429 [rseq_cs] "m" (__rseq_abi.rseq_cs), 430 /* try store input */ 431 [v2] "m" (*v2), 432 [newv2] "r" (newv2), 433 /* final store input */ 434 [v] "m" (*v), 435 [expect] "r" (expect), 436 [newv] "r" (newv) 437 RSEQ_INJECT_INPUT 438 : "memory", "cc", "r17" 439 RSEQ_INJECT_CLOBBER 440 : abort, cmpfail 441 #ifdef RSEQ_COMPARE_TWICE 442 , error1, error2 443 #endif 444 ); 445 return 0; 446 abort: 447 RSEQ_INJECT_FAILED 448 return -1; 449 cmpfail: 450 return 1; 451 #ifdef RSEQ_COMPARE_TWICE 452 error1: 453 rseq_bug("cpu_id comparison failed"); 454 error2: 455 rseq_bug("expected value comparison failed"); 456 #endif 457 } 458 459 static inline __attribute__((always_inline)) 460 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, 461 intptr_t *v2, intptr_t expect2, 462 intptr_t newv, int cpu) 463 { 464 RSEQ_INJECT_C(9) 465 466 __asm__ __volatile__ goto ( 467 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ 468 /* Start rseq by storing table entry pointer into rseq_cs. */ 469 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) 470 /* cmp cpuid */ 471 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 472 RSEQ_INJECT_ASM(3) 473 /* cmp @v equal to @expect */ 474 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) 475 RSEQ_INJECT_ASM(4) 476 /* cmp @v2 equal to @expct2 */ 477 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail]) 478 RSEQ_INJECT_ASM(5) 479 #ifdef RSEQ_COMPARE_TWICE 480 /* cmp cpuid */ 481 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 482 /* cmp @v equal to @expect */ 483 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) 484 /* cmp @v2 equal to @expct2 */ 485 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3]) 486 #endif 487 /* final store */ 488 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) 489 RSEQ_INJECT_ASM(6) 490 RSEQ_ASM_DEFINE_ABORT(4, abort) 491 : /* gcc asm goto does not allow outputs */ 492 : [cpu_id] "r" (cpu), 493 [current_cpu_id] "m" (__rseq_abi.cpu_id), 494 [rseq_cs] "m" (__rseq_abi.rseq_cs), 495 /* cmp2 input */ 496 [v2] "m" (*v2), 497 [expect2] "r" (expect2), 498 /* final store input */ 499 [v] "m" (*v), 500 [expect] "r" (expect), 501 [newv] "r" (newv) 502 RSEQ_INJECT_INPUT 503 : "memory", "cc", "r17" 504 RSEQ_INJECT_CLOBBER 505 : abort, cmpfail 506 #ifdef RSEQ_COMPARE_TWICE 507 , error1, error2, error3 508 #endif 509 ); 510 return 0; 511 abort: 512 RSEQ_INJECT_FAILED 513 return -1; 514 cmpfail: 515 return 1; 516 #ifdef RSEQ_COMPARE_TWICE 517 error1: 518 rseq_bug("cpu_id comparison failed"); 519 error2: 520 rseq_bug("1st expected value comparison failed"); 521 error3: 522 rseq_bug("2nd expected value comparison failed"); 523 #endif 524 } 525 526 static inline __attribute__((always_inline)) 527 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, 528 void *dst, void *src, size_t len, 529 intptr_t newv, int cpu) 530 { 531 RSEQ_INJECT_C(9) 532 533 __asm__ __volatile__ goto ( 534 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ 535 /* setup for mempcy */ 536 "mr %%r19, %[len]\n\t" 537 "mr %%r20, %[src]\n\t" 538 "mr %%r21, %[dst]\n\t" 539 /* Start rseq by storing table entry pointer into rseq_cs. */ 540 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) 541 /* cmp cpuid */ 542 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 543 RSEQ_INJECT_ASM(3) 544 /* cmp @v equal to @expect */ 545 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) 546 RSEQ_INJECT_ASM(4) 547 #ifdef RSEQ_COMPARE_TWICE 548 /* cmp cpuid */ 549 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 550 /* cmp @v equal to @expect */ 551 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) 552 #endif 553 /* try memcpy */ 554 RSEQ_ASM_OP_R_MEMCPY() 555 RSEQ_INJECT_ASM(5) 556 /* final store */ 557 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) 558 RSEQ_INJECT_ASM(6) 559 /* teardown */ 560 RSEQ_ASM_DEFINE_ABORT(4, abort) 561 : /* gcc asm goto does not allow outputs */ 562 : [cpu_id] "r" (cpu), 563 [current_cpu_id] "m" (__rseq_abi.cpu_id), 564 [rseq_cs] "m" (__rseq_abi.rseq_cs), 565 /* final store input */ 566 [v] "m" (*v), 567 [expect] "r" (expect), 568 [newv] "r" (newv), 569 /* try memcpy input */ 570 [dst] "r" (dst), 571 [src] "r" (src), 572 [len] "r" (len) 573 RSEQ_INJECT_INPUT 574 : "memory", "cc", "r17", "r18", "r19", "r20", "r21" 575 RSEQ_INJECT_CLOBBER 576 : abort, cmpfail 577 #ifdef RSEQ_COMPARE_TWICE 578 , error1, error2 579 #endif 580 ); 581 return 0; 582 abort: 583 RSEQ_INJECT_FAILED 584 return -1; 585 cmpfail: 586 return 1; 587 #ifdef RSEQ_COMPARE_TWICE 588 error1: 589 rseq_bug("cpu_id comparison failed"); 590 error2: 591 rseq_bug("expected value comparison failed"); 592 #endif 593 } 594 595 static inline __attribute__((always_inline)) 596 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, 597 void *dst, void *src, size_t len, 598 intptr_t newv, int cpu) 599 { 600 RSEQ_INJECT_C(9) 601 602 __asm__ __volatile__ goto ( 603 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ 604 /* setup for mempcy */ 605 "mr %%r19, %[len]\n\t" 606 "mr %%r20, %[src]\n\t" 607 "mr %%r21, %[dst]\n\t" 608 /* Start rseq by storing table entry pointer into rseq_cs. */ 609 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) 610 /* cmp cpuid */ 611 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 612 RSEQ_INJECT_ASM(3) 613 /* cmp @v equal to @expect */ 614 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) 615 RSEQ_INJECT_ASM(4) 616 #ifdef RSEQ_COMPARE_TWICE 617 /* cmp cpuid */ 618 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 619 /* cmp @v equal to @expect */ 620 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) 621 #endif 622 /* try memcpy */ 623 RSEQ_ASM_OP_R_MEMCPY() 624 RSEQ_INJECT_ASM(5) 625 /* for 'release' */ 626 "lwsync\n\t" 627 /* final store */ 628 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) 629 RSEQ_INJECT_ASM(6) 630 /* teardown */ 631 RSEQ_ASM_DEFINE_ABORT(4, abort) 632 : /* gcc asm goto does not allow outputs */ 633 : [cpu_id] "r" (cpu), 634 [current_cpu_id] "m" (__rseq_abi.cpu_id), 635 [rseq_cs] "m" (__rseq_abi.rseq_cs), 636 /* final store input */ 637 [v] "m" (*v), 638 [expect] "r" (expect), 639 [newv] "r" (newv), 640 /* try memcpy input */ 641 [dst] "r" (dst), 642 [src] "r" (src), 643 [len] "r" (len) 644 RSEQ_INJECT_INPUT 645 : "memory", "cc", "r17", "r18", "r19", "r20", "r21" 646 RSEQ_INJECT_CLOBBER 647 : abort, cmpfail 648 #ifdef RSEQ_COMPARE_TWICE 649 , error1, error2 650 #endif 651 ); 652 return 0; 653 abort: 654 RSEQ_INJECT_FAILED 655 return -1; 656 cmpfail: 657 return 1; 658 #ifdef RSEQ_COMPARE_TWICE 659 error1: 660 rseq_bug("cpu_id comparison failed"); 661 error2: 662 rseq_bug("expected value comparison failed"); 663 #endif 664 } 665 666 #undef STORE_WORD 667 #undef LOAD_WORD 668 #undef LOADX_WORD 669 #undef CMP_WORD 670 671 #endif /* !RSEQ_SKIP_FASTPATH */ 672