rseq-mips-bits.h 13 KB

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