2 * Copyright 2017, Gustavo Romero, Breno Leitao, Cyril Bur, IBM Corp.
3 * Licensed under GPLv2.
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.
31 /* Unavailable exceptions to test in HTM */
32 #define FP_UNA_EXCEPTION 0
33 #define VEC_UNA_EXCEPTION 1
34 #define VSX_UNA_EXCEPTION 2
36 #define NUM_EXCEPTIONS 3
37 #define err_at_line(status, errnum, format, ...) \
38 error_at_line(status, errnum, __FILE__, __LINE__, format ##__VA_ARGS__)
40 #define pr_warn(code, format, ...) err_at_line(0, code, format, ##__VA_ARGS__)
41 #define pr_err(code, format, ...) err_at_line(1, code, format, ##__VA_ARGS__)
50 bool expecting_failure(void)
52 if (flags.touch_fp && flags.exception == FP_UNA_EXCEPTION)
55 if (flags.touch_vec && flags.exception == VEC_UNA_EXCEPTION)
59 * If both FP and VEC are touched it does not mean that touching VSX
60 * won't raise an exception. However since FP and VEC state are already
61 * correctly loaded, the transaction is not aborted (i.e.
62 * treclaimed/trecheckpointed) and MSR.VSX is just set as 1, so a TM
63 * failure is not expected also in this case.
65 if ((flags.touch_fp && flags.touch_vec) &&
66 flags.exception == VSX_UNA_EXCEPTION)
72 /* Check if failure occurred whilst in transaction. */
73 bool is_failure(uint64_t condition_reg)
76 * When failure handling occurs, CR0 is set to 0b1010 (0xa). Otherwise
77 * transaction completes without failure and hence reaches out 'tend.'
78 * that sets CR0 to 0b0100 (0x4).
80 return ((condition_reg >> 28) & 0xa) == 0xa;
83 void *tm_una_ping(void *input)
87 * Expected values for vs0 and vs32 after a TM failure. They must never
88 * change, otherwise they got corrupted.
90 uint64_t high_vs0 = 0x5555555555555555;
91 uint64_t low_vs0 = 0xffffffffffffffff;
92 uint64_t high_vs32 = 0x5555555555555555;
93 uint64_t low_vs32 = 0xffffffffffffffff;
95 /* Counter for busy wait */
96 uint64_t counter = 0x1ff000000;
99 * Variable to keep a copy of CR register content taken just after we
100 * leave the transactional state.
105 * Wait a bit so thread can get its name "ping". This is not important
106 * to reproduce the issue but it's nice to have for systemtap debugging.
111 printf("If MSR.FP=%d MSR.VEC=%d: ", flags.touch_fp, flags.touch_vec);
113 if (flags.exception != FP_UNA_EXCEPTION &&
114 flags.exception != VEC_UNA_EXCEPTION &&
115 flags.exception != VSX_UNA_EXCEPTION) {
116 printf("No valid exception specified to test.\n");
121 /* Prepare to merge low and high. */
122 " mtvsrd 33, %[high_vs0] ;"
123 " mtvsrd 34, %[low_vs0] ;"
126 * Adjust VS0 expected value after an TM failure,
127 * i.e. vs0 = 0x5555555555555555555FFFFFFFFFFFFFFFF
129 " xxmrghd 0, 33, 34 ;"
132 * Adjust VS32 expected value after an TM failure,
133 * i.e. vs32 = 0x5555555555555555555FFFFFFFFFFFFFFFF
135 " xxmrghd 32, 33, 34 ;"
138 * Wait an amount of context switches so load_fp and load_vec
139 * overflow and MSR.FP, MSR.VEC, and MSR.VSX become zero (off).
141 " mtctr %[counter] ;"
143 /* Decrement CTR branch if CTR non zero. */
147 * Check if we want to touch FP prior to the test in order
148 * to set MSR.FP = 1 before provoking an unavailable
151 " cmpldi %[touch_fp], 0 ;"
157 * Check if we want to touch VEC prior to the test in order
158 * to set MSR.VEC = 1 before provoking an unavailable
161 " cmpldi %[touch_vec], 0 ;"
163 " vaddcuw 10, 10, 10 ;"
167 * Perhaps it would be a better idea to do the
168 * compares outside transactional context and simply
174 /* Do we do FP Unavailable? */
175 " cmpldi %[exception], %[ex_fp] ;"
180 /* Do we do VEC Unavailable? */
181 "1: cmpldi %[exception], %[ex_vec] ;"
183 " vaddcuw 10, 10, 10 ;"
187 * Not FP or VEC, therefore VSX. Ensure this
188 * instruction always generates a VSX Unavailable.
189 * ISA 3.0 is tricky here.
190 * (xxmrghd will on ISA 2.07 and ISA 3.0)
192 "2: xxmrghd 10, 10, 10 ;"
198 /* Give values back to C. */
199 " mfvsrd %[high_vs0], 0 ;"
200 " xxsldwi 3, 0, 0, 2 ;"
201 " mfvsrd %[low_vs0], 3 ;"
202 " mfvsrd %[high_vs32], 32 ;"
203 " xxsldwi 3, 32, 32, 2 ;"
204 " mfvsrd %[low_vs32], 3 ;"
206 /* Give CR back to C so that it can check what happened. */
209 : [high_vs0] "+r" (high_vs0),
210 [low_vs0] "+r" (low_vs0),
211 [high_vs32] "=r" (high_vs32),
212 [low_vs32] "=r" (low_vs32),
214 : [touch_fp] "r" (flags.touch_fp),
215 [touch_vec] "r" (flags.touch_vec),
216 [exception] "r" (flags.exception),
217 [ex_fp] "i" (FP_UNA_EXCEPTION),
218 [ex_vec] "i" (VEC_UNA_EXCEPTION),
219 [ex_vsx] "i" (VSX_UNA_EXCEPTION),
220 [counter] "r" (counter)
222 : "cr0", "ctr", "v10", "vs0", "vs10", "vs3", "vs32", "vs33",
228 * Check if we were expecting a failure and it did not occur by checking
229 * CR0 state just after we leave the transaction. Either way we check if
230 * vs0 or vs32 got corrupted.
232 if (expecting_failure() && !is_failure(cr_)) {
233 printf("\n\tExpecting the transaction to fail, %s",
234 "but it didn't\n\t");
238 /* Check if we were not expecting a failure and a it occurred. */
239 if (!expecting_failure() && is_failure(cr_)) {
240 printf("\n\tUnexpected transaction failure 0x%02lx\n\t",
246 * Check if TM failed due to the cause we were expecting. 0xda is a
247 * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause.
249 if (is_failure(cr_) && !failure_is_unavailable()) {
250 printf("\n\tUnexpected failure cause 0x%02lx\n\t",
255 /* 0x4 is a success and 0xa is a fail. See comment in is_failure(). */
257 printf("CR0: 0x%1lx ", cr_ >> 28);
259 /* Check FP (vs0) for the expected value. */
260 if (high_vs0 != 0x5555555555555555 || low_vs0 != 0xFFFFFFFFFFFFFFFF) {
261 printf("FP corrupted!");
262 printf(" high = %#16" PRIx64 " low = %#16" PRIx64 " ",
268 /* Check VEC (vs32) for the expected value. */
269 if (high_vs32 != 0x5555555555555555 || low_vs32 != 0xFFFFFFFFFFFFFFFF) {
270 printf("VEC corrupted!");
271 printf(" high = %#16" PRIx64 " low = %#16" PRIx64,
272 high_vs32, low_vs32);
282 /* Thread to force context switch */
283 void *tm_una_pong(void *not_used)
285 /* Wait thread get its name "pong". */
289 /* Classed as an interactive-like thread. */
294 /* Function that creates a thread and launches the "ping" task. */
295 void test_fp_vec(int fp, int vec, pthread_attr_t *attr)
302 flags.touch_vec = vec;
305 * Without luck it's possible that the transaction is aborted not due to
306 * the unavailable exception caught in the middle as we expect but also,
307 * for instance, due to a context switch or due to a KVM reschedule (if
308 * it's running on a VM). Thus we try a few times before giving up,
309 * checking if the failure cause is the one we expect.
314 /* Bind to CPU 0, as specified in 'attr'. */
315 rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags);
317 pr_err(rc, "pthread_create()");
318 rc = pthread_setname_np(t0, "tm_una_ping");
320 pr_warn(rc, "pthread_setname_np");
321 rc = pthread_join(t0, &ret_value);
323 pr_err(rc, "pthread_join");
326 } while (ret_value != NULL && retries);
331 printf("All transactions failed unexpectedly\n");
336 int tm_unavailable_test(void)
338 int rc, exception; /* FP = 0, VEC = 1, VSX = 2 */
343 SKIP_IF(!have_htm());
345 /* Set only CPU 0 in the mask. Both threads will be bound to CPU 0. */
349 /* Init pthread attribute. */
350 rc = pthread_attr_init(&attr);
352 pr_err(rc, "pthread_attr_init()");
354 /* Set CPU 0 mask into the pthread attribute. */
355 rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
357 pr_err(rc, "pthread_attr_setaffinity_np()");
359 rc = pthread_create(&t1, &attr /* Bind to CPU 0 */, tm_una_pong, NULL);
361 pr_err(rc, "pthread_create()");
363 /* Name it for systemtap convenience */
364 rc = pthread_setname_np(t1, "tm_una_pong");
366 pr_warn(rc, "pthread_create()");
370 for (exception = 0; exception < NUM_EXCEPTIONS; exception++) {
371 printf("Checking if FP/VEC registers are sane after");
373 if (exception == FP_UNA_EXCEPTION)
374 printf(" a FP unavailable exception...\n");
376 else if (exception == VEC_UNA_EXCEPTION)
377 printf(" a VEC unavailable exception...\n");
380 printf(" a VSX unavailable exception...\n");
382 flags.exception = exception;
384 test_fp_vec(0, 0, &attr);
385 test_fp_vec(1, 0, &attr);
386 test_fp_vec(0, 1, &attr);
387 test_fp_vec(1, 1, &attr);
391 if (flags.result > 0) {
392 printf("result: failed!\n");
395 printf("result: success\n");
400 int main(int argc, char **argv)
402 test_harness_set_timeout(220);
403 return test_harness(tm_unavailable_test, "tm_unavailable_test");