12e155fb7SMathieu Desnoyers /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 22e155fb7SMathieu Desnoyers /* 32e155fb7SMathieu Desnoyers * rseq-ppc.h 42e155fb7SMathieu Desnoyers * 5e61bd94cSMathieu Desnoyers * (C) Copyright 2016-2022 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> 62e155fb7SMathieu Desnoyers * (C) Copyright 2016-2018 - Boqun Feng <boqun.feng@gmail.com> 72e155fb7SMathieu Desnoyers */ 82e155fb7SMathieu Desnoyers 9496fd0fcSMathieu Desnoyers /* 10496fd0fcSMathieu Desnoyers * RSEQ_SIG is used with the following trap instruction: 11496fd0fcSMathieu Desnoyers * 12496fd0fcSMathieu Desnoyers * powerpc-be: 0f e5 00 0b twui r5,11 13496fd0fcSMathieu Desnoyers * powerpc64-le: 0b 00 e5 0f twui r5,11 14496fd0fcSMathieu Desnoyers * powerpc64-be: 0f e5 00 0b twui r5,11 15496fd0fcSMathieu Desnoyers */ 16496fd0fcSMathieu Desnoyers 17496fd0fcSMathieu Desnoyers #define RSEQ_SIG 0x0fe5000b 182e155fb7SMathieu Desnoyers 192e155fb7SMathieu Desnoyers #define rseq_smp_mb() __asm__ __volatile__ ("sync" ::: "memory", "cc") 202e155fb7SMathieu Desnoyers #define rseq_smp_lwsync() __asm__ __volatile__ ("lwsync" ::: "memory", "cc") 212e155fb7SMathieu Desnoyers #define rseq_smp_rmb() rseq_smp_lwsync() 222e155fb7SMathieu Desnoyers #define rseq_smp_wmb() rseq_smp_lwsync() 232e155fb7SMathieu Desnoyers 242e155fb7SMathieu Desnoyers #define rseq_smp_load_acquire(p) \ 252e155fb7SMathieu Desnoyers __extension__ ({ \ 26*2b2fe605SMathieu Desnoyers rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \ 272e155fb7SMathieu Desnoyers rseq_smp_lwsync(); \ 282e155fb7SMathieu Desnoyers ____p1; \ 292e155fb7SMathieu Desnoyers }) 302e155fb7SMathieu Desnoyers 312e155fb7SMathieu Desnoyers #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_lwsync() 322e155fb7SMathieu Desnoyers 332e155fb7SMathieu Desnoyers #define rseq_smp_store_release(p, v) \ 342e155fb7SMathieu Desnoyers do { \ 352e155fb7SMathieu Desnoyers rseq_smp_lwsync(); \ 36*2b2fe605SMathieu Desnoyers RSEQ_WRITE_ONCE(*(p), v); \ 372e155fb7SMathieu Desnoyers } while (0) 382e155fb7SMathieu Desnoyers 392e155fb7SMathieu Desnoyers /* 40a3e3131fSMathieu Desnoyers * The __rseq_cs_ptr_array and __rseq_cs sections can be used by debuggers to 41a3e3131fSMathieu Desnoyers * better handle single-stepping through the restartable critical sections. 422e155fb7SMathieu Desnoyers */ 432e155fb7SMathieu Desnoyers 442e155fb7SMathieu Desnoyers #ifdef __PPC64__ 452e155fb7SMathieu Desnoyers 46de6b52a2SMathieu Desnoyers #define RSEQ_STORE_LONG(arg) "std%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */ 47de6b52a2SMathieu Desnoyers #define RSEQ_STORE_INT(arg) "stw%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */ 48de6b52a2SMathieu Desnoyers #define RSEQ_LOAD_LONG(arg) "ld%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */ 49de6b52a2SMathieu Desnoyers #define RSEQ_LOAD_INT(arg) "lwz%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */ 50de6b52a2SMathieu Desnoyers #define RSEQ_LOADX_LONG "ldx " /* From base register ("b" constraint) */ 51de6b52a2SMathieu Desnoyers #define RSEQ_CMP_LONG "cmpd " 52de6b52a2SMathieu Desnoyers #define RSEQ_CMP_LONG_INT "cmpdi " 532e155fb7SMathieu Desnoyers 542e155fb7SMathieu Desnoyers #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ 552e155fb7SMathieu Desnoyers start_ip, post_commit_offset, abort_ip) \ 56a3e3131fSMathieu Desnoyers ".pushsection __rseq_cs, \"aw\"\n\t" \ 572e155fb7SMathieu Desnoyers ".balign 32\n\t" \ 582e155fb7SMathieu Desnoyers __rseq_str(label) ":\n\t" \ 592e155fb7SMathieu Desnoyers ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ 602e155fb7SMathieu Desnoyers ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \ 61a3e3131fSMathieu Desnoyers ".popsection\n\t" \ 62a3e3131fSMathieu Desnoyers ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \ 63a3e3131fSMathieu Desnoyers ".quad " __rseq_str(label) "b\n\t" \ 642e155fb7SMathieu Desnoyers ".popsection\n\t" 652e155fb7SMathieu Desnoyers 662e155fb7SMathieu Desnoyers #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ 672e155fb7SMathieu Desnoyers RSEQ_INJECT_ASM(1) \ 682e155fb7SMathieu Desnoyers "lis %%r17, (" __rseq_str(cs_label) ")@highest\n\t" \ 692e155fb7SMathieu Desnoyers "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@higher\n\t" \ 702e155fb7SMathieu Desnoyers "rldicr %%r17, %%r17, 32, 31\n\t" \ 712e155fb7SMathieu Desnoyers "oris %%r17, %%r17, (" __rseq_str(cs_label) ")@high\n\t" \ 722e155fb7SMathieu Desnoyers "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \ 732e155fb7SMathieu Desnoyers "std %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \ 742e155fb7SMathieu Desnoyers __rseq_str(label) ":\n\t" 752e155fb7SMathieu Desnoyers 764fe2088eSMathieu Desnoyers /* 774fe2088eSMathieu Desnoyers * Exit points of a rseq critical section consist of all instructions outside 784fe2088eSMathieu Desnoyers * of the critical section where a critical section can either branch to or 794fe2088eSMathieu Desnoyers * reach through the normal course of its execution. The abort IP and the 80a3e3131fSMathieu Desnoyers * post-commit IP are already part of the __rseq_cs section and should not be 81a3e3131fSMathieu Desnoyers * explicitly defined as additional exit points. Knowing all exit points is 824fe2088eSMathieu Desnoyers * useful to assist debuggers stepping over the critical section. 834fe2088eSMathieu Desnoyers */ 844fe2088eSMathieu Desnoyers #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \ 854fe2088eSMathieu Desnoyers ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \ 864fe2088eSMathieu Desnoyers ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \ 874fe2088eSMathieu Desnoyers ".popsection\n\t" 884fe2088eSMathieu Desnoyers 892e155fb7SMathieu Desnoyers #else /* #ifdef __PPC64__ */ 902e155fb7SMathieu Desnoyers 91de6b52a2SMathieu Desnoyers #define RSEQ_STORE_LONG(arg) "stw%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */ 92de6b52a2SMathieu Desnoyers #define RSEQ_STORE_INT(arg) RSEQ_STORE_LONG(arg) /* To memory ("m" constraint) */ 93de6b52a2SMathieu Desnoyers #define RSEQ_LOAD_LONG(arg) "lwz%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */ 94de6b52a2SMathieu Desnoyers #define RSEQ_LOAD_INT(arg) RSEQ_LOAD_LONG(arg) /* From memory ("m" constraint) */ 95de6b52a2SMathieu Desnoyers #define RSEQ_LOADX_LONG "lwzx " /* From base register ("b" constraint) */ 96de6b52a2SMathieu Desnoyers #define RSEQ_CMP_LONG "cmpw " 97de6b52a2SMathieu Desnoyers #define RSEQ_CMP_LONG_INT "cmpwi " 982e155fb7SMathieu Desnoyers 992e155fb7SMathieu Desnoyers #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ 1002e155fb7SMathieu Desnoyers start_ip, post_commit_offset, abort_ip) \ 101a3e3131fSMathieu Desnoyers ".pushsection __rseq_cs, \"aw\"\n\t" \ 1022e155fb7SMathieu Desnoyers ".balign 32\n\t" \ 1032e155fb7SMathieu Desnoyers __rseq_str(label) ":\n\t" \ 1042e155fb7SMathieu Desnoyers ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ 1052e155fb7SMathieu Desnoyers /* 32-bit only supported on BE */ \ 1062e155fb7SMathieu Desnoyers ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \ 107a3e3131fSMathieu Desnoyers ".popsection\n\t" \ 108a3e3131fSMathieu Desnoyers ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \ 109a3e3131fSMathieu Desnoyers ".long 0x0, " __rseq_str(label) "b\n\t" \ 1102e155fb7SMathieu Desnoyers ".popsection\n\t" 1112e155fb7SMathieu Desnoyers 1124fe2088eSMathieu Desnoyers /* 1134fe2088eSMathieu Desnoyers * Exit points of a rseq critical section consist of all instructions outside 1144fe2088eSMathieu Desnoyers * of the critical section where a critical section can either branch to or 1154fe2088eSMathieu Desnoyers * reach through the normal course of its execution. The abort IP and the 116a3e3131fSMathieu Desnoyers * post-commit IP are already part of the __rseq_cs section and should not be 117a3e3131fSMathieu Desnoyers * explicitly defined as additional exit points. Knowing all exit points is 1184fe2088eSMathieu Desnoyers * useful to assist debuggers stepping over the critical section. 1194fe2088eSMathieu Desnoyers */ 1204fe2088eSMathieu Desnoyers #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \ 1214fe2088eSMathieu Desnoyers ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \ 1224fe2088eSMathieu Desnoyers /* 32-bit only supported on BE */ \ 1234fe2088eSMathieu Desnoyers ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) "\n\t" \ 1244fe2088eSMathieu Desnoyers ".popsection\n\t" 1254fe2088eSMathieu Desnoyers 1262e155fb7SMathieu Desnoyers #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ 1272e155fb7SMathieu Desnoyers RSEQ_INJECT_ASM(1) \ 1282e155fb7SMathieu Desnoyers "lis %%r17, (" __rseq_str(cs_label) ")@ha\n\t" \ 1292e155fb7SMathieu Desnoyers "addi %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \ 130de6b52a2SMathieu Desnoyers RSEQ_STORE_INT(rseq_cs) "%%r17, %[" __rseq_str(rseq_cs) "]\n\t" \ 1312e155fb7SMathieu Desnoyers __rseq_str(label) ":\n\t" 1322e155fb7SMathieu Desnoyers 1332e155fb7SMathieu Desnoyers #endif /* #ifdef __PPC64__ */ 1342e155fb7SMathieu Desnoyers 1352e155fb7SMathieu Desnoyers #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \ 1362e155fb7SMathieu Desnoyers __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \ 1372e155fb7SMathieu Desnoyers (post_commit_ip - start_ip), abort_ip) 1382e155fb7SMathieu Desnoyers 1392e155fb7SMathieu Desnoyers #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ 1402e155fb7SMathieu Desnoyers RSEQ_INJECT_ASM(2) \ 141de6b52a2SMathieu Desnoyers RSEQ_LOAD_INT(current_cpu_id) "%%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \ 1422e155fb7SMathieu Desnoyers "cmpw cr7, %[" __rseq_str(cpu_id) "], %%r17\n\t" \ 1432e155fb7SMathieu Desnoyers "bne- cr7, " __rseq_str(label) "\n\t" 1442e155fb7SMathieu Desnoyers 1452e155fb7SMathieu Desnoyers #define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \ 1462e155fb7SMathieu Desnoyers ".pushsection __rseq_failure, \"ax\"\n\t" \ 1472e155fb7SMathieu Desnoyers ".long " __rseq_str(RSEQ_SIG) "\n\t" \ 1482e155fb7SMathieu Desnoyers __rseq_str(label) ":\n\t" \ 1492e155fb7SMathieu Desnoyers "b %l[" __rseq_str(abort_label) "]\n\t" \ 1502e155fb7SMathieu Desnoyers ".popsection\n\t" 1512e155fb7SMathieu Desnoyers 1522e155fb7SMathieu Desnoyers /* 1532e155fb7SMathieu Desnoyers * RSEQ_ASM_OPs: asm operations for rseq 1542e155fb7SMathieu Desnoyers * RSEQ_ASM_OP_R_*: has hard-code registers in it 1552e155fb7SMathieu Desnoyers * RSEQ_ASM_OP_* (else): doesn't have hard-code registers(unless cr7) 1562e155fb7SMathieu Desnoyers */ 1572e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_CMPEQ(var, expect, label) \ 158de6b52a2SMathieu Desnoyers RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \ 159de6b52a2SMathieu Desnoyers RSEQ_CMP_LONG "cr7, %%r17, %[" __rseq_str(expect) "]\n\t" \ 1602e155fb7SMathieu Desnoyers "bne- cr7, " __rseq_str(label) "\n\t" 1612e155fb7SMathieu Desnoyers 1622e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_CMPNE(var, expectnot, label) \ 163de6b52a2SMathieu Desnoyers RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \ 164de6b52a2SMathieu Desnoyers RSEQ_CMP_LONG "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t" \ 1652e155fb7SMathieu Desnoyers "beq- cr7, " __rseq_str(label) "\n\t" 1662e155fb7SMathieu Desnoyers 1672e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_STORE(value, var) \ 168de6b52a2SMathieu Desnoyers RSEQ_STORE_LONG(var) "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" 1692e155fb7SMathieu Desnoyers 1702e155fb7SMathieu Desnoyers /* Load @var to r17 */ 1712e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_LOAD(var) \ 172de6b52a2SMathieu Desnoyers RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" 1732e155fb7SMathieu Desnoyers 1742e155fb7SMathieu Desnoyers /* Store r17 to @var */ 1752e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_STORE(var) \ 176de6b52a2SMathieu Desnoyers RSEQ_STORE_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" 1772e155fb7SMathieu Desnoyers 1782e155fb7SMathieu Desnoyers /* Add @count to r17 */ 1792e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_ADD(count) \ 1802e155fb7SMathieu Desnoyers "add %%r17, %[" __rseq_str(count) "], %%r17\n\t" 1812e155fb7SMathieu Desnoyers 1822e155fb7SMathieu Desnoyers /* Load (r17 + voffp) to r17 */ 1832e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_LOADX(voffp) \ 184de6b52a2SMathieu Desnoyers RSEQ_LOADX_LONG "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t" 1852e155fb7SMathieu Desnoyers 1862e155fb7SMathieu Desnoyers /* TODO: implement a faster memcpy. */ 1872e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_MEMCPY() \ 188de6b52a2SMathieu Desnoyers RSEQ_CMP_LONG_INT "%%r19, 0\n\t" \ 1892e155fb7SMathieu Desnoyers "beq 333f\n\t" \ 1902e155fb7SMathieu Desnoyers "addi %%r20, %%r20, -1\n\t" \ 1912e155fb7SMathieu Desnoyers "addi %%r21, %%r21, -1\n\t" \ 1922e155fb7SMathieu Desnoyers "222:\n\t" \ 1932e155fb7SMathieu Desnoyers "lbzu %%r18, 1(%%r20)\n\t" \ 1942e155fb7SMathieu Desnoyers "stbu %%r18, 1(%%r21)\n\t" \ 1952e155fb7SMathieu Desnoyers "addi %%r19, %%r19, -1\n\t" \ 196de6b52a2SMathieu Desnoyers RSEQ_CMP_LONG_INT "%%r19, 0\n\t" \ 1972e155fb7SMathieu Desnoyers "bne 222b\n\t" \ 1982e155fb7SMathieu Desnoyers "333:\n\t" \ 1992e155fb7SMathieu Desnoyers 2002e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \ 201de6b52a2SMathieu Desnoyers RSEQ_STORE_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \ 2022e155fb7SMathieu Desnoyers __rseq_str(post_commit_label) ":\n\t" 2032e155fb7SMathieu Desnoyers 2042e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \ 205de6b52a2SMathieu Desnoyers RSEQ_STORE_LONG(var) "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \ 2062e155fb7SMathieu Desnoyers __rseq_str(post_commit_label) ":\n\t" 2072e155fb7SMathieu Desnoyers 208e61bd94cSMathieu Desnoyers /* Per-cpu-id indexing. */ 2092e155fb7SMathieu Desnoyers 210e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_CPU_ID 211e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELAXED 212e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h" 213e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELAXED 2142e155fb7SMathieu Desnoyers 215e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELEASE 216e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h" 217e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELEASE 218e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_CPU_ID 2192e155fb7SMathieu Desnoyers 220e61bd94cSMathieu Desnoyers /* Per-mm-cid indexing. */ 2212e155fb7SMathieu Desnoyers 222e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MM_CID 223e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELAXED 224e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h" 225e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELAXED 2262e155fb7SMathieu Desnoyers 227e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELEASE 228e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h" 229e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELEASE 230e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MM_CID 2312e155fb7SMathieu Desnoyers 232e61bd94cSMathieu Desnoyers /* APIs which are not based on cpu ids. */ 2332e155fb7SMathieu Desnoyers 234e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_CPU_ID_NONE 235e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELAXED 236e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h" 237e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELAXED 238e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_CPU_ID_NONE 239