162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2017, Gustavo Romero, Breno Leitao, Cyril Bur, IBM Corp.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Force FP, VEC and VSX unavailable exception during transaction in all
662306a36Sopenharmony_ci * possible scenarios regarding the MSR.FP and MSR.VEC state, e.g. when FP
762306a36Sopenharmony_ci * is enable and VEC is disable, when FP is disable and VEC is enable, and
862306a36Sopenharmony_ci * so on. Then we check if the restored state is correctly set for the
962306a36Sopenharmony_ci * FP and VEC registers to the previous state we set just before we entered
1062306a36Sopenharmony_ci * in TM, i.e. we check if it corrupts somehow the recheckpointed FP and
1162306a36Sopenharmony_ci * VEC/Altivec registers on abortion due to an unavailable exception in TM.
1262306a36Sopenharmony_ci * N.B. In this test we do not test all the FP/Altivec/VSX registers for
1362306a36Sopenharmony_ci * corruption, but only for registers vs0 and vs32, which are respectively
1462306a36Sopenharmony_ci * representatives of FP and VEC/Altivec reg sets.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define _GNU_SOURCE
1862306a36Sopenharmony_ci#include <error.h>
1962306a36Sopenharmony_ci#include <stdio.h>
2062306a36Sopenharmony_ci#include <stdlib.h>
2162306a36Sopenharmony_ci#include <unistd.h>
2262306a36Sopenharmony_ci#include <inttypes.h>
2362306a36Sopenharmony_ci#include <stdbool.h>
2462306a36Sopenharmony_ci#include <pthread.h>
2562306a36Sopenharmony_ci#include <sched.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "tm.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define DEBUG 0
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* Unavailable exceptions to test in HTM */
3262306a36Sopenharmony_ci#define FP_UNA_EXCEPTION	0
3362306a36Sopenharmony_ci#define VEC_UNA_EXCEPTION	1
3462306a36Sopenharmony_ci#define VSX_UNA_EXCEPTION	2
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define NUM_EXCEPTIONS		3
3762306a36Sopenharmony_ci#define err_at_line(status, errnum, format, ...) \
3862306a36Sopenharmony_ci	error_at_line(status, errnum,  __FILE__, __LINE__, format ##__VA_ARGS__)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define pr_warn(code, format, ...) err_at_line(0, code, format, ##__VA_ARGS__)
4162306a36Sopenharmony_ci#define pr_err(code, format, ...) err_at_line(1, code, format, ##__VA_ARGS__)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct Flags {
4462306a36Sopenharmony_ci	int touch_fp;
4562306a36Sopenharmony_ci	int touch_vec;
4662306a36Sopenharmony_ci	int result;
4762306a36Sopenharmony_ci	int exception;
4862306a36Sopenharmony_ci} flags;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cibool expecting_failure(void)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	if (flags.touch_fp && flags.exception == FP_UNA_EXCEPTION)
5362306a36Sopenharmony_ci		return false;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (flags.touch_vec && flags.exception == VEC_UNA_EXCEPTION)
5662306a36Sopenharmony_ci		return false;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/*
5962306a36Sopenharmony_ci	 * If both FP and VEC are touched it does not mean that touching VSX
6062306a36Sopenharmony_ci	 * won't raise an exception. However since FP and VEC state are already
6162306a36Sopenharmony_ci	 * correctly loaded, the transaction is not aborted (i.e.
6262306a36Sopenharmony_ci	 * treclaimed/trecheckpointed) and MSR.VSX is just set as 1, so a TM
6362306a36Sopenharmony_ci	 * failure is not expected also in this case.
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	if ((flags.touch_fp && flags.touch_vec) &&
6662306a36Sopenharmony_ci	     flags.exception == VSX_UNA_EXCEPTION)
6762306a36Sopenharmony_ci		return false;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return true;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Check if failure occurred whilst in transaction. */
7362306a36Sopenharmony_cibool is_failure(uint64_t condition_reg)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	/*
7662306a36Sopenharmony_ci	 * When failure handling occurs, CR0 is set to 0b1010 (0xa). Otherwise
7762306a36Sopenharmony_ci	 * transaction completes without failure and hence reaches out 'tend.'
7862306a36Sopenharmony_ci	 * that sets CR0 to 0b0100 (0x4).
7962306a36Sopenharmony_ci	 */
8062306a36Sopenharmony_ci	return ((condition_reg >> 28) & 0xa) == 0xa;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_civoid *tm_una_ping(void *input)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/*
8762306a36Sopenharmony_ci	 * Expected values for vs0 and vs32 after a TM failure. They must never
8862306a36Sopenharmony_ci	 * change, otherwise they got corrupted.
8962306a36Sopenharmony_ci	 */
9062306a36Sopenharmony_ci	uint64_t high_vs0 = 0x5555555555555555;
9162306a36Sopenharmony_ci	uint64_t low_vs0 = 0xffffffffffffffff;
9262306a36Sopenharmony_ci	uint64_t high_vs32 = 0x5555555555555555;
9362306a36Sopenharmony_ci	uint64_t low_vs32 = 0xffffffffffffffff;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* Counter for busy wait */
9662306a36Sopenharmony_ci	uint64_t counter = 0x1ff000000;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/*
9962306a36Sopenharmony_ci	 * Variable to keep a copy of CR register content taken just after we
10062306a36Sopenharmony_ci	 * leave the transactional state.
10162306a36Sopenharmony_ci	 */
10262306a36Sopenharmony_ci	uint64_t cr_ = 0;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/*
10562306a36Sopenharmony_ci	 * Wait a bit so thread can get its name "ping". This is not important
10662306a36Sopenharmony_ci	 * to reproduce the issue but it's nice to have for systemtap debugging.
10762306a36Sopenharmony_ci	 */
10862306a36Sopenharmony_ci	if (DEBUG)
10962306a36Sopenharmony_ci		sleep(1);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	printf("If MSR.FP=%d MSR.VEC=%d: ", flags.touch_fp, flags.touch_vec);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (flags.exception != FP_UNA_EXCEPTION &&
11462306a36Sopenharmony_ci	    flags.exception != VEC_UNA_EXCEPTION &&
11562306a36Sopenharmony_ci	    flags.exception != VSX_UNA_EXCEPTION) {
11662306a36Sopenharmony_ci		printf("No valid exception specified to test.\n");
11762306a36Sopenharmony_ci		return NULL;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	asm (
12162306a36Sopenharmony_ci		/* Prepare to merge low and high. */
12262306a36Sopenharmony_ci		"	mtvsrd		33, %[high_vs0]		;"
12362306a36Sopenharmony_ci		"	mtvsrd		34, %[low_vs0]		;"
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		/*
12662306a36Sopenharmony_ci		 * Adjust VS0 expected value after an TM failure,
12762306a36Sopenharmony_ci		 * i.e. vs0 = 0x5555555555555555555FFFFFFFFFFFFFFFF
12862306a36Sopenharmony_ci		 */
12962306a36Sopenharmony_ci		"	xxmrghd		0, 33, 34		;"
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		/*
13262306a36Sopenharmony_ci		 * Adjust VS32 expected value after an TM failure,
13362306a36Sopenharmony_ci		 * i.e. vs32 = 0x5555555555555555555FFFFFFFFFFFFFFFF
13462306a36Sopenharmony_ci		 */
13562306a36Sopenharmony_ci		"	xxmrghd		32, 33, 34		;"
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		/*
13862306a36Sopenharmony_ci		 * Wait an amount of context switches so load_fp and load_vec
13962306a36Sopenharmony_ci		 * overflow and MSR.FP, MSR.VEC, and MSR.VSX become zero (off).
14062306a36Sopenharmony_ci		 */
14162306a36Sopenharmony_ci		"	mtctr		%[counter]		;"
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci		/* Decrement CTR branch if CTR non zero. */
14462306a36Sopenharmony_ci		"1:	bdnz 1b					;"
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		/*
14762306a36Sopenharmony_ci		 * Check if we want to touch FP prior to the test in order
14862306a36Sopenharmony_ci		 * to set MSR.FP = 1 before provoking an unavailable
14962306a36Sopenharmony_ci		 * exception in TM.
15062306a36Sopenharmony_ci		 */
15162306a36Sopenharmony_ci		"	cmpldi		%[touch_fp], 0		;"
15262306a36Sopenharmony_ci		"	beq		no_fp			;"
15362306a36Sopenharmony_ci		"	fadd		10, 10, 10		;"
15462306a36Sopenharmony_ci		"no_fp:						;"
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci		/*
15762306a36Sopenharmony_ci		 * Check if we want to touch VEC prior to the test in order
15862306a36Sopenharmony_ci		 * to set MSR.VEC = 1 before provoking an unavailable
15962306a36Sopenharmony_ci		 * exception in TM.
16062306a36Sopenharmony_ci		 */
16162306a36Sopenharmony_ci		"	cmpldi		%[touch_vec], 0		;"
16262306a36Sopenharmony_ci		"	beq		no_vec			;"
16362306a36Sopenharmony_ci		"	vaddcuw		10, 10, 10		;"
16462306a36Sopenharmony_ci		"no_vec:					;"
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci		/*
16762306a36Sopenharmony_ci		 * Perhaps it would be a better idea to do the
16862306a36Sopenharmony_ci		 * compares outside transactional context and simply
16962306a36Sopenharmony_ci		 * duplicate code.
17062306a36Sopenharmony_ci		 */
17162306a36Sopenharmony_ci		"	tbegin.					;"
17262306a36Sopenharmony_ci		"	beq		trans_fail		;"
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci		/* Do we do FP Unavailable? */
17562306a36Sopenharmony_ci		"	cmpldi		%[exception], %[ex_fp]	;"
17662306a36Sopenharmony_ci		"	bne		1f			;"
17762306a36Sopenharmony_ci		"	fadd		10, 10, 10		;"
17862306a36Sopenharmony_ci		"	b		done			;"
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		/* Do we do VEC Unavailable? */
18162306a36Sopenharmony_ci		"1:	cmpldi		%[exception], %[ex_vec]	;"
18262306a36Sopenharmony_ci		"	bne		2f			;"
18362306a36Sopenharmony_ci		"	vaddcuw		10, 10, 10		;"
18462306a36Sopenharmony_ci		"	b		done			;"
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		/*
18762306a36Sopenharmony_ci		 * Not FP or VEC, therefore VSX. Ensure this
18862306a36Sopenharmony_ci		 * instruction always generates a VSX Unavailable.
18962306a36Sopenharmony_ci		 * ISA 3.0 is tricky here.
19062306a36Sopenharmony_ci		 * (xxmrghd will on ISA 2.07 and ISA 3.0)
19162306a36Sopenharmony_ci		 */
19262306a36Sopenharmony_ci		"2:	xxmrghd		10, 10, 10		;"
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		"done:	tend. ;"
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		"trans_fail: ;"
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		/* Give values back to C. */
19962306a36Sopenharmony_ci		"	mfvsrd		%[high_vs0], 0		;"
20062306a36Sopenharmony_ci		"	xxsldwi		3, 0, 0, 2		;"
20162306a36Sopenharmony_ci		"	mfvsrd		%[low_vs0], 3		;"
20262306a36Sopenharmony_ci		"	mfvsrd		%[high_vs32], 32	;"
20362306a36Sopenharmony_ci		"	xxsldwi		3, 32, 32, 2		;"
20462306a36Sopenharmony_ci		"	mfvsrd		%[low_vs32], 3		;"
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		/* Give CR back to C so that it can check what happened. */
20762306a36Sopenharmony_ci		"	mfcr		%[cr_]		;"
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		: [high_vs0]  "+r" (high_vs0),
21062306a36Sopenharmony_ci		  [low_vs0]   "+r" (low_vs0),
21162306a36Sopenharmony_ci		  [high_vs32] "=r" (high_vs32),
21262306a36Sopenharmony_ci		  [low_vs32]  "=r" (low_vs32),
21362306a36Sopenharmony_ci		  [cr_]       "+r" (cr_)
21462306a36Sopenharmony_ci		: [touch_fp]  "r"  (flags.touch_fp),
21562306a36Sopenharmony_ci		  [touch_vec] "r"  (flags.touch_vec),
21662306a36Sopenharmony_ci		  [exception] "r"  (flags.exception),
21762306a36Sopenharmony_ci		  [ex_fp]     "i"  (FP_UNA_EXCEPTION),
21862306a36Sopenharmony_ci		  [ex_vec]    "i"  (VEC_UNA_EXCEPTION),
21962306a36Sopenharmony_ci		  [ex_vsx]    "i"  (VSX_UNA_EXCEPTION),
22062306a36Sopenharmony_ci		  [counter]   "r"  (counter)
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		: "cr0", "ctr", "v10", "vs0", "vs10", "vs3", "vs32", "vs33",
22362306a36Sopenharmony_ci		  "vs34", "fr10"
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/*
22862306a36Sopenharmony_ci	 * Check if we were expecting a failure and it did not occur by checking
22962306a36Sopenharmony_ci	 * CR0 state just after we leave the transaction. Either way we check if
23062306a36Sopenharmony_ci	 * vs0 or vs32 got corrupted.
23162306a36Sopenharmony_ci	 */
23262306a36Sopenharmony_ci	if (expecting_failure() && !is_failure(cr_)) {
23362306a36Sopenharmony_ci		printf("\n\tExpecting the transaction to fail, %s",
23462306a36Sopenharmony_ci			"but it didn't\n\t");
23562306a36Sopenharmony_ci		flags.result++;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/* Check if we were not expecting a failure and a it occurred. */
23962306a36Sopenharmony_ci	if (!expecting_failure() && is_failure(cr_) &&
24062306a36Sopenharmony_ci	    !failure_is_reschedule()) {
24162306a36Sopenharmony_ci		printf("\n\tUnexpected transaction failure 0x%02lx\n\t",
24262306a36Sopenharmony_ci			failure_code());
24362306a36Sopenharmony_ci		return (void *) -1;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/*
24762306a36Sopenharmony_ci	 * Check if TM failed due to the cause we were expecting. 0xda is a
24862306a36Sopenharmony_ci	 * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause, unless
24962306a36Sopenharmony_ci	 * it was caused by a reschedule.
25062306a36Sopenharmony_ci	 */
25162306a36Sopenharmony_ci	if (is_failure(cr_) && !failure_is_unavailable() &&
25262306a36Sopenharmony_ci	    !failure_is_reschedule()) {
25362306a36Sopenharmony_ci		printf("\n\tUnexpected failure cause 0x%02lx\n\t",
25462306a36Sopenharmony_ci			failure_code());
25562306a36Sopenharmony_ci		return (void *) -1;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* 0x4 is a success and 0xa is a fail. See comment in is_failure(). */
25962306a36Sopenharmony_ci	if (DEBUG)
26062306a36Sopenharmony_ci		printf("CR0: 0x%1lx ", cr_ >> 28);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Check FP (vs0) for the expected value. */
26362306a36Sopenharmony_ci	if (high_vs0 != 0x5555555555555555 || low_vs0 != 0xFFFFFFFFFFFFFFFF) {
26462306a36Sopenharmony_ci		printf("FP corrupted!");
26562306a36Sopenharmony_ci			printf("  high = %#16" PRIx64 "  low = %#16" PRIx64 " ",
26662306a36Sopenharmony_ci				high_vs0, low_vs0);
26762306a36Sopenharmony_ci		flags.result++;
26862306a36Sopenharmony_ci	} else
26962306a36Sopenharmony_ci		printf("FP ok ");
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Check VEC (vs32) for the expected value. */
27262306a36Sopenharmony_ci	if (high_vs32 != 0x5555555555555555 || low_vs32 != 0xFFFFFFFFFFFFFFFF) {
27362306a36Sopenharmony_ci		printf("VEC corrupted!");
27462306a36Sopenharmony_ci			printf("  high = %#16" PRIx64 "  low = %#16" PRIx64,
27562306a36Sopenharmony_ci				high_vs32, low_vs32);
27662306a36Sopenharmony_ci		flags.result++;
27762306a36Sopenharmony_ci	} else
27862306a36Sopenharmony_ci		printf("VEC ok");
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	putchar('\n');
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return NULL;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/* Thread to force context switch */
28662306a36Sopenharmony_civoid *tm_una_pong(void *not_used)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	/* Wait thread get its name "pong". */
28962306a36Sopenharmony_ci	if (DEBUG)
29062306a36Sopenharmony_ci		sleep(1);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/* Classed as an interactive-like thread. */
29362306a36Sopenharmony_ci	while (1)
29462306a36Sopenharmony_ci		sched_yield();
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/* Function that creates a thread and launches the "ping" task. */
29862306a36Sopenharmony_civoid test_fp_vec(int fp, int vec, pthread_attr_t *attr)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	int retries = 2;
30162306a36Sopenharmony_ci	void *ret_value;
30262306a36Sopenharmony_ci	pthread_t t0;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	flags.touch_fp = fp;
30562306a36Sopenharmony_ci	flags.touch_vec = vec;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/*
30862306a36Sopenharmony_ci	 * Without luck it's possible that the transaction is aborted not due to
30962306a36Sopenharmony_ci	 * the unavailable exception caught in the middle as we expect but also,
31062306a36Sopenharmony_ci	 * for instance, due to a context switch or due to a KVM reschedule (if
31162306a36Sopenharmony_ci	 * it's running on a VM). Thus we try a few times before giving up,
31262306a36Sopenharmony_ci	 * checking if the failure cause is the one we expect.
31362306a36Sopenharmony_ci	 */
31462306a36Sopenharmony_ci	do {
31562306a36Sopenharmony_ci		int rc;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		/* Bind to CPU 0, as specified in 'attr'. */
31862306a36Sopenharmony_ci		rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags);
31962306a36Sopenharmony_ci		if (rc)
32062306a36Sopenharmony_ci			pr_err(rc, "pthread_create()");
32162306a36Sopenharmony_ci		rc = pthread_setname_np(t0, "tm_una_ping");
32262306a36Sopenharmony_ci		if (rc)
32362306a36Sopenharmony_ci			pr_warn(rc, "pthread_setname_np");
32462306a36Sopenharmony_ci		rc = pthread_join(t0, &ret_value);
32562306a36Sopenharmony_ci		if (rc)
32662306a36Sopenharmony_ci			pr_err(rc, "pthread_join");
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		retries--;
32962306a36Sopenharmony_ci	} while (ret_value != NULL && retries);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (!retries) {
33262306a36Sopenharmony_ci		flags.result = 1;
33362306a36Sopenharmony_ci		if (DEBUG)
33462306a36Sopenharmony_ci			printf("All transactions failed unexpectedly\n");
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciint tm_unavailable_test(void)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	int cpu, rc, exception; /* FP = 0, VEC = 1, VSX = 2 */
34262306a36Sopenharmony_ci	pthread_t t1;
34362306a36Sopenharmony_ci	pthread_attr_t attr;
34462306a36Sopenharmony_ci	cpu_set_t cpuset;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	SKIP_IF(!have_htm());
34762306a36Sopenharmony_ci	SKIP_IF(htm_is_synthetic());
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	cpu = pick_online_cpu();
35062306a36Sopenharmony_ci	FAIL_IF(cpu < 0);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	// Set only one CPU in the mask. Both threads will be bound to that CPU.
35362306a36Sopenharmony_ci	CPU_ZERO(&cpuset);
35462306a36Sopenharmony_ci	CPU_SET(cpu, &cpuset);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* Init pthread attribute. */
35762306a36Sopenharmony_ci	rc = pthread_attr_init(&attr);
35862306a36Sopenharmony_ci	if (rc)
35962306a36Sopenharmony_ci		pr_err(rc, "pthread_attr_init()");
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* Set CPU 0 mask into the pthread attribute. */
36262306a36Sopenharmony_ci	rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
36362306a36Sopenharmony_ci	if (rc)
36462306a36Sopenharmony_ci		pr_err(rc, "pthread_attr_setaffinity_np()");
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	rc = pthread_create(&t1, &attr /* Bind to CPU 0 */, tm_una_pong, NULL);
36762306a36Sopenharmony_ci	if (rc)
36862306a36Sopenharmony_ci		pr_err(rc, "pthread_create()");
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Name it for systemtap convenience */
37162306a36Sopenharmony_ci	rc = pthread_setname_np(t1, "tm_una_pong");
37262306a36Sopenharmony_ci	if (rc)
37362306a36Sopenharmony_ci		pr_warn(rc, "pthread_create()");
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	flags.result = 0;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	for (exception = 0; exception < NUM_EXCEPTIONS; exception++) {
37862306a36Sopenharmony_ci		printf("Checking if FP/VEC registers are sane after");
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		if (exception == FP_UNA_EXCEPTION)
38162306a36Sopenharmony_ci			printf(" a FP unavailable exception...\n");
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		else if (exception == VEC_UNA_EXCEPTION)
38462306a36Sopenharmony_ci			printf(" a VEC unavailable exception...\n");
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		else
38762306a36Sopenharmony_ci			printf(" a VSX unavailable exception...\n");
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		flags.exception = exception;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		test_fp_vec(0, 0, &attr);
39262306a36Sopenharmony_ci		test_fp_vec(1, 0, &attr);
39362306a36Sopenharmony_ci		test_fp_vec(0, 1, &attr);
39462306a36Sopenharmony_ci		test_fp_vec(1, 1, &attr);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (flags.result > 0) {
39962306a36Sopenharmony_ci		printf("result: failed!\n");
40062306a36Sopenharmony_ci		exit(1);
40162306a36Sopenharmony_ci	} else {
40262306a36Sopenharmony_ci		printf("result: success\n");
40362306a36Sopenharmony_ci		exit(0);
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ciint main(int argc, char **argv)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	test_harness_set_timeout(220);
41062306a36Sopenharmony_ci	return test_harness(tm_unavailable_test, "tm_unavailable_test");
41162306a36Sopenharmony_ci}
412