18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015-2019 ARM Limited. 48c2ecf20Sopenharmony_ci * Original author: Dave Martin <Dave.Martin@arm.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#define _GNU_SOURCE 78c2ecf20Sopenharmony_ci#include <assert.h> 88c2ecf20Sopenharmony_ci#include <errno.h> 98c2ecf20Sopenharmony_ci#include <limits.h> 108c2ecf20Sopenharmony_ci#include <stddef.h> 118c2ecf20Sopenharmony_ci#include <stdio.h> 128c2ecf20Sopenharmony_ci#include <stdlib.h> 138c2ecf20Sopenharmony_ci#include <string.h> 148c2ecf20Sopenharmony_ci#include <getopt.h> 158c2ecf20Sopenharmony_ci#include <unistd.h> 168c2ecf20Sopenharmony_ci#include <sys/auxv.h> 178c2ecf20Sopenharmony_ci#include <sys/prctl.h> 188c2ecf20Sopenharmony_ci#include <asm/hwcap.h> 198c2ecf20Sopenharmony_ci#include <asm/sigcontext.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int inherit = 0; 228c2ecf20Sopenharmony_cistatic int no_inherit = 0; 238c2ecf20Sopenharmony_cistatic int force = 0; 248c2ecf20Sopenharmony_cistatic unsigned long vl; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic const struct option options[] = { 278c2ecf20Sopenharmony_ci { "force", no_argument, NULL, 'f' }, 288c2ecf20Sopenharmony_ci { "inherit", no_argument, NULL, 'i' }, 298c2ecf20Sopenharmony_ci { "max", no_argument, NULL, 'M' }, 308c2ecf20Sopenharmony_ci { "no-inherit", no_argument, &no_inherit, 1 }, 318c2ecf20Sopenharmony_ci { "help", no_argument, NULL, '?' }, 328c2ecf20Sopenharmony_ci {} 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic char const *program_name; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int parse_options(int argc, char **argv) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci int c; 408c2ecf20Sopenharmony_ci char *rest; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci program_name = strrchr(argv[0], '/'); 438c2ecf20Sopenharmony_ci if (program_name) 448c2ecf20Sopenharmony_ci ++program_name; 458c2ecf20Sopenharmony_ci else 468c2ecf20Sopenharmony_ci program_name = argv[0]; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci while ((c = getopt_long(argc, argv, "Mfhi", options, NULL)) != -1) 498c2ecf20Sopenharmony_ci switch (c) { 508c2ecf20Sopenharmony_ci case 'M': vl = SVE_VL_MAX; break; 518c2ecf20Sopenharmony_ci case 'f': force = 1; break; 528c2ecf20Sopenharmony_ci case 'i': inherit = 1; break; 538c2ecf20Sopenharmony_ci case 0: break; 548c2ecf20Sopenharmony_ci default: goto error; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (inherit && no_inherit) 588c2ecf20Sopenharmony_ci goto error; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (!vl) { 618c2ecf20Sopenharmony_ci /* vector length */ 628c2ecf20Sopenharmony_ci if (optind >= argc) 638c2ecf20Sopenharmony_ci goto error; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci errno = 0; 668c2ecf20Sopenharmony_ci vl = strtoul(argv[optind], &rest, 0); 678c2ecf20Sopenharmony_ci if (*rest) { 688c2ecf20Sopenharmony_ci vl = ULONG_MAX; 698c2ecf20Sopenharmony_ci errno = EINVAL; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci if (vl == ULONG_MAX && errno) { 728c2ecf20Sopenharmony_ci fprintf(stderr, "%s: %s: %s\n", 738c2ecf20Sopenharmony_ci program_name, argv[optind], strerror(errno)); 748c2ecf20Sopenharmony_ci goto error; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ++optind; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* command */ 818c2ecf20Sopenharmony_ci if (optind >= argc) 828c2ecf20Sopenharmony_ci goto error; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cierror: 878c2ecf20Sopenharmony_ci fprintf(stderr, 888c2ecf20Sopenharmony_ci "Usage: %s [-f | --force] " 898c2ecf20Sopenharmony_ci "[-i | --inherit | --no-inherit] " 908c2ecf20Sopenharmony_ci "{-M | --max | <vector length>} " 918c2ecf20Sopenharmony_ci "<command> [<arguments> ...]\n", 928c2ecf20Sopenharmony_ci program_name); 938c2ecf20Sopenharmony_ci return -1; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint main(int argc, char **argv) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci int ret = 126; /* same as sh(1) command-not-executable error */ 998c2ecf20Sopenharmony_ci long flags; 1008c2ecf20Sopenharmony_ci char *path; 1018c2ecf20Sopenharmony_ci int t, e; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (parse_options(argc, argv)) 1048c2ecf20Sopenharmony_ci return 2; /* same as sh(1) builtin incorrect-usage */ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (vl & ~(vl & PR_SVE_VL_LEN_MASK)) { 1078c2ecf20Sopenharmony_ci fprintf(stderr, "%s: Invalid vector length %lu\n", 1088c2ecf20Sopenharmony_ci program_name, vl); 1098c2ecf20Sopenharmony_ci return 2; /* same as sh(1) builtin incorrect-usage */ 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (!(getauxval(AT_HWCAP) & HWCAP_SVE)) { 1138c2ecf20Sopenharmony_ci fprintf(stderr, "%s: Scalable Vector Extension not present\n", 1148c2ecf20Sopenharmony_ci program_name); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (!force) 1178c2ecf20Sopenharmony_ci goto error; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci fputs("Going ahead anyway (--force): " 1208c2ecf20Sopenharmony_ci "This is a debug option. Don't rely on it.\n", 1218c2ecf20Sopenharmony_ci stderr); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci flags = PR_SVE_SET_VL_ONEXEC; 1258c2ecf20Sopenharmony_ci if (inherit) 1268c2ecf20Sopenharmony_ci flags |= PR_SVE_VL_INHERIT; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci t = prctl(PR_SVE_SET_VL, vl | flags); 1298c2ecf20Sopenharmony_ci if (t < 0) { 1308c2ecf20Sopenharmony_ci fprintf(stderr, "%s: PR_SVE_SET_VL: %s\n", 1318c2ecf20Sopenharmony_ci program_name, strerror(errno)); 1328c2ecf20Sopenharmony_ci goto error; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci t = prctl(PR_SVE_GET_VL); 1368c2ecf20Sopenharmony_ci if (t == -1) { 1378c2ecf20Sopenharmony_ci fprintf(stderr, "%s: PR_SVE_GET_VL: %s\n", 1388c2ecf20Sopenharmony_ci program_name, strerror(errno)); 1398c2ecf20Sopenharmony_ci goto error; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci flags = PR_SVE_VL_LEN_MASK; 1428c2ecf20Sopenharmony_ci flags = t & ~flags; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci assert(optind < argc); 1458c2ecf20Sopenharmony_ci path = argv[optind]; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci execvp(path, &argv[optind]); 1488c2ecf20Sopenharmony_ci e = errno; 1498c2ecf20Sopenharmony_ci if (errno == ENOENT) 1508c2ecf20Sopenharmony_ci ret = 127; /* same as sh(1) not-found error */ 1518c2ecf20Sopenharmony_ci fprintf(stderr, "%s: %s: %s\n", program_name, path, strerror(e)); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cierror: 1548c2ecf20Sopenharmony_ci return ret; /* same as sh(1) not-executable error */ 1558c2ecf20Sopenharmony_ci} 156