1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2015, Michael Neuling, IBM Corp. |
4 | * |
5 | * Original: Michael Neuling 3/4/2014 |
6 | * Modified: Rashmica Gupta 8/12/2015 |
7 | * |
8 | * Check if any of the Transaction Memory SPRs get corrupted. |
9 | * - TFIAR - stores address of location of transaction failure |
10 | * - TFHAR - stores address of software failure handler (if transaction |
11 | * fails) |
12 | * - TEXASR - lots of info about the transacion(s) |
13 | * |
14 | * (1) create more threads than cpus |
15 | * (2) in each thread: |
16 | * (a) set TFIAR and TFHAR a unique value |
17 | * (b) loop for awhile, continually checking to see if |
18 | * either register has been corrupted. |
19 | * |
20 | * (3) Loop: |
21 | * (a) begin transaction |
22 | * (b) abort transaction |
23 | * (c) check TEXASR to see if FS has been corrupted |
24 | */ |
25 | |
26 | #define _GNU_SOURCE |
27 | #include <stdio.h> |
28 | #include <stdlib.h> |
29 | #include <unistd.h> |
30 | #include <pthread.h> |
31 | #include <string.h> |
32 | |
33 | #include "utils.h" |
34 | #include "tm.h" |
35 | |
36 | int num_loops = 1000000; |
37 | int passed = 1; |
38 | |
39 | void tfiar_tfhar(void *in) |
40 | { |
41 | unsigned long tfhar, tfhar_rd, tfiar, tfiar_rd; |
42 | int i; |
43 | |
44 | /* TFIAR: Last bit has to be high so userspace can read register */ |
45 | tfiar = ((unsigned long)in) + 1; |
46 | tfiar += 2; |
47 | mtspr(SPRN_TFIAR, tfiar); |
48 | |
49 | /* TFHAR: Last two bits are reserved */ |
50 | tfhar = ((unsigned long)in); |
51 | tfhar &= ~0x3UL; |
52 | tfhar += 4; |
53 | mtspr(SPRN_TFHAR, tfhar); |
54 | |
55 | for (i = 0; i < num_loops; i++) { |
56 | tfhar_rd = mfspr(SPRN_TFHAR); |
57 | tfiar_rd = mfspr(SPRN_TFIAR); |
58 | if ( (tfhar != tfhar_rd) || (tfiar != tfiar_rd) ) { |
59 | passed = 0; |
60 | return; |
61 | } |
62 | } |
63 | return; |
64 | } |
65 | |
66 | void texasr(void *in) |
67 | { |
68 | unsigned long i; |
69 | uint64_t result = 0; |
70 | |
71 | for (i = 0; i < num_loops; i++) { |
72 | asm __volatile__( |
73 | "tbegin.;" |
74 | "beq 3f ;" |
75 | "tabort. 0 ;" |
76 | "tend.;" |
77 | |
78 | /* Abort handler */ |
79 | "3: ;" |
80 | ::: "memory" ); |
81 | |
82 | /* Check the TEXASR */ |
83 | result = mfspr(SPRN_TEXASR); |
84 | if ((result & TEXASR_FS) == 0) { |
85 | passed = 0; |
86 | return; |
87 | } |
88 | } |
89 | return; |
90 | } |
91 | |
92 | int test_tmspr() |
93 | { |
94 | pthread_t *thread; |
95 | int thread_num; |
96 | unsigned long i; |
97 | |
98 | SKIP_IF(!have_htm()); |
99 | SKIP_IF(htm_is_synthetic()); |
100 | |
101 | /* To cause some context switching */ |
102 | thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN); |
103 | |
104 | thread = malloc(thread_num * sizeof(pthread_t)); |
105 | if (thread == NULL) |
106 | return EXIT_FAILURE; |
107 | |
108 | /* Test TFIAR and TFHAR */ |
109 | for (i = 0; i < thread_num; i += 2) { |
110 | if (pthread_create(&thread[i], NULL, (void *)tfiar_tfhar, |
111 | (void *)i)) |
112 | return EXIT_FAILURE; |
113 | } |
114 | /* Test TEXASR */ |
115 | for (i = 1; i < thread_num; i += 2) { |
116 | if (pthread_create(&thread[i], NULL, (void *)texasr, (void *)i)) |
117 | return EXIT_FAILURE; |
118 | } |
119 | |
120 | for (i = 0; i < thread_num; i++) { |
121 | if (pthread_join(thread[i], NULL) != 0) |
122 | return EXIT_FAILURE; |
123 | } |
124 | |
125 | free(thread); |
126 | |
127 | if (passed) |
128 | return 0; |
129 | else |
130 | return 1; |
131 | } |
132 | |
133 | int main(int argc, char *argv[]) |
134 | { |
135 | if (argc > 1) { |
136 | if (strcmp(argv[1], "-h" ) == 0) { |
137 | printf("Syntax:\t [<num loops>]\n" ); |
138 | return 0; |
139 | } else { |
140 | num_loops = atoi(argv[1]); |
141 | } |
142 | } |
143 | return test_harness(test_tmspr, "tm_tmspr" ); |
144 | } |
145 | |