~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/arm64/abi/tpidr2.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 
  3 #include <linux/sched.h>
  4 #include <linux/wait.h>
  5 
  6 #define SYS_TPIDR2 "S3_3_C13_C0_5"
  7 
  8 #define EXPECTED_TESTS 5
  9 
 10 static void putstr(const char *str)
 11 {
 12         write(1, str, strlen(str));
 13 }
 14 
 15 static void putnum(unsigned int num)
 16 {
 17         char c;
 18 
 19         if (num / 10)
 20                 putnum(num / 10);
 21 
 22         c = '' + (num % 10);
 23         write(1, &c, 1);
 24 }
 25 
 26 static int tests_run;
 27 static int tests_passed;
 28 static int tests_failed;
 29 static int tests_skipped;
 30 
 31 static void set_tpidr2(uint64_t val)
 32 {
 33         asm volatile (
 34                 "msr    " SYS_TPIDR2 ", %0\n"
 35                 :
 36                 : "r"(val)
 37                 : "cc");
 38 }
 39 
 40 static uint64_t get_tpidr2(void)
 41 {
 42         uint64_t val;
 43 
 44         asm volatile (
 45                 "mrs    %0, " SYS_TPIDR2 "\n"
 46                 : "=r"(val)
 47                 :
 48                 : "cc");
 49 
 50         return val;
 51 }
 52 
 53 static void print_summary(void)
 54 {
 55         if (tests_passed + tests_failed + tests_skipped != EXPECTED_TESTS)
 56                 putstr("# UNEXPECTED TEST COUNT: ");
 57 
 58         putstr("# Totals: pass:");
 59         putnum(tests_passed);
 60         putstr(" fail:");
 61         putnum(tests_failed);
 62         putstr(" xfail:0 xpass:0 skip:");
 63         putnum(tests_skipped);
 64         putstr(" error:0\n");
 65 }
 66 
 67 /* Processes should start with TPIDR2 == 0 */
 68 static int default_value(void)
 69 {
 70         return get_tpidr2() == 0;
 71 }
 72 
 73 /* If we set TPIDR2 we should read that value */
 74 static int write_read(void)
 75 {
 76         set_tpidr2(getpid());
 77 
 78         return getpid() == get_tpidr2();
 79 }
 80 
 81 /* If we set a value we should read the same value after scheduling out */
 82 static int write_sleep_read(void)
 83 {
 84         set_tpidr2(getpid());
 85 
 86         msleep(100);
 87 
 88         return getpid() == get_tpidr2();
 89 }
 90 
 91 /*
 92  * If we fork the value in the parent should be unchanged and the
 93  * child should start with the same value and be able to set its own
 94  * value.
 95  */
 96 static int write_fork_read(void)
 97 {
 98         pid_t newpid, waiting, oldpid;
 99         int status;
100 
101         set_tpidr2(getpid());
102 
103         oldpid = getpid();
104         newpid = fork();
105         if (newpid == 0) {
106                 /* In child */
107                 if (get_tpidr2() != oldpid) {
108                         putstr("# TPIDR2 changed in child: ");
109                         putnum(get_tpidr2());
110                         putstr("\n");
111                         exit(0);
112                 }
113 
114                 set_tpidr2(getpid());
115                 if (get_tpidr2() == getpid()) {
116                         exit(1);
117                 } else {
118                         putstr("# Failed to set TPIDR2 in child\n");
119                         exit(0);
120                 }
121         }
122         if (newpid < 0) {
123                 putstr("# fork() failed: -");
124                 putnum(-newpid);
125                 putstr("\n");
126                 return 0;
127         }
128 
129         for (;;) {
130                 waiting = waitpid(newpid, &status, 0);
131 
132                 if (waiting < 0) {
133                         if (errno == EINTR)
134                                 continue;
135                         putstr("# waitpid() failed: ");
136                         putnum(errno);
137                         putstr("\n");
138                         return 0;
139                 }
140                 if (waiting != newpid) {
141                         putstr("# waitpid() returned wrong PID\n");
142                         return 0;
143                 }
144 
145                 if (!WIFEXITED(status)) {
146                         putstr("# child did not exit\n");
147                         return 0;
148                 }
149 
150                 if (getpid() != get_tpidr2()) {
151                         putstr("# TPIDR2 corrupted in parent\n");
152                         return 0;
153                 }
154 
155                 return WEXITSTATUS(status);
156         }
157 }
158 
159 /*
160  * sys_clone() has a lot of per architecture variation so just define
161  * it here rather than adding it to nolibc, plus the raw API is a
162  * little more convenient for this test.
163  */
164 static int sys_clone(unsigned long clone_flags, unsigned long newsp,
165                      int *parent_tidptr, unsigned long tls,
166                      int *child_tidptr)
167 {
168         return my_syscall5(__NR_clone, clone_flags, newsp, parent_tidptr, tls,
169                            child_tidptr);
170 }
171 
172 /*
173  * If we clone with CLONE_SETTLS then the value in the parent should
174  * be unchanged and the child should start with zero and be able to
175  * set its own value.
176  */
177 static int write_clone_read(void)
178 {
179         int parent_tid, child_tid;
180         pid_t parent, waiting;
181         int ret, status;
182 
183         parent = getpid();
184         set_tpidr2(parent);
185 
186         ret = sys_clone(CLONE_SETTLS, 0, &parent_tid, 0, &child_tid);
187         if (ret == -1) {
188                 putstr("# clone() failed\n");
189                 putnum(errno);
190                 putstr("\n");
191                 return 0;
192         }
193 
194         if (ret == 0) {
195                 /* In child */
196                 if (get_tpidr2() != 0) {
197                         putstr("# TPIDR2 non-zero in child: ");
198                         putnum(get_tpidr2());
199                         putstr("\n");
200                         exit(0);
201                 }
202 
203                 if (gettid() == 0)
204                         putstr("# Child TID==0\n");
205                 set_tpidr2(gettid());
206                 if (get_tpidr2() == gettid()) {
207                         exit(1);
208                 } else {
209                         putstr("# Failed to set TPIDR2 in child\n");
210                         exit(0);
211                 }
212         }
213 
214         for (;;) {
215                 waiting = wait4(ret, &status, __WCLONE, NULL);
216 
217                 if (waiting < 0) {
218                         if (errno == EINTR)
219                                 continue;
220                         putstr("# wait4() failed: ");
221                         putnum(errno);
222                         putstr("\n");
223                         return 0;
224                 }
225                 if (waiting != ret) {
226                         putstr("# wait4() returned wrong PID ");
227                         putnum(waiting);
228                         putstr("\n");
229                         return 0;
230                 }
231 
232                 if (!WIFEXITED(status)) {
233                         putstr("# child did not exit\n");
234                         return 0;
235                 }
236 
237                 if (parent != get_tpidr2()) {
238                         putstr("# TPIDR2 corrupted in parent\n");
239                         return 0;
240                 }
241 
242                 return WEXITSTATUS(status);
243         }
244 }
245 
246 #define run_test(name)                       \
247         if (name()) {                        \
248                 tests_passed++;              \
249         } else {                             \
250                 tests_failed++;              \
251                 putstr("not ");              \
252         }                                    \
253         putstr("ok ");                       \
254         putnum(++tests_run);                 \
255         putstr(" " #name "\n");
256 
257 #define skip_test(name)                      \
258         tests_skipped++;                     \
259         putstr("ok ");                       \
260         putnum(++tests_run);                 \
261         putstr(" # SKIP " #name "\n");
262 
263 int main(int argc, char **argv)
264 {
265         int ret;
266 
267         putstr("TAP version 13\n");
268         putstr("1..");
269         putnum(EXPECTED_TESTS);
270         putstr("\n");
271 
272         putstr("# PID: ");
273         putnum(getpid());
274         putstr("\n");
275 
276         /*
277          * This test is run with nolibc which doesn't support hwcap and
278          * it's probably disproportionate to implement so instead check
279          * for the default vector length configuration in /proc.
280          */
281         ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0);
282         if (ret >= 0) {
283                 run_test(default_value);
284                 run_test(write_read);
285                 run_test(write_sleep_read);
286                 run_test(write_fork_read);
287                 run_test(write_clone_read);
288 
289         } else {
290                 putstr("# SME support not present\n");
291 
292                 skip_test(default_value);
293                 skip_test(write_read);
294                 skip_test(write_sleep_read);
295                 skip_test(write_fork_read);
296                 skip_test(write_clone_read);
297         }
298 
299         print_summary();
300 
301         return 0;
302 }
303 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php