rseq-s390-bits.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
  2. #include "rseq-bits-template.h"
  3. #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
  4. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
  5. static inline __attribute__((always_inline))
  6. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev)(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
  7. {
  8. RSEQ_INJECT_C(9)
  9. __asm__ __volatile__ goto (
  10. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  11. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  12. #ifdef RSEQ_COMPARE_TWICE
  13. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  14. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  15. #endif
  16. /* Start rseq by storing table entry pointer into rseq_cs. */
  17. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  18. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  19. RSEQ_INJECT_ASM(3)
  20. LONG_CMP " %[expect], %[v]\n\t"
  21. "jnz %l[cmpfail]\n\t"
  22. RSEQ_INJECT_ASM(4)
  23. #ifdef RSEQ_COMPARE_TWICE
  24. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  25. LONG_CMP " %[expect], %[v]\n\t"
  26. "jnz %l[error2]\n\t"
  27. #endif
  28. /* final store */
  29. LONG_S " %[newv], %[v]\n\t"
  30. "2:\n\t"
  31. RSEQ_INJECT_ASM(5)
  32. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  33. : /* gcc asm goto does not allow outputs */
  34. : [cpu_id] "r" (cpu),
  35. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  36. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  37. [v] "m" (*v),
  38. [expect] "r" (expect),
  39. [newv] "r" (newv)
  40. RSEQ_INJECT_INPUT
  41. : "memory", "cc", "r0"
  42. RSEQ_INJECT_CLOBBER
  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. /*
  67. * Compare @v against @expectnot. When it does _not_ match, load @v
  68. * into @load, and store the content of *@v + voffp into @v.
  69. */
  70. static inline __attribute__((always_inline))
  71. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load)(intptr_t *v, intptr_t expectnot,
  72. long voffp, intptr_t *load, int cpu)
  73. {
  74. RSEQ_INJECT_C(9)
  75. __asm__ __volatile__ goto (
  76. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  77. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  78. #ifdef RSEQ_COMPARE_TWICE
  79. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  80. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  81. #endif
  82. /* Start rseq by storing table entry pointer into rseq_cs. */
  83. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  84. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  85. RSEQ_INJECT_ASM(3)
  86. LONG_L " %%r1, %[v]\n\t"
  87. LONG_CMP_R " %%r1, %[expectnot]\n\t"
  88. "je %l[cmpfail]\n\t"
  89. RSEQ_INJECT_ASM(4)
  90. #ifdef RSEQ_COMPARE_TWICE
  91. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  92. LONG_L " %%r1, %[v]\n\t"
  93. LONG_CMP_R " %%r1, %[expectnot]\n\t"
  94. "je %l[error2]\n\t"
  95. #endif
  96. LONG_S " %%r1, %[load]\n\t"
  97. LONG_ADD_R " %%r1, %[voffp]\n\t"
  98. LONG_L " %%r1, 0(%%r1)\n\t"
  99. /* final store */
  100. LONG_S " %%r1, %[v]\n\t"
  101. "2:\n\t"
  102. RSEQ_INJECT_ASM(5)
  103. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  104. : /* gcc asm goto does not allow outputs */
  105. : [cpu_id] "r" (cpu),
  106. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  107. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  108. /* final store input */
  109. [v] "m" (*v),
  110. [expectnot] "r" (expectnot),
  111. [voffp] "r" (voffp),
  112. [load] "m" (*load)
  113. RSEQ_INJECT_INPUT
  114. : "memory", "cc", "r0", "r1"
  115. RSEQ_INJECT_CLOBBER
  116. : abort, cmpfail
  117. #ifdef RSEQ_COMPARE_TWICE
  118. , error1, error2
  119. #endif
  120. );
  121. rseq_after_asm_goto();
  122. return 0;
  123. abort:
  124. rseq_after_asm_goto();
  125. RSEQ_INJECT_FAILED
  126. return -1;
  127. cmpfail:
  128. rseq_after_asm_goto();
  129. return 1;
  130. #ifdef RSEQ_COMPARE_TWICE
  131. error1:
  132. rseq_after_asm_goto();
  133. rseq_bug("cpu_id comparison failed");
  134. error2:
  135. rseq_after_asm_goto();
  136. rseq_bug("expected value comparison failed");
  137. #endif
  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. __asm__ __volatile__ goto (
  144. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  145. #ifdef RSEQ_COMPARE_TWICE
  146. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  147. #endif
  148. /* Start rseq by storing table entry pointer into rseq_cs. */
  149. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  150. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  151. RSEQ_INJECT_ASM(3)
  152. #ifdef RSEQ_COMPARE_TWICE
  153. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  154. #endif
  155. LONG_L " %%r0, %[v]\n\t"
  156. LONG_ADD_R " %%r0, %[count]\n\t"
  157. /* final store */
  158. LONG_S " %%r0, %[v]\n\t"
  159. "2:\n\t"
  160. RSEQ_INJECT_ASM(4)
  161. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  162. : /* gcc asm goto does not allow outputs */
  163. : [cpu_id] "r" (cpu),
  164. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  165. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  166. /* final store input */
  167. [v] "m" (*v),
  168. [count] "r" (count)
  169. RSEQ_INJECT_INPUT
  170. : "memory", "cc", "r0"
  171. RSEQ_INJECT_CLOBBER
  172. : abort
  173. #ifdef RSEQ_COMPARE_TWICE
  174. , error1
  175. #endif
  176. );
  177. rseq_after_asm_goto();
  178. return 0;
  179. abort:
  180. rseq_after_asm_goto();
  181. RSEQ_INJECT_FAILED
  182. return -1;
  183. #ifdef RSEQ_COMPARE_TWICE
  184. error1:
  185. rseq_after_asm_goto();
  186. rseq_bug("cpu_id comparison failed");
  187. #endif
  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. __asm__ __volatile__ goto (
  196. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  197. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  198. #ifdef RSEQ_COMPARE_TWICE
  199. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  200. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  201. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
  202. #endif
  203. /* Start rseq by storing table entry pointer into rseq_cs. */
  204. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  205. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  206. RSEQ_INJECT_ASM(3)
  207. LONG_CMP " %[expect], %[v]\n\t"
  208. "jnz %l[cmpfail]\n\t"
  209. RSEQ_INJECT_ASM(4)
  210. LONG_CMP " %[expect2], %[v2]\n\t"
  211. "jnz %l[cmpfail]\n\t"
  212. RSEQ_INJECT_ASM(5)
  213. #ifdef RSEQ_COMPARE_TWICE
  214. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
  215. LONG_CMP " %[expect], %[v]\n\t"
  216. "jnz %l[error2]\n\t"
  217. LONG_CMP " %[expect2], %[v2]\n\t"
  218. "jnz %l[error3]\n\t"
  219. #endif
  220. /* final store */
  221. LONG_S " %[newv], %[v]\n\t"
  222. "2:\n\t"
  223. RSEQ_INJECT_ASM(6)
  224. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  225. : /* gcc asm goto does not allow outputs */
  226. : [cpu_id] "r" (cpu),
  227. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  228. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  229. /* cmp2 input */
  230. [v2] "m" (*v2),
  231. [expect2] "r" (expect2),
  232. /* final store input */
  233. [v] "m" (*v),
  234. [expect] "r" (expect),
  235. [newv] "r" (newv)
  236. RSEQ_INJECT_INPUT
  237. : "memory", "cc", "r0"
  238. RSEQ_INJECT_CLOBBER
  239. : abort, cmpfail
  240. #ifdef RSEQ_COMPARE_TWICE
  241. , error1, error2, error3
  242. #endif
  243. );
  244. rseq_after_asm_goto();
  245. return 0;
  246. abort:
  247. rseq_after_asm_goto();
  248. RSEQ_INJECT_FAILED
  249. return -1;
  250. cmpfail:
  251. rseq_after_asm_goto();
  252. return 1;
  253. #ifdef RSEQ_COMPARE_TWICE
  254. error1:
  255. rseq_after_asm_goto();
  256. rseq_bug("cpu_id comparison failed");
  257. error2:
  258. rseq_after_asm_goto();
  259. rseq_bug("1st expected value comparison failed");
  260. error3:
  261. rseq_after_asm_goto();
  262. rseq_bug("2nd expected value comparison failed");
  263. #endif
  264. }
  265. #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
  266. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
  267. #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
  268. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
  269. /* s390 is TSO. */
  270. static inline __attribute__((always_inline))
  271. int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev)(intptr_t *v, intptr_t expect,
  272. intptr_t *v2, intptr_t newv2,
  273. intptr_t newv, int cpu)
  274. {
  275. RSEQ_INJECT_C(9)
  276. __asm__ __volatile__ goto (
  277. RSEQ_ASM_DEFINE_TABLE(3, 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, 3b, rseq_cs)
  285. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  286. RSEQ_INJECT_ASM(3)
  287. LONG_CMP " %[expect], %[v]\n\t"
  288. "jnz %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_CMP " %[expect], %[v]\n\t"
  293. "jnz %l[error2]\n\t"
  294. #endif
  295. /* try store */
  296. LONG_S " %[newv2], %[v2]\n\t"
  297. RSEQ_INJECT_ASM(5)
  298. /* final store */
  299. LONG_S " %[newv], %[v]\n\t"
  300. "2:\n\t"
  301. RSEQ_INJECT_ASM(6)
  302. RSEQ_ASM_DEFINE_ABORT(4, "", abort)
  303. : /* gcc asm goto does not allow outputs */
  304. : [cpu_id] "r" (cpu),
  305. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  306. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  307. /* try store input */
  308. [v2] "m" (*v2),
  309. [newv2] "r" (newv2),
  310. /* final store input */
  311. [v] "m" (*v),
  312. [expect] "r" (expect),
  313. [newv] "r" (newv)
  314. RSEQ_INJECT_INPUT
  315. : "memory", "cc", "r0"
  316. RSEQ_INJECT_CLOBBER
  317. : abort, cmpfail
  318. #ifdef RSEQ_COMPARE_TWICE
  319. , error1, error2
  320. #endif
  321. );
  322. rseq_after_asm_goto();
  323. return 0;
  324. abort:
  325. rseq_after_asm_goto();
  326. RSEQ_INJECT_FAILED
  327. return -1;
  328. cmpfail:
  329. rseq_after_asm_goto();
  330. return 1;
  331. #ifdef RSEQ_COMPARE_TWICE
  332. error1:
  333. rseq_after_asm_goto();
  334. rseq_bug("cpu_id comparison failed");
  335. error2:
  336. rseq_after_asm_goto();
  337. rseq_bug("expected value comparison failed");
  338. #endif
  339. }
  340. /* s390 is TSO. */
  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. uint64_t rseq_scratch[3];
  347. RSEQ_INJECT_C(9)
  348. __asm__ __volatile__ goto (
  349. RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
  350. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
  351. #ifdef RSEQ_COMPARE_TWICE
  352. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
  353. RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
  354. #endif
  355. LONG_S " %[src], %[rseq_scratch0]\n\t"
  356. LONG_S " %[dst], %[rseq_scratch1]\n\t"
  357. LONG_S " %[len], %[rseq_scratch2]\n\t"
  358. /* Start rseq by storing table entry pointer into rseq_cs. */
  359. RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
  360. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
  361. RSEQ_INJECT_ASM(3)
  362. LONG_CMP " %[expect], %[v]\n\t"
  363. "jnz 5f\n\t"
  364. RSEQ_INJECT_ASM(4)
  365. #ifdef RSEQ_COMPARE_TWICE
  366. RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
  367. LONG_CMP " %[expect], %[v]\n\t"
  368. "jnz 7f\n\t"
  369. #endif
  370. /* try memcpy */
  371. LONG_LT_R " %[len], %[len]\n\t"
  372. "jz 333f\n\t"
  373. "222:\n\t"
  374. "ic %%r0,0(%[src])\n\t"
  375. "stc %%r0,0(%[dst])\n\t"
  376. LONG_ADDI " %[src], 1\n\t"
  377. LONG_ADDI " %[dst], 1\n\t"
  378. LONG_ADDI " %[len], -1\n\t"
  379. "jnz 222b\n\t"
  380. "333:\n\t"
  381. RSEQ_INJECT_ASM(5)
  382. /* final store */
  383. LONG_S " %[newv], %[v]\n\t"
  384. "2:\n\t"
  385. RSEQ_INJECT_ASM(6)
  386. /* teardown */
  387. LONG_L " %[len], %[rseq_scratch2]\n\t"
  388. LONG_L " %[dst], %[rseq_scratch1]\n\t"
  389. LONG_L " %[src], %[rseq_scratch0]\n\t"
  390. RSEQ_ASM_DEFINE_ABORT(4,
  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. abort)
  395. RSEQ_ASM_DEFINE_CMPFAIL(5,
  396. LONG_L " %[len], %[rseq_scratch2]\n\t"
  397. LONG_L " %[dst], %[rseq_scratch1]\n\t"
  398. LONG_L " %[src], %[rseq_scratch0]\n\t",
  399. cmpfail)
  400. #ifdef RSEQ_COMPARE_TWICE
  401. RSEQ_ASM_DEFINE_CMPFAIL(6,
  402. LONG_L " %[len], %[rseq_scratch2]\n\t"
  403. LONG_L " %[dst], %[rseq_scratch1]\n\t"
  404. LONG_L " %[src], %[rseq_scratch0]\n\t",
  405. error1)
  406. RSEQ_ASM_DEFINE_CMPFAIL(7,
  407. LONG_L " %[len], %[rseq_scratch2]\n\t"
  408. LONG_L " %[dst], %[rseq_scratch1]\n\t"
  409. LONG_L " %[src], %[rseq_scratch0]\n\t",
  410. error2)
  411. #endif
  412. : /* gcc asm goto does not allow outputs */
  413. : [cpu_id] "r" (cpu),
  414. [current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
  415. [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
  416. /* final store input */
  417. [v] "m" (*v),
  418. [expect] "r" (expect),
  419. [newv] "r" (newv),
  420. /* try memcpy input */
  421. [dst] "r" (dst),
  422. [src] "r" (src),
  423. [len] "r" (len),
  424. [rseq_scratch0] "m" (rseq_scratch[0]),
  425. [rseq_scratch1] "m" (rseq_scratch[1]),
  426. [rseq_scratch2] "m" (rseq_scratch[2])
  427. RSEQ_INJECT_INPUT
  428. : "memory", "cc", "r0"
  429. RSEQ_INJECT_CLOBBER
  430. : abort, cmpfail
  431. #ifdef RSEQ_COMPARE_TWICE
  432. , error1, error2
  433. #endif
  434. );
  435. rseq_after_asm_goto();
  436. return 0;
  437. abort:
  438. rseq_after_asm_goto();
  439. RSEQ_INJECT_FAILED
  440. return -1;
  441. cmpfail:
  442. rseq_after_asm_goto();
  443. return 1;
  444. #ifdef RSEQ_COMPARE_TWICE
  445. error1:
  446. rseq_after_asm_goto();
  447. rseq_bug("cpu_id comparison failed");
  448. error2:
  449. rseq_after_asm_goto();
  450. rseq_bug("expected value comparison failed");
  451. #endif
  452. }
  453. #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
  454. (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
  455. #include "rseq-bits-reset.h"