Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2021 ARM Limited.
0004  */
0005 #include <errno.h>
0006 #include <stdbool.h>
0007 #include <stddef.h>
0008 #include <stdio.h>
0009 #include <stdlib.h>
0010 #include <string.h>
0011 #include <unistd.h>
0012 #include <sys/auxv.h>
0013 #include <sys/prctl.h>
0014 #include <sys/ptrace.h>
0015 #include <sys/types.h>
0016 #include <sys/uio.h>
0017 #include <sys/wait.h>
0018 #include <asm/sigcontext.h>
0019 #include <asm/ptrace.h>
0020 
0021 #include "../../kselftest.h"
0022 
0023 /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
0024 #ifndef NT_ARM_ZA
0025 #define NT_ARM_ZA 0x40c
0026 #endif
0027 
0028 #define EXPECTED_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
0029 
0030 static void fill_buf(char *buf, size_t size)
0031 {
0032     int i;
0033 
0034     for (i = 0; i < size; i++)
0035         buf[i] = random();
0036 }
0037 
0038 static int do_child(void)
0039 {
0040     if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
0041         ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
0042 
0043     if (raise(SIGSTOP))
0044         ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
0045 
0046     return EXIT_SUCCESS;
0047 }
0048 
0049 static struct user_za_header *get_za(pid_t pid, void **buf, size_t *size)
0050 {
0051     struct user_za_header *za;
0052     void *p;
0053     size_t sz = sizeof(*za);
0054     struct iovec iov;
0055 
0056     while (1) {
0057         if (*size < sz) {
0058             p = realloc(*buf, sz);
0059             if (!p) {
0060                 errno = ENOMEM;
0061                 goto error;
0062             }
0063 
0064             *buf = p;
0065             *size = sz;
0066         }
0067 
0068         iov.iov_base = *buf;
0069         iov.iov_len = sz;
0070         if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZA, &iov))
0071             goto error;
0072 
0073         za = *buf;
0074         if (za->size <= sz)
0075             break;
0076 
0077         sz = za->size;
0078     }
0079 
0080     return za;
0081 
0082 error:
0083     return NULL;
0084 }
0085 
0086 static int set_za(pid_t pid, const struct user_za_header *za)
0087 {
0088     struct iovec iov;
0089 
0090     iov.iov_base = (void *)za;
0091     iov.iov_len = za->size;
0092     return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZA, &iov);
0093 }
0094 
0095 /* Validate attempting to set the specfied VL via ptrace */
0096 static void ptrace_set_get_vl(pid_t child, unsigned int vl, bool *supported)
0097 {
0098     struct user_za_header za;
0099     struct user_za_header *new_za = NULL;
0100     size_t new_za_size = 0;
0101     int ret, prctl_vl;
0102 
0103     *supported = false;
0104 
0105     /* Check if the VL is supported in this process */
0106     prctl_vl = prctl(PR_SME_SET_VL, vl);
0107     if (prctl_vl == -1)
0108         ksft_exit_fail_msg("prctl(PR_SME_SET_VL) failed: %s (%d)\n",
0109                    strerror(errno), errno);
0110 
0111     /* If the VL is not supported then a supported VL will be returned */
0112     *supported = (prctl_vl == vl);
0113 
0114     /* Set the VL by doing a set with no register payload */
0115     memset(&za, 0, sizeof(za));
0116     za.size = sizeof(za);
0117     za.vl = vl;
0118     ret = set_za(child, &za);
0119     if (ret != 0) {
0120         ksft_test_result_fail("Failed to set VL %u\n", vl);
0121         return;
0122     }
0123 
0124     /*
0125      * Read back the new register state and verify that we have the
0126      * same VL that we got from prctl() on ourselves.
0127      */
0128     if (!get_za(child, (void **)&new_za, &new_za_size)) {
0129         ksft_test_result_fail("Failed to read VL %u\n", vl);
0130         return;
0131     }
0132 
0133     ksft_test_result(new_za->vl = prctl_vl, "Set VL %u\n", vl);
0134 
0135     free(new_za);
0136 }
0137 
0138 /* Validate attempting to set no ZA data and read it back */
0139 static void ptrace_set_no_data(pid_t child, unsigned int vl)
0140 {
0141     void *read_buf = NULL;
0142     struct user_za_header write_za;
0143     struct user_za_header *read_za;
0144     size_t read_za_size = 0;
0145     int ret;
0146 
0147     /* Set up some data and write it out */
0148     memset(&write_za, 0, sizeof(write_za));
0149     write_za.size = ZA_PT_ZA_OFFSET;
0150     write_za.vl = vl;
0151 
0152     ret = set_za(child, &write_za);
0153     if (ret != 0) {
0154         ksft_test_result_fail("Failed to set VL %u no data\n", vl);
0155         return;
0156     }
0157 
0158     /* Read the data back */
0159     if (!get_za(child, (void **)&read_buf, &read_za_size)) {
0160         ksft_test_result_fail("Failed to read VL %u no data\n", vl);
0161         return;
0162     }
0163     read_za = read_buf;
0164 
0165     /* We might read more data if there's extensions we don't know */
0166     if (read_za->size < write_za.size) {
0167         ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
0168                       vl, write_za.size, read_za->size);
0169         goto out_read;
0170     }
0171 
0172     ksft_test_result(read_za->size == write_za.size,
0173              "Disabled ZA for VL %u\n", vl);
0174 
0175 out_read:
0176     free(read_buf);
0177 }
0178 
0179 /* Validate attempting to set data and read it back */
0180 static void ptrace_set_get_data(pid_t child, unsigned int vl)
0181 {
0182     void *write_buf;
0183     void *read_buf = NULL;
0184     struct user_za_header *write_za;
0185     struct user_za_header *read_za;
0186     size_t read_za_size = 0;
0187     unsigned int vq = sve_vq_from_vl(vl);
0188     int ret;
0189     size_t data_size;
0190 
0191     data_size = ZA_PT_SIZE(vq);
0192     write_buf = malloc(data_size);
0193     if (!write_buf) {
0194         ksft_test_result_fail("Error allocating %d byte buffer for VL %u\n",
0195                       data_size, vl);
0196         return;
0197     }
0198     write_za = write_buf;
0199 
0200     /* Set up some data and write it out */
0201     memset(write_za, 0, data_size);
0202     write_za->size = data_size;
0203     write_za->vl = vl;
0204 
0205     fill_buf(write_buf + ZA_PT_ZA_OFFSET, ZA_PT_ZA_SIZE(vq));
0206 
0207     ret = set_za(child, write_za);
0208     if (ret != 0) {
0209         ksft_test_result_fail("Failed to set VL %u data\n", vl);
0210         goto out;
0211     }
0212 
0213     /* Read the data back */
0214     if (!get_za(child, (void **)&read_buf, &read_za_size)) {
0215         ksft_test_result_fail("Failed to read VL %u data\n", vl);
0216         goto out;
0217     }
0218     read_za = read_buf;
0219 
0220     /* We might read more data if there's extensions we don't know */
0221     if (read_za->size < write_za->size) {
0222         ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
0223                       vl, write_za->size, read_za->size);
0224         goto out_read;
0225     }
0226 
0227     ksft_test_result(memcmp(write_buf + ZA_PT_ZA_OFFSET,
0228                 read_buf + ZA_PT_ZA_OFFSET,
0229                 ZA_PT_ZA_SIZE(vq)) == 0,
0230              "Data match for VL %u\n", vl);
0231 
0232 out_read:
0233     free(read_buf);
0234 out:
0235     free(write_buf);
0236 }
0237 
0238 static int do_parent(pid_t child)
0239 {
0240     int ret = EXIT_FAILURE;
0241     pid_t pid;
0242     int status;
0243     siginfo_t si;
0244     unsigned int vq, vl;
0245     bool vl_supported;
0246 
0247     /* Attach to the child */
0248     while (1) {
0249         int sig;
0250 
0251         pid = wait(&status);
0252         if (pid == -1) {
0253             perror("wait");
0254             goto error;
0255         }
0256 
0257         /*
0258          * This should never happen but it's hard to flag in
0259          * the framework.
0260          */
0261         if (pid != child)
0262             continue;
0263 
0264         if (WIFEXITED(status) || WIFSIGNALED(status))
0265             ksft_exit_fail_msg("Child died unexpectedly\n");
0266 
0267         if (!WIFSTOPPED(status))
0268             goto error;
0269 
0270         sig = WSTOPSIG(status);
0271 
0272         if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
0273             if (errno == ESRCH)
0274                 goto disappeared;
0275 
0276             if (errno == EINVAL) {
0277                 sig = 0; /* bust group-stop */
0278                 goto cont;
0279             }
0280 
0281             ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
0282                           strerror(errno));
0283             goto error;
0284         }
0285 
0286         if (sig == SIGSTOP && si.si_code == SI_TKILL &&
0287             si.si_pid == pid)
0288             break;
0289 
0290     cont:
0291         if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
0292             if (errno == ESRCH)
0293                 goto disappeared;
0294 
0295             ksft_test_result_fail("PTRACE_CONT: %s\n",
0296                           strerror(errno));
0297             goto error;
0298         }
0299     }
0300 
0301     ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
0302 
0303     /* Step through every possible VQ */
0304     for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
0305         vl = sve_vl_from_vq(vq);
0306 
0307         /* First, try to set this vector length */
0308         ptrace_set_get_vl(child, vl, &vl_supported);
0309 
0310         /* If the VL is supported validate data set/get */
0311         if (vl_supported) {
0312             ptrace_set_no_data(child, vl);
0313             ptrace_set_get_data(child, vl);
0314         } else {
0315             ksft_test_result_skip("Disabled ZA for VL %u\n", vl);
0316             ksft_test_result_skip("Get and set data for VL %u\n",
0317                           vl);
0318         }
0319     }
0320 
0321     ret = EXIT_SUCCESS;
0322 
0323 error:
0324     kill(child, SIGKILL);
0325 
0326 disappeared:
0327     return ret;
0328 }
0329 
0330 int main(void)
0331 {
0332     int ret = EXIT_SUCCESS;
0333     pid_t child;
0334 
0335     srandom(getpid());
0336 
0337     ksft_print_header();
0338 
0339     if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
0340         ksft_set_plan(1);
0341         ksft_exit_skip("SME not available\n");
0342     }
0343 
0344     ksft_set_plan(EXPECTED_TESTS);
0345 
0346     child = fork();
0347     if (!child)
0348         return do_child();
0349 
0350     if (do_parent(child))
0351         ret = EXIT_FAILURE;
0352 
0353     ksft_print_cnts();
0354 
0355     return ret;
0356 }