rseq-arm64-bits.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
  2. /*
  3. * rseq-arm64-bits.h
  4. *
  5. * (C) Copyright 2016-2022 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  6. * (C) Copyright 2018 - Will Deacon <will.deacon@arm.com>
  7. */
  8. #include "rseq-bits-template.h"
  9. #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
  10. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
  11. static inline __attribute__((always_inline))
  12. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev)(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
  13. {
  14. RSEQ_INJECT_C(9)
  15. __asm__ __volatile__ goto (
  16. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  17. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
  18. #ifdef RSEQ_COMPARE_TWICE
  19. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
  20. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
  21. #endif
  22. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  23. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  24. RSEQ_INJECT_ASM(3)
  25. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  26. RSEQ_INJECT_ASM(4)
  27. #ifdef RSEQ_COMPARE_TWICE
  28. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  29. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  30. #endif
  31. RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
  32. RSEQ_INJECT_ASM(5)
  33. RSEQ_ASM_DEFINE_ABORT(4, abort)
  34. : /* gcc asm goto does not allow outputs */
  35. : [cpu_id] "r" (cpu),
  36. [current_cpu_id] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  37. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  38. [v] "Qo" (*v),
  39. [expect] "r" (expect),
  40. [newv] "r" (newv)
  41. RSEQ_INJECT_INPUT
  42. : "memory", RSEQ_ASM_TMP_REG
  43. : abort, cmpfail
  44. #ifdef RSEQ_COMPARE_TWICE
  45. , error1, error2
  46. #endif
  47. );
  48. rseq_after_asm_goto();
  49. return 0;
  50. abort:
  51. rseq_after_asm_goto();
  52. RSEQ_INJECT_FAILED
  53. return -1;
  54. cmpfail:
  55. rseq_after_asm_goto();
  56. return 1;
  57. #ifdef RSEQ_COMPARE_TWICE
  58. error1:
  59. rseq_after_asm_goto();
  60. rseq_bug("cpu_id comparison failed");
  61. error2:
  62. rseq_after_asm_goto();
  63. rseq_bug("expected value comparison failed");
  64. #endif
  65. }
  66. static inline __attribute__((always_inline))
  67. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load)(intptr_t *v, intptr_t expectnot,
  68. long voffp, intptr_t *load, int cpu)
  69. {
  70. RSEQ_INJECT_C(9)
  71. __asm__ __volatile__ goto (
  72. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  73. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
  74. #ifdef RSEQ_COMPARE_TWICE
  75. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
  76. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
  77. #endif
  78. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  79. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  80. RSEQ_INJECT_ASM(3)
  81. RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail])
  82. RSEQ_INJECT_ASM(4)
  83. #ifdef RSEQ_COMPARE_TWICE
  84. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  85. RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2])
  86. #endif
  87. RSEQ_ASM_OP_R_LOAD(v)
  88. RSEQ_ASM_OP_R_STORE(load)
  89. RSEQ_ASM_OP_R_LOAD_OFF(voffp)
  90. RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
  91. RSEQ_INJECT_ASM(5)
  92. RSEQ_ASM_DEFINE_ABORT(4, abort)
  93. : /* gcc asm goto does not allow outputs */
  94. : [cpu_id] "r" (cpu),
  95. [current_cpu_id] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  96. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  97. [v] "Qo" (*v),
  98. [expectnot] "r" (expectnot),
  99. [load] "Qo" (*load),
  100. [voffp] "r" (voffp)
  101. RSEQ_INJECT_INPUT
  102. : "memory", RSEQ_ASM_TMP_REG
  103. : abort, cmpfail
  104. #ifdef RSEQ_COMPARE_TWICE
  105. , error1, error2
  106. #endif
  107. );
  108. rseq_after_asm_goto();
  109. return 0;
  110. abort:
  111. rseq_after_asm_goto();
  112. RSEQ_INJECT_FAILED
  113. return -1;
  114. cmpfail:
  115. rseq_after_asm_goto();
  116. return 1;
  117. #ifdef RSEQ_COMPARE_TWICE
  118. error1:
  119. rseq_after_asm_goto();
  120. rseq_bug("cpu_id comparison failed");
  121. error2:
  122. rseq_after_asm_goto();
  123. rseq_bug("expected value comparison failed");
  124. #endif
  125. }
  126. static inline __attribute__((always_inline))
  127. int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv)(intptr_t *v, intptr_t count, int cpu)
  128. {
  129. RSEQ_INJECT_C(9)
  130. __asm__ __volatile__ goto (
  131. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  132. #ifdef RSEQ_COMPARE_TWICE
  133. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
  134. #endif
  135. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  136. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  137. RSEQ_INJECT_ASM(3)
  138. #ifdef RSEQ_COMPARE_TWICE
  139. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  140. #endif
  141. RSEQ_ASM_OP_R_LOAD(v)
  142. RSEQ_ASM_OP_R_ADD(count)
  143. RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
  144. RSEQ_INJECT_ASM(4)
  145. RSEQ_ASM_DEFINE_ABORT(4, abort)
  146. : /* gcc asm goto does not allow outputs */
  147. : [cpu_id] "r" (cpu),
  148. [current_cpu_id] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  149. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  150. [v] "Qo" (*v),
  151. [count] "r" (count)
  152. RSEQ_INJECT_INPUT
  153. : "memory", RSEQ_ASM_TMP_REG
  154. : abort
  155. #ifdef RSEQ_COMPARE_TWICE
  156. , error1
  157. #endif
  158. );
  159. rseq_after_asm_goto();
  160. return 0;
  161. abort:
  162. rseq_after_asm_goto();
  163. RSEQ_INJECT_FAILED
  164. return -1;
  165. #ifdef RSEQ_COMPARE_TWICE
  166. error1:
  167. rseq_after_asm_goto();
  168. rseq_bug("cpu_id comparison failed");
  169. #endif
  170. }
  171. static inline __attribute__((always_inline))
  172. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev)(intptr_t *v, intptr_t expect,
  173. intptr_t *v2, intptr_t expect2,
  174. intptr_t newv, int cpu)
  175. {
  176. RSEQ_INJECT_C(9)
  177. __asm__ __volatile__ goto (
  178. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  179. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
  180. #ifdef RSEQ_COMPARE_TWICE
  181. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
  182. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
  183. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error3])
  184. #endif
  185. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  186. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  187. RSEQ_INJECT_ASM(3)
  188. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  189. RSEQ_INJECT_ASM(4)
  190. RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail])
  191. RSEQ_INJECT_ASM(5)
  192. #ifdef RSEQ_COMPARE_TWICE
  193. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  194. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  195. RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3])
  196. #endif
  197. RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
  198. RSEQ_INJECT_ASM(6)
  199. RSEQ_ASM_DEFINE_ABORT(4, abort)
  200. : /* gcc asm goto does not allow outputs */
  201. : [cpu_id] "r" (cpu),
  202. [current_cpu_id] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  203. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  204. [v] "Qo" (*v),
  205. [expect] "r" (expect),
  206. [v2] "Qo" (*v2),
  207. [expect2] "r" (expect2),
  208. [newv] "r" (newv)
  209. RSEQ_INJECT_INPUT
  210. : "memory", RSEQ_ASM_TMP_REG
  211. : abort, cmpfail
  212. #ifdef RSEQ_COMPARE_TWICE
  213. , error1, error2, error3
  214. #endif
  215. );
  216. rseq_after_asm_goto();
  217. return 0;
  218. abort:
  219. rseq_after_asm_goto();
  220. RSEQ_INJECT_FAILED
  221. return -1;
  222. cmpfail:
  223. rseq_after_asm_goto();
  224. return 1;
  225. #ifdef RSEQ_COMPARE_TWICE
  226. error1:
  227. rseq_after_asm_goto();
  228. rseq_bug("cpu_id comparison failed");
  229. error2:
  230. rseq_after_asm_goto();
  231. rseq_bug("expected value comparison failed");
  232. error3:
  233. rseq_after_asm_goto();
  234. rseq_bug("2nd expected value comparison failed");
  235. #endif
  236. }
  237. #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
  238. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
  239. #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
  240. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
  241. static inline __attribute__((always_inline))
  242. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev)(intptr_t *v, intptr_t expect,
  243. intptr_t *v2, intptr_t newv2,
  244. intptr_t newv, int cpu)
  245. {
  246. RSEQ_INJECT_C(9)
  247. __asm__ __volatile__ goto (
  248. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  249. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
  250. #ifdef RSEQ_COMPARE_TWICE
  251. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
  252. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
  253. #endif
  254. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  255. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  256. RSEQ_INJECT_ASM(3)
  257. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  258. RSEQ_INJECT_ASM(4)
  259. #ifdef RSEQ_COMPARE_TWICE
  260. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  261. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  262. #endif
  263. RSEQ_ASM_OP_STORE(newv2, v2)
  264. RSEQ_INJECT_ASM(5)
  265. #ifdef RSEQ_TEMPLATE_MO_RELEASE
  266. RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
  267. #else
  268. RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
  269. #endif
  270. RSEQ_INJECT_ASM(6)
  271. RSEQ_ASM_DEFINE_ABORT(4, abort)
  272. : /* gcc asm goto does not allow outputs */
  273. : [cpu_id] "r" (cpu),
  274. [current_cpu_id] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  275. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  276. [expect] "r" (expect),
  277. [v] "Qo" (*v),
  278. [newv] "r" (newv),
  279. [v2] "Qo" (*v2),
  280. [newv2] "r" (newv2)
  281. RSEQ_INJECT_INPUT
  282. : "memory", RSEQ_ASM_TMP_REG
  283. : abort, cmpfail
  284. #ifdef RSEQ_COMPARE_TWICE
  285. , error1, error2
  286. #endif
  287. );
  288. rseq_after_asm_goto();
  289. return 0;
  290. abort:
  291. rseq_after_asm_goto();
  292. RSEQ_INJECT_FAILED
  293. return -1;
  294. cmpfail:
  295. rseq_after_asm_goto();
  296. return 1;
  297. #ifdef RSEQ_COMPARE_TWICE
  298. error1:
  299. rseq_after_asm_goto();
  300. rseq_bug("cpu_id comparison failed");
  301. error2:
  302. rseq_after_asm_goto();
  303. rseq_bug("expected value comparison failed");
  304. #endif
  305. }
  306. static inline __attribute__((always_inline))
  307. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev)(intptr_t *v, intptr_t expect,
  308. void *dst, void *src, size_t len,
  309. intptr_t newv, int cpu)
  310. {
  311. RSEQ_INJECT_C(9)
  312. __asm__ __volatile__ goto (
  313. RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
  314. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
  315. #ifdef RSEQ_COMPARE_TWICE
  316. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
  317. RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
  318. #endif
  319. RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
  320. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  321. RSEQ_INJECT_ASM(3)
  322. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  323. RSEQ_INJECT_ASM(4)
  324. #ifdef RSEQ_COMPARE_TWICE
  325. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  326. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  327. #endif
  328. RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)
  329. RSEQ_INJECT_ASM(5)
  330. #ifdef RSEQ_TEMPLATE_MO_RELEASE
  331. RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
  332. #else
  333. RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
  334. #endif
  335. RSEQ_INJECT_ASM(6)
  336. RSEQ_ASM_DEFINE_ABORT(4, abort)
  337. : /* gcc asm goto does not allow outputs */
  338. : [cpu_id] "r" (cpu),
  339. [current_cpu_id] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  340. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  341. [expect] "r" (expect),
  342. [v] "Qo" (*v),
  343. [newv] "r" (newv),
  344. [dst] "r" (dst),
  345. [src] "r" (src),
  346. [len] "r" (len)
  347. RSEQ_INJECT_INPUT
  348. : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2
  349. : abort, cmpfail
  350. #ifdef RSEQ_COMPARE_TWICE
  351. , error1, error2
  352. #endif
  353. );
  354. rseq_after_asm_goto();
  355. return 0;
  356. abort:
  357. rseq_after_asm_goto();
  358. RSEQ_INJECT_FAILED
  359. return -1;
  360. cmpfail:
  361. rseq_after_asm_goto();
  362. return 1;
  363. #ifdef RSEQ_COMPARE_TWICE
  364. error1:
  365. rseq_after_asm_goto();
  366. rseq_bug("cpu_id comparison failed");
  367. error2:
  368. rseq_after_asm_goto();
  369. rseq_bug("expected value comparison failed");
  370. #endif
  371. }
  372. #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
  373. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
  374. #include "rseq-bits-reset.h"