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 !failure_is_reschedule()) {
241 printf("\n\tUnexpected transaction failure 0x%02lx\n\t",
247 * Check if TM failed due to the cause we were expecting. 0xda is a
248 * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause, unless
249 * it was caused by a reschedule.
251 if (is_failure(cr_
) && !failure_is_unavailable() &&
252 !failure_is_reschedule()) {
253 printf("\n\tUnexpected failure cause 0x%02lx\n\t",
258 /* 0x4 is a success and 0xa is a fail. See comment in is_failure(). */
260 printf("CR0: 0x%1lx ", cr_
>> 28);
262 /* Check FP (vs0) for the expected value. */
263 if (high_vs0
!= 0x5555555555555555 || low_vs0
!= 0xFFFFFFFFFFFFFFFF) {
264 printf("FP corrupted!");
265 printf(" high = %#16" PRIx64
" low = %#16" PRIx64
" ",
271 /* Check VEC (vs32) for the expected value. */
272 if (high_vs32
!= 0x5555555555555555 || low_vs32
!= 0xFFFFFFFFFFFFFFFF) {
273 printf("VEC corrupted!");
274 printf(" high = %#16" PRIx64
" low = %#16" PRIx64
,
275 high_vs32
, low_vs32
);
285 /* Thread to force context switch */
286 void *tm_una_pong(void *not_used
)
288 /* Wait thread get its name "pong". */
292 /* Classed as an interactive-like thread. */
297 /* Function that creates a thread and launches the "ping" task. */
298 void test_fp_vec(int fp
, int vec
, pthread_attr_t
*attr
)
305 flags
.touch_vec
= vec
;
308 * Without luck it's possible that the transaction is aborted not due to
309 * the unavailable exception caught in the middle as we expect but also,
310 * for instance, due to a context switch or due to a KVM reschedule (if
311 * it's running on a VM). Thus we try a few times before giving up,
312 * checking if the failure cause is the one we expect.
317 /* Bind to CPU 0, as specified in 'attr'. */
318 rc
= pthread_create(&t0
, attr
, tm_una_ping
, (void *) &flags
);
320 pr_err(rc
, "pthread_create()");
321 rc
= pthread_setname_np(t0
, "tm_una_ping");
323 pr_warn(rc
, "pthread_setname_np");
324 rc
= pthread_join(t0
, &ret_value
);
326 pr_err(rc
, "pthread_join");
329 } while (ret_value
!= NULL
&& retries
);
334 printf("All transactions failed unexpectedly\n");
339 int tm_unavailable_test(void)
341 int rc
, exception
; /* FP = 0, VEC = 1, VSX = 2 */
346 SKIP_IF(!have_htm());
348 /* Set only CPU 0 in the mask. Both threads will be bound to CPU 0. */
352 /* Init pthread attribute. */
353 rc
= pthread_attr_init(&attr
);
355 pr_err(rc
, "pthread_attr_init()");
357 /* Set CPU 0 mask into the pthread attribute. */
358 rc
= pthread_attr_setaffinity_np(&attr
, sizeof(cpu_set_t
), &cpuset
);
360 pr_err(rc
, "pthread_attr_setaffinity_np()");
362 rc
= pthread_create(&t1
, &attr
/* Bind to CPU 0 */, tm_una_pong
, NULL
);
364 pr_err(rc
, "pthread_create()");
366 /* Name it for systemtap convenience */
367 rc
= pthread_setname_np(t1
, "tm_una_pong");
369 pr_warn(rc
, "pthread_create()");
373 for (exception
= 0; exception
< NUM_EXCEPTIONS
; exception
++) {
374 printf("Checking if FP/VEC registers are sane after");
376 if (exception
== FP_UNA_EXCEPTION
)
377 printf(" a FP unavailable exception...\n");
379 else if (exception
== VEC_UNA_EXCEPTION
)
380 printf(" a VEC unavailable exception...\n");
383 printf(" a VSX unavailable exception...\n");
385 flags
.exception
= exception
;
387 test_fp_vec(0, 0, &attr
);
388 test_fp_vec(1, 0, &attr
);
389 test_fp_vec(0, 1, &attr
);
390 test_fp_vec(1, 1, &attr
);
394 if (flags
.result
> 0) {
395 printf("result: failed!\n");
398 printf("result: success\n");
403 int main(int argc
, char **argv
)
405 test_harness_set_timeout(220);
406 return test_harness(tm_unavailable_test
, "tm_unavailable_test");