tpidr2.c 5.5 KB

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