Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2021 ARM Limited.
0004  * Original author: Mark Brown <broonie@kernel.org>
0005  */
0006 #include <assert.h>
0007 #include <errno.h>
0008 #include <fcntl.h>
0009 #include <stddef.h>
0010 #include <stdio.h>
0011 #include <stdlib.h>
0012 #include <string.h>
0013 #include <unistd.h>
0014 #include <sys/auxv.h>
0015 #include <sys/prctl.h>
0016 #include <sys/types.h>
0017 #include <sys/wait.h>
0018 #include <asm/sigcontext.h>
0019 #include <asm/hwcap.h>
0020 
0021 #include "../../kselftest.h"
0022 #include "rdvl.h"
0023 
0024 #define ARCH_MIN_VL SVE_VL_MIN
0025 
0026 struct vec_data {
0027     const char *name;
0028     unsigned long hwcap_type;
0029     unsigned long hwcap;
0030     const char *rdvl_binary;
0031     int (*rdvl)(void);
0032 
0033     int prctl_get;
0034     int prctl_set;
0035     const char *default_vl_file;
0036 
0037     int default_vl;
0038     int min_vl;
0039     int max_vl;
0040 };
0041 
0042 
0043 static struct vec_data vec_data[] = {
0044     {
0045         .name = "SVE",
0046         .hwcap_type = AT_HWCAP,
0047         .hwcap = HWCAP_SVE,
0048         .rdvl = rdvl_sve,
0049         .rdvl_binary = "./rdvl-sve",
0050         .prctl_get = PR_SVE_GET_VL,
0051         .prctl_set = PR_SVE_SET_VL,
0052         .default_vl_file = "/proc/sys/abi/sve_default_vector_length",
0053     },
0054     {
0055         .name = "SME",
0056         .hwcap_type = AT_HWCAP2,
0057         .hwcap = HWCAP2_SME,
0058         .rdvl = rdvl_sme,
0059         .rdvl_binary = "./rdvl-sme",
0060         .prctl_get = PR_SME_GET_VL,
0061         .prctl_set = PR_SME_SET_VL,
0062         .default_vl_file = "/proc/sys/abi/sme_default_vector_length",
0063     },
0064 };
0065 
0066 static int stdio_read_integer(FILE *f, const char *what, int *val)
0067 {
0068     int n = 0;
0069     int ret;
0070 
0071     ret = fscanf(f, "%d%*1[\n]%n", val, &n);
0072     if (ret < 1 || n < 1) {
0073         ksft_print_msg("failed to parse integer from %s\n", what);
0074         return -1;
0075     }
0076 
0077     return 0;
0078 }
0079 
0080 /* Start a new process and return the vector length it sees */
0081 static int get_child_rdvl(struct vec_data *data)
0082 {
0083     FILE *out;
0084     int pipefd[2];
0085     pid_t pid, child;
0086     int read_vl, ret;
0087 
0088     ret = pipe(pipefd);
0089     if (ret == -1) {
0090         ksft_print_msg("pipe() failed: %d (%s)\n",
0091                    errno, strerror(errno));
0092         return -1;
0093     }
0094 
0095     fflush(stdout);
0096 
0097     child = fork();
0098     if (child == -1) {
0099         ksft_print_msg("fork() failed: %d (%s)\n",
0100                    errno, strerror(errno));
0101         close(pipefd[0]);
0102         close(pipefd[1]);
0103         return -1;
0104     }
0105 
0106     /* Child: put vector length on the pipe */
0107     if (child == 0) {
0108         /*
0109          * Replace stdout with the pipe, errors to stderr from
0110          * here as kselftest prints to stdout.
0111          */
0112         ret = dup2(pipefd[1], 1);
0113         if (ret == -1) {
0114             fprintf(stderr, "dup2() %d\n", errno);
0115             exit(EXIT_FAILURE);
0116         }
0117 
0118         /* exec() a new binary which puts the VL on stdout */
0119         ret = execl(data->rdvl_binary, data->rdvl_binary, NULL);
0120         fprintf(stderr, "execl(%s) failed: %d (%s)\n",
0121             data->rdvl_binary, errno, strerror(errno));
0122 
0123         exit(EXIT_FAILURE);
0124     }
0125 
0126     close(pipefd[1]);
0127 
0128     /* Parent; wait for the exit status from the child & verify it */
0129     do {
0130         pid = wait(&ret);
0131         if (pid == -1) {
0132             ksft_print_msg("wait() failed: %d (%s)\n",
0133                        errno, strerror(errno));
0134             close(pipefd[0]);
0135             return -1;
0136         }
0137     } while (pid != child);
0138 
0139     assert(pid == child);
0140 
0141     if (!WIFEXITED(ret)) {
0142         ksft_print_msg("child exited abnormally\n");
0143         close(pipefd[0]);
0144         return -1;
0145     }
0146 
0147     if (WEXITSTATUS(ret) != 0) {
0148         ksft_print_msg("child returned error %d\n",
0149                    WEXITSTATUS(ret));
0150         close(pipefd[0]);
0151         return -1;
0152     }
0153 
0154     out = fdopen(pipefd[0], "r");
0155     if (!out) {
0156         ksft_print_msg("failed to open child stdout\n");
0157         close(pipefd[0]);
0158         return -1;
0159     }
0160 
0161     ret = stdio_read_integer(out, "child", &read_vl);
0162     fclose(out);
0163     if (ret != 0)
0164         return ret;
0165 
0166     return read_vl;
0167 }
0168 
0169 static int file_read_integer(const char *name, int *val)
0170 {
0171     FILE *f;
0172     int ret;
0173 
0174     f = fopen(name, "r");
0175     if (!f) {
0176         ksft_test_result_fail("Unable to open %s: %d (%s)\n",
0177                       name, errno,
0178                       strerror(errno));
0179         return -1;
0180     }
0181 
0182     ret = stdio_read_integer(f, name, val);
0183     fclose(f);
0184 
0185     return ret;
0186 }
0187 
0188 static int file_write_integer(const char *name, int val)
0189 {
0190     FILE *f;
0191 
0192     f = fopen(name, "w");
0193     if (!f) {
0194         ksft_test_result_fail("Unable to open %s: %d (%s)\n",
0195                       name, errno,
0196                       strerror(errno));
0197         return -1;
0198     }
0199 
0200     fprintf(f, "%d", val);
0201     fclose(f);
0202 
0203     return 0;
0204 }
0205 
0206 /*
0207  * Verify that we can read the default VL via proc, checking that it
0208  * is set in a freshly spawned child.
0209  */
0210 static void proc_read_default(struct vec_data *data)
0211 {
0212     int default_vl, child_vl, ret;
0213 
0214     ret = file_read_integer(data->default_vl_file, &default_vl);
0215     if (ret != 0)
0216         return;
0217 
0218     /* Is this the actual default seen by new processes? */
0219     child_vl = get_child_rdvl(data);
0220     if (child_vl != default_vl) {
0221         ksft_test_result_fail("%s is %d but child VL is %d\n",
0222                       data->default_vl_file,
0223                       default_vl, child_vl);
0224         return;
0225     }
0226 
0227     ksft_test_result_pass("%s default vector length %d\n", data->name,
0228                   default_vl);
0229     data->default_vl = default_vl;
0230 }
0231 
0232 /* Verify that we can write a minimum value and have it take effect */
0233 static void proc_write_min(struct vec_data *data)
0234 {
0235     int ret, new_default, child_vl;
0236 
0237     if (geteuid() != 0) {
0238         ksft_test_result_skip("Need to be root to write to /proc\n");
0239         return;
0240     }
0241 
0242     ret = file_write_integer(data->default_vl_file, ARCH_MIN_VL);
0243     if (ret != 0)
0244         return;
0245 
0246     /* What was the new value? */
0247     ret = file_read_integer(data->default_vl_file, &new_default);
0248     if (ret != 0)
0249         return;
0250 
0251     /* Did it take effect in a new process? */
0252     child_vl = get_child_rdvl(data);
0253     if (child_vl != new_default) {
0254         ksft_test_result_fail("%s is %d but child VL is %d\n",
0255                       data->default_vl_file,
0256                       new_default, child_vl);
0257         return;
0258     }
0259 
0260     ksft_test_result_pass("%s minimum vector length %d\n", data->name,
0261                   new_default);
0262     data->min_vl = new_default;
0263 
0264     file_write_integer(data->default_vl_file, data->default_vl);
0265 }
0266 
0267 /* Verify that we can write a maximum value and have it take effect */
0268 static void proc_write_max(struct vec_data *data)
0269 {
0270     int ret, new_default, child_vl;
0271 
0272     if (geteuid() != 0) {
0273         ksft_test_result_skip("Need to be root to write to /proc\n");
0274         return;
0275     }
0276 
0277     /* -1 is accepted by the /proc interface as the maximum VL */
0278     ret = file_write_integer(data->default_vl_file, -1);
0279     if (ret != 0)
0280         return;
0281 
0282     /* What was the new value? */
0283     ret = file_read_integer(data->default_vl_file, &new_default);
0284     if (ret != 0)
0285         return;
0286 
0287     /* Did it take effect in a new process? */
0288     child_vl = get_child_rdvl(data);
0289     if (child_vl != new_default) {
0290         ksft_test_result_fail("%s is %d but child VL is %d\n",
0291                       data->default_vl_file,
0292                       new_default, child_vl);
0293         return;
0294     }
0295 
0296     ksft_test_result_pass("%s maximum vector length %d\n", data->name,
0297                   new_default);
0298     data->max_vl = new_default;
0299 
0300     file_write_integer(data->default_vl_file, data->default_vl);
0301 }
0302 
0303 /* Can we read back a VL from prctl? */
0304 static void prctl_get(struct vec_data *data)
0305 {
0306     int ret;
0307 
0308     ret = prctl(data->prctl_get);
0309     if (ret == -1) {
0310         ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
0311                       data->name, errno, strerror(errno));
0312         return;
0313     }
0314 
0315     /* Mask out any flags */
0316     ret &= PR_SVE_VL_LEN_MASK;
0317 
0318     /* Is that what we can read back directly? */
0319     if (ret == data->rdvl())
0320         ksft_test_result_pass("%s current VL is %d\n",
0321                       data->name, ret);
0322     else
0323         ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n",
0324                       data->name, ret, data->rdvl());
0325 }
0326 
0327 /* Does the prctl let us set the VL we already have? */
0328 static void prctl_set_same(struct vec_data *data)
0329 {
0330     int cur_vl = data->rdvl();
0331     int ret;
0332 
0333     ret = prctl(data->prctl_set, cur_vl);
0334     if (ret < 0) {
0335         ksft_test_result_fail("%s prctl set failed: %d (%s)\n",
0336                       data->name, errno, strerror(errno));
0337         return;
0338     }
0339 
0340     ksft_test_result(cur_vl == data->rdvl(),
0341              "%s set VL %d and have VL %d\n",
0342              data->name, cur_vl, data->rdvl());
0343 }
0344 
0345 /* Can we set a new VL for this process? */
0346 static void prctl_set(struct vec_data *data)
0347 {
0348     int ret;
0349 
0350     if (data->min_vl == data->max_vl) {
0351         ksft_test_result_skip("%s only one VL supported\n",
0352                       data->name);
0353         return;
0354     }
0355 
0356     /* Try to set the minimum VL */
0357     ret = prctl(data->prctl_set, data->min_vl);
0358     if (ret < 0) {
0359         ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
0360                       data->name, data->min_vl,
0361                       errno, strerror(errno));
0362         return;
0363     }
0364 
0365     if ((ret & PR_SVE_VL_LEN_MASK) != data->min_vl) {
0366         ksft_test_result_fail("%s prctl set %d but return value is %d\n",
0367                       data->name, data->min_vl, data->rdvl());
0368         return;
0369     }
0370 
0371     if (data->rdvl() != data->min_vl) {
0372         ksft_test_result_fail("%s set %d but RDVL is %d\n",
0373                       data->name, data->min_vl, data->rdvl());
0374         return;
0375     }
0376 
0377     /* Try to set the maximum VL */
0378     ret = prctl(data->prctl_set, data->max_vl);
0379     if (ret < 0) {
0380         ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
0381                       data->name, data->max_vl,
0382                       errno, strerror(errno));
0383         return;
0384     }
0385 
0386     if ((ret & PR_SVE_VL_LEN_MASK) != data->max_vl) {
0387         ksft_test_result_fail("%s prctl() set %d but return value is %d\n",
0388                       data->name, data->max_vl, data->rdvl());
0389         return;
0390     }
0391 
0392     /* The _INHERIT flag should not be present when we read the VL */
0393     ret = prctl(data->prctl_get);
0394     if (ret == -1) {
0395         ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
0396                       data->name, errno, strerror(errno));
0397         return;
0398     }
0399 
0400     if (ret & PR_SVE_VL_INHERIT) {
0401         ksft_test_result_fail("%s prctl() reports _INHERIT\n",
0402                       data->name);
0403         return;
0404     }
0405 
0406     ksft_test_result_pass("%s prctl() set min/max\n", data->name);
0407 }
0408 
0409 /* If we didn't request it a new VL shouldn't affect the child */
0410 static void prctl_set_no_child(struct vec_data *data)
0411 {
0412     int ret, child_vl;
0413 
0414     if (data->min_vl == data->max_vl) {
0415         ksft_test_result_skip("%s only one VL supported\n",
0416                       data->name);
0417         return;
0418     }
0419 
0420     ret = prctl(data->prctl_set, data->min_vl);
0421     if (ret < 0) {
0422         ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
0423                       data->name, data->min_vl,
0424                       errno, strerror(errno));
0425         return;
0426     }
0427 
0428     /* Ensure the default VL is different */
0429     ret = file_write_integer(data->default_vl_file, data->max_vl);
0430     if (ret != 0)
0431         return;
0432 
0433     /* Check that the child has the default we just set */
0434     child_vl = get_child_rdvl(data);
0435     if (child_vl != data->max_vl) {
0436         ksft_test_result_fail("%s is %d but child VL is %d\n",
0437                       data->default_vl_file,
0438                       data->max_vl, child_vl);
0439         return;
0440     }
0441 
0442     ksft_test_result_pass("%s vector length used default\n", data->name);
0443 
0444     file_write_integer(data->default_vl_file, data->default_vl);
0445 }
0446 
0447 /* If we didn't request it a new VL shouldn't affect the child */
0448 static void prctl_set_for_child(struct vec_data *data)
0449 {
0450     int ret, child_vl;
0451 
0452     if (data->min_vl == data->max_vl) {
0453         ksft_test_result_skip("%s only one VL supported\n",
0454                       data->name);
0455         return;
0456     }
0457 
0458     ret = prctl(data->prctl_set, data->min_vl | PR_SVE_VL_INHERIT);
0459     if (ret < 0) {
0460         ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
0461                       data->name, data->min_vl,
0462                       errno, strerror(errno));
0463         return;
0464     }
0465 
0466     /* The _INHERIT flag should be present when we read the VL */
0467     ret = prctl(data->prctl_get);
0468     if (ret == -1) {
0469         ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
0470                       data->name, errno, strerror(errno));
0471         return;
0472     }
0473     if (!(ret & PR_SVE_VL_INHERIT)) {
0474         ksft_test_result_fail("%s prctl() does not report _INHERIT\n",
0475                       data->name);
0476         return;
0477     }
0478 
0479     /* Ensure the default VL is different */
0480     ret = file_write_integer(data->default_vl_file, data->max_vl);
0481     if (ret != 0)
0482         return;
0483 
0484     /* Check that the child inherited our VL */
0485     child_vl = get_child_rdvl(data);
0486     if (child_vl != data->min_vl) {
0487         ksft_test_result_fail("%s is %d but child VL is %d\n",
0488                       data->default_vl_file,
0489                       data->min_vl, child_vl);
0490         return;
0491     }
0492 
0493     ksft_test_result_pass("%s vector length was inherited\n", data->name);
0494 
0495     file_write_integer(data->default_vl_file, data->default_vl);
0496 }
0497 
0498 /* _ONEXEC takes effect only in the child process */
0499 static void prctl_set_onexec(struct vec_data *data)
0500 {
0501     int ret, child_vl;
0502 
0503     if (data->min_vl == data->max_vl) {
0504         ksft_test_result_skip("%s only one VL supported\n",
0505                       data->name);
0506         return;
0507     }
0508 
0509     /* Set a known value for the default and our current VL */
0510     ret = file_write_integer(data->default_vl_file, data->max_vl);
0511     if (ret != 0)
0512         return;
0513 
0514     ret = prctl(data->prctl_set, data->max_vl);
0515     if (ret < 0) {
0516         ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
0517                       data->name, data->min_vl,
0518                       errno, strerror(errno));
0519         return;
0520     }
0521 
0522     /* Set a different value for the child to have on exec */
0523     ret = prctl(data->prctl_set, data->min_vl | PR_SVE_SET_VL_ONEXEC);
0524     if (ret < 0) {
0525         ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
0526                       data->name, data->min_vl,
0527                       errno, strerror(errno));
0528         return;
0529     }
0530 
0531     /* Our current VL should stay the same */
0532     if (data->rdvl() != data->max_vl) {
0533         ksft_test_result_fail("%s VL changed by _ONEXEC prctl()\n",
0534                       data->name);
0535         return;
0536     }
0537 
0538     /* Check that the child inherited our VL */
0539     child_vl = get_child_rdvl(data);
0540     if (child_vl != data->min_vl) {
0541         ksft_test_result_fail("Set %d _ONEXEC but child VL is %d\n",
0542                       data->min_vl, child_vl);
0543         return;
0544     }
0545 
0546     ksft_test_result_pass("%s vector length set on exec\n", data->name);
0547 
0548     file_write_integer(data->default_vl_file, data->default_vl);
0549 }
0550 
0551 /* For each VQ verify that setting via prctl() does the right thing */
0552 static void prctl_set_all_vqs(struct vec_data *data)
0553 {
0554     int ret, vq, vl, new_vl;
0555     int errors = 0;
0556 
0557     if (!data->min_vl || !data->max_vl) {
0558         ksft_test_result_skip("%s Failed to enumerate VLs, not testing VL setting\n",
0559                       data->name);
0560         return;
0561     }
0562 
0563     for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
0564         vl = sve_vl_from_vq(vq);
0565 
0566         /* Attempt to set the VL */
0567         ret = prctl(data->prctl_set, vl);
0568         if (ret < 0) {
0569             errors++;
0570             ksft_print_msg("%s prctl set failed for %d: %d (%s)\n",
0571                        data->name, vl,
0572                        errno, strerror(errno));
0573             continue;
0574         }
0575 
0576         new_vl = ret & PR_SVE_VL_LEN_MASK;
0577 
0578         /* Check that we actually have the reported new VL */
0579         if (data->rdvl() != new_vl) {
0580             ksft_print_msg("Set %s VL %d but RDVL reports %d\n",
0581                        data->name, new_vl, data->rdvl());
0582             errors++;
0583         }
0584 
0585         /* Was that the VL we asked for? */
0586         if (new_vl == vl)
0587             continue;
0588 
0589         /* Should round up to the minimum VL if below it */
0590         if (vl < data->min_vl) {
0591             if (new_vl != data->min_vl) {
0592                 ksft_print_msg("%s VL %d returned %d not minimum %d\n",
0593                            data->name, vl, new_vl,
0594                            data->min_vl);
0595                 errors++;
0596             }
0597 
0598             continue;
0599         }
0600 
0601         /* Should round down to maximum VL if above it */
0602         if (vl > data->max_vl) {
0603             if (new_vl != data->max_vl) {
0604                 ksft_print_msg("%s VL %d returned %d not maximum %d\n",
0605                            data->name, vl, new_vl,
0606                            data->max_vl);
0607                 errors++;
0608             }
0609 
0610             continue;
0611         }
0612 
0613         /* Otherwise we should've rounded down */
0614         if (!(new_vl < vl)) {
0615             ksft_print_msg("%s VL %d returned %d, did not round down\n",
0616                        data->name, vl, new_vl);
0617             errors++;
0618 
0619             continue;
0620         }
0621     }
0622 
0623     ksft_test_result(errors == 0, "%s prctl() set all VLs, %d errors\n",
0624              data->name, errors);
0625 }
0626 
0627 typedef void (*test_type)(struct vec_data *);
0628 
0629 static const test_type tests[] = {
0630     /*
0631      * The default/min/max tests must be first and in this order
0632      * to provide data for other tests.
0633      */
0634     proc_read_default,
0635     proc_write_min,
0636     proc_write_max,
0637 
0638     prctl_get,
0639     prctl_set_same,
0640     prctl_set,
0641     prctl_set_no_child,
0642     prctl_set_for_child,
0643     prctl_set_onexec,
0644     prctl_set_all_vqs,
0645 };
0646 
0647 int main(void)
0648 {
0649     int i, j;
0650 
0651     ksft_print_header();
0652     ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data));
0653 
0654     for (i = 0; i < ARRAY_SIZE(vec_data); i++) {
0655         struct vec_data *data = &vec_data[i];
0656         unsigned long supported;
0657 
0658         supported = getauxval(data->hwcap_type) & data->hwcap;
0659 
0660         for (j = 0; j < ARRAY_SIZE(tests); j++) {
0661             if (supported)
0662                 tests[j](data);
0663             else
0664                 ksft_test_result_skip("%s not supported\n",
0665                               data->name);
0666         }
0667     }
0668 
0669     ksft_exit_pass();
0670 }