tm-unavailable.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * Copyright 2017, Gustavo Romero, Breno Leitao, Cyril Bur, IBM Corp.
  3. * Licensed under GPLv2.
  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. printf("\n\tUnexpected transaction failure 0x%02lx\n\t",
  202. failure_code());
  203. return (void *) -1;
  204. }
  205. /*
  206. * Check if TM failed due to the cause we were expecting. 0xda is a
  207. * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause.
  208. */
  209. if (is_failure(cr_) && !failure_is_unavailable()) {
  210. printf("\n\tUnexpected failure cause 0x%02lx\n\t",
  211. failure_code());
  212. return (void *) -1;
  213. }
  214. /* 0x4 is a success and 0xa is a fail. See comment in is_failure(). */
  215. if (DEBUG)
  216. printf("CR0: 0x%1lx ", cr_ >> 28);
  217. /* Check FP (vs0) for the expected value. */
  218. if (high_vs0 != 0x5555555555555555 || low_vs0 != 0xFFFFFFFFFFFFFFFF) {
  219. printf("FP corrupted!");
  220. printf(" high = %#16" PRIx64 " low = %#16" PRIx64 " ",
  221. high_vs0, low_vs0);
  222. flags.result++;
  223. } else
  224. printf("FP ok ");
  225. /* Check VEC (vs32) for the expected value. */
  226. if (high_vs32 != 0x5555555555555555 || low_vs32 != 0xFFFFFFFFFFFFFFFF) {
  227. printf("VEC corrupted!");
  228. printf(" high = %#16" PRIx64 " low = %#16" PRIx64,
  229. high_vs32, low_vs32);
  230. flags.result++;
  231. } else
  232. printf("VEC ok");
  233. putchar('\n');
  234. return NULL;
  235. }
  236. /* Thread to force context switch */
  237. void *tm_una_pong(void *not_used)
  238. {
  239. /* Wait thread get its name "pong". */
  240. if (DEBUG)
  241. sleep(1);
  242. /* Classed as an interactive-like thread. */
  243. while (1)
  244. sched_yield();
  245. }
  246. /* Function that creates a thread and launches the "ping" task. */
  247. void test_fp_vec(int fp, int vec, pthread_attr_t *attr)
  248. {
  249. int retries = 2;
  250. void *ret_value;
  251. pthread_t t0;
  252. flags.touch_fp = fp;
  253. flags.touch_vec = vec;
  254. /*
  255. * Without luck it's possible that the transaction is aborted not due to
  256. * the unavailable exception caught in the middle as we expect but also,
  257. * for instance, due to a context switch or due to a KVM reschedule (if
  258. * it's running on a VM). Thus we try a few times before giving up,
  259. * checking if the failure cause is the one we expect.
  260. */
  261. do {
  262. int rc;
  263. /* Bind to CPU 0, as specified in 'attr'. */
  264. rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags);
  265. if (rc)
  266. pr_err(rc, "pthread_create()");
  267. rc = pthread_setname_np(t0, "tm_una_ping");
  268. if (rc)
  269. pr_warn(rc, "pthread_setname_np");
  270. rc = pthread_join(t0, &ret_value);
  271. if (rc)
  272. pr_err(rc, "pthread_join");
  273. retries--;
  274. } while (ret_value != NULL && retries);
  275. if (!retries) {
  276. flags.result = 1;
  277. if (DEBUG)
  278. printf("All transactions failed unexpectedly\n");
  279. }
  280. }
  281. int tm_unavailable_test(void)
  282. {
  283. int rc, exception; /* FP = 0, VEC = 1, VSX = 2 */
  284. pthread_t t1;
  285. pthread_attr_t attr;
  286. cpu_set_t cpuset;
  287. SKIP_IF(!have_htm());
  288. /* Set only CPU 0 in the mask. Both threads will be bound to CPU 0. */
  289. CPU_ZERO(&cpuset);
  290. CPU_SET(0, &cpuset);
  291. /* Init pthread attribute. */
  292. rc = pthread_attr_init(&attr);
  293. if (rc)
  294. pr_err(rc, "pthread_attr_init()");
  295. /* Set CPU 0 mask into the pthread attribute. */
  296. rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
  297. if (rc)
  298. pr_err(rc, "pthread_attr_setaffinity_np()");
  299. rc = pthread_create(&t1, &attr /* Bind to CPU 0 */, tm_una_pong, NULL);
  300. if (rc)
  301. pr_err(rc, "pthread_create()");
  302. /* Name it for systemtap convenience */
  303. rc = pthread_setname_np(t1, "tm_una_pong");
  304. if (rc)
  305. pr_warn(rc, "pthread_create()");
  306. flags.result = 0;
  307. for (exception = 0; exception < NUM_EXCEPTIONS; exception++) {
  308. printf("Checking if FP/VEC registers are sane after");
  309. if (exception == FP_UNA_EXCEPTION)
  310. printf(" a FP unavailable exception...\n");
  311. else if (exception == VEC_UNA_EXCEPTION)
  312. printf(" a VEC unavailable exception...\n");
  313. else
  314. printf(" a VSX unavailable exception...\n");
  315. flags.exception = exception;
  316. test_fp_vec(0, 0, &attr);
  317. test_fp_vec(1, 0, &attr);
  318. test_fp_vec(0, 1, &attr);
  319. test_fp_vec(1, 1, &attr);
  320. }
  321. if (flags.result > 0) {
  322. printf("result: failed!\n");
  323. exit(1);
  324. } else {
  325. printf("result: success\n");
  326. exit(0);
  327. }
  328. }
  329. int main(int argc, char **argv)
  330. {
  331. test_harness_set_timeout(220);
  332. return test_harness(tm_unavailable_test, "tm_unavailable_test");
  333. }