linux/tools/testing/selftests/arm64/fp/sve-ptrace.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2015-2021 ARM Limited.
   4 * Original author: Dave Martin <Dave.Martin@arm.com>
   5 */
   6#include <errno.h>
   7#include <stdbool.h>
   8#include <stddef.h>
   9#include <stdio.h>
  10#include <stdlib.h>
  11#include <string.h>
  12#include <unistd.h>
  13#include <sys/auxv.h>
  14#include <sys/prctl.h>
  15#include <sys/ptrace.h>
  16#include <sys/types.h>
  17#include <sys/uio.h>
  18#include <sys/wait.h>
  19#include <asm/sigcontext.h>
  20#include <asm/ptrace.h>
  21
  22#include "../../kselftest.h"
  23
  24/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
  25#ifndef NT_ARM_SVE
  26#define NT_ARM_SVE 0x405
  27#endif
  28
  29struct vec_type {
  30        const char *name;
  31        unsigned long hwcap_type;
  32        unsigned long hwcap;
  33        int regset;
  34        int prctl_set;
  35};
  36
  37static const struct vec_type vec_types[] = {
  38        {
  39                .name = "SVE",
  40                .hwcap_type = AT_HWCAP,
  41                .hwcap = HWCAP_SVE,
  42                .regset = NT_ARM_SVE,
  43                .prctl_set = PR_SVE_SET_VL,
  44        },
  45};
  46
  47#define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
  48#define FLAG_TESTS 2
  49#define FPSIMD_TESTS 3
  50
  51#define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types))
  52
  53static void fill_buf(char *buf, size_t size)
  54{
  55        int i;
  56
  57        for (i = 0; i < size; i++)
  58                buf[i] = random();
  59}
  60
  61static int do_child(void)
  62{
  63        if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
  64                ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
  65
  66        if (raise(SIGSTOP))
  67                ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
  68
  69        return EXIT_SUCCESS;
  70}
  71
  72static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
  73{
  74        struct iovec iov;
  75
  76        iov.iov_base = fpsimd;
  77        iov.iov_len = sizeof(*fpsimd);
  78        return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
  79}
  80
  81static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
  82                                       void **buf, size_t *size)
  83{
  84        struct user_sve_header *sve;
  85        void *p;
  86        size_t sz = sizeof *sve;
  87        struct iovec iov;
  88
  89        while (1) {
  90                if (*size < sz) {
  91                        p = realloc(*buf, sz);
  92                        if (!p) {
  93                                errno = ENOMEM;
  94                                goto error;
  95                        }
  96
  97                        *buf = p;
  98                        *size = sz;
  99                }
 100
 101                iov.iov_base = *buf;
 102                iov.iov_len = sz;
 103                if (ptrace(PTRACE_GETREGSET, pid, type->regset, &iov))
 104                        goto error;
 105
 106                sve = *buf;
 107                if (sve->size <= sz)
 108                        break;
 109
 110                sz = sve->size;
 111        }
 112
 113        return sve;
 114
 115error:
 116        return NULL;
 117}
 118
 119static int set_sve(pid_t pid, const struct vec_type *type,
 120                   const struct user_sve_header *sve)
 121{
 122        struct iovec iov;
 123
 124        iov.iov_base = (void *)sve;
 125        iov.iov_len = sve->size;
 126        return ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);
 127}
 128
 129/* Validate setting and getting the inherit flag */
 130static void ptrace_set_get_inherit(pid_t child, const struct vec_type *type)
 131{
 132        struct user_sve_header sve;
 133        struct user_sve_header *new_sve = NULL;
 134        size_t new_sve_size = 0;
 135        int ret;
 136
 137        /* First set the flag */
 138        memset(&sve, 0, sizeof(sve));
 139        sve.size = sizeof(sve);
 140        sve.vl = sve_vl_from_vq(SVE_VQ_MIN);
 141        sve.flags = SVE_PT_VL_INHERIT;
 142        ret = set_sve(child, type, &sve);
 143        if (ret != 0) {
 144                ksft_test_result_fail("Failed to set %s SVE_PT_VL_INHERIT\n",
 145                                      type->name);
 146                return;
 147        }
 148
 149        /*
 150         * Read back the new register state and verify that we have
 151         * set the flags we expected.
 152         */
 153        if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
 154                ksft_test_result_fail("Failed to read %s SVE flags\n",
 155                                      type->name);
 156                return;
 157        }
 158
 159        ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT,
 160                         "%s SVE_PT_VL_INHERIT set\n", type->name);
 161
 162        /* Now clear */
 163        sve.flags &= ~SVE_PT_VL_INHERIT;
 164        ret = set_sve(child, type, &sve);
 165        if (ret != 0) {
 166                ksft_test_result_fail("Failed to clear %s SVE_PT_VL_INHERIT\n",
 167                                      type->name);
 168                return;
 169        }
 170
 171        if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
 172                ksft_test_result_fail("Failed to read %s SVE flags\n",
 173                                      type->name);
 174                return;
 175        }
 176
 177        ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT),
 178                         "%s SVE_PT_VL_INHERIT cleared\n", type->name);
 179
 180        free(new_sve);
 181}
 182
 183/* Validate attempting to set the specfied VL via ptrace */
 184static void ptrace_set_get_vl(pid_t child, const struct vec_type *type,
 185                              unsigned int vl, bool *supported)
 186{
 187        struct user_sve_header sve;
 188        struct user_sve_header *new_sve = NULL;
 189        size_t new_sve_size = 0;
 190        int ret, prctl_vl;
 191
 192        *supported = false;
 193
 194        /* Check if the VL is supported in this process */
 195        prctl_vl = prctl(type->prctl_set, vl);
 196        if (prctl_vl == -1)
 197                ksft_exit_fail_msg("prctl(PR_%s_SET_VL) failed: %s (%d)\n",
 198                                   type->name, strerror(errno), errno);
 199
 200        /* If the VL is not supported then a supported VL will be returned */
 201        *supported = (prctl_vl == vl);
 202
 203        /* Set the VL by doing a set with no register payload */
 204        memset(&sve, 0, sizeof(sve));
 205        sve.size = sizeof(sve);
 206        sve.vl = vl;
 207        ret = set_sve(child, type, &sve);
 208        if (ret != 0) {
 209                ksft_test_result_fail("Failed to set %s VL %u\n",
 210                                      type->name, vl);
 211                return;
 212        }
 213
 214        /*
 215         * Read back the new register state and verify that we have the
 216         * same VL that we got from prctl() on ourselves.
 217         */
 218        if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
 219                ksft_test_result_fail("Failed to read %s VL %u\n",
 220                                      type->name, vl);
 221                return;
 222        }
 223
 224        ksft_test_result(new_sve->vl = prctl_vl, "Set %s VL %u\n",
 225                         type->name, vl);
 226
 227        free(new_sve);
 228}
 229
 230static void check_u32(unsigned int vl, const char *reg,
 231                      uint32_t *in, uint32_t *out, int *errors)
 232{
 233        if (*in != *out) {
 234                printf("# VL %d %s wrote %x read %x\n",
 235                       vl, reg, *in, *out);
 236                (*errors)++;
 237        }
 238}
 239
 240/* Access the FPSIMD registers via the SVE regset */
 241static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
 242{
 243        void *svebuf = NULL;
 244        size_t svebufsz = 0;
 245        struct user_sve_header *sve;
 246        struct user_fpsimd_state *fpsimd, new_fpsimd;
 247        unsigned int i, j;
 248        unsigned char *p;
 249
 250        /* New process should start with FPSIMD registers only */
 251        sve = get_sve(child, type, &svebuf, &svebufsz);
 252        if (!sve) {
 253                ksft_test_result_fail("get_sve(%s): %s\n",
 254                                      type->name, strerror(errno));
 255
 256                return;
 257        } else {
 258                ksft_test_result_pass("get_sve(%s FPSIMD)\n", type->name);
 259        }
 260
 261        ksft_test_result((sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD,
 262                         "Got FPSIMD registers via %s\n", type->name);
 263        if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_FPSIMD)
 264                goto out;
 265
 266        /* Try to set a known FPSIMD state via PT_REGS_SVE */
 267        fpsimd = (struct user_fpsimd_state *)((char *)sve +
 268                                              SVE_PT_FPSIMD_OFFSET);
 269        for (i = 0; i < 32; ++i) {
 270                p = (unsigned char *)&fpsimd->vregs[i];
 271
 272                for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
 273                        p[j] = j;
 274        }
 275
 276        if (set_sve(child, type, sve)) {
 277                ksft_test_result_fail("set_sve(%s FPSIMD): %s\n",
 278                                      type->name, strerror(errno));
 279
 280                goto out;
 281        }
 282
 283        /* Verify via the FPSIMD regset */
 284        if (get_fpsimd(child, &new_fpsimd)) {
 285                ksft_test_result_fail("get_fpsimd(): %s\n",
 286                                      strerror(errno));
 287                goto out;
 288        }
 289        if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)
 290                ksft_test_result_pass("%s get_fpsimd() gave same state\n",
 291                                      type->name);
 292        else
 293                ksft_test_result_fail("%s get_fpsimd() gave different state\n",
 294                                      type->name);
 295
 296out:
 297        free(svebuf);
 298}
 299
 300/* Validate attempting to set SVE data and read SVE data */
 301static void ptrace_set_sve_get_sve_data(pid_t child,
 302                                        const struct vec_type *type,
 303                                        unsigned int vl)
 304{
 305        void *write_buf;
 306        void *read_buf = NULL;
 307        struct user_sve_header *write_sve;
 308        struct user_sve_header *read_sve;
 309        size_t read_sve_size = 0;
 310        unsigned int vq = sve_vq_from_vl(vl);
 311        int ret, i;
 312        size_t data_size;
 313        int errors = 0;
 314
 315        data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
 316        write_buf = malloc(data_size);
 317        if (!write_buf) {
 318                ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
 319                                      data_size, type->name, vl);
 320                return;
 321        }
 322        write_sve = write_buf;
 323
 324        /* Set up some data and write it out */
 325        memset(write_sve, 0, data_size);
 326        write_sve->size = data_size;
 327        write_sve->vl = vl;
 328        write_sve->flags = SVE_PT_REGS_SVE;
 329
 330        for (i = 0; i < __SVE_NUM_ZREGS; i++)
 331                fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
 332                         SVE_PT_SVE_ZREG_SIZE(vq));
 333
 334        for (i = 0; i < __SVE_NUM_PREGS; i++)
 335                fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
 336                         SVE_PT_SVE_PREG_SIZE(vq));
 337
 338        fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
 339        fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
 340
 341        /* TODO: Generate a valid FFR pattern */
 342
 343        ret = set_sve(child, type, write_sve);
 344        if (ret != 0) {
 345                ksft_test_result_fail("Failed to set %s VL %u data\n",
 346                                      type->name, vl);
 347                goto out;
 348        }
 349
 350        /* Read the data back */
 351        if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
 352                ksft_test_result_fail("Failed to read %s VL %u data\n",
 353                                      type->name, vl);
 354                goto out;
 355        }
 356        read_sve = read_buf;
 357
 358        /* We might read more data if there's extensions we don't know */
 359        if (read_sve->size < write_sve->size) {
 360                ksft_test_result_fail("%s wrote %d bytes, only read %d\n",
 361                                      type->name, write_sve->size,
 362                                      read_sve->size);
 363                goto out_read;
 364        }
 365
 366        for (i = 0; i < __SVE_NUM_ZREGS; i++) {
 367                if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
 368                           read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
 369                           SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {
 370                        printf("# Mismatch in %u Z%d\n", vl, i);
 371                        errors++;
 372                }
 373        }
 374
 375        for (i = 0; i < __SVE_NUM_PREGS; i++) {
 376                if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
 377                           read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
 378                           SVE_PT_SVE_PREG_SIZE(vq)) != 0) {
 379                        printf("# Mismatch in %u P%d\n", vl, i);
 380                        errors++;
 381                }
 382        }
 383
 384        check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
 385                  read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
 386        check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
 387                  read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
 388
 389        ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",
 390                         type->name, vl);
 391
 392out_read:
 393        free(read_buf);
 394out:
 395        free(write_buf);
 396}
 397
 398/* Validate attempting to set SVE data and read SVE data */
 399static void ptrace_set_sve_get_fpsimd_data(pid_t child,
 400                                           const struct vec_type *type,
 401                                           unsigned int vl)
 402{
 403        void *write_buf;
 404        struct user_sve_header *write_sve;
 405        unsigned int vq = sve_vq_from_vl(vl);
 406        struct user_fpsimd_state fpsimd_state;
 407        int ret, i;
 408        size_t data_size;
 409        int errors = 0;
 410
 411        if (__BYTE_ORDER == __BIG_ENDIAN) {
 412                ksft_test_result_skip("Big endian not supported\n");
 413                return;
 414        }
 415
 416        data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
 417        write_buf = malloc(data_size);
 418        if (!write_buf) {
 419                ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n",
 420                                      data_size, type->name, vl);
 421                return;
 422        }
 423        write_sve = write_buf;
 424
 425        /* Set up some data and write it out */
 426        memset(write_sve, 0, data_size);
 427        write_sve->size = data_size;
 428        write_sve->vl = vl;
 429        write_sve->flags = SVE_PT_REGS_SVE;
 430
 431        for (i = 0; i < __SVE_NUM_ZREGS; i++)
 432                fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
 433                         SVE_PT_SVE_ZREG_SIZE(vq));
 434
 435        fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
 436        fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
 437
 438        ret = set_sve(child, type, write_sve);
 439        if (ret != 0) {
 440                ksft_test_result_fail("Failed to set %s VL %u data\n",
 441                                      type->name, vl);
 442                goto out;
 443        }
 444
 445        /* Read the data back */
 446        if (get_fpsimd(child, &fpsimd_state)) {
 447                ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",
 448                                      type->name, vl);
 449                goto out;
 450        }
 451
 452        for (i = 0; i < __SVE_NUM_ZREGS; i++) {
 453                __uint128_t tmp = 0;
 454
 455                /*
 456                 * Z regs are stored endianness invariant, this won't
 457                 * work for big endian
 458                 */
 459                memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
 460                       sizeof(tmp));
 461
 462                if (tmp != fpsimd_state.vregs[i]) {
 463                        printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",
 464                               type->name, vl, i);
 465                        errors++;
 466                }
 467        }
 468
 469        check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
 470                  &fpsimd_state.fpsr, &errors);
 471        check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
 472                  &fpsimd_state.fpcr, &errors);
 473
 474        ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",
 475                         type->name, vl);
 476
 477out:
 478        free(write_buf);
 479}
 480
 481static int do_parent(pid_t child)
 482{
 483        int ret = EXIT_FAILURE;
 484        pid_t pid;
 485        int status, i;
 486        siginfo_t si;
 487        unsigned int vq, vl;
 488        bool vl_supported;
 489
 490        ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
 491
 492        /* Attach to the child */
 493        while (1) {
 494                int sig;
 495
 496                pid = wait(&status);
 497                if (pid == -1) {
 498                        perror("wait");
 499                        goto error;
 500                }
 501
 502                /*
 503                 * This should never happen but it's hard to flag in
 504                 * the framework.
 505                 */
 506                if (pid != child)
 507                        continue;
 508
 509                if (WIFEXITED(status) || WIFSIGNALED(status))
 510                        ksft_exit_fail_msg("Child died unexpectedly\n");
 511
 512                if (!WIFSTOPPED(status))
 513                        goto error;
 514
 515                sig = WSTOPSIG(status);
 516
 517                if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
 518                        if (errno == ESRCH)
 519                                goto disappeared;
 520
 521                        if (errno == EINVAL) {
 522                                sig = 0; /* bust group-stop */
 523                                goto cont;
 524                        }
 525
 526                        ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
 527                                              strerror(errno));
 528                        goto error;
 529                }
 530
 531                if (sig == SIGSTOP && si.si_code == SI_TKILL &&
 532                    si.si_pid == pid)
 533                        break;
 534
 535        cont:
 536                if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
 537                        if (errno == ESRCH)
 538                                goto disappeared;
 539
 540                        ksft_test_result_fail("PTRACE_CONT: %s\n",
 541                                              strerror(errno));
 542                        goto error;
 543                }
 544        }
 545
 546        for (i = 0; i < ARRAY_SIZE(vec_types); i++) {
 547                /* FPSIMD via SVE regset */
 548                if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
 549                        ptrace_sve_fpsimd(child, &vec_types[i]);
 550                } else {
 551                        ksft_test_result_skip("%s FPSIMD get via SVE\n",
 552                                              vec_types[i].name);
 553                        ksft_test_result_skip("%s FPSIMD set via SVE\n",
 554                                              vec_types[i].name);
 555                        ksft_test_result_skip("%s set read via FPSIMD\n",
 556                                              vec_types[i].name);
 557                }
 558
 559                /* prctl() flags */
 560                if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
 561                        ptrace_set_get_inherit(child, &vec_types[i]);
 562                } else {
 563                        ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",
 564                                              vec_types[i].name);
 565                        ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",
 566                                              vec_types[i].name);
 567                }
 568
 569                /* Step through every possible VQ */
 570                for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
 571                        vl = sve_vl_from_vq(vq);
 572
 573                        /* First, try to set this vector length */
 574                        if (getauxval(vec_types[i].hwcap_type) &
 575                            vec_types[i].hwcap) {
 576                                ptrace_set_get_vl(child, &vec_types[i], vl,
 577                                                  &vl_supported);
 578                        } else {
 579                                ksft_test_result_skip("%s get/set VL %d\n",
 580                                                      vec_types[i].name, vl);
 581                                vl_supported = false;
 582                        }
 583
 584                        /* If the VL is supported validate data set/get */
 585                        if (vl_supported) {
 586                                ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);
 587                                ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);
 588                        } else {
 589                                ksft_test_result_skip("%s set SVE get SVE for VL %d\n",
 590                                                      vec_types[i].name, vl);
 591                                ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",
 592                                                      vec_types[i].name, vl);
 593                        }
 594                }
 595        }
 596
 597        ret = EXIT_SUCCESS;
 598
 599error:
 600        kill(child, SIGKILL);
 601
 602disappeared:
 603        return ret;
 604}
 605
 606int main(void)
 607{
 608        int ret = EXIT_SUCCESS;
 609        pid_t child;
 610
 611        srandom(getpid());
 612
 613        ksft_print_header();
 614        ksft_set_plan(EXPECTED_TESTS);
 615
 616        if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
 617                ksft_exit_skip("SVE not available\n");
 618
 619        child = fork();
 620        if (!child)
 621                return do_child();
 622
 623        if (do_parent(child))
 624                ret = EXIT_FAILURE;
 625
 626        ksft_print_cnts();
 627
 628        return ret;
 629}
 630