root/tools/testing/selftests/rseq/rseq-s390.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. rseq_cmpeqv_storev
  2. rseq_cmpnev_storeoffp_load
  3. rseq_addv
  4. rseq_cmpeqv_trystorev_storev
  5. rseq_cmpeqv_trystorev_storev_release
  6. rseq_cmpeqv_cmpeqv_storev
  7. rseq_cmpeqv_trymemcpy_storev
  8. rseq_cmpeqv_trymemcpy_storev_release

   1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
   2 
   3 /*
   4  * RSEQ_SIG uses the trap4 instruction. As Linux does not make use of the
   5  * access-register mode nor the linkage stack this instruction will always
   6  * cause a special-operation exception (the trap-enabled bit in the DUCT
   7  * is and will stay 0). The instruction pattern is
   8  *      b2 ff 0f ff     trap4   4095(%r0)
   9  */
  10 #define RSEQ_SIG        0xB2FF0FFF
  11 
  12 #define rseq_smp_mb()   __asm__ __volatile__ ("bcr 15,0" ::: "memory")
  13 #define rseq_smp_rmb()  rseq_smp_mb()
  14 #define rseq_smp_wmb()  rseq_smp_mb()
  15 
  16 #define rseq_smp_load_acquire(p)                                        \
  17 __extension__ ({                                                        \
  18         __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p);                       \
  19         rseq_barrier();                                                 \
  20         ____p1;                                                         \
  21 })
  22 
  23 #define rseq_smp_acquire__after_ctrl_dep()      rseq_smp_rmb()
  24 
  25 #define rseq_smp_store_release(p, v)                                    \
  26 do {                                                                    \
  27         rseq_barrier();                                                 \
  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 #ifdef __s390x__
  36 
  37 #define LONG_L                  "lg"
  38 #define LONG_S                  "stg"
  39 #define LONG_LT_R               "ltgr"
  40 #define LONG_CMP                "cg"
  41 #define LONG_CMP_R              "cgr"
  42 #define LONG_ADDI               "aghi"
  43 #define LONG_ADD_R              "agr"
  44 
  45 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,                  \
  46                                 start_ip, post_commit_offset, abort_ip) \
  47                 ".pushsection __rseq_cs, \"aw\"\n\t"                    \
  48                 ".balign 32\n\t"                                        \
  49                 __rseq_str(label) ":\n\t"                               \
  50                 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
  51                 ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
  52                 ".popsection\n\t"                                       \
  53                 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"          \
  54                 ".quad " __rseq_str(label) "b\n\t"                      \
  55                 ".popsection\n\t"
  56 
  57 /*
  58  * Exit points of a rseq critical section consist of all instructions outside
  59  * of the critical section where a critical section can either branch to or
  60  * reach through the normal course of its execution. The abort IP and the
  61  * post-commit IP are already part of the __rseq_cs section and should not be
  62  * explicitly defined as additional exit points. Knowing all exit points is
  63  * useful to assist debuggers stepping over the critical section.
  64  */
  65 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                   \
  66                 ".pushsection __rseq_exit_point_array, \"aw\"\n\t"      \
  67                 ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
  68                 ".popsection\n\t"
  69 
  70 #elif __s390__
  71 
  72 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,                  \
  73                                 start_ip, post_commit_offset, abort_ip) \
  74                 ".pushsection __rseq_cs, \"aw\"\n\t"                    \
  75                 ".balign 32\n\t"                                        \
  76                 __rseq_str(label) ":\n\t"                               \
  77                 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
  78                 ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \
  79                 ".popsection\n\t"                                       \
  80                 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"          \
  81                 ".long 0x0, " __rseq_str(label) "b\n\t"                 \
  82                 ".popsection\n\t"
  83 
  84 /*
  85  * Exit points of a rseq critical section consist of all instructions outside
  86  * of the critical section where a critical section can either branch to or
  87  * reach through the normal course of its execution. The abort IP and the
  88  * post-commit IP are already part of the __rseq_cs section and should not be
  89  * explicitly defined as additional exit points. Knowing all exit points is
  90  * useful to assist debuggers stepping over the critical section.
  91  */
  92 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)                   \
  93                 ".pushsection __rseq_exit_point_array, \"aw\"\n\t"      \
  94                 ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) "\n\t" \
  95                 ".popsection\n\t"
  96 
  97 #define LONG_L                  "l"
  98 #define LONG_S                  "st"
  99 #define LONG_LT_R               "ltr"
 100 #define LONG_CMP                "c"
 101 #define LONG_CMP_R              "cr"
 102 #define LONG_ADDI               "ahi"
 103 #define LONG_ADD_R              "ar"
 104 
 105 #endif
 106 
 107 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
 108         __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip,              \
 109                                 (post_commit_ip - start_ip), abort_ip)
 110 
 111 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)                \
 112                 RSEQ_INJECT_ASM(1)                                      \
 113                 "larl %%r0, " __rseq_str(cs_label) "\n\t"               \
 114                 LONG_S " %%r0, %[" __rseq_str(rseq_cs) "]\n\t"          \
 115                 __rseq_str(label) ":\n\t"
 116 
 117 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label)              \
 118                 RSEQ_INJECT_ASM(2)                                      \
 119                 "c %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \
 120                 "jnz " __rseq_str(label) "\n\t"
 121 
 122 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label)             \
 123                 ".pushsection __rseq_failure, \"ax\"\n\t"               \
 124                 ".long " __rseq_str(RSEQ_SIG) "\n\t"                    \
 125                 __rseq_str(label) ":\n\t"                               \
 126                 teardown                                                \
 127                 "jg %l[" __rseq_str(abort_label) "]\n\t"                \
 128                 ".popsection\n\t"
 129 
 130 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label)         \
 131                 ".pushsection __rseq_failure, \"ax\"\n\t"               \
 132                 __rseq_str(label) ":\n\t"                               \
 133                 teardown                                                \
 134                 "jg %l[" __rseq_str(cmpfail_label) "]\n\t"              \
 135                 ".popsection\n\t"
 136 
 137 static inline __attribute__((always_inline))
 138 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
 139 {
 140         RSEQ_INJECT_C(9)
 141 
 142         __asm__ __volatile__ goto (
 143                 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
 144                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
 145 #ifdef RSEQ_COMPARE_TWICE
 146                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
 147                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
 148 #endif
 149                 /* Start rseq by storing table entry pointer into rseq_cs. */
 150                 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
 151                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
 152                 RSEQ_INJECT_ASM(3)
 153                 LONG_CMP " %[expect], %[v]\n\t"
 154                 "jnz %l[cmpfail]\n\t"
 155                 RSEQ_INJECT_ASM(4)
 156 #ifdef RSEQ_COMPARE_TWICE
 157                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
 158                 LONG_CMP " %[expect], %[v]\n\t"
 159                 "jnz %l[error2]\n\t"
 160 #endif
 161                 /* final store */
 162                 LONG_S " %[newv], %[v]\n\t"
 163                 "2:\n\t"
 164                 RSEQ_INJECT_ASM(5)
 165                 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
 166                 : /* gcc asm goto does not allow outputs */
 167                 : [cpu_id]              "r" (cpu),
 168                   [current_cpu_id]      "m" (__rseq_abi.cpu_id),
 169                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
 170                   [v]                   "m" (*v),
 171                   [expect]              "r" (expect),
 172                   [newv]                "r" (newv)
 173                   RSEQ_INJECT_INPUT
 174                 : "memory", "cc", "r0"
 175                   RSEQ_INJECT_CLOBBER
 176                 : abort, cmpfail
 177 #ifdef RSEQ_COMPARE_TWICE
 178                   , error1, error2
 179 #endif
 180         );
 181         return 0;
 182 abort:
 183         RSEQ_INJECT_FAILED
 184         return -1;
 185 cmpfail:
 186         return 1;
 187 #ifdef RSEQ_COMPARE_TWICE
 188 error1:
 189         rseq_bug("cpu_id comparison failed");
 190 error2:
 191         rseq_bug("expected value comparison failed");
 192 #endif
 193 }
 194 
 195 /*
 196  * Compare @v against @expectnot. When it does _not_ match, load @v
 197  * into @load, and store the content of *@v + voffp into @v.
 198  */
 199 static inline __attribute__((always_inline))
 200 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
 201                                off_t voffp, intptr_t *load, int cpu)
 202 {
 203         RSEQ_INJECT_C(9)
 204 
 205         __asm__ __volatile__ goto (
 206                 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
 207                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
 208 #ifdef RSEQ_COMPARE_TWICE
 209                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
 210                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
 211 #endif
 212                 /* Start rseq by storing table entry pointer into rseq_cs. */
 213                 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
 214                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
 215                 RSEQ_INJECT_ASM(3)
 216                 LONG_L " %%r1, %[v]\n\t"
 217                 LONG_CMP_R " %%r1, %[expectnot]\n\t"
 218                 "je %l[cmpfail]\n\t"
 219                 RSEQ_INJECT_ASM(4)
 220 #ifdef RSEQ_COMPARE_TWICE
 221                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
 222                 LONG_L " %%r1, %[v]\n\t"
 223                 LONG_CMP_R " %%r1, %[expectnot]\n\t"
 224                 "je %l[error2]\n\t"
 225 #endif
 226                 LONG_S " %%r1, %[load]\n\t"
 227                 LONG_ADD_R " %%r1, %[voffp]\n\t"
 228                 LONG_L " %%r1, 0(%%r1)\n\t"
 229                 /* final store */
 230                 LONG_S " %%r1, %[v]\n\t"
 231                 "2:\n\t"
 232                 RSEQ_INJECT_ASM(5)
 233                 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
 234                 : /* gcc asm goto does not allow outputs */
 235                 : [cpu_id]              "r" (cpu),
 236                   [current_cpu_id]      "m" (__rseq_abi.cpu_id),
 237                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
 238                   /* final store input */
 239                   [v]                   "m" (*v),
 240                   [expectnot]           "r" (expectnot),
 241                   [voffp]               "r" (voffp),
 242                   [load]                "m" (*load)
 243                   RSEQ_INJECT_INPUT
 244                 : "memory", "cc", "r0", "r1"
 245                   RSEQ_INJECT_CLOBBER
 246                 : abort, cmpfail
 247 #ifdef RSEQ_COMPARE_TWICE
 248                   , error1, error2
 249 #endif
 250         );
 251         return 0;
 252 abort:
 253         RSEQ_INJECT_FAILED
 254         return -1;
 255 cmpfail:
 256         return 1;
 257 #ifdef RSEQ_COMPARE_TWICE
 258 error1:
 259         rseq_bug("cpu_id comparison failed");
 260 error2:
 261         rseq_bug("expected value comparison failed");
 262 #endif
 263 }
 264 
 265 static inline __attribute__((always_inline))
 266 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 267 {
 268         RSEQ_INJECT_C(9)
 269 
 270         __asm__ __volatile__ goto (
 271                 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
 272 #ifdef RSEQ_COMPARE_TWICE
 273                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
 274 #endif
 275                 /* Start rseq by storing table entry pointer into rseq_cs. */
 276                 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
 277                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
 278                 RSEQ_INJECT_ASM(3)
 279 #ifdef RSEQ_COMPARE_TWICE
 280                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
 281 #endif
 282                 LONG_L " %%r0, %[v]\n\t"
 283                 LONG_ADD_R " %%r0, %[count]\n\t"
 284                 /* final store */
 285                 LONG_S " %%r0, %[v]\n\t"
 286                 "2:\n\t"
 287                 RSEQ_INJECT_ASM(4)
 288                 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
 289                 : /* gcc asm goto does not allow outputs */
 290                 : [cpu_id]              "r" (cpu),
 291                   [current_cpu_id]      "m" (__rseq_abi.cpu_id),
 292                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
 293                   /* final store input */
 294                   [v]                   "m" (*v),
 295                   [count]               "r" (count)
 296                   RSEQ_INJECT_INPUT
 297                 : "memory", "cc", "r0"
 298                   RSEQ_INJECT_CLOBBER
 299                 : abort
 300 #ifdef RSEQ_COMPARE_TWICE
 301                   , error1
 302 #endif
 303         );
 304         return 0;
 305 abort:
 306         RSEQ_INJECT_FAILED
 307         return -1;
 308 #ifdef RSEQ_COMPARE_TWICE
 309 error1:
 310         rseq_bug("cpu_id comparison failed");
 311 #endif
 312 }
 313 
 314 static inline __attribute__((always_inline))
 315 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
 316                                  intptr_t *v2, intptr_t newv2,
 317                                  intptr_t newv, int cpu)
 318 {
 319         RSEQ_INJECT_C(9)
 320 
 321         __asm__ __volatile__ goto (
 322                 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
 323                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
 324 #ifdef RSEQ_COMPARE_TWICE
 325                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
 326                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
 327 #endif
 328                 /* Start rseq by storing table entry pointer into rseq_cs. */
 329                 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
 330                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
 331                 RSEQ_INJECT_ASM(3)
 332                 LONG_CMP " %[expect], %[v]\n\t"
 333                 "jnz %l[cmpfail]\n\t"
 334                 RSEQ_INJECT_ASM(4)
 335 #ifdef RSEQ_COMPARE_TWICE
 336                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
 337                 LONG_CMP " %[expect], %[v]\n\t"
 338                 "jnz %l[error2]\n\t"
 339 #endif
 340                 /* try store */
 341                 LONG_S " %[newv2], %[v2]\n\t"
 342                 RSEQ_INJECT_ASM(5)
 343                 /* final store */
 344                 LONG_S " %[newv], %[v]\n\t"
 345                 "2:\n\t"
 346                 RSEQ_INJECT_ASM(6)
 347                 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
 348                 : /* gcc asm goto does not allow outputs */
 349                 : [cpu_id]              "r" (cpu),
 350                   [current_cpu_id]      "m" (__rseq_abi.cpu_id),
 351                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
 352                   /* try store input */
 353                   [v2]                  "m" (*v2),
 354                   [newv2]               "r" (newv2),
 355                   /* final store input */
 356                   [v]                   "m" (*v),
 357                   [expect]              "r" (expect),
 358                   [newv]                "r" (newv)
 359                   RSEQ_INJECT_INPUT
 360                 : "memory", "cc", "r0"
 361                   RSEQ_INJECT_CLOBBER
 362                 : abort, cmpfail
 363 #ifdef RSEQ_COMPARE_TWICE
 364                   , error1, error2
 365 #endif
 366         );
 367         return 0;
 368 abort:
 369         RSEQ_INJECT_FAILED
 370         return -1;
 371 cmpfail:
 372         return 1;
 373 #ifdef RSEQ_COMPARE_TWICE
 374 error1:
 375         rseq_bug("cpu_id comparison failed");
 376 error2:
 377         rseq_bug("expected value comparison failed");
 378 #endif
 379 }
 380 
 381 /* s390 is TSO. */
 382 static inline __attribute__((always_inline))
 383 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
 384                                          intptr_t *v2, intptr_t newv2,
 385                                          intptr_t newv, int cpu)
 386 {
 387         return rseq_cmpeqv_trystorev_storev(v, expect, v2, newv2, newv, cpu);
 388 }
 389 
 390 static inline __attribute__((always_inline))
 391 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
 392                               intptr_t *v2, intptr_t expect2,
 393                               intptr_t newv, int cpu)
 394 {
 395         RSEQ_INJECT_C(9)
 396 
 397         __asm__ __volatile__ goto (
 398                 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
 399                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
 400 #ifdef RSEQ_COMPARE_TWICE
 401                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
 402                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
 403                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
 404 #endif
 405                 /* Start rseq by storing table entry pointer into rseq_cs. */
 406                 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
 407                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
 408                 RSEQ_INJECT_ASM(3)
 409                 LONG_CMP " %[expect], %[v]\n\t"
 410                 "jnz %l[cmpfail]\n\t"
 411                 RSEQ_INJECT_ASM(4)
 412                 LONG_CMP " %[expect2], %[v2]\n\t"
 413                 "jnz %l[cmpfail]\n\t"
 414                 RSEQ_INJECT_ASM(5)
 415 #ifdef RSEQ_COMPARE_TWICE
 416                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
 417                 LONG_CMP " %[expect], %[v]\n\t"
 418                 "jnz %l[error2]\n\t"
 419                 LONG_CMP " %[expect2], %[v2]\n\t"
 420                 "jnz %l[error3]\n\t"
 421 #endif
 422                 /* final store */
 423                 LONG_S " %[newv], %[v]\n\t"
 424                 "2:\n\t"
 425                 RSEQ_INJECT_ASM(6)
 426                 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
 427                 : /* gcc asm goto does not allow outputs */
 428                 : [cpu_id]              "r" (cpu),
 429                   [current_cpu_id]      "m" (__rseq_abi.cpu_id),
 430                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
 431                   /* cmp2 input */
 432                   [v2]                  "m" (*v2),
 433                   [expect2]             "r" (expect2),
 434                   /* final store input */
 435                   [v]                   "m" (*v),
 436                   [expect]              "r" (expect),
 437                   [newv]                "r" (newv)
 438                   RSEQ_INJECT_INPUT
 439                 : "memory", "cc", "r0"
 440                   RSEQ_INJECT_CLOBBER
 441                 : abort, cmpfail
 442 #ifdef RSEQ_COMPARE_TWICE
 443                   , error1, error2, error3
 444 #endif
 445         );
 446         return 0;
 447 abort:
 448         RSEQ_INJECT_FAILED
 449         return -1;
 450 cmpfail:
 451         return 1;
 452 #ifdef RSEQ_COMPARE_TWICE
 453 error1:
 454         rseq_bug("cpu_id comparison failed");
 455 error2:
 456         rseq_bug("1st expected value comparison failed");
 457 error3:
 458         rseq_bug("2nd expected value comparison failed");
 459 #endif
 460 }
 461 
 462 static inline __attribute__((always_inline))
 463 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
 464                                  void *dst, void *src, size_t len,
 465                                  intptr_t newv, int cpu)
 466 {
 467         uint64_t rseq_scratch[3];
 468 
 469         RSEQ_INJECT_C(9)
 470 
 471         __asm__ __volatile__ goto (
 472                 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
 473                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
 474 #ifdef RSEQ_COMPARE_TWICE
 475                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
 476                 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
 477 #endif
 478                 LONG_S " %[src], %[rseq_scratch0]\n\t"
 479                 LONG_S " %[dst], %[rseq_scratch1]\n\t"
 480                 LONG_S " %[len], %[rseq_scratch2]\n\t"
 481                 /* Start rseq by storing table entry pointer into rseq_cs. */
 482                 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
 483                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
 484                 RSEQ_INJECT_ASM(3)
 485                 LONG_CMP " %[expect], %[v]\n\t"
 486                 "jnz 5f\n\t"
 487                 RSEQ_INJECT_ASM(4)
 488 #ifdef RSEQ_COMPARE_TWICE
 489                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
 490                 LONG_CMP " %[expect], %[v]\n\t"
 491                 "jnz 7f\n\t"
 492 #endif
 493                 /* try memcpy */
 494                 LONG_LT_R " %[len], %[len]\n\t"
 495                 "jz 333f\n\t"
 496                 "222:\n\t"
 497                 "ic %%r0,0(%[src])\n\t"
 498                 "stc %%r0,0(%[dst])\n\t"
 499                 LONG_ADDI " %[src], 1\n\t"
 500                 LONG_ADDI " %[dst], 1\n\t"
 501                 LONG_ADDI " %[len], -1\n\t"
 502                 "jnz 222b\n\t"
 503                 "333:\n\t"
 504                 RSEQ_INJECT_ASM(5)
 505                 /* final store */
 506                 LONG_S " %[newv], %[v]\n\t"
 507                 "2:\n\t"
 508                 RSEQ_INJECT_ASM(6)
 509                 /* teardown */
 510                 LONG_L " %[len], %[rseq_scratch2]\n\t"
 511                 LONG_L " %[dst], %[rseq_scratch1]\n\t"
 512                 LONG_L " %[src], %[rseq_scratch0]\n\t"
 513                 RSEQ_ASM_DEFINE_ABORT(4,
 514                         LONG_L " %[len], %[rseq_scratch2]\n\t"
 515                         LONG_L " %[dst], %[rseq_scratch1]\n\t"
 516                         LONG_L " %[src], %[rseq_scratch0]\n\t",
 517                         abort)
 518                 RSEQ_ASM_DEFINE_CMPFAIL(5,
 519                         LONG_L " %[len], %[rseq_scratch2]\n\t"
 520                         LONG_L " %[dst], %[rseq_scratch1]\n\t"
 521                         LONG_L " %[src], %[rseq_scratch0]\n\t",
 522                         cmpfail)
 523 #ifdef RSEQ_COMPARE_TWICE
 524                 RSEQ_ASM_DEFINE_CMPFAIL(6,
 525                         LONG_L " %[len], %[rseq_scratch2]\n\t"
 526                         LONG_L " %[dst], %[rseq_scratch1]\n\t"
 527                         LONG_L " %[src], %[rseq_scratch0]\n\t",
 528                         error1)
 529                 RSEQ_ASM_DEFINE_CMPFAIL(7,
 530                         LONG_L " %[len], %[rseq_scratch2]\n\t"
 531                         LONG_L " %[dst], %[rseq_scratch1]\n\t"
 532                         LONG_L " %[src], %[rseq_scratch0]\n\t",
 533                         error2)
 534 #endif
 535                 : /* gcc asm goto does not allow outputs */
 536                 : [cpu_id]              "r" (cpu),
 537                   [current_cpu_id]      "m" (__rseq_abi.cpu_id),
 538                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
 539                   /* final store input */
 540                   [v]                   "m" (*v),
 541                   [expect]              "r" (expect),
 542                   [newv]                "r" (newv),
 543                   /* try memcpy input */
 544                   [dst]                 "r" (dst),
 545                   [src]                 "r" (src),
 546                   [len]                 "r" (len),
 547                   [rseq_scratch0]       "m" (rseq_scratch[0]),
 548                   [rseq_scratch1]       "m" (rseq_scratch[1]),
 549                   [rseq_scratch2]       "m" (rseq_scratch[2])
 550                   RSEQ_INJECT_INPUT
 551                 : "memory", "cc", "r0"
 552                   RSEQ_INJECT_CLOBBER
 553                 : abort, cmpfail
 554 #ifdef RSEQ_COMPARE_TWICE
 555                   , error1, error2
 556 #endif
 557         );
 558         return 0;
 559 abort:
 560         RSEQ_INJECT_FAILED
 561         return -1;
 562 cmpfail:
 563         return 1;
 564 #ifdef RSEQ_COMPARE_TWICE
 565 error1:
 566         rseq_bug("cpu_id comparison failed");
 567 error2:
 568         rseq_bug("expected value comparison failed");
 569 #endif
 570 }
 571 
 572 /* s390 is TSO. */
 573 static inline __attribute__((always_inline))
 574 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
 575                                          void *dst, void *src, size_t len,
 576                                          intptr_t newv, int cpu)
 577 {
 578         return rseq_cmpeqv_trymemcpy_storev(v, expect, dst, src, len,
 579                                             newv, cpu);
 580 }
 581 #endif /* !RSEQ_SKIP_FASTPATH */

/* [<][>][^][v][top][bottom][index][help] */