rseq-arm64.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
  2. /*
  3. * rseq-arm64.h
  4. *
  5. * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  6. * (C) Copyright 2018 - Will Deacon <will.deacon@arm.com>
  7. */
  8. #define RSEQ_SIG 0xd428bc00 /* BRK #0x45E0 */
  9. #define rseq_smp_mb() __asm__ __volatile__ ("dmb ish" ::: "memory")
  10. #define rseq_smp_rmb() __asm__ __volatile__ ("dmb ishld" ::: "memory")
  11. #define rseq_smp_wmb() __asm__ __volatile__ ("dmb ishst" ::: "memory")
  12. #define rseq_smp_load_acquire(p) \
  13. __extension__ ({ \
  14. __typeof(*p) ____p1; \
  15. switch (sizeof(*p)) { \
  16. case 1: \
  17. asm volatile ("ldarb %w0, %1" \
  18. : "=r" (*(__u8 *)p) \
  19. : "Q" (*p) : "memory"); \
  20. break; \
  21. case 2: \
  22. asm volatile ("ldarh %w0, %1" \
  23. : "=r" (*(__u16 *)p) \
  24. : "Q" (*p) : "memory"); \
  25. break; \
  26. case 4: \
  27. asm volatile ("ldar %w0, %1" \
  28. : "=r" (*(__u32 *)p) \
  29. : "Q" (*p) : "memory"); \
  30. break; \
  31. case 8: \
  32. asm volatile ("ldar %0, %1" \
  33. : "=r" (*(__u64 *)p) \
  34. : "Q" (*p) : "memory"); \
  35. break; \
  36. } \
  37. ____p1; \
  38. })
  39. #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
  40. #define rseq_smp_store_release(p, v) \
  41. do { \
  42. switch (sizeof(*p)) { \
  43. case 1: \
  44. asm volatile ("stlrb %w1, %0" \
  45. : "=Q" (*p) \
  46. : "r" ((__u8)v) \
  47. : "memory"); \
  48. break; \
  49. case 2: \
  50. asm volatile ("stlrh %w1, %0" \
  51. : "=Q" (*p) \
  52. : "r" ((__u16)v) \
  53. : "memory"); \
  54. break; \
  55. case 4: \
  56. asm volatile ("stlr %w1, %0" \
  57. : "=Q" (*p) \
  58. : "r" ((__u32)v) \
  59. : "memory"); \
  60. break; \
  61. case 8: \
  62. asm volatile ("stlr %1, %0" \
  63. : "=Q" (*p) \
  64. : "r" ((__u64)v) \
  65. : "memory"); \
  66. break; \
  67. } \
  68. } while (0)
  69. #ifdef RSEQ_SKIP_FASTPATH
  70. #include "rseq-skip.h"
  71. #else /* !RSEQ_SKIP_FASTPATH */
  72. #define RSEQ_ASM_TMP_REG32 "w15"
  73. #define RSEQ_ASM_TMP_REG "x15"
  74. #define RSEQ_ASM_TMP_REG_2 "x14"
  75. #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
  76. post_commit_offset, abort_ip) \
  77. " .pushsection __rseq_table, \"aw\"\n" \
  78. " .balign 32\n" \
  79. __rseq_str(label) ":\n" \
  80. " .long " __rseq_str(version) ", " __rseq_str(flags) "\n" \
  81. " .quad " __rseq_str(start_ip) ", " \
  82. __rseq_str(post_commit_offset) ", " \
  83. __rseq_str(abort_ip) "\n" \
  84. " .popsection\n"
  85. #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
  86. __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
  87. (post_commit_ip - start_ip), abort_ip)
  88. #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
  89. RSEQ_INJECT_ASM(1) \
  90. " adrp " RSEQ_ASM_TMP_REG ", " __rseq_str(cs_label) "\n" \
  91. " add " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
  92. ", :lo12:" __rseq_str(cs_label) "\n" \
  93. " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(rseq_cs) "]\n" \
  94. __rseq_str(label) ":\n"
  95. #define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \
  96. " b 222f\n" \
  97. " .inst " __rseq_str(RSEQ_SIG) "\n" \
  98. __rseq_str(label) ":\n" \
  99. " b %l[" __rseq_str(abort_label) "]\n" \
  100. "222:\n"
  101. #define RSEQ_ASM_OP_STORE(value, var) \
  102. " str %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
  103. #define RSEQ_ASM_OP_STORE_RELEASE(value, var) \
  104. " stlr %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
  105. #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \
  106. RSEQ_ASM_OP_STORE(value, var) \
  107. __rseq_str(post_commit_label) ":\n"
  108. #define RSEQ_ASM_OP_FINAL_STORE_RELEASE(value, var, post_commit_label) \
  109. RSEQ_ASM_OP_STORE_RELEASE(value, var) \
  110. __rseq_str(post_commit_label) ":\n"
  111. #define RSEQ_ASM_OP_CMPEQ(var, expect, label) \
  112. " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
  113. " sub " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
  114. ", %[" __rseq_str(expect) "]\n" \
  115. " cbnz " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n"
  116. #define RSEQ_ASM_OP_CMPEQ32(var, expect, label) \
  117. " ldr " RSEQ_ASM_TMP_REG32 ", %[" __rseq_str(var) "]\n" \
  118. " sub " RSEQ_ASM_TMP_REG32 ", " RSEQ_ASM_TMP_REG32 \
  119. ", %w[" __rseq_str(expect) "]\n" \
  120. " cbnz " RSEQ_ASM_TMP_REG32 ", " __rseq_str(label) "\n"
  121. #define RSEQ_ASM_OP_CMPNE(var, expect, label) \
  122. " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
  123. " sub " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
  124. ", %[" __rseq_str(expect) "]\n" \
  125. " cbz " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n"
  126. #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
  127. RSEQ_INJECT_ASM(2) \
  128. RSEQ_ASM_OP_CMPEQ32(current_cpu_id, cpu_id, label)
  129. #define RSEQ_ASM_OP_R_LOAD(var) \
  130. " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"
  131. #define RSEQ_ASM_OP_R_STORE(var) \
  132. " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"
  133. #define RSEQ_ASM_OP_R_LOAD_OFF(offset) \
  134. " ldr " RSEQ_ASM_TMP_REG ", [" RSEQ_ASM_TMP_REG \
  135. ", %[" __rseq_str(offset) "]]\n"
  136. #define RSEQ_ASM_OP_R_ADD(count) \
  137. " add " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
  138. ", %[" __rseq_str(count) "]\n"
  139. #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \
  140. " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
  141. __rseq_str(post_commit_label) ":\n"
  142. #define RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len) \
  143. " cbz %[" __rseq_str(len) "], 333f\n" \
  144. " mov " RSEQ_ASM_TMP_REG_2 ", %[" __rseq_str(len) "]\n" \
  145. "222: sub " RSEQ_ASM_TMP_REG_2 ", " RSEQ_ASM_TMP_REG_2 ", #1\n" \
  146. " ldrb " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(src) "]" \
  147. ", " RSEQ_ASM_TMP_REG_2 "]\n" \
  148. " strb " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(dst) "]" \
  149. ", " RSEQ_ASM_TMP_REG_2 "]\n" \
  150. " cbnz " RSEQ_ASM_TMP_REG_2 ", 222b\n" \
  151. "333:\n"
  152. static inline __attribute__((always_inline))
  153. int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
  154. {
  155. RSEQ_INJECT_C(9)
  156. __asm__ __volatile__ goto (
  157. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  158. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  159. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  160. RSEQ_INJECT_ASM(3)
  161. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  162. RSEQ_INJECT_ASM(4)
  163. #ifdef RSEQ_COMPARE_TWICE
  164. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  165. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  166. #endif
  167. RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
  168. RSEQ_INJECT_ASM(5)
  169. RSEQ_ASM_DEFINE_ABORT(4, abort)
  170. : /* gcc asm goto does not allow outputs */
  171. : [cpu_id] "r" (cpu),
  172. [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
  173. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  174. [v] "Qo" (*v),
  175. [expect] "r" (expect),
  176. [newv] "r" (newv)
  177. RSEQ_INJECT_INPUT
  178. : "memory", RSEQ_ASM_TMP_REG
  179. : abort, cmpfail
  180. #ifdef RSEQ_COMPARE_TWICE
  181. , error1, error2
  182. #endif
  183. );
  184. return 0;
  185. abort:
  186. RSEQ_INJECT_FAILED
  187. return -1;
  188. cmpfail:
  189. return 1;
  190. #ifdef RSEQ_COMPARE_TWICE
  191. error1:
  192. rseq_bug("cpu_id comparison failed");
  193. error2:
  194. rseq_bug("expected value comparison failed");
  195. #endif
  196. }
  197. static inline __attribute__((always_inline))
  198. int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
  199. off_t voffp, intptr_t *load, int cpu)
  200. {
  201. RSEQ_INJECT_C(9)
  202. __asm__ __volatile__ goto (
  203. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  204. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  205. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  206. RSEQ_INJECT_ASM(3)
  207. RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail])
  208. RSEQ_INJECT_ASM(4)
  209. #ifdef RSEQ_COMPARE_TWICE
  210. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  211. RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2])
  212. #endif
  213. RSEQ_ASM_OP_R_LOAD(v)
  214. RSEQ_ASM_OP_R_STORE(load)
  215. RSEQ_ASM_OP_R_LOAD_OFF(voffp)
  216. RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
  217. RSEQ_INJECT_ASM(5)
  218. RSEQ_ASM_DEFINE_ABORT(4, abort)
  219. : /* gcc asm goto does not allow outputs */
  220. : [cpu_id] "r" (cpu),
  221. [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
  222. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  223. [v] "Qo" (*v),
  224. [expectnot] "r" (expectnot),
  225. [load] "Qo" (*load),
  226. [voffp] "r" (voffp)
  227. RSEQ_INJECT_INPUT
  228. : "memory", RSEQ_ASM_TMP_REG
  229. : abort, cmpfail
  230. #ifdef RSEQ_COMPARE_TWICE
  231. , error1, error2
  232. #endif
  233. );
  234. return 0;
  235. abort:
  236. RSEQ_INJECT_FAILED
  237. return -1;
  238. cmpfail:
  239. return 1;
  240. #ifdef RSEQ_COMPARE_TWICE
  241. error1:
  242. rseq_bug("cpu_id comparison failed");
  243. error2:
  244. rseq_bug("expected value comparison failed");
  245. #endif
  246. }
  247. static inline __attribute__((always_inline))
  248. int rseq_addv(intptr_t *v, intptr_t count, int cpu)
  249. {
  250. RSEQ_INJECT_C(9)
  251. __asm__ __volatile__ goto (
  252. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  253. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  254. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  255. RSEQ_INJECT_ASM(3)
  256. #ifdef RSEQ_COMPARE_TWICE
  257. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  258. #endif
  259. RSEQ_ASM_OP_R_LOAD(v)
  260. RSEQ_ASM_OP_R_ADD(count)
  261. RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
  262. RSEQ_INJECT_ASM(4)
  263. RSEQ_ASM_DEFINE_ABORT(4, abort)
  264. : /* gcc asm goto does not allow outputs */
  265. : [cpu_id] "r" (cpu),
  266. [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
  267. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  268. [v] "Qo" (*v),
  269. [count] "r" (count)
  270. RSEQ_INJECT_INPUT
  271. : "memory", RSEQ_ASM_TMP_REG
  272. : abort
  273. #ifdef RSEQ_COMPARE_TWICE
  274. , error1
  275. #endif
  276. );
  277. return 0;
  278. abort:
  279. RSEQ_INJECT_FAILED
  280. return -1;
  281. #ifdef RSEQ_COMPARE_TWICE
  282. error1:
  283. rseq_bug("cpu_id comparison failed");
  284. #endif
  285. }
  286. static inline __attribute__((always_inline))
  287. int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
  288. intptr_t *v2, intptr_t newv2,
  289. intptr_t newv, int cpu)
  290. {
  291. RSEQ_INJECT_C(9)
  292. __asm__ __volatile__ goto (
  293. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  294. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  295. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  296. RSEQ_INJECT_ASM(3)
  297. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  298. RSEQ_INJECT_ASM(4)
  299. #ifdef RSEQ_COMPARE_TWICE
  300. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  301. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  302. #endif
  303. RSEQ_ASM_OP_STORE(newv2, v2)
  304. RSEQ_INJECT_ASM(5)
  305. RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
  306. RSEQ_INJECT_ASM(6)
  307. RSEQ_ASM_DEFINE_ABORT(4, abort)
  308. : /* gcc asm goto does not allow outputs */
  309. : [cpu_id] "r" (cpu),
  310. [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
  311. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  312. [expect] "r" (expect),
  313. [v] "Qo" (*v),
  314. [newv] "r" (newv),
  315. [v2] "Qo" (*v2),
  316. [newv2] "r" (newv2)
  317. RSEQ_INJECT_INPUT
  318. : "memory", RSEQ_ASM_TMP_REG
  319. : abort, cmpfail
  320. #ifdef RSEQ_COMPARE_TWICE
  321. , error1, error2
  322. #endif
  323. );
  324. return 0;
  325. abort:
  326. RSEQ_INJECT_FAILED
  327. return -1;
  328. cmpfail:
  329. return 1;
  330. #ifdef RSEQ_COMPARE_TWICE
  331. error1:
  332. rseq_bug("cpu_id comparison failed");
  333. error2:
  334. rseq_bug("expected value comparison failed");
  335. #endif
  336. }
  337. static inline __attribute__((always_inline))
  338. int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
  339. intptr_t *v2, intptr_t newv2,
  340. intptr_t newv, int cpu)
  341. {
  342. RSEQ_INJECT_C(9)
  343. __asm__ __volatile__ goto (
  344. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  345. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  346. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  347. RSEQ_INJECT_ASM(3)
  348. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  349. RSEQ_INJECT_ASM(4)
  350. #ifdef RSEQ_COMPARE_TWICE
  351. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  352. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  353. #endif
  354. RSEQ_ASM_OP_STORE(newv2, v2)
  355. RSEQ_INJECT_ASM(5)
  356. RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
  357. RSEQ_INJECT_ASM(6)
  358. RSEQ_ASM_DEFINE_ABORT(4, abort)
  359. : /* gcc asm goto does not allow outputs */
  360. : [cpu_id] "r" (cpu),
  361. [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
  362. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  363. [expect] "r" (expect),
  364. [v] "Qo" (*v),
  365. [newv] "r" (newv),
  366. [v2] "Qo" (*v2),
  367. [newv2] "r" (newv2)
  368. RSEQ_INJECT_INPUT
  369. : "memory", RSEQ_ASM_TMP_REG
  370. : abort, cmpfail
  371. #ifdef RSEQ_COMPARE_TWICE
  372. , error1, error2
  373. #endif
  374. );
  375. return 0;
  376. abort:
  377. RSEQ_INJECT_FAILED
  378. return -1;
  379. cmpfail:
  380. return 1;
  381. #ifdef RSEQ_COMPARE_TWICE
  382. error1:
  383. rseq_bug("cpu_id comparison failed");
  384. error2:
  385. rseq_bug("expected value comparison failed");
  386. #endif
  387. }
  388. static inline __attribute__((always_inline))
  389. int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
  390. intptr_t *v2, intptr_t expect2,
  391. intptr_t newv, int cpu)
  392. {
  393. RSEQ_INJECT_C(9)
  394. __asm__ __volatile__ goto (
  395. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  396. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  397. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  398. RSEQ_INJECT_ASM(3)
  399. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  400. RSEQ_INJECT_ASM(4)
  401. RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail])
  402. RSEQ_INJECT_ASM(5)
  403. #ifdef RSEQ_COMPARE_TWICE
  404. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  405. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  406. RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3])
  407. #endif
  408. RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
  409. RSEQ_INJECT_ASM(6)
  410. RSEQ_ASM_DEFINE_ABORT(4, abort)
  411. : /* gcc asm goto does not allow outputs */
  412. : [cpu_id] "r" (cpu),
  413. [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
  414. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  415. [v] "Qo" (*v),
  416. [expect] "r" (expect),
  417. [v2] "Qo" (*v2),
  418. [expect2] "r" (expect2),
  419. [newv] "r" (newv)
  420. RSEQ_INJECT_INPUT
  421. : "memory", RSEQ_ASM_TMP_REG
  422. : abort, cmpfail
  423. #ifdef RSEQ_COMPARE_TWICE
  424. , error1, error2, error3
  425. #endif
  426. );
  427. return 0;
  428. abort:
  429. RSEQ_INJECT_FAILED
  430. return -1;
  431. cmpfail:
  432. return 1;
  433. #ifdef RSEQ_COMPARE_TWICE
  434. error1:
  435. rseq_bug("cpu_id comparison failed");
  436. error2:
  437. rseq_bug("expected value comparison failed");
  438. error3:
  439. rseq_bug("2nd expected value comparison failed");
  440. #endif
  441. }
  442. static inline __attribute__((always_inline))
  443. int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
  444. void *dst, void *src, size_t len,
  445. intptr_t newv, int cpu)
  446. {
  447. RSEQ_INJECT_C(9)
  448. __asm__ __volatile__ goto (
  449. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  450. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  451. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  452. RSEQ_INJECT_ASM(3)
  453. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  454. RSEQ_INJECT_ASM(4)
  455. #ifdef RSEQ_COMPARE_TWICE
  456. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  457. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  458. #endif
  459. RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)
  460. RSEQ_INJECT_ASM(5)
  461. RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
  462. RSEQ_INJECT_ASM(6)
  463. RSEQ_ASM_DEFINE_ABORT(4, abort)
  464. : /* gcc asm goto does not allow outputs */
  465. : [cpu_id] "r" (cpu),
  466. [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
  467. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  468. [expect] "r" (expect),
  469. [v] "Qo" (*v),
  470. [newv] "r" (newv),
  471. [dst] "r" (dst),
  472. [src] "r" (src),
  473. [len] "r" (len)
  474. RSEQ_INJECT_INPUT
  475. : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2
  476. : abort, cmpfail
  477. #ifdef RSEQ_COMPARE_TWICE
  478. , error1, error2
  479. #endif
  480. );
  481. return 0;
  482. abort:
  483. RSEQ_INJECT_FAILED
  484. return -1;
  485. cmpfail:
  486. return 1;
  487. #ifdef RSEQ_COMPARE_TWICE
  488. error1:
  489. rseq_bug("cpu_id comparison failed");
  490. error2:
  491. rseq_bug("expected value comparison failed");
  492. #endif
  493. }
  494. static inline __attribute__((always_inline))
  495. int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
  496. void *dst, void *src, size_t len,
  497. intptr_t newv, int cpu)
  498. {
  499. RSEQ_INJECT_C(9)
  500. __asm__ __volatile__ goto (
  501. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  502. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  503. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  504. RSEQ_INJECT_ASM(3)
  505. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  506. RSEQ_INJECT_ASM(4)
  507. #ifdef RSEQ_COMPARE_TWICE
  508. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  509. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  510. #endif
  511. RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)
  512. RSEQ_INJECT_ASM(5)
  513. RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
  514. RSEQ_INJECT_ASM(6)
  515. RSEQ_ASM_DEFINE_ABORT(4, abort)
  516. : /* gcc asm goto does not allow outputs */
  517. : [cpu_id] "r" (cpu),
  518. [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
  519. [rseq_cs] "m" (__rseq_abi.rseq_cs),
  520. [expect] "r" (expect),
  521. [v] "Qo" (*v),
  522. [newv] "r" (newv),
  523. [dst] "r" (dst),
  524. [src] "r" (src),
  525. [len] "r" (len)
  526. RSEQ_INJECT_INPUT
  527. : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2
  528. : abort, cmpfail
  529. #ifdef RSEQ_COMPARE_TWICE
  530. , error1, error2
  531. #endif
  532. );
  533. return 0;
  534. abort:
  535. RSEQ_INJECT_FAILED
  536. return -1;
  537. cmpfail:
  538. return 1;
  539. #ifdef RSEQ_COMPARE_TWICE
  540. error1:
  541. rseq_bug("cpu_id comparison failed");
  542. error2:
  543. rseq_bug("expected value comparison failed");
  544. #endif
  545. }
  546. #endif /* !RSEQ_SKIP_FASTPATH */