Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include <linux/sched.h>
0004 #include <linux/wait.h>
0005 
0006 #define SYS_TPIDR2 "S3_3_C13_C0_5"
0007 
0008 #define EXPECTED_TESTS 5
0009 
0010 static void putstr(const char *str)
0011 {
0012     write(1, str, strlen(str));
0013 }
0014 
0015 static void putnum(unsigned int num)
0016 {
0017     char c;
0018 
0019     if (num / 10)
0020         putnum(num / 10);
0021 
0022     c = '0' + (num % 10);
0023     write(1, &c, 1);
0024 }
0025 
0026 static int tests_run;
0027 static int tests_passed;
0028 static int tests_failed;
0029 static int tests_skipped;
0030 
0031 static void set_tpidr2(uint64_t val)
0032 {
0033     asm volatile (
0034         "msr    " SYS_TPIDR2 ", %0\n"
0035         :
0036         : "r"(val)
0037         : "cc");
0038 }
0039 
0040 static uint64_t get_tpidr2(void)
0041 {
0042     uint64_t val;
0043 
0044     asm volatile (
0045         "mrs    %0, " SYS_TPIDR2 "\n"
0046         : "=r"(val)
0047         :
0048         : "cc");
0049 
0050     return val;
0051 }
0052 
0053 static void print_summary(void)
0054 {
0055     if (tests_passed + tests_failed + tests_skipped != EXPECTED_TESTS)
0056         putstr("# UNEXPECTED TEST COUNT: ");
0057 
0058     putstr("# Totals: pass:");
0059     putnum(tests_passed);
0060     putstr(" fail:");
0061     putnum(tests_failed);
0062     putstr(" xfail:0 xpass:0 skip:");
0063     putnum(tests_skipped);
0064     putstr(" error:0\n");
0065 }
0066 
0067 /* Processes should start with TPIDR2 == 0 */
0068 static int default_value(void)
0069 {
0070     return get_tpidr2() == 0;
0071 }
0072 
0073 /* If we set TPIDR2 we should read that value */
0074 static int write_read(void)
0075 {
0076     set_tpidr2(getpid());
0077 
0078     return getpid() == get_tpidr2();
0079 }
0080 
0081 /* If we set a value we should read the same value after scheduling out */
0082 static int write_sleep_read(void)
0083 {
0084     set_tpidr2(getpid());
0085 
0086     msleep(100);
0087 
0088     return getpid() == get_tpidr2();
0089 }
0090 
0091 /*
0092  * If we fork the value in the parent should be unchanged and the
0093  * child should start with the same value and be able to set its own
0094  * value.
0095  */
0096 static int write_fork_read(void)
0097 {
0098     pid_t newpid, waiting, oldpid;
0099     int status;
0100 
0101     set_tpidr2(getpid());
0102 
0103     oldpid = getpid();
0104     newpid = fork();
0105     if (newpid == 0) {
0106         /* In child */
0107         if (get_tpidr2() != oldpid) {
0108             putstr("# TPIDR2 changed in child: ");
0109             putnum(get_tpidr2());
0110             putstr("\n");
0111             exit(0);
0112         }
0113 
0114         set_tpidr2(getpid());
0115         if (get_tpidr2() == getpid()) {
0116             exit(1);
0117         } else {
0118             putstr("# Failed to set TPIDR2 in child\n");
0119             exit(0);
0120         }
0121     }
0122     if (newpid < 0) {
0123         putstr("# fork() failed: -");
0124         putnum(-newpid);
0125         putstr("\n");
0126         return 0;
0127     }
0128 
0129     for (;;) {
0130         waiting = waitpid(newpid, &status, 0);
0131 
0132         if (waiting < 0) {
0133             if (errno == EINTR)
0134                 continue;
0135             putstr("# waitpid() failed: ");
0136             putnum(errno);
0137             putstr("\n");
0138             return 0;
0139         }
0140         if (waiting != newpid) {
0141             putstr("# waitpid() returned wrong PID\n");
0142             return 0;
0143         }
0144 
0145         if (!WIFEXITED(status)) {
0146             putstr("# child did not exit\n");
0147             return 0;
0148         }
0149 
0150         if (getpid() != get_tpidr2()) {
0151             putstr("# TPIDR2 corrupted in parent\n");
0152             return 0;
0153         }
0154 
0155         return WEXITSTATUS(status);
0156     }
0157 }
0158 
0159 /*
0160  * sys_clone() has a lot of per architecture variation so just define
0161  * it here rather than adding it to nolibc, plus the raw API is a
0162  * little more convenient for this test.
0163  */
0164 static int sys_clone(unsigned long clone_flags, unsigned long newsp,
0165              int *parent_tidptr, unsigned long tls,
0166              int *child_tidptr)
0167 {
0168     return my_syscall5(__NR_clone, clone_flags, newsp, parent_tidptr, tls,
0169                child_tidptr);
0170 }
0171 
0172 /*
0173  * If we clone with CLONE_SETTLS then the value in the parent should
0174  * be unchanged and the child should start with zero and be able to
0175  * set its own value.
0176  */
0177 static int write_clone_read(void)
0178 {
0179     int parent_tid, child_tid;
0180     pid_t parent, waiting;
0181     int ret, status;
0182 
0183     parent = getpid();
0184     set_tpidr2(parent);
0185 
0186     ret = sys_clone(CLONE_SETTLS, 0, &parent_tid, 0, &child_tid);
0187     if (ret == -1) {
0188         putstr("# clone() failed\n");
0189         putnum(errno);
0190         putstr("\n");
0191         return 0;
0192     }
0193 
0194     if (ret == 0) {
0195         /* In child */
0196         if (get_tpidr2() != 0) {
0197             putstr("# TPIDR2 non-zero in child: ");
0198             putnum(get_tpidr2());
0199             putstr("\n");
0200             exit(0);
0201         }
0202 
0203         if (gettid() == 0)
0204             putstr("# Child TID==0\n");
0205         set_tpidr2(gettid());
0206         if (get_tpidr2() == gettid()) {
0207             exit(1);
0208         } else {
0209             putstr("# Failed to set TPIDR2 in child\n");
0210             exit(0);
0211         }
0212     }
0213 
0214     for (;;) {
0215         waiting = wait4(ret, &status, __WCLONE, NULL);
0216 
0217         if (waiting < 0) {
0218             if (errno == EINTR)
0219                 continue;
0220             putstr("# wait4() failed: ");
0221             putnum(errno);
0222             putstr("\n");
0223             return 0;
0224         }
0225         if (waiting != ret) {
0226             putstr("# wait4() returned wrong PID ");
0227             putnum(waiting);
0228             putstr("\n");
0229             return 0;
0230         }
0231 
0232         if (!WIFEXITED(status)) {
0233             putstr("# child did not exit\n");
0234             return 0;
0235         }
0236 
0237         if (parent != get_tpidr2()) {
0238             putstr("# TPIDR2 corrupted in parent\n");
0239             return 0;
0240         }
0241 
0242         return WEXITSTATUS(status);
0243     }
0244 }
0245 
0246 #define run_test(name)               \
0247     if (name()) {                \
0248         tests_passed++;          \
0249     } else {                 \
0250         tests_failed++;          \
0251         putstr("not ");          \
0252     }                    \
0253     putstr("ok ");               \
0254     putnum(++tests_run);             \
0255     putstr(" " #name "\n");
0256 
0257 int main(int argc, char **argv)
0258 {
0259     int ret, i;
0260 
0261     putstr("TAP version 13\n");
0262     putstr("1..");
0263     putnum(EXPECTED_TESTS);
0264     putstr("\n");
0265 
0266     putstr("# PID: ");
0267     putnum(getpid());
0268     putstr("\n");
0269 
0270     /*
0271      * This test is run with nolibc which doesn't support hwcap and
0272      * it's probably disproportionate to implement so instead check
0273      * for the default vector length configuration in /proc.
0274      */
0275     ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0);
0276     if (ret >= 0) {
0277         run_test(default_value);
0278         run_test(write_read);
0279         run_test(write_sleep_read);
0280         run_test(write_fork_read);
0281         run_test(write_clone_read);
0282 
0283     } else {
0284         putstr("# SME support not present\n");
0285 
0286         for (i = 0; i < EXPECTED_TESTS; i++) {
0287             putstr("ok ");
0288             putnum(i);
0289             putstr(" skipped, TPIDR2 not supported\n");
0290         }
0291 
0292         tests_skipped += EXPECTED_TESTS;
0293     }
0294 
0295     print_summary();
0296 
0297     return 0;
0298 }