367 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 <sys/ptrace.h>15#include <sys/types.h>16#include <sys/uio.h>17#include <sys/wait.h>18#include <asm/sigcontext.h>19#include <asm/ptrace.h>20 21#include "../../kselftest.h"22 23/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */24#ifndef NT_ARM_ZA25#define NT_ARM_ZA 0x40c26#endif27 28/*29 * The architecture defines the maximum VQ as 16 but for extensibility30 * the kernel specifies the SVE_VQ_MAX as 512 resulting in us running31 * a *lot* more tests than are useful if we use it. Until the32 * architecture is extended let's limit our coverage to what is33 * currently allowed, plus one extra to ensure we cover constraining34 * the VL as expected.35 */36#define TEST_VQ_MAX 1737 38#define EXPECTED_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 3)39 40static void fill_buf(char *buf, size_t size)41{42 int i;43 44 for (i = 0; i < size; i++)45 buf[i] = random();46}47 48static int do_child(void)49{50 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))51 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));52 53 if (raise(SIGSTOP))54 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));55 56 return EXIT_SUCCESS;57}58 59static struct user_za_header *get_za(pid_t pid, void **buf, size_t *size)60{61 struct user_za_header *za;62 void *p;63 size_t sz = sizeof(*za);64 struct iovec iov;65 66 while (1) {67 if (*size < sz) {68 p = realloc(*buf, sz);69 if (!p) {70 errno = ENOMEM;71 goto error;72 }73 74 *buf = p;75 *size = sz;76 }77 78 iov.iov_base = *buf;79 iov.iov_len = sz;80 if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZA, &iov))81 goto error;82 83 za = *buf;84 if (za->size <= sz)85 break;86 87 sz = za->size;88 }89 90 return za;91 92error:93 return NULL;94}95 96static int set_za(pid_t pid, const struct user_za_header *za)97{98 struct iovec iov;99 100 iov.iov_base = (void *)za;101 iov.iov_len = za->size;102 return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZA, &iov);103}104 105/* Validate attempting to set the specfied VL via ptrace */106static void ptrace_set_get_vl(pid_t child, unsigned int vl, bool *supported)107{108 struct user_za_header za;109 struct user_za_header *new_za = NULL;110 size_t new_za_size = 0;111 int ret, prctl_vl;112 113 *supported = false;114 115 /* Check if the VL is supported in this process */116 prctl_vl = prctl(PR_SME_SET_VL, vl);117 if (prctl_vl == -1)118 ksft_exit_fail_msg("prctl(PR_SME_SET_VL) failed: %s (%d)\n",119 strerror(errno), errno);120 121 /* If the VL is not supported then a supported VL will be returned */122 *supported = (prctl_vl == vl);123 124 /* Set the VL by doing a set with no register payload */125 memset(&za, 0, sizeof(za));126 za.size = sizeof(za);127 za.vl = vl;128 ret = set_za(child, &za);129 if (ret != 0) {130 ksft_test_result_fail("Failed to set VL %u\n", vl);131 return;132 }133 134 /*135 * Read back the new register state and verify that we have the136 * same VL that we got from prctl() on ourselves.137 */138 if (!get_za(child, (void **)&new_za, &new_za_size)) {139 ksft_test_result_fail("Failed to read VL %u\n", vl);140 return;141 }142 143 ksft_test_result(new_za->vl = prctl_vl, "Set VL %u\n", vl);144 145 free(new_za);146}147 148/* Validate attempting to set no ZA data and read it back */149static void ptrace_set_no_data(pid_t child, unsigned int vl)150{151 void *read_buf = NULL;152 struct user_za_header write_za;153 struct user_za_header *read_za;154 size_t read_za_size = 0;155 int ret;156 157 /* Set up some data and write it out */158 memset(&write_za, 0, sizeof(write_za));159 write_za.size = ZA_PT_ZA_OFFSET;160 write_za.vl = vl;161 162 ret = set_za(child, &write_za);163 if (ret != 0) {164 ksft_test_result_fail("Failed to set VL %u no data\n", vl);165 return;166 }167 168 /* Read the data back */169 if (!get_za(child, (void **)&read_buf, &read_za_size)) {170 ksft_test_result_fail("Failed to read VL %u no data\n", vl);171 return;172 }173 read_za = read_buf;174 175 /* We might read more data if there's extensions we don't know */176 if (read_za->size < write_za.size) {177 ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",178 vl, write_za.size, read_za->size);179 goto out_read;180 }181 182 ksft_test_result(read_za->size == write_za.size,183 "Disabled ZA for VL %u\n", vl);184 185out_read:186 free(read_buf);187}188 189/* Validate attempting to set data and read it back */190static void ptrace_set_get_data(pid_t child, unsigned int vl)191{192 void *write_buf;193 void *read_buf = NULL;194 struct user_za_header *write_za;195 struct user_za_header *read_za;196 size_t read_za_size = 0;197 unsigned int vq = sve_vq_from_vl(vl);198 int ret;199 size_t data_size;200 201 data_size = ZA_PT_SIZE(vq);202 write_buf = malloc(data_size);203 if (!write_buf) {204 ksft_test_result_fail("Error allocating %d byte buffer for VL %u\n",205 data_size, vl);206 return;207 }208 write_za = write_buf;209 210 /* Set up some data and write it out */211 memset(write_za, 0, data_size);212 write_za->size = data_size;213 write_za->vl = vl;214 215 fill_buf(write_buf + ZA_PT_ZA_OFFSET, ZA_PT_ZA_SIZE(vq));216 217 ret = set_za(child, write_za);218 if (ret != 0) {219 ksft_test_result_fail("Failed to set VL %u data\n", vl);220 goto out;221 }222 223 /* Read the data back */224 if (!get_za(child, (void **)&read_buf, &read_za_size)) {225 ksft_test_result_fail("Failed to read VL %u data\n", vl);226 goto out;227 }228 read_za = read_buf;229 230 /* We might read more data if there's extensions we don't know */231 if (read_za->size < write_za->size) {232 ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",233 vl, write_za->size, read_za->size);234 goto out_read;235 }236 237 ksft_test_result(memcmp(write_buf + ZA_PT_ZA_OFFSET,238 read_buf + ZA_PT_ZA_OFFSET,239 ZA_PT_ZA_SIZE(vq)) == 0,240 "Data match for VL %u\n", vl);241 242out_read:243 free(read_buf);244out:245 free(write_buf);246}247 248static int do_parent(pid_t child)249{250 int ret = EXIT_FAILURE;251 pid_t pid;252 int status;253 siginfo_t si;254 unsigned int vq, vl;255 bool vl_supported;256 257 /* Attach to the child */258 while (1) {259 int sig;260 261 pid = wait(&status);262 if (pid == -1) {263 perror("wait");264 goto error;265 }266 267 /*268 * This should never happen but it's hard to flag in269 * the framework.270 */271 if (pid != child)272 continue;273 274 if (WIFEXITED(status) || WIFSIGNALED(status))275 ksft_exit_fail_msg("Child died unexpectedly\n");276 277 if (!WIFSTOPPED(status))278 goto error;279 280 sig = WSTOPSIG(status);281 282 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {283 if (errno == ESRCH)284 goto disappeared;285 286 if (errno == EINVAL) {287 sig = 0; /* bust group-stop */288 goto cont;289 }290 291 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",292 strerror(errno));293 goto error;294 }295 296 if (sig == SIGSTOP && si.si_code == SI_TKILL &&297 si.si_pid == pid)298 break;299 300 cont:301 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {302 if (errno == ESRCH)303 goto disappeared;304 305 ksft_test_result_fail("PTRACE_CONT: %s\n",306 strerror(errno));307 goto error;308 }309 }310 311 ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);312 313 /* Step through every possible VQ */314 for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {315 vl = sve_vl_from_vq(vq);316 317 /* First, try to set this vector length */318 ptrace_set_get_vl(child, vl, &vl_supported);319 320 /* If the VL is supported validate data set/get */321 if (vl_supported) {322 ptrace_set_no_data(child, vl);323 ptrace_set_get_data(child, vl);324 } else {325 ksft_test_result_skip("Disabled ZA for VL %u\n", vl);326 ksft_test_result_skip("Get and set data for VL %u\n",327 vl);328 }329 }330 331 ret = EXIT_SUCCESS;332 333error:334 kill(child, SIGKILL);335 336disappeared:337 return ret;338}339 340int main(void)341{342 int ret = EXIT_SUCCESS;343 pid_t child;344 345 srandom(getpid());346 347 ksft_print_header();348 349 if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {350 ksft_set_plan(1);351 ksft_exit_skip("SME not available\n");352 }353 354 ksft_set_plan(EXPECTED_TESTS);355 356 child = fork();357 if (!child)358 return do_child();359 360 if (do_parent(child))361 ret = EXIT_FAILURE;362 363 ksft_print_cnts();364 365 return ret;366}367