tm-unavailable.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright 2017, Gustavo Romero, Breno Leitao, Cyril Bur, IBM Corp.
  4. *
  5. * Force FP, VEC and VSX unavailable exception during transaction in all
  6. * possible scenarios regarding the MSR.FP and MSR.VEC state, e.g. when FP
  7. * is enable and VEC is disable, when FP is disable and VEC is enable, and
  8. * so on. Then we check if the restored state is correctly set for the
  9. * FP and VEC registers to the previous state we set just before we entered
  10. * in TM, i.e. we check if it corrupts somehow the recheckpointed FP and
  11. * VEC/Altivec registers on abortion due to an unavailable exception in TM.
  12. * N.B. In this test we do not test all the FP/Altivec/VSX registers for
  13. * corruption, but only for registers vs0 and vs32, which are respectively
  14. * representatives of FP and VEC/Altivec reg sets.
  15. */
  16. #define _GNU_SOURCE
  17. #include <error.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <inttypes.h>
  22. #include <stdbool.h>
  23. #include <pthread.h>
  24. #include <sched.h>
  25. #include "tm.h"
  26. #define DEBUG 0
  27. /* Unavailable exceptions to test in HTM */
  28. #define FP_UNA_EXCEPTION 0
  29. #define VEC_UNA_EXCEPTION 1
  30. #define VSX_UNA_EXCEPTION 2
  31. #define NUM_EXCEPTIONS 3
  32. #define err_at_line(status, errnum, format, ...) \
  33. error_at_line(status, errnum, __FILE__, __LINE__, format ##__VA_ARGS__)
  34. #define pr_warn(code, format, ...) err_at_line(0, code, format, ##__VA_ARGS__)
  35. #define pr_err(code, format, ...) err_at_line(1, code, format, ##__VA_ARGS__)
  36. struct Flags {
  37. int touch_fp;
  38. int touch_vec;
  39. int result;
  40. int exception;
  41. } flags;
  42. bool expecting_failure(void)
  43. {
  44. if (flags.touch_fp && flags.exception == FP_UNA_EXCEPTION)
  45. return false;
  46. if (flags.touch_vec && flags.exception == VEC_UNA_EXCEPTION)
  47. return false;
  48. /*
  49. * If both FP and VEC are touched it does not mean that touching VSX
  50. * won't raise an exception. However since FP and VEC state are already
  51. * correctly loaded, the transaction is not aborted (i.e.
  52. * treclaimed/trecheckpointed) and MSR.VSX is just set as 1, so a TM
  53. * failure is not expected also in this case.
  54. */
  55. if ((flags.touch_fp && flags.touch_vec) &&
  56. flags.exception == VSX_UNA_EXCEPTION)
  57. return false;
  58. return true;
  59. }
  60. /* Check if failure occurred whilst in transaction. */
  61. bool is_failure(uint64_t condition_reg)
  62. {
  63. /*
  64. * When failure handling occurs, CR0 is set to 0b1010 (0xa). Otherwise
  65. * transaction completes without failure and hence reaches out 'tend.'
  66. * that sets CR0 to 0b0100 (0x4).
  67. */
  68. return ((condition_reg >> 28) & 0xa) == 0xa;
  69. }
  70. void *tm_una_ping(void *input)
  71. {
  72. /*
  73. * Expected values for vs0 and vs32 after a TM failure. They must never
  74. * change, otherwise they got corrupted.
  75. */
  76. uint64_t high_vs0 = 0x5555555555555555;
  77. uint64_t low_vs0 = 0xffffffffffffffff;
  78. uint64_t high_vs32 = 0x5555555555555555;
  79. uint64_t low_vs32 = 0xffffffffffffffff;
  80. /* Counter for busy wait */
  81. uint64_t counter = 0x1ff000000;
  82. /*
  83. * Variable to keep a copy of CR register content taken just after we
  84. * leave the transactional state.
  85. */
  86. uint64_t cr_ = 0;
  87. /*
  88. * Wait a bit so thread can get its name "ping". This is not important
  89. * to reproduce the issue but it's nice to have for systemtap debugging.
  90. */
  91. if (DEBUG)
  92. sleep(1);
  93. printf("If MSR.FP=%d MSR.VEC=%d: ", flags.touch_fp, flags.touch_vec);
  94. if (flags.exception != FP_UNA_EXCEPTION &&
  95. flags.exception != VEC_UNA_EXCEPTION &&
  96. flags.exception != VSX_UNA_EXCEPTION) {
  97. printf("No valid exception specified to test.\n");
  98. return NULL;
  99. }
  100. asm (
  101. /* Prepare to merge low and high. */
  102. " mtvsrd 33, %[high_vs0] ;"
  103. " mtvsrd 34, %[low_vs0] ;"
  104. /*
  105. * Adjust VS0 expected value after an TM failure,
  106. * i.e. vs0 = 0x5555555555555555555FFFFFFFFFFFFFFFF
  107. */
  108. " xxmrghd 0, 33, 34 ;"
  109. /*
  110. * Adjust VS32 expected value after an TM failure,
  111. * i.e. vs32 = 0x5555555555555555555FFFFFFFFFFFFFFFF
  112. */
  113. " xxmrghd 32, 33, 34 ;"
  114. /*
  115. * Wait an amount of context switches so load_fp and load_vec
  116. * overflow and MSR.FP, MSR.VEC, and MSR.VSX become zero (off).
  117. */
  118. " mtctr %[counter] ;"
  119. /* Decrement CTR branch if CTR non zero. */
  120. "1: bdnz 1b ;"
  121. /*
  122. * Check if we want to touch FP prior to the test in order
  123. * to set MSR.FP = 1 before provoking an unavailable
  124. * exception in TM.
  125. */
  126. " cmpldi %[touch_fp], 0 ;"
  127. " beq no_fp ;"
  128. " fadd 10, 10, 10 ;"
  129. "no_fp: ;"
  130. /*
  131. * Check if we want to touch VEC prior to the test in order
  132. * to set MSR.VEC = 1 before provoking an unavailable
  133. * exception in TM.
  134. */
  135. " cmpldi %[touch_vec], 0 ;"
  136. " beq no_vec ;"
  137. " vaddcuw 10, 10, 10 ;"
  138. "no_vec: ;"
  139. /*
  140. * Perhaps it would be a better idea to do the
  141. * compares outside transactional context and simply
  142. * duplicate code.
  143. */
  144. " tbegin. ;"
  145. " beq trans_fail ;"
  146. /* Do we do FP Unavailable? */
  147. " cmpldi %[exception], %[ex_fp] ;"
  148. " bne 1f ;"
  149. " fadd 10, 10, 10 ;"
  150. " b done ;"
  151. /* Do we do VEC Unavailable? */
  152. "1: cmpldi %[exception], %[ex_vec] ;"
  153. " bne 2f ;"
  154. " vaddcuw 10, 10, 10 ;"
  155. " b done ;"
  156. /*
  157. * Not FP or VEC, therefore VSX. Ensure this
  158. * instruction always generates a VSX Unavailable.
  159. * ISA 3.0 is tricky here.
  160. * (xxmrghd will on ISA 2.07 and ISA 3.0)
  161. */
  162. "2: xxmrghd 10, 10, 10 ;"
  163. "done: tend. ;"
  164. "trans_fail: ;"
  165. /* Give values back to C. */
  166. " mfvsrd %[high_vs0], 0 ;"
  167. " xxsldwi 3, 0, 0, 2 ;"
  168. " mfvsrd %[low_vs0], 3 ;"
  169. " mfvsrd %[high_vs32], 32 ;"
  170. " xxsldwi 3, 32, 32, 2 ;"
  171. " mfvsrd %[low_vs32], 3 ;"
  172. /* Give CR back to C so that it can check what happened. */
  173. " mfcr %[cr_] ;"
  174. : [high_vs0] "+r" (high_vs0),
  175. [low_vs0] "+r" (low_vs0),
  176. [high_vs32] "=r" (high_vs32),
  177. [low_vs32] "=r" (low_vs32),
  178. [cr_] "+r" (cr_)
  179. : [touch_fp] "r" (flags.touch_fp),
  180. [touch_vec] "r" (flags.touch_vec),
  181. [exception] "r" (flags.exception),
  182. [ex_fp] "i" (FP_UNA_EXCEPTION),
  183. [ex_vec] "i" (VEC_UNA_EXCEPTION),
  184. [ex_vsx] "i" (VSX_UNA_EXCEPTION),
  185. [counter] "r" (counter)
  186. : "cr0", "ctr", "v10", "vs0", "vs10", "vs3", "vs32", "vs33",
  187. "vs34", "fr10"
  188. );
  189. /*
  190. * Check if we were expecting a failure and it did not occur by checking
  191. * CR0 state just after we leave the transaction. Either way we check if
  192. * vs0 or vs32 got corrupted.
  193. */
  194. if (expecting_failure() && !is_failure(cr_)) {
  195. printf("\n\tExpecting the transaction to fail, %s",
  196. "but it didn't\n\t");
  197. flags.result++;
  198. }
  199. /* Check if we were not expecting a failure and a it occurred. */
  200. if (!expecting_failure() && is_failure(cr_) &&
  201. !failure_is_reschedule()) {
  202. printf("\n\tUnexpected transaction failure 0x%02lx\n\t",
  203. failure_code());
  204. return (void *) -1;
  205. }
  206. /*
  207. * Check if TM failed due to the cause we were expecting. 0xda is a
  208. * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause, unless
  209. * it was caused by a reschedule.
  210. */
  211. if (is_failure(cr_) && !failure_is_unavailable() &&
  212. !failure_is_reschedule()) {
  213. printf("\n\tUnexpected failure cause 0x%02lx\n\t",
  214. failure_code());
  215. return (void *) -1;
  216. }
  217. /* 0x4 is a success and 0xa is a fail. See comment in is_failure(). */
  218. if (DEBUG)
  219. printf("CR0: 0x%1lx ", cr_ >> 28);
  220. /* Check FP (vs0) for the expected value. */
  221. if (high_vs0 != 0x5555555555555555 || low_vs0 != 0xFFFFFFFFFFFFFFFF) {
  222. printf("FP corrupted!");
  223. printf(" high = %#16" PRIx64 " low = %#16" PRIx64 " ",
  224. high_vs0, low_vs0);
  225. flags.result++;
  226. } else
  227. printf("FP ok ");
  228. /* Check VEC (vs32) for the expected value. */
  229. if (high_vs32 != 0x5555555555555555 || low_vs32 != 0xFFFFFFFFFFFFFFFF) {
  230. printf("VEC corrupted!");
  231. printf(" high = %#16" PRIx64 " low = %#16" PRIx64,
  232. high_vs32, low_vs32);
  233. flags.result++;
  234. } else
  235. printf("VEC ok");
  236. putchar('\n');
  237. return NULL;
  238. }
  239. /* Thread to force context switch */
  240. void *tm_una_pong(void *not_used)
  241. {
  242. /* Wait thread get its name "pong". */
  243. if (DEBUG)
  244. sleep(1);
  245. /* Classed as an interactive-like thread. */
  246. while (1)
  247. sched_yield();
  248. }
  249. /* Function that creates a thread and launches the "ping" task. */
  250. void test_fp_vec(int fp, int vec, pthread_attr_t *attr)
  251. {
  252. int retries = 2;
  253. void *ret_value;
  254. pthread_t t0;
  255. flags.touch_fp = fp;
  256. flags.touch_vec = vec;
  257. /*
  258. * Without luck it's possible that the transaction is aborted not due to
  259. * the unavailable exception caught in the middle as we expect but also,
  260. * for instance, due to a context switch or due to a KVM reschedule (if
  261. * it's running on a VM). Thus we try a few times before giving up,
  262. * checking if the failure cause is the one we expect.
  263. */
  264. do {
  265. int rc;
  266. /* Bind to CPU 0, as specified in 'attr'. */
  267. rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags);
  268. if (rc)
  269. pr_err(rc, "pthread_create()");
  270. rc = pthread_setname_np(t0, "tm_una_ping");
  271. if (rc)
  272. pr_warn(rc, "pthread_setname_np");
  273. rc = pthread_join(t0, &ret_value);
  274. if (rc)
  275. pr_err(rc, "pthread_join");
  276. retries--;
  277. } while (ret_value != NULL && retries);
  278. if (!retries) {
  279. flags.result = 1;
  280. if (DEBUG)
  281. printf("All transactions failed unexpectedly\n");
  282. }
  283. }
  284. int tm_unavailable_test(void)
  285. {
  286. int cpu, rc, exception; /* FP = 0, VEC = 1, VSX = 2 */
  287. pthread_t t1;
  288. pthread_attr_t attr;
  289. cpu_set_t cpuset;
  290. SKIP_IF(!have_htm());
  291. SKIP_IF(htm_is_synthetic());
  292. cpu = pick_online_cpu();
  293. FAIL_IF(cpu < 0);
  294. // Set only one CPU in the mask. Both threads will be bound to that CPU.
  295. CPU_ZERO(&cpuset);
  296. CPU_SET(cpu, &cpuset);
  297. /* Init pthread attribute. */
  298. rc = pthread_attr_init(&attr);
  299. if (rc)
  300. pr_err(rc, "pthread_attr_init()");
  301. /* Set CPU 0 mask into the pthread attribute. */
  302. rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
  303. if (rc)
  304. pr_err(rc, "pthread_attr_setaffinity_np()");
  305. rc = pthread_create(&t1, &attr /* Bind to CPU 0 */, tm_una_pong, NULL);
  306. if (rc)
  307. pr_err(rc, "pthread_create()");
  308. /* Name it for systemtap convenience */
  309. rc = pthread_setname_np(t1, "tm_una_pong");
  310. if (rc)
  311. pr_warn(rc, "pthread_create()");
  312. flags.result = 0;
  313. for (exception = 0; exception < NUM_EXCEPTIONS; exception++) {
  314. printf("Checking if FP/VEC registers are sane after");
  315. if (exception == FP_UNA_EXCEPTION)
  316. printf(" a FP unavailable exception...\n");
  317. else if (exception == VEC_UNA_EXCEPTION)
  318. printf(" a VEC unavailable exception...\n");
  319. else
  320. printf(" a VSX unavailable exception...\n");
  321. flags.exception = exception;
  322. test_fp_vec(0, 0, &attr);
  323. test_fp_vec(1, 0, &attr);
  324. test_fp_vec(0, 1, &attr);
  325. test_fp_vec(1, 1, &attr);
  326. }
  327. if (flags.result > 0) {
  328. printf("result: failed!\n");
  329. exit(1);
  330. } else {
  331. printf("result: success\n");
  332. exit(0);
  333. }
  334. }
  335. int main(int argc, char **argv)
  336. {
  337. test_harness_set_timeout(220);
  338. return test_harness(tm_unavailable_test, "tm_unavailable_test");
  339. }