Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/rseq: mips: Template memory ordering and percpu access mode

Introduce a rseq-mips-bits.h template header which is internally
included to generate the static inline functions covering:

- relaxed and release memory ordering,
- per-cpu-id and per-mm-cid per-cpu data access.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20221122203932.231377-15-mathieu.desnoyers@efficios.com

authored by

Mathieu Desnoyers and committed by
Peter Zijlstra
431b6328 8d4eeb8b

+487 -615
+462
tools/testing/selftests/rseq/rseq-mips-bits.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Author: Paul Burton <paul.burton@mips.com> 4 + * (C) Copyright 2018 MIPS Tech LLC 5 + * (C) Copyright 2016-2022 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> 6 + */ 7 + 8 + #include "rseq-bits-template.h" 9 + 10 + #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \ 11 + (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) 12 + 13 + static inline __attribute__((always_inline)) 14 + int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev)(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) 15 + { 16 + RSEQ_INJECT_C(9) 17 + 18 + __asm__ __volatile__ goto ( 19 + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 20 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 21 + #ifdef RSEQ_COMPARE_TWICE 22 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 23 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 24 + #endif 25 + /* Start rseq by storing table entry pointer into rseq_cs. */ 26 + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 27 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 28 + RSEQ_INJECT_ASM(3) 29 + LONG_L " $4, %[v]\n\t" 30 + "bne $4, %[expect], %l[cmpfail]\n\t" 31 + RSEQ_INJECT_ASM(4) 32 + #ifdef RSEQ_COMPARE_TWICE 33 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 34 + LONG_L " $4, %[v]\n\t" 35 + "bne $4, %[expect], %l[error2]\n\t" 36 + #endif 37 + /* final store */ 38 + LONG_S " %[newv], %[v]\n\t" 39 + "2:\n\t" 40 + RSEQ_INJECT_ASM(5) 41 + "b 5f\n\t" 42 + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 43 + "5:\n\t" 44 + : /* gcc asm goto does not allow outputs */ 45 + : [cpu_id] "r" (cpu), 46 + [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD), 47 + [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 48 + [v] "m" (*v), 49 + [expect] "r" (expect), 50 + [newv] "r" (newv) 51 + RSEQ_INJECT_INPUT 52 + : "$4", "memory" 53 + RSEQ_INJECT_CLOBBER 54 + : abort, cmpfail 55 + #ifdef RSEQ_COMPARE_TWICE 56 + , error1, error2 57 + #endif 58 + ); 59 + return 0; 60 + abort: 61 + RSEQ_INJECT_FAILED 62 + return -1; 63 + cmpfail: 64 + return 1; 65 + #ifdef RSEQ_COMPARE_TWICE 66 + error1: 67 + rseq_bug("cpu_id comparison failed"); 68 + error2: 69 + rseq_bug("expected value comparison failed"); 70 + #endif 71 + } 72 + 73 + static inline __attribute__((always_inline)) 74 + int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load)(intptr_t *v, intptr_t expectnot, 75 + long voffp, intptr_t *load, int cpu) 76 + { 77 + RSEQ_INJECT_C(9) 78 + 79 + __asm__ __volatile__ goto ( 80 + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 81 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 82 + #ifdef RSEQ_COMPARE_TWICE 83 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 84 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 85 + #endif 86 + /* Start rseq by storing table entry pointer into rseq_cs. */ 87 + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 88 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 89 + RSEQ_INJECT_ASM(3) 90 + LONG_L " $4, %[v]\n\t" 91 + "beq $4, %[expectnot], %l[cmpfail]\n\t" 92 + RSEQ_INJECT_ASM(4) 93 + #ifdef RSEQ_COMPARE_TWICE 94 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 95 + LONG_L " $4, %[v]\n\t" 96 + "beq $4, %[expectnot], %l[error2]\n\t" 97 + #endif 98 + LONG_S " $4, %[load]\n\t" 99 + LONG_ADDI " $4, %[voffp]\n\t" 100 + LONG_L " $4, 0($4)\n\t" 101 + /* final store */ 102 + LONG_S " $4, %[v]\n\t" 103 + "2:\n\t" 104 + RSEQ_INJECT_ASM(5) 105 + "b 5f\n\t" 106 + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 107 + "5:\n\t" 108 + : /* gcc asm goto does not allow outputs */ 109 + : [cpu_id] "r" (cpu), 110 + [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD), 111 + [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 112 + /* final store input */ 113 + [v] "m" (*v), 114 + [expectnot] "r" (expectnot), 115 + [voffp] "Ir" (voffp), 116 + [load] "m" (*load) 117 + RSEQ_INJECT_INPUT 118 + : "$4", "memory" 119 + RSEQ_INJECT_CLOBBER 120 + : abort, cmpfail 121 + #ifdef RSEQ_COMPARE_TWICE 122 + , error1, error2 123 + #endif 124 + ); 125 + return 0; 126 + abort: 127 + RSEQ_INJECT_FAILED 128 + return -1; 129 + cmpfail: 130 + return 1; 131 + #ifdef RSEQ_COMPARE_TWICE 132 + error1: 133 + rseq_bug("cpu_id comparison failed"); 134 + error2: 135 + rseq_bug("expected value comparison failed"); 136 + #endif 137 + } 138 + 139 + static inline __attribute__((always_inline)) 140 + int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv)(intptr_t *v, intptr_t count, int cpu) 141 + { 142 + RSEQ_INJECT_C(9) 143 + 144 + __asm__ __volatile__ goto ( 145 + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 146 + #ifdef RSEQ_COMPARE_TWICE 147 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 148 + #endif 149 + /* Start rseq by storing table entry pointer into rseq_cs. */ 150 + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 151 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 152 + RSEQ_INJECT_ASM(3) 153 + #ifdef RSEQ_COMPARE_TWICE 154 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 155 + #endif 156 + LONG_L " $4, %[v]\n\t" 157 + LONG_ADDI " $4, %[count]\n\t" 158 + /* final store */ 159 + LONG_S " $4, %[v]\n\t" 160 + "2:\n\t" 161 + RSEQ_INJECT_ASM(4) 162 + "b 5f\n\t" 163 + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 164 + "5:\n\t" 165 + : /* gcc asm goto does not allow outputs */ 166 + : [cpu_id] "r" (cpu), 167 + [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD), 168 + [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 169 + [v] "m" (*v), 170 + [count] "Ir" (count) 171 + RSEQ_INJECT_INPUT 172 + : "$4", "memory" 173 + RSEQ_INJECT_CLOBBER 174 + : abort 175 + #ifdef RSEQ_COMPARE_TWICE 176 + , error1 177 + #endif 178 + ); 179 + return 0; 180 + abort: 181 + RSEQ_INJECT_FAILED 182 + return -1; 183 + #ifdef RSEQ_COMPARE_TWICE 184 + error1: 185 + rseq_bug("cpu_id comparison failed"); 186 + #endif 187 + } 188 + 189 + static inline __attribute__((always_inline)) 190 + int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev)(intptr_t *v, intptr_t expect, 191 + intptr_t *v2, intptr_t expect2, 192 + intptr_t newv, int cpu) 193 + { 194 + RSEQ_INJECT_C(9) 195 + 196 + __asm__ __volatile__ goto ( 197 + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 198 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 199 + #ifdef RSEQ_COMPARE_TWICE 200 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 201 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 202 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3]) 203 + #endif 204 + /* Start rseq by storing table entry pointer into rseq_cs. */ 205 + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 206 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 207 + RSEQ_INJECT_ASM(3) 208 + LONG_L " $4, %[v]\n\t" 209 + "bne $4, %[expect], %l[cmpfail]\n\t" 210 + RSEQ_INJECT_ASM(4) 211 + LONG_L " $4, %[v2]\n\t" 212 + "bne $4, %[expect2], %l[cmpfail]\n\t" 213 + RSEQ_INJECT_ASM(5) 214 + #ifdef RSEQ_COMPARE_TWICE 215 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 216 + LONG_L " $4, %[v]\n\t" 217 + "bne $4, %[expect], %l[error2]\n\t" 218 + LONG_L " $4, %[v2]\n\t" 219 + "bne $4, %[expect2], %l[error3]\n\t" 220 + #endif 221 + /* final store */ 222 + LONG_S " %[newv], %[v]\n\t" 223 + "2:\n\t" 224 + RSEQ_INJECT_ASM(6) 225 + "b 5f\n\t" 226 + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 227 + "5:\n\t" 228 + : /* gcc asm goto does not allow outputs */ 229 + : [cpu_id] "r" (cpu), 230 + [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD), 231 + [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 232 + /* cmp2 input */ 233 + [v2] "m" (*v2), 234 + [expect2] "r" (expect2), 235 + /* final store input */ 236 + [v] "m" (*v), 237 + [expect] "r" (expect), 238 + [newv] "r" (newv) 239 + RSEQ_INJECT_INPUT 240 + : "$4", "memory" 241 + RSEQ_INJECT_CLOBBER 242 + : abort, cmpfail 243 + #ifdef RSEQ_COMPARE_TWICE 244 + , error1, error2, error3 245 + #endif 246 + ); 247 + return 0; 248 + abort: 249 + RSEQ_INJECT_FAILED 250 + return -1; 251 + cmpfail: 252 + return 1; 253 + #ifdef RSEQ_COMPARE_TWICE 254 + error1: 255 + rseq_bug("cpu_id comparison failed"); 256 + error2: 257 + rseq_bug("1st expected value comparison failed"); 258 + error3: 259 + rseq_bug("2nd expected value comparison failed"); 260 + #endif 261 + } 262 + 263 + #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) && 264 + (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */ 265 + 266 + #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \ 267 + (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) 268 + 269 + static inline __attribute__((always_inline)) 270 + int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev)(intptr_t *v, intptr_t expect, 271 + intptr_t *v2, intptr_t newv2, 272 + intptr_t newv, int cpu) 273 + { 274 + RSEQ_INJECT_C(9) 275 + 276 + __asm__ __volatile__ goto ( 277 + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 278 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 279 + #ifdef RSEQ_COMPARE_TWICE 280 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 281 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 282 + #endif 283 + /* Start rseq by storing table entry pointer into rseq_cs. */ 284 + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 285 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 286 + RSEQ_INJECT_ASM(3) 287 + LONG_L " $4, %[v]\n\t" 288 + "bne $4, %[expect], %l[cmpfail]\n\t" 289 + RSEQ_INJECT_ASM(4) 290 + #ifdef RSEQ_COMPARE_TWICE 291 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 292 + LONG_L " $4, %[v]\n\t" 293 + "bne $4, %[expect], %l[error2]\n\t" 294 + #endif 295 + /* try store */ 296 + LONG_S " %[newv2], %[v2]\n\t" 297 + RSEQ_INJECT_ASM(5) 298 + #ifdef RSEQ_TEMPLATE_MO_RELEASE 299 + "sync\n\t" /* full sync provides store-release */ 300 + #endif 301 + /* final store */ 302 + LONG_S " %[newv], %[v]\n\t" 303 + "2:\n\t" 304 + RSEQ_INJECT_ASM(6) 305 + "b 5f\n\t" 306 + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 307 + "5:\n\t" 308 + : /* gcc asm goto does not allow outputs */ 309 + : [cpu_id] "r" (cpu), 310 + [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD), 311 + [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 312 + /* try store input */ 313 + [v2] "m" (*v2), 314 + [newv2] "r" (newv2), 315 + /* final store input */ 316 + [v] "m" (*v), 317 + [expect] "r" (expect), 318 + [newv] "r" (newv) 319 + RSEQ_INJECT_INPUT 320 + : "$4", "memory" 321 + RSEQ_INJECT_CLOBBER 322 + : abort, cmpfail 323 + #ifdef RSEQ_COMPARE_TWICE 324 + , error1, error2 325 + #endif 326 + ); 327 + return 0; 328 + abort: 329 + RSEQ_INJECT_FAILED 330 + return -1; 331 + cmpfail: 332 + return 1; 333 + #ifdef RSEQ_COMPARE_TWICE 334 + error1: 335 + rseq_bug("cpu_id comparison failed"); 336 + error2: 337 + rseq_bug("expected value comparison failed"); 338 + #endif 339 + } 340 + 341 + static inline __attribute__((always_inline)) 342 + int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev)(intptr_t *v, intptr_t expect, 343 + void *dst, void *src, size_t len, 344 + intptr_t newv, int cpu) 345 + { 346 + uintptr_t rseq_scratch[3]; 347 + 348 + RSEQ_INJECT_C(9) 349 + 350 + __asm__ __volatile__ goto ( 351 + RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 352 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 353 + #ifdef RSEQ_COMPARE_TWICE 354 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 355 + RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 356 + #endif 357 + LONG_S " %[src], %[rseq_scratch0]\n\t" 358 + LONG_S " %[dst], %[rseq_scratch1]\n\t" 359 + LONG_S " %[len], %[rseq_scratch2]\n\t" 360 + /* Start rseq by storing table entry pointer into rseq_cs. */ 361 + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 362 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 363 + RSEQ_INJECT_ASM(3) 364 + LONG_L " $4, %[v]\n\t" 365 + "bne $4, %[expect], 5f\n\t" 366 + RSEQ_INJECT_ASM(4) 367 + #ifdef RSEQ_COMPARE_TWICE 368 + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) 369 + LONG_L " $4, %[v]\n\t" 370 + "bne $4, %[expect], 7f\n\t" 371 + #endif 372 + /* try memcpy */ 373 + "beqz %[len], 333f\n\t" \ 374 + "222:\n\t" \ 375 + "lb $4, 0(%[src])\n\t" \ 376 + "sb $4, 0(%[dst])\n\t" \ 377 + LONG_ADDI " %[src], 1\n\t" \ 378 + LONG_ADDI " %[dst], 1\n\t" \ 379 + LONG_ADDI " %[len], -1\n\t" \ 380 + "bnez %[len], 222b\n\t" \ 381 + "333:\n\t" \ 382 + RSEQ_INJECT_ASM(5) 383 + #ifdef RSEQ_TEMPLATE_MO_RELEASE 384 + "sync\n\t" /* full sync provides store-release */ 385 + #endif 386 + /* final store */ 387 + LONG_S " %[newv], %[v]\n\t" 388 + "2:\n\t" 389 + RSEQ_INJECT_ASM(6) 390 + /* teardown */ 391 + LONG_L " %[len], %[rseq_scratch2]\n\t" 392 + LONG_L " %[dst], %[rseq_scratch1]\n\t" 393 + LONG_L " %[src], %[rseq_scratch0]\n\t" 394 + "b 8f\n\t" 395 + RSEQ_ASM_DEFINE_ABORT(3, 4, 396 + /* teardown */ 397 + LONG_L " %[len], %[rseq_scratch2]\n\t" 398 + LONG_L " %[dst], %[rseq_scratch1]\n\t" 399 + LONG_L " %[src], %[rseq_scratch0]\n\t", 400 + abort, 1b, 2b, 4f) 401 + RSEQ_ASM_DEFINE_CMPFAIL(5, 402 + /* teardown */ 403 + LONG_L " %[len], %[rseq_scratch2]\n\t" 404 + LONG_L " %[dst], %[rseq_scratch1]\n\t" 405 + LONG_L " %[src], %[rseq_scratch0]\n\t", 406 + cmpfail) 407 + #ifdef RSEQ_COMPARE_TWICE 408 + RSEQ_ASM_DEFINE_CMPFAIL(6, 409 + /* teardown */ 410 + LONG_L " %[len], %[rseq_scratch2]\n\t" 411 + LONG_L " %[dst], %[rseq_scratch1]\n\t" 412 + LONG_L " %[src], %[rseq_scratch0]\n\t", 413 + error1) 414 + RSEQ_ASM_DEFINE_CMPFAIL(7, 415 + /* teardown */ 416 + LONG_L " %[len], %[rseq_scratch2]\n\t" 417 + LONG_L " %[dst], %[rseq_scratch1]\n\t" 418 + LONG_L " %[src], %[rseq_scratch0]\n\t", 419 + error2) 420 + #endif 421 + "8:\n\t" 422 + : /* gcc asm goto does not allow outputs */ 423 + : [cpu_id] "r" (cpu), 424 + [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD), 425 + [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 426 + /* final store input */ 427 + [v] "m" (*v), 428 + [expect] "r" (expect), 429 + [newv] "r" (newv), 430 + /* try memcpy input */ 431 + [dst] "r" (dst), 432 + [src] "r" (src), 433 + [len] "r" (len), 434 + [rseq_scratch0] "m" (rseq_scratch[0]), 435 + [rseq_scratch1] "m" (rseq_scratch[1]), 436 + [rseq_scratch2] "m" (rseq_scratch[2]) 437 + RSEQ_INJECT_INPUT 438 + : "$4", "memory" 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 + #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && 460 + (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */ 461 + 462 + #include "rseq-bits-reset.h"
+25 -615
tools/testing/selftests/rseq/rseq-mips.h
··· 2 2 /* 3 3 * Author: Paul Burton <paul.burton@mips.com> 4 4 * (C) Copyright 2018 MIPS Tech LLC 5 - * 6 - * Based on rseq-arm.h: 7 - * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> 5 + * (C) Copyright 2016-2022 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> 8 6 */ 9 7 10 8 /* ··· 148 150 teardown \ 149 151 "b %l[" __rseq_str(cmpfail_label) "]\n\t" 150 152 151 - static inline __attribute__((always_inline)) 152 - int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) 153 - { 154 - RSEQ_INJECT_C(9) 153 + /* Per-cpu-id indexing. */ 155 154 156 - __asm__ __volatile__ goto ( 157 - RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 158 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 159 - #ifdef RSEQ_COMPARE_TWICE 160 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 161 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 162 - #endif 163 - /* Start rseq by storing table entry pointer into rseq_cs. */ 164 - RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 165 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 166 - RSEQ_INJECT_ASM(3) 167 - LONG_L " $4, %[v]\n\t" 168 - "bne $4, %[expect], %l[cmpfail]\n\t" 169 - RSEQ_INJECT_ASM(4) 170 - #ifdef RSEQ_COMPARE_TWICE 171 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 172 - LONG_L " $4, %[v]\n\t" 173 - "bne $4, %[expect], %l[error2]\n\t" 174 - #endif 175 - /* final store */ 176 - LONG_S " %[newv], %[v]\n\t" 177 - "2:\n\t" 178 - RSEQ_INJECT_ASM(5) 179 - "b 5f\n\t" 180 - RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 181 - "5:\n\t" 182 - : /* gcc asm goto does not allow outputs */ 183 - : [cpu_id] "r" (cpu), 184 - [current_cpu_id] "m" (rseq_get_abi()->cpu_id), 185 - [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 186 - [v] "m" (*v), 187 - [expect] "r" (expect), 188 - [newv] "r" (newv) 189 - RSEQ_INJECT_INPUT 190 - : "$4", "memory" 191 - RSEQ_INJECT_CLOBBER 192 - : abort, cmpfail 193 - #ifdef RSEQ_COMPARE_TWICE 194 - , error1, error2 195 - #endif 196 - ); 197 - return 0; 198 - abort: 199 - RSEQ_INJECT_FAILED 200 - return -1; 201 - cmpfail: 202 - return 1; 203 - #ifdef RSEQ_COMPARE_TWICE 204 - error1: 205 - rseq_bug("cpu_id comparison failed"); 206 - error2: 207 - rseq_bug("expected value comparison failed"); 208 - #endif 209 - } 155 + #define RSEQ_TEMPLATE_CPU_ID 156 + #define RSEQ_TEMPLATE_MO_RELAXED 157 + #include "rseq-mips-bits.h" 158 + #undef RSEQ_TEMPLATE_MO_RELAXED 210 159 211 - static inline __attribute__((always_inline)) 212 - int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, 213 - long voffp, intptr_t *load, int cpu) 214 - { 215 - RSEQ_INJECT_C(9) 160 + #define RSEQ_TEMPLATE_MO_RELEASE 161 + #include "rseq-mips-bits.h" 162 + #undef RSEQ_TEMPLATE_MO_RELEASE 163 + #undef RSEQ_TEMPLATE_CPU_ID 216 164 217 - __asm__ __volatile__ goto ( 218 - RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 219 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 220 - #ifdef RSEQ_COMPARE_TWICE 221 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 222 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 223 - #endif 224 - /* Start rseq by storing table entry pointer into rseq_cs. */ 225 - RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 226 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 227 - RSEQ_INJECT_ASM(3) 228 - LONG_L " $4, %[v]\n\t" 229 - "beq $4, %[expectnot], %l[cmpfail]\n\t" 230 - RSEQ_INJECT_ASM(4) 231 - #ifdef RSEQ_COMPARE_TWICE 232 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 233 - LONG_L " $4, %[v]\n\t" 234 - "beq $4, %[expectnot], %l[error2]\n\t" 235 - #endif 236 - LONG_S " $4, %[load]\n\t" 237 - LONG_ADDI " $4, %[voffp]\n\t" 238 - LONG_L " $4, 0($4)\n\t" 239 - /* final store */ 240 - LONG_S " $4, %[v]\n\t" 241 - "2:\n\t" 242 - RSEQ_INJECT_ASM(5) 243 - "b 5f\n\t" 244 - RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 245 - "5:\n\t" 246 - : /* gcc asm goto does not allow outputs */ 247 - : [cpu_id] "r" (cpu), 248 - [current_cpu_id] "m" (rseq_get_abi()->cpu_id), 249 - [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 250 - /* final store input */ 251 - [v] "m" (*v), 252 - [expectnot] "r" (expectnot), 253 - [voffp] "Ir" (voffp), 254 - [load] "m" (*load) 255 - RSEQ_INJECT_INPUT 256 - : "$4", "memory" 257 - RSEQ_INJECT_CLOBBER 258 - : abort, cmpfail 259 - #ifdef RSEQ_COMPARE_TWICE 260 - , error1, error2 261 - #endif 262 - ); 263 - return 0; 264 - abort: 265 - RSEQ_INJECT_FAILED 266 - return -1; 267 - cmpfail: 268 - return 1; 269 - #ifdef RSEQ_COMPARE_TWICE 270 - error1: 271 - rseq_bug("cpu_id comparison failed"); 272 - error2: 273 - rseq_bug("expected value comparison failed"); 274 - #endif 275 - } 165 + /* Per-mm-cid indexing. */ 276 166 277 - static inline __attribute__((always_inline)) 278 - int rseq_addv(intptr_t *v, intptr_t count, int cpu) 279 - { 280 - RSEQ_INJECT_C(9) 167 + #define RSEQ_TEMPLATE_MM_CID 168 + #define RSEQ_TEMPLATE_MO_RELAXED 169 + #include "rseq-mips-bits.h" 170 + #undef RSEQ_TEMPLATE_MO_RELAXED 281 171 282 - __asm__ __volatile__ goto ( 283 - RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 284 - #ifdef RSEQ_COMPARE_TWICE 285 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 286 - #endif 287 - /* Start rseq by storing table entry pointer into rseq_cs. */ 288 - RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 289 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 290 - RSEQ_INJECT_ASM(3) 291 - #ifdef RSEQ_COMPARE_TWICE 292 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 293 - #endif 294 - LONG_L " $4, %[v]\n\t" 295 - LONG_ADDI " $4, %[count]\n\t" 296 - /* final store */ 297 - LONG_S " $4, %[v]\n\t" 298 - "2:\n\t" 299 - RSEQ_INJECT_ASM(4) 300 - "b 5f\n\t" 301 - RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 302 - "5:\n\t" 303 - : /* gcc asm goto does not allow outputs */ 304 - : [cpu_id] "r" (cpu), 305 - [current_cpu_id] "m" (rseq_get_abi()->cpu_id), 306 - [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 307 - [v] "m" (*v), 308 - [count] "Ir" (count) 309 - RSEQ_INJECT_INPUT 310 - : "$4", "memory" 311 - RSEQ_INJECT_CLOBBER 312 - : abort 313 - #ifdef RSEQ_COMPARE_TWICE 314 - , error1 315 - #endif 316 - ); 317 - return 0; 318 - abort: 319 - RSEQ_INJECT_FAILED 320 - return -1; 321 - #ifdef RSEQ_COMPARE_TWICE 322 - error1: 323 - rseq_bug("cpu_id comparison failed"); 324 - #endif 325 - } 172 + #define RSEQ_TEMPLATE_MO_RELEASE 173 + #include "rseq-mips-bits.h" 174 + #undef RSEQ_TEMPLATE_MO_RELEASE 175 + #undef RSEQ_TEMPLATE_MM_CID 326 176 327 - static inline __attribute__((always_inline)) 328 - int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, 329 - intptr_t *v2, intptr_t newv2, 330 - intptr_t newv, int cpu) 331 - { 332 - RSEQ_INJECT_C(9) 177 + /* APIs which are not based on cpu ids. */ 333 178 334 - __asm__ __volatile__ goto ( 335 - RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 336 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 337 - #ifdef RSEQ_COMPARE_TWICE 338 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 339 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 340 - #endif 341 - /* Start rseq by storing table entry pointer into rseq_cs. */ 342 - RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 343 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 344 - RSEQ_INJECT_ASM(3) 345 - LONG_L " $4, %[v]\n\t" 346 - "bne $4, %[expect], %l[cmpfail]\n\t" 347 - RSEQ_INJECT_ASM(4) 348 - #ifdef RSEQ_COMPARE_TWICE 349 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 350 - LONG_L " $4, %[v]\n\t" 351 - "bne $4, %[expect], %l[error2]\n\t" 352 - #endif 353 - /* try store */ 354 - LONG_S " %[newv2], %[v2]\n\t" 355 - RSEQ_INJECT_ASM(5) 356 - /* final store */ 357 - LONG_S " %[newv], %[v]\n\t" 358 - "2:\n\t" 359 - RSEQ_INJECT_ASM(6) 360 - "b 5f\n\t" 361 - RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 362 - "5:\n\t" 363 - : /* gcc asm goto does not allow outputs */ 364 - : [cpu_id] "r" (cpu), 365 - [current_cpu_id] "m" (rseq_get_abi()->cpu_id), 366 - [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 367 - /* try store input */ 368 - [v2] "m" (*v2), 369 - [newv2] "r" (newv2), 370 - /* final store input */ 371 - [v] "m" (*v), 372 - [expect] "r" (expect), 373 - [newv] "r" (newv) 374 - RSEQ_INJECT_INPUT 375 - : "$4", "memory" 376 - RSEQ_INJECT_CLOBBER 377 - : abort, cmpfail 378 - #ifdef RSEQ_COMPARE_TWICE 379 - , error1, error2 380 - #endif 381 - ); 382 - return 0; 383 - abort: 384 - RSEQ_INJECT_FAILED 385 - return -1; 386 - cmpfail: 387 - return 1; 388 - #ifdef RSEQ_COMPARE_TWICE 389 - error1: 390 - rseq_bug("cpu_id comparison failed"); 391 - error2: 392 - rseq_bug("expected value comparison failed"); 393 - #endif 394 - } 395 - 396 - static inline __attribute__((always_inline)) 397 - int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, 398 - intptr_t *v2, intptr_t newv2, 399 - intptr_t newv, int cpu) 400 - { 401 - RSEQ_INJECT_C(9) 402 - 403 - __asm__ __volatile__ goto ( 404 - RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 405 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 406 - #ifdef RSEQ_COMPARE_TWICE 407 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 408 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 409 - #endif 410 - /* Start rseq by storing table entry pointer into rseq_cs. */ 411 - RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 412 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 413 - RSEQ_INJECT_ASM(3) 414 - LONG_L " $4, %[v]\n\t" 415 - "bne $4, %[expect], %l[cmpfail]\n\t" 416 - RSEQ_INJECT_ASM(4) 417 - #ifdef RSEQ_COMPARE_TWICE 418 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 419 - LONG_L " $4, %[v]\n\t" 420 - "bne $4, %[expect], %l[error2]\n\t" 421 - #endif 422 - /* try store */ 423 - LONG_S " %[newv2], %[v2]\n\t" 424 - RSEQ_INJECT_ASM(5) 425 - "sync\n\t" /* full sync provides store-release */ 426 - /* final store */ 427 - LONG_S " %[newv], %[v]\n\t" 428 - "2:\n\t" 429 - RSEQ_INJECT_ASM(6) 430 - "b 5f\n\t" 431 - RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 432 - "5:\n\t" 433 - : /* gcc asm goto does not allow outputs */ 434 - : [cpu_id] "r" (cpu), 435 - [current_cpu_id] "m" (rseq_get_abi()->cpu_id), 436 - [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 437 - /* try store input */ 438 - [v2] "m" (*v2), 439 - [newv2] "r" (newv2), 440 - /* final store input */ 441 - [v] "m" (*v), 442 - [expect] "r" (expect), 443 - [newv] "r" (newv) 444 - RSEQ_INJECT_INPUT 445 - : "$4", "memory" 446 - RSEQ_INJECT_CLOBBER 447 - : abort, cmpfail 448 - #ifdef RSEQ_COMPARE_TWICE 449 - , error1, error2 450 - #endif 451 - ); 452 - return 0; 453 - abort: 454 - RSEQ_INJECT_FAILED 455 - return -1; 456 - cmpfail: 457 - return 1; 458 - #ifdef RSEQ_COMPARE_TWICE 459 - error1: 460 - rseq_bug("cpu_id comparison failed"); 461 - error2: 462 - rseq_bug("expected value comparison failed"); 463 - #endif 464 - } 465 - 466 - static inline __attribute__((always_inline)) 467 - int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, 468 - intptr_t *v2, intptr_t expect2, 469 - intptr_t newv, int cpu) 470 - { 471 - RSEQ_INJECT_C(9) 472 - 473 - __asm__ __volatile__ goto ( 474 - RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 475 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 476 - #ifdef RSEQ_COMPARE_TWICE 477 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 478 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 479 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3]) 480 - #endif 481 - /* Start rseq by storing table entry pointer into rseq_cs. */ 482 - RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 483 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 484 - RSEQ_INJECT_ASM(3) 485 - LONG_L " $4, %[v]\n\t" 486 - "bne $4, %[expect], %l[cmpfail]\n\t" 487 - RSEQ_INJECT_ASM(4) 488 - LONG_L " $4, %[v2]\n\t" 489 - "bne $4, %[expect2], %l[cmpfail]\n\t" 490 - RSEQ_INJECT_ASM(5) 491 - #ifdef RSEQ_COMPARE_TWICE 492 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) 493 - LONG_L " $4, %[v]\n\t" 494 - "bne $4, %[expect], %l[error2]\n\t" 495 - LONG_L " $4, %[v2]\n\t" 496 - "bne $4, %[expect2], %l[error3]\n\t" 497 - #endif 498 - /* final store */ 499 - LONG_S " %[newv], %[v]\n\t" 500 - "2:\n\t" 501 - RSEQ_INJECT_ASM(6) 502 - "b 5f\n\t" 503 - RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) 504 - "5:\n\t" 505 - : /* gcc asm goto does not allow outputs */ 506 - : [cpu_id] "r" (cpu), 507 - [current_cpu_id] "m" (rseq_get_abi()->cpu_id), 508 - [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 509 - /* cmp2 input */ 510 - [v2] "m" (*v2), 511 - [expect2] "r" (expect2), 512 - /* final store input */ 513 - [v] "m" (*v), 514 - [expect] "r" (expect), 515 - [newv] "r" (newv) 516 - RSEQ_INJECT_INPUT 517 - : "$4", "memory" 518 - RSEQ_INJECT_CLOBBER 519 - : abort, cmpfail 520 - #ifdef RSEQ_COMPARE_TWICE 521 - , error1, error2, error3 522 - #endif 523 - ); 524 - return 0; 525 - abort: 526 - RSEQ_INJECT_FAILED 527 - return -1; 528 - cmpfail: 529 - return 1; 530 - #ifdef RSEQ_COMPARE_TWICE 531 - error1: 532 - rseq_bug("cpu_id comparison failed"); 533 - error2: 534 - rseq_bug("1st expected value comparison failed"); 535 - error3: 536 - rseq_bug("2nd expected value comparison failed"); 537 - #endif 538 - } 539 - 540 - static inline __attribute__((always_inline)) 541 - int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, 542 - void *dst, void *src, size_t len, 543 - intptr_t newv, int cpu) 544 - { 545 - uintptr_t rseq_scratch[3]; 546 - 547 - RSEQ_INJECT_C(9) 548 - 549 - __asm__ __volatile__ goto ( 550 - RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 551 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 552 - #ifdef RSEQ_COMPARE_TWICE 553 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 554 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 555 - #endif 556 - LONG_S " %[src], %[rseq_scratch0]\n\t" 557 - LONG_S " %[dst], %[rseq_scratch1]\n\t" 558 - LONG_S " %[len], %[rseq_scratch2]\n\t" 559 - /* Start rseq by storing table entry pointer into rseq_cs. */ 560 - RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 561 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 562 - RSEQ_INJECT_ASM(3) 563 - LONG_L " $4, %[v]\n\t" 564 - "bne $4, %[expect], 5f\n\t" 565 - RSEQ_INJECT_ASM(4) 566 - #ifdef RSEQ_COMPARE_TWICE 567 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) 568 - LONG_L " $4, %[v]\n\t" 569 - "bne $4, %[expect], 7f\n\t" 570 - #endif 571 - /* try memcpy */ 572 - "beqz %[len], 333f\n\t" \ 573 - "222:\n\t" \ 574 - "lb $4, 0(%[src])\n\t" \ 575 - "sb $4, 0(%[dst])\n\t" \ 576 - LONG_ADDI " %[src], 1\n\t" \ 577 - LONG_ADDI " %[dst], 1\n\t" \ 578 - LONG_ADDI " %[len], -1\n\t" \ 579 - "bnez %[len], 222b\n\t" \ 580 - "333:\n\t" \ 581 - RSEQ_INJECT_ASM(5) 582 - /* final store */ 583 - LONG_S " %[newv], %[v]\n\t" 584 - "2:\n\t" 585 - RSEQ_INJECT_ASM(6) 586 - /* teardown */ 587 - LONG_L " %[len], %[rseq_scratch2]\n\t" 588 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 589 - LONG_L " %[src], %[rseq_scratch0]\n\t" 590 - "b 8f\n\t" 591 - RSEQ_ASM_DEFINE_ABORT(3, 4, 592 - /* teardown */ 593 - LONG_L " %[len], %[rseq_scratch2]\n\t" 594 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 595 - LONG_L " %[src], %[rseq_scratch0]\n\t", 596 - abort, 1b, 2b, 4f) 597 - RSEQ_ASM_DEFINE_CMPFAIL(5, 598 - /* teardown */ 599 - LONG_L " %[len], %[rseq_scratch2]\n\t" 600 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 601 - LONG_L " %[src], %[rseq_scratch0]\n\t", 602 - cmpfail) 603 - #ifdef RSEQ_COMPARE_TWICE 604 - RSEQ_ASM_DEFINE_CMPFAIL(6, 605 - /* teardown */ 606 - LONG_L " %[len], %[rseq_scratch2]\n\t" 607 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 608 - LONG_L " %[src], %[rseq_scratch0]\n\t", 609 - error1) 610 - RSEQ_ASM_DEFINE_CMPFAIL(7, 611 - /* teardown */ 612 - LONG_L " %[len], %[rseq_scratch2]\n\t" 613 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 614 - LONG_L " %[src], %[rseq_scratch0]\n\t", 615 - error2) 616 - #endif 617 - "8:\n\t" 618 - : /* gcc asm goto does not allow outputs */ 619 - : [cpu_id] "r" (cpu), 620 - [current_cpu_id] "m" (rseq_get_abi()->cpu_id), 621 - [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 622 - /* final store input */ 623 - [v] "m" (*v), 624 - [expect] "r" (expect), 625 - [newv] "r" (newv), 626 - /* try memcpy input */ 627 - [dst] "r" (dst), 628 - [src] "r" (src), 629 - [len] "r" (len), 630 - [rseq_scratch0] "m" (rseq_scratch[0]), 631 - [rseq_scratch1] "m" (rseq_scratch[1]), 632 - [rseq_scratch2] "m" (rseq_scratch[2]) 633 - RSEQ_INJECT_INPUT 634 - : "$4", "memory" 635 - RSEQ_INJECT_CLOBBER 636 - : abort, cmpfail 637 - #ifdef RSEQ_COMPARE_TWICE 638 - , error1, error2 639 - #endif 640 - ); 641 - return 0; 642 - abort: 643 - RSEQ_INJECT_FAILED 644 - return -1; 645 - cmpfail: 646 - return 1; 647 - #ifdef RSEQ_COMPARE_TWICE 648 - error1: 649 - rseq_bug("cpu_id comparison failed"); 650 - error2: 651 - rseq_bug("expected value comparison failed"); 652 - #endif 653 - } 654 - 655 - static inline __attribute__((always_inline)) 656 - int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, 657 - void *dst, void *src, size_t len, 658 - intptr_t newv, int cpu) 659 - { 660 - uintptr_t rseq_scratch[3]; 661 - 662 - RSEQ_INJECT_C(9) 663 - 664 - __asm__ __volatile__ goto ( 665 - RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */ 666 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail]) 667 - #ifdef RSEQ_COMPARE_TWICE 668 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1]) 669 - RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2]) 670 - #endif 671 - LONG_S " %[src], %[rseq_scratch0]\n\t" 672 - LONG_S " %[dst], %[rseq_scratch1]\n\t" 673 - LONG_S " %[len], %[rseq_scratch2]\n\t" 674 - /* Start rseq by storing table entry pointer into rseq_cs. */ 675 - RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) 676 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) 677 - RSEQ_INJECT_ASM(3) 678 - LONG_L " $4, %[v]\n\t" 679 - "bne $4, %[expect], 5f\n\t" 680 - RSEQ_INJECT_ASM(4) 681 - #ifdef RSEQ_COMPARE_TWICE 682 - RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) 683 - LONG_L " $4, %[v]\n\t" 684 - "bne $4, %[expect], 7f\n\t" 685 - #endif 686 - /* try memcpy */ 687 - "beqz %[len], 333f\n\t" \ 688 - "222:\n\t" \ 689 - "lb $4, 0(%[src])\n\t" \ 690 - "sb $4, 0(%[dst])\n\t" \ 691 - LONG_ADDI " %[src], 1\n\t" \ 692 - LONG_ADDI " %[dst], 1\n\t" \ 693 - LONG_ADDI " %[len], -1\n\t" \ 694 - "bnez %[len], 222b\n\t" \ 695 - "333:\n\t" \ 696 - RSEQ_INJECT_ASM(5) 697 - "sync\n\t" /* full sync provides store-release */ 698 - /* final store */ 699 - LONG_S " %[newv], %[v]\n\t" 700 - "2:\n\t" 701 - RSEQ_INJECT_ASM(6) 702 - /* teardown */ 703 - LONG_L " %[len], %[rseq_scratch2]\n\t" 704 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 705 - LONG_L " %[src], %[rseq_scratch0]\n\t" 706 - "b 8f\n\t" 707 - RSEQ_ASM_DEFINE_ABORT(3, 4, 708 - /* teardown */ 709 - LONG_L " %[len], %[rseq_scratch2]\n\t" 710 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 711 - LONG_L " %[src], %[rseq_scratch0]\n\t", 712 - abort, 1b, 2b, 4f) 713 - RSEQ_ASM_DEFINE_CMPFAIL(5, 714 - /* teardown */ 715 - LONG_L " %[len], %[rseq_scratch2]\n\t" 716 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 717 - LONG_L " %[src], %[rseq_scratch0]\n\t", 718 - cmpfail) 719 - #ifdef RSEQ_COMPARE_TWICE 720 - RSEQ_ASM_DEFINE_CMPFAIL(6, 721 - /* teardown */ 722 - LONG_L " %[len], %[rseq_scratch2]\n\t" 723 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 724 - LONG_L " %[src], %[rseq_scratch0]\n\t", 725 - error1) 726 - RSEQ_ASM_DEFINE_CMPFAIL(7, 727 - /* teardown */ 728 - LONG_L " %[len], %[rseq_scratch2]\n\t" 729 - LONG_L " %[dst], %[rseq_scratch1]\n\t" 730 - LONG_L " %[src], %[rseq_scratch0]\n\t", 731 - error2) 732 - #endif 733 - "8:\n\t" 734 - : /* gcc asm goto does not allow outputs */ 735 - : [cpu_id] "r" (cpu), 736 - [current_cpu_id] "m" (rseq_get_abi()->cpu_id), 737 - [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr), 738 - /* final store input */ 739 - [v] "m" (*v), 740 - [expect] "r" (expect), 741 - [newv] "r" (newv), 742 - /* try memcpy input */ 743 - [dst] "r" (dst), 744 - [src] "r" (src), 745 - [len] "r" (len), 746 - [rseq_scratch0] "m" (rseq_scratch[0]), 747 - [rseq_scratch1] "m" (rseq_scratch[1]), 748 - [rseq_scratch2] "m" (rseq_scratch[2]) 749 - RSEQ_INJECT_INPUT 750 - : "$4", "memory" 751 - RSEQ_INJECT_CLOBBER 752 - : abort, cmpfail 753 - #ifdef RSEQ_COMPARE_TWICE 754 - , error1, error2 755 - #endif 756 - ); 757 - return 0; 758 - abort: 759 - RSEQ_INJECT_FAILED 760 - return -1; 761 - cmpfail: 762 - return 1; 763 - #ifdef RSEQ_COMPARE_TWICE 764 - error1: 765 - rseq_bug("cpu_id comparison failed"); 766 - error2: 767 - rseq_bug("expected value comparison failed"); 768 - #endif 769 - } 179 + #define RSEQ_TEMPLATE_CPU_ID_NONE 180 + #define RSEQ_TEMPLATE_MO_RELAXED 181 + #include "rseq-mips-bits.h" 182 + #undef RSEQ_TEMPLATE_MO_RELAXED 183 + #undef RSEQ_TEMPLATE_CPU_ID_NONE