0001
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
0068 static int default_value(void)
0069 {
0070 return get_tpidr2() == 0;
0071 }
0072
0073
0074 static int write_read(void)
0075 {
0076 set_tpidr2(getpid());
0077
0078 return getpid() == get_tpidr2();
0079 }
0080
0081
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
0093
0094
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
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
0161
0162
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
0174
0175
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
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
0272
0273
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 }