rseq-ppc-bits.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
  2. /*
  3. * rseq-ppc-bits.h
  4. *
  5. * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  6. * (C) Copyright 2016-2018 - Boqun Feng <boqun.feng@gmail.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(3, 1f, 2f, 4f) /* start, commit, abort */
  17. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  18. #ifdef RSEQ_COMPARE_TWICE
  19. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  20. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  21. #endif
  22. /* Start rseq by storing table entry pointer into rseq_cs. */
  23. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  24. /* cmp cpuid */
  25. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  26. RSEQ_INJECT_ASM(3)
  27. /* cmp @v equal to @expect */
  28. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  29. RSEQ_INJECT_ASM(4)
  30. #ifdef RSEQ_COMPARE_TWICE
  31. /* cmp cpuid */
  32. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  33. /* cmp @v equal to @expect */
  34. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  35. #endif
  36. /* final store */
  37. RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
  38. RSEQ_INJECT_ASM(5)
  39. RSEQ_ASM_DEFINE_ABORT(4, abort)
  40. : /* gcc asm goto does not allow outputs */
  41. : [cpu_id] "r" (cpu),
  42. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  43. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  44. [v] "m" (*v),
  45. [expect] "r" (expect),
  46. [newv] "r" (newv)
  47. RSEQ_INJECT_INPUT
  48. : "memory", "cc", "r17"
  49. RSEQ_INJECT_CLOBBER
  50. : abort, cmpfail
  51. #ifdef RSEQ_COMPARE_TWICE
  52. , error1, error2
  53. #endif
  54. );
  55. rseq_after_asm_goto();
  56. return 0;
  57. abort:
  58. rseq_after_asm_goto();
  59. RSEQ_INJECT_FAILED
  60. return -1;
  61. cmpfail:
  62. rseq_after_asm_goto();
  63. return 1;
  64. #ifdef RSEQ_COMPARE_TWICE
  65. error1:
  66. rseq_after_asm_goto();
  67. rseq_bug("cpu_id comparison failed");
  68. error2:
  69. rseq_after_asm_goto();
  70. rseq_bug("expected value comparison failed");
  71. #endif
  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. __asm__ __volatile__ goto (
  79. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  80. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  81. #ifdef RSEQ_COMPARE_TWICE
  82. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  83. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  84. #endif
  85. /* Start rseq by storing table entry pointer into rseq_cs. */
  86. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  87. /* cmp cpuid */
  88. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  89. RSEQ_INJECT_ASM(3)
  90. /* cmp @v not equal to @expectnot */
  91. RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail])
  92. RSEQ_INJECT_ASM(4)
  93. #ifdef RSEQ_COMPARE_TWICE
  94. /* cmp cpuid */
  95. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  96. /* cmp @v not equal to @expectnot */
  97. RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2])
  98. #endif
  99. /* load the value of @v */
  100. RSEQ_ASM_OP_R_LOAD(v)
  101. /* store it in @load */
  102. RSEQ_ASM_OP_R_STORE(load)
  103. /* dereference voffp(v) */
  104. RSEQ_ASM_OP_R_LOADX(voffp)
  105. /* final store the value at voffp(v) */
  106. RSEQ_ASM_OP_R_FINAL_STORE(v, 2)
  107. RSEQ_INJECT_ASM(5)
  108. RSEQ_ASM_DEFINE_ABORT(4, abort)
  109. : /* gcc asm goto does not allow outputs */
  110. : [cpu_id] "r" (cpu),
  111. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  112. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  113. /* final store input */
  114. [v] "m" (*v),
  115. [expectnot] "r" (expectnot),
  116. [voffp] "b" (voffp),
  117. [load] "m" (*load)
  118. RSEQ_INJECT_INPUT
  119. : "memory", "cc", "r17"
  120. RSEQ_INJECT_CLOBBER
  121. : abort, cmpfail
  122. #ifdef RSEQ_COMPARE_TWICE
  123. , error1, error2
  124. #endif
  125. );
  126. rseq_after_asm_goto();
  127. return 0;
  128. abort:
  129. rseq_after_asm_goto();
  130. RSEQ_INJECT_FAILED
  131. return -1;
  132. cmpfail:
  133. rseq_after_asm_goto();
  134. return 1;
  135. #ifdef RSEQ_COMPARE_TWICE
  136. error1:
  137. rseq_after_asm_goto();
  138. rseq_bug("cpu_id comparison failed");
  139. error2:
  140. rseq_after_asm_goto();
  141. rseq_bug("expected value comparison failed");
  142. #endif
  143. }
  144. static inline __attribute__((always_inline))
  145. int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv)(intptr_t *v, intptr_t count, int cpu)
  146. {
  147. RSEQ_INJECT_C(9)
  148. __asm__ __volatile__ goto (
  149. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  150. #ifdef RSEQ_COMPARE_TWICE
  151. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  152. #endif
  153. /* Start rseq by storing table entry pointer into rseq_cs. */
  154. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  155. /* cmp cpuid */
  156. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  157. RSEQ_INJECT_ASM(3)
  158. #ifdef RSEQ_COMPARE_TWICE
  159. /* cmp cpuid */
  160. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  161. #endif
  162. /* load the value of @v */
  163. RSEQ_ASM_OP_R_LOAD(v)
  164. /* add @count to it */
  165. RSEQ_ASM_OP_R_ADD(count)
  166. /* final store */
  167. RSEQ_ASM_OP_R_FINAL_STORE(v, 2)
  168. RSEQ_INJECT_ASM(4)
  169. RSEQ_ASM_DEFINE_ABORT(4, abort)
  170. : /* gcc asm goto does not allow outputs */
  171. : [cpu_id] "r" (cpu),
  172. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  173. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  174. /* final store input */
  175. [v] "m" (*v),
  176. [count] "r" (count)
  177. RSEQ_INJECT_INPUT
  178. : "memory", "cc", "r17"
  179. RSEQ_INJECT_CLOBBER
  180. : abort
  181. #ifdef RSEQ_COMPARE_TWICE
  182. , error1
  183. #endif
  184. );
  185. rseq_after_asm_goto();
  186. return 0;
  187. abort:
  188. rseq_after_asm_goto();
  189. RSEQ_INJECT_FAILED
  190. return -1;
  191. #ifdef RSEQ_COMPARE_TWICE
  192. error1:
  193. rseq_after_asm_goto();
  194. rseq_bug("cpu_id comparison failed");
  195. #endif
  196. }
  197. static inline __attribute__((always_inline))
  198. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev)(intptr_t *v, intptr_t expect,
  199. intptr_t *v2, intptr_t expect2,
  200. intptr_t newv, int cpu)
  201. {
  202. RSEQ_INJECT_C(9)
  203. __asm__ __volatile__ goto (
  204. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  205. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  206. #ifdef RSEQ_COMPARE_TWICE
  207. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  208. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  209. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
  210. #endif
  211. /* Start rseq by storing table entry pointer into rseq_cs. */
  212. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  213. /* cmp cpuid */
  214. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  215. RSEQ_INJECT_ASM(3)
  216. /* cmp @v equal to @expect */
  217. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  218. RSEQ_INJECT_ASM(4)
  219. /* cmp @v2 equal to @expct2 */
  220. RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail])
  221. RSEQ_INJECT_ASM(5)
  222. #ifdef RSEQ_COMPARE_TWICE
  223. /* cmp cpuid */
  224. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  225. /* cmp @v equal to @expect */
  226. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  227. /* cmp @v2 equal to @expct2 */
  228. RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3])
  229. #endif
  230. /* final store */
  231. RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
  232. RSEQ_INJECT_ASM(6)
  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_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  237. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  238. /* cmp2 input */
  239. [v2] "m" (*v2),
  240. [expect2] "r" (expect2),
  241. /* final store input */
  242. [v] "m" (*v),
  243. [expect] "r" (expect),
  244. [newv] "r" (newv)
  245. RSEQ_INJECT_INPUT
  246. : "memory", "cc", "r17"
  247. RSEQ_INJECT_CLOBBER
  248. : abort, cmpfail
  249. #ifdef RSEQ_COMPARE_TWICE
  250. , error1, error2, error3
  251. #endif
  252. );
  253. rseq_after_asm_goto();
  254. return 0;
  255. abort:
  256. rseq_after_asm_goto();
  257. RSEQ_INJECT_FAILED
  258. return -1;
  259. cmpfail:
  260. rseq_after_asm_goto();
  261. return 1;
  262. #ifdef RSEQ_COMPARE_TWICE
  263. error1:
  264. rseq_after_asm_goto();
  265. rseq_bug("cpu_id comparison failed");
  266. error2:
  267. rseq_after_asm_goto();
  268. rseq_bug("1st expected value comparison failed");
  269. error3:
  270. rseq_after_asm_goto();
  271. rseq_bug("2nd expected value comparison failed");
  272. #endif
  273. }
  274. #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
  275. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
  276. #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
  277. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
  278. static inline __attribute__((always_inline))
  279. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev)(intptr_t *v, intptr_t expect,
  280. intptr_t *v2, intptr_t newv2,
  281. intptr_t newv, int cpu)
  282. {
  283. RSEQ_INJECT_C(9)
  284. __asm__ __volatile__ goto (
  285. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  286. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  287. #ifdef RSEQ_COMPARE_TWICE
  288. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  289. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  290. #endif
  291. /* Start rseq by storing table entry pointer into rseq_cs. */
  292. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  293. /* cmp cpuid */
  294. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  295. RSEQ_INJECT_ASM(3)
  296. /* cmp @v equal to @expect */
  297. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  298. RSEQ_INJECT_ASM(4)
  299. #ifdef RSEQ_COMPARE_TWICE
  300. /* cmp cpuid */
  301. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  302. /* cmp @v equal to @expect */
  303. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  304. #endif
  305. /* try store */
  306. RSEQ_ASM_OP_STORE(newv2, v2)
  307. RSEQ_INJECT_ASM(5)
  308. #ifdef RSEQ_TEMPLATE_MO_RELEASE
  309. /* for 'release' */
  310. "lwsync\n\t"
  311. #endif
  312. /* final store */
  313. RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
  314. RSEQ_INJECT_ASM(6)
  315. RSEQ_ASM_DEFINE_ABORT(4, abort)
  316. : /* gcc asm goto does not allow outputs */
  317. : [cpu_id] "r" (cpu),
  318. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  319. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  320. /* try store input */
  321. [v2] "m" (*v2),
  322. [newv2] "r" (newv2),
  323. /* final store input */
  324. [v] "m" (*v),
  325. [expect] "r" (expect),
  326. [newv] "r" (newv)
  327. RSEQ_INJECT_INPUT
  328. : "memory", "cc", "r17"
  329. RSEQ_INJECT_CLOBBER
  330. : abort, cmpfail
  331. #ifdef RSEQ_COMPARE_TWICE
  332. , error1, error2
  333. #endif
  334. );
  335. rseq_after_asm_goto();
  336. return 0;
  337. abort:
  338. rseq_after_asm_goto();
  339. RSEQ_INJECT_FAILED
  340. return -1;
  341. cmpfail:
  342. rseq_after_asm_goto();
  343. return 1;
  344. #ifdef RSEQ_COMPARE_TWICE
  345. error1:
  346. rseq_after_asm_goto();
  347. rseq_bug("cpu_id comparison failed");
  348. error2:
  349. rseq_after_asm_goto();
  350. rseq_bug("expected value comparison failed");
  351. #endif
  352. }
  353. static inline __attribute__((always_inline))
  354. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev)(intptr_t *v, intptr_t expect,
  355. void *dst, void *src, size_t len,
  356. intptr_t newv, int cpu)
  357. {
  358. RSEQ_INJECT_C(9)
  359. __asm__ __volatile__ goto (
  360. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  361. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  362. #ifdef RSEQ_COMPARE_TWICE
  363. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  364. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  365. #endif
  366. /* setup for mempcy */
  367. "mr %%r19, %[len]\n\t"
  368. "mr %%r20, %[src]\n\t"
  369. "mr %%r21, %[dst]\n\t"
  370. /* Start rseq by storing table entry pointer into rseq_cs. */
  371. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  372. /* cmp cpuid */
  373. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  374. RSEQ_INJECT_ASM(3)
  375. /* cmp @v equal to @expect */
  376. RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
  377. RSEQ_INJECT_ASM(4)
  378. #ifdef RSEQ_COMPARE_TWICE
  379. /* cmp cpuid */
  380. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  381. /* cmp @v equal to @expect */
  382. RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
  383. #endif
  384. /* try memcpy */
  385. RSEQ_ASM_OP_R_MEMCPY()
  386. RSEQ_INJECT_ASM(5)
  387. #ifdef RSEQ_TEMPLATE_MO_RELEASE
  388. /* for 'release' */
  389. "lwsync\n\t"
  390. #endif
  391. /* final store */
  392. RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
  393. RSEQ_INJECT_ASM(6)
  394. /* teardown */
  395. RSEQ_ASM_DEFINE_ABORT(4, abort)
  396. : /* gcc asm goto does not allow outputs */
  397. : [cpu_id] "r" (cpu),
  398. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  399. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  400. /* final store input */
  401. [v] "m" (*v),
  402. [expect] "r" (expect),
  403. [newv] "r" (newv),
  404. /* try memcpy input */
  405. [dst] "r" (dst),
  406. [src] "r" (src),
  407. [len] "r" (len)
  408. RSEQ_INJECT_INPUT
  409. : "memory", "cc", "r17", "r18", "r19", "r20", "r21"
  410. RSEQ_INJECT_CLOBBER
  411. : abort, cmpfail
  412. #ifdef RSEQ_COMPARE_TWICE
  413. , error1, error2
  414. #endif
  415. );
  416. rseq_after_asm_goto();
  417. return 0;
  418. abort:
  419. rseq_after_asm_goto();
  420. RSEQ_INJECT_FAILED
  421. return -1;
  422. cmpfail:
  423. rseq_after_asm_goto();
  424. return 1;
  425. #ifdef RSEQ_COMPARE_TWICE
  426. error1:
  427. rseq_after_asm_goto();
  428. rseq_bug("cpu_id comparison failed");
  429. error2:
  430. rseq_after_asm_goto();
  431. rseq_bug("expected value comparison failed");
  432. #endif
  433. }
  434. #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
  435. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
  436. #include "rseq-bits-reset.h"