syscall-abi.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2021 ARM Limited.
  4. */
  5. #include <errno.h>
  6. #include <stdbool.h>
  7. #include <stddef.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include <sys/auxv.h>
  13. #include <sys/prctl.h>
  14. #include <asm/hwcap.h>
  15. #include <asm/sigcontext.h>
  16. #include <asm/unistd.h>
  17. #include "../../kselftest.h"
  18. #include "syscall-abi.h"
  19. /*
  20. * The kernel defines a much larger SVE_VQ_MAX than is expressable in
  21. * the architecture, this creates a *lot* of overhead filling the
  22. * buffers (especially ZA) on emulated platforms so use the actual
  23. * architectural maximum instead.
  24. */
  25. #define ARCH_SVE_VQ_MAX 16
  26. static int default_sme_vl;
  27. static int sve_vl_count;
  28. static unsigned int sve_vls[ARCH_SVE_VQ_MAX];
  29. static int sme_vl_count;
  30. static unsigned int sme_vls[ARCH_SVE_VQ_MAX];
  31. extern void do_syscall(int sve_vl, int sme_vl);
  32. static void fill_random(void *buf, size_t size)
  33. {
  34. int i;
  35. uint32_t *lbuf = buf;
  36. /* random() returns a 32 bit number regardless of the size of long */
  37. for (i = 0; i < size / sizeof(uint32_t); i++)
  38. lbuf[i] = random();
  39. }
  40. /*
  41. * We also repeat the test for several syscalls to try to expose different
  42. * behaviour.
  43. */
  44. static struct syscall_cfg {
  45. int syscall_nr;
  46. const char *name;
  47. } syscalls[] = {
  48. { __NR_getpid, "getpid()" },
  49. { __NR_sched_yield, "sched_yield()" },
  50. };
  51. #define NUM_GPR 31
  52. uint64_t gpr_in[NUM_GPR];
  53. uint64_t gpr_out[NUM_GPR];
  54. static void setup_gpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  55. uint64_t svcr)
  56. {
  57. fill_random(gpr_in, sizeof(gpr_in));
  58. gpr_in[8] = cfg->syscall_nr;
  59. memset(gpr_out, 0, sizeof(gpr_out));
  60. }
  61. static int check_gpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, uint64_t svcr)
  62. {
  63. int errors = 0;
  64. int i;
  65. /*
  66. * GPR x0-x7 may be clobbered, and all others should be preserved.
  67. */
  68. for (i = 9; i < ARRAY_SIZE(gpr_in); i++) {
  69. if (gpr_in[i] != gpr_out[i]) {
  70. ksft_print_msg("%s SVE VL %d mismatch in GPR %d: %llx != %llx\n",
  71. cfg->name, sve_vl, i,
  72. gpr_in[i], gpr_out[i]);
  73. errors++;
  74. }
  75. }
  76. return errors;
  77. }
  78. #define NUM_FPR 32
  79. uint64_t fpr_in[NUM_FPR * 2];
  80. uint64_t fpr_out[NUM_FPR * 2];
  81. uint64_t fpr_zero[NUM_FPR * 2];
  82. static void setup_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  83. uint64_t svcr)
  84. {
  85. fill_random(fpr_in, sizeof(fpr_in));
  86. memset(fpr_out, 0, sizeof(fpr_out));
  87. }
  88. static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  89. uint64_t svcr)
  90. {
  91. int errors = 0;
  92. int i;
  93. if (!sve_vl && !(svcr & SVCR_SM_MASK)) {
  94. for (i = 0; i < ARRAY_SIZE(fpr_in); i++) {
  95. if (fpr_in[i] != fpr_out[i]) {
  96. ksft_print_msg("%s Q%d/%d mismatch %llx != %llx\n",
  97. cfg->name,
  98. i / 2, i % 2,
  99. fpr_in[i], fpr_out[i]);
  100. errors++;
  101. }
  102. }
  103. }
  104. /*
  105. * In streaming mode the whole register set should be cleared
  106. * by the transition out of streaming mode.
  107. */
  108. if (svcr & SVCR_SM_MASK) {
  109. if (memcmp(fpr_zero, fpr_out, sizeof(fpr_out)) != 0) {
  110. ksft_print_msg("%s FPSIMD registers non-zero exiting SM\n",
  111. cfg->name);
  112. errors++;
  113. }
  114. }
  115. return errors;
  116. }
  117. #define SVE_Z_SHARED_BYTES (128 / 8)
  118. static uint8_t z_zero[__SVE_ZREG_SIZE(ARCH_SVE_VQ_MAX)];
  119. uint8_t z_in[SVE_NUM_ZREGS * __SVE_ZREG_SIZE(ARCH_SVE_VQ_MAX)];
  120. uint8_t z_out[SVE_NUM_ZREGS * __SVE_ZREG_SIZE(ARCH_SVE_VQ_MAX)];
  121. static void setup_z(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  122. uint64_t svcr)
  123. {
  124. fill_random(z_in, sizeof(z_in));
  125. fill_random(z_out, sizeof(z_out));
  126. }
  127. static int check_z(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  128. uint64_t svcr)
  129. {
  130. size_t reg_size = sve_vl;
  131. int errors = 0;
  132. int i;
  133. if (!sve_vl)
  134. return 0;
  135. for (i = 0; i < SVE_NUM_ZREGS; i++) {
  136. uint8_t *in = &z_in[reg_size * i];
  137. uint8_t *out = &z_out[reg_size * i];
  138. if (svcr & SVCR_SM_MASK) {
  139. /*
  140. * In streaming mode the whole register should
  141. * be cleared by the transition out of
  142. * streaming mode.
  143. */
  144. if (memcmp(z_zero, out, reg_size) != 0) {
  145. ksft_print_msg("%s SVE VL %d Z%d non-zero\n",
  146. cfg->name, sve_vl, i);
  147. errors++;
  148. }
  149. } else {
  150. /*
  151. * For standard SVE the low 128 bits should be
  152. * preserved and any additional bits cleared.
  153. */
  154. if (memcmp(in, out, SVE_Z_SHARED_BYTES) != 0) {
  155. ksft_print_msg("%s SVE VL %d Z%d low 128 bits changed\n",
  156. cfg->name, sve_vl, i);
  157. errors++;
  158. }
  159. if (reg_size > SVE_Z_SHARED_BYTES &&
  160. (memcmp(z_zero, out + SVE_Z_SHARED_BYTES,
  161. reg_size - SVE_Z_SHARED_BYTES) != 0)) {
  162. ksft_print_msg("%s SVE VL %d Z%d high bits non-zero\n",
  163. cfg->name, sve_vl, i);
  164. errors++;
  165. }
  166. }
  167. }
  168. return errors;
  169. }
  170. uint8_t p_in[SVE_NUM_PREGS * __SVE_PREG_SIZE(ARCH_SVE_VQ_MAX)];
  171. uint8_t p_out[SVE_NUM_PREGS * __SVE_PREG_SIZE(ARCH_SVE_VQ_MAX)];
  172. static void setup_p(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  173. uint64_t svcr)
  174. {
  175. fill_random(p_in, sizeof(p_in));
  176. fill_random(p_out, sizeof(p_out));
  177. }
  178. static int check_p(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  179. uint64_t svcr)
  180. {
  181. size_t reg_size = sve_vq_from_vl(sve_vl) * 2; /* 1 bit per VL byte */
  182. int errors = 0;
  183. int i;
  184. if (!sve_vl)
  185. return 0;
  186. /* After a syscall the P registers should be zeroed */
  187. for (i = 0; i < SVE_NUM_PREGS * reg_size; i++)
  188. if (p_out[i])
  189. errors++;
  190. if (errors)
  191. ksft_print_msg("%s SVE VL %d predicate registers non-zero\n",
  192. cfg->name, sve_vl);
  193. return errors;
  194. }
  195. uint8_t ffr_in[__SVE_PREG_SIZE(ARCH_SVE_VQ_MAX)];
  196. uint8_t ffr_out[__SVE_PREG_SIZE(ARCH_SVE_VQ_MAX)];
  197. static void setup_ffr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  198. uint64_t svcr)
  199. {
  200. /*
  201. * If we are in streaming mode and do not have FA64 then FFR
  202. * is unavailable.
  203. */
  204. if ((svcr & SVCR_SM_MASK) &&
  205. !(getauxval(AT_HWCAP2) & HWCAP2_SME_FA64)) {
  206. memset(&ffr_in, 0, sizeof(ffr_in));
  207. return;
  208. }
  209. /*
  210. * It is only valid to set a contiguous set of bits starting
  211. * at 0. For now since we're expecting this to be cleared by
  212. * a syscall just set all bits.
  213. */
  214. memset(ffr_in, 0xff, sizeof(ffr_in));
  215. fill_random(ffr_out, sizeof(ffr_out));
  216. }
  217. static int check_ffr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  218. uint64_t svcr)
  219. {
  220. size_t reg_size = sve_vq_from_vl(sve_vl) * 2; /* 1 bit per VL byte */
  221. int errors = 0;
  222. int i;
  223. if (!sve_vl)
  224. return 0;
  225. if ((svcr & SVCR_SM_MASK) &&
  226. !(getauxval(AT_HWCAP2) & HWCAP2_SME_FA64))
  227. return 0;
  228. /* After a syscall FFR should be zeroed */
  229. for (i = 0; i < reg_size; i++)
  230. if (ffr_out[i])
  231. errors++;
  232. if (errors)
  233. ksft_print_msg("%s SVE VL %d FFR non-zero\n",
  234. cfg->name, sve_vl);
  235. return errors;
  236. }
  237. uint64_t svcr_in, svcr_out;
  238. static void setup_svcr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  239. uint64_t svcr)
  240. {
  241. svcr_in = svcr;
  242. }
  243. static int check_svcr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  244. uint64_t svcr)
  245. {
  246. int errors = 0;
  247. if (svcr_out & SVCR_SM_MASK) {
  248. ksft_print_msg("%s Still in SM, SVCR %llx\n",
  249. cfg->name, svcr_out);
  250. errors++;
  251. }
  252. if ((svcr_in & SVCR_ZA_MASK) != (svcr_out & SVCR_ZA_MASK)) {
  253. ksft_print_msg("%s PSTATE.ZA changed, SVCR %llx != %llx\n",
  254. cfg->name, svcr_in, svcr_out);
  255. errors++;
  256. }
  257. return errors;
  258. }
  259. uint8_t za_in[ZA_SIG_REGS_SIZE(ARCH_SVE_VQ_MAX)];
  260. uint8_t za_out[ZA_SIG_REGS_SIZE(ARCH_SVE_VQ_MAX)];
  261. static void setup_za(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  262. uint64_t svcr)
  263. {
  264. fill_random(za_in, sizeof(za_in));
  265. memset(za_out, 0, sizeof(za_out));
  266. }
  267. static int check_za(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  268. uint64_t svcr)
  269. {
  270. size_t reg_size = sme_vl * sme_vl;
  271. int errors = 0;
  272. if (!(svcr & SVCR_ZA_MASK))
  273. return 0;
  274. if (memcmp(za_in, za_out, reg_size) != 0) {
  275. ksft_print_msg("SME VL %d ZA does not match\n", sme_vl);
  276. errors++;
  277. }
  278. return errors;
  279. }
  280. uint8_t zt_in[ZT_SIG_REG_BYTES] __attribute__((aligned(16)));
  281. uint8_t zt_out[ZT_SIG_REG_BYTES] __attribute__((aligned(16)));
  282. static void setup_zt(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  283. uint64_t svcr)
  284. {
  285. fill_random(zt_in, sizeof(zt_in));
  286. memset(zt_out, 0, sizeof(zt_out));
  287. }
  288. static int check_zt(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  289. uint64_t svcr)
  290. {
  291. int errors = 0;
  292. if (!(getauxval(AT_HWCAP2) & HWCAP2_SME2))
  293. return 0;
  294. if (!(svcr & SVCR_ZA_MASK))
  295. return 0;
  296. if (memcmp(zt_in, zt_out, sizeof(zt_in)) != 0) {
  297. ksft_print_msg("SME VL %d ZT does not match\n", sme_vl);
  298. errors++;
  299. }
  300. return errors;
  301. }
  302. typedef void (*setup_fn)(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  303. uint64_t svcr);
  304. typedef int (*check_fn)(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  305. uint64_t svcr);
  306. /*
  307. * Each set of registers has a setup function which is called before
  308. * the syscall to fill values in a global variable for loading by the
  309. * test code and a check function which validates that the results are
  310. * as expected. Vector lengths are passed everywhere, a vector length
  311. * of 0 should be treated as do not test.
  312. */
  313. static struct {
  314. setup_fn setup;
  315. check_fn check;
  316. } regset[] = {
  317. { setup_gpr, check_gpr },
  318. { setup_fpr, check_fpr },
  319. { setup_z, check_z },
  320. { setup_p, check_p },
  321. { setup_ffr, check_ffr },
  322. { setup_svcr, check_svcr },
  323. { setup_za, check_za },
  324. { setup_zt, check_zt },
  325. };
  326. static bool do_test(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
  327. uint64_t svcr)
  328. {
  329. int errors = 0;
  330. int i;
  331. for (i = 0; i < ARRAY_SIZE(regset); i++)
  332. regset[i].setup(cfg, sve_vl, sme_vl, svcr);
  333. do_syscall(sve_vl, sme_vl);
  334. for (i = 0; i < ARRAY_SIZE(regset); i++)
  335. errors += regset[i].check(cfg, sve_vl, sme_vl, svcr);
  336. return errors == 0;
  337. }
  338. static void test_one_syscall(struct syscall_cfg *cfg)
  339. {
  340. int sve, sme;
  341. int ret;
  342. /* FPSIMD only case */
  343. ksft_test_result(do_test(cfg, 0, default_sme_vl, 0),
  344. "%s FPSIMD\n", cfg->name);
  345. for (sve = 0; sve < sve_vl_count; sve++) {
  346. ret = prctl(PR_SVE_SET_VL, sve_vls[sve]);
  347. if (ret == -1)
  348. ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n",
  349. strerror(errno), errno);
  350. ksft_test_result(do_test(cfg, sve_vls[sve], default_sme_vl, 0),
  351. "%s SVE VL %d\n", cfg->name, sve_vls[sve]);
  352. for (sme = 0; sme < sme_vl_count; sme++) {
  353. ret = prctl(PR_SME_SET_VL, sme_vls[sme]);
  354. if (ret == -1)
  355. ksft_exit_fail_msg("PR_SME_SET_VL failed: %s (%d)\n",
  356. strerror(errno), errno);
  357. ksft_test_result(do_test(cfg, sve_vls[sve],
  358. sme_vls[sme],
  359. SVCR_ZA_MASK | SVCR_SM_MASK),
  360. "%s SVE VL %d/SME VL %d SM+ZA\n",
  361. cfg->name, sve_vls[sve],
  362. sme_vls[sme]);
  363. ksft_test_result(do_test(cfg, sve_vls[sve],
  364. sme_vls[sme], SVCR_SM_MASK),
  365. "%s SVE VL %d/SME VL %d SM\n",
  366. cfg->name, sve_vls[sve],
  367. sme_vls[sme]);
  368. ksft_test_result(do_test(cfg, sve_vls[sve],
  369. sme_vls[sme], SVCR_ZA_MASK),
  370. "%s SVE VL %d/SME VL %d ZA\n",
  371. cfg->name, sve_vls[sve],
  372. sme_vls[sme]);
  373. }
  374. }
  375. for (sme = 0; sme < sme_vl_count; sme++) {
  376. ret = prctl(PR_SME_SET_VL, sme_vls[sme]);
  377. if (ret == -1)
  378. ksft_exit_fail_msg("PR_SME_SET_VL failed: %s (%d)\n",
  379. strerror(errno), errno);
  380. ksft_test_result(do_test(cfg, 0, sme_vls[sme],
  381. SVCR_ZA_MASK | SVCR_SM_MASK),
  382. "%s SME VL %d SM+ZA\n",
  383. cfg->name, sme_vls[sme]);
  384. ksft_test_result(do_test(cfg, 0, sme_vls[sme], SVCR_SM_MASK),
  385. "%s SME VL %d SM\n",
  386. cfg->name, sme_vls[sme]);
  387. ksft_test_result(do_test(cfg, 0, sme_vls[sme], SVCR_ZA_MASK),
  388. "%s SME VL %d ZA\n",
  389. cfg->name, sme_vls[sme]);
  390. }
  391. }
  392. void sve_count_vls(void)
  393. {
  394. unsigned int vq;
  395. int vl;
  396. if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
  397. return;
  398. /*
  399. * Enumerate up to ARCH_SVE_VQ_MAX vector lengths
  400. */
  401. for (vq = ARCH_SVE_VQ_MAX; vq > 0; vq /= 2) {
  402. vl = prctl(PR_SVE_SET_VL, vq * 16);
  403. if (vl == -1)
  404. ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n",
  405. strerror(errno), errno);
  406. vl &= PR_SVE_VL_LEN_MASK;
  407. if (vq != sve_vq_from_vl(vl))
  408. vq = sve_vq_from_vl(vl);
  409. sve_vls[sve_vl_count++] = vl;
  410. }
  411. }
  412. void sme_count_vls(void)
  413. {
  414. unsigned int vq;
  415. int vl;
  416. if (!(getauxval(AT_HWCAP2) & HWCAP2_SME))
  417. return;
  418. /*
  419. * Enumerate up to ARCH_SVE_VQ_MAX vector lengths
  420. */
  421. for (vq = ARCH_SVE_VQ_MAX; vq > 0; vq /= 2) {
  422. vl = prctl(PR_SME_SET_VL, vq * 16);
  423. if (vl == -1)
  424. ksft_exit_fail_msg("PR_SME_SET_VL failed: %s (%d)\n",
  425. strerror(errno), errno);
  426. vl &= PR_SME_VL_LEN_MASK;
  427. /* Found lowest VL */
  428. if (sve_vq_from_vl(vl) > vq)
  429. break;
  430. if (vq != sve_vq_from_vl(vl))
  431. vq = sve_vq_from_vl(vl);
  432. sme_vls[sme_vl_count++] = vl;
  433. }
  434. /* Ensure we configure a SME VL, used to flag if SVCR is set */
  435. default_sme_vl = sme_vls[0];
  436. }
  437. int main(void)
  438. {
  439. int i;
  440. int tests = 1; /* FPSIMD */
  441. int sme_ver;
  442. srandom(getpid());
  443. ksft_print_header();
  444. sve_count_vls();
  445. sme_count_vls();
  446. tests += sve_vl_count;
  447. tests += sme_vl_count * 3;
  448. tests += (sve_vl_count * sme_vl_count) * 3;
  449. ksft_set_plan(ARRAY_SIZE(syscalls) * tests);
  450. if (getauxval(AT_HWCAP2) & HWCAP2_SME2)
  451. sme_ver = 2;
  452. else
  453. sme_ver = 1;
  454. if (getauxval(AT_HWCAP2) & HWCAP2_SME_FA64)
  455. ksft_print_msg("SME%d with FA64\n", sme_ver);
  456. else if (getauxval(AT_HWCAP2) & HWCAP2_SME)
  457. ksft_print_msg("SME%d without FA64\n", sme_ver);
  458. for (i = 0; i < ARRAY_SIZE(syscalls); i++)
  459. test_one_syscall(&syscalls[i]);
  460. ksft_print_cnts();
  461. return 0;
  462. }