cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vec-syscfg.c (15711B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2021 ARM Limited.
      4 * Original author: Mark Brown <broonie@kernel.org>
      5 */
      6#include <assert.h>
      7#include <errno.h>
      8#include <fcntl.h>
      9#include <stddef.h>
     10#include <stdio.h>
     11#include <stdlib.h>
     12#include <string.h>
     13#include <unistd.h>
     14#include <sys/auxv.h>
     15#include <sys/prctl.h>
     16#include <sys/types.h>
     17#include <sys/wait.h>
     18#include <asm/sigcontext.h>
     19#include <asm/hwcap.h>
     20
     21#include "../../kselftest.h"
     22#include "rdvl.h"
     23
     24#define ARCH_MIN_VL SVE_VL_MIN
     25
     26struct vec_data {
     27	const char *name;
     28	unsigned long hwcap_type;
     29	unsigned long hwcap;
     30	const char *rdvl_binary;
     31	int (*rdvl)(void);
     32
     33	int prctl_get;
     34	int prctl_set;
     35	const char *default_vl_file;
     36
     37	int default_vl;
     38	int min_vl;
     39	int max_vl;
     40};
     41
     42
     43static struct vec_data vec_data[] = {
     44	{
     45		.name = "SVE",
     46		.hwcap_type = AT_HWCAP,
     47		.hwcap = HWCAP_SVE,
     48		.rdvl = rdvl_sve,
     49		.rdvl_binary = "./rdvl-sve",
     50		.prctl_get = PR_SVE_GET_VL,
     51		.prctl_set = PR_SVE_SET_VL,
     52		.default_vl_file = "/proc/sys/abi/sve_default_vector_length",
     53	},
     54	{
     55		.name = "SME",
     56		.hwcap_type = AT_HWCAP2,
     57		.hwcap = HWCAP2_SME,
     58		.rdvl = rdvl_sme,
     59		.rdvl_binary = "./rdvl-sme",
     60		.prctl_get = PR_SME_GET_VL,
     61		.prctl_set = PR_SME_SET_VL,
     62		.default_vl_file = "/proc/sys/abi/sme_default_vector_length",
     63	},
     64};
     65
     66static int stdio_read_integer(FILE *f, const char *what, int *val)
     67{
     68	int n = 0;
     69	int ret;
     70
     71	ret = fscanf(f, "%d%*1[\n]%n", val, &n);
     72	if (ret < 1 || n < 1) {
     73		ksft_print_msg("failed to parse integer from %s\n", what);
     74		return -1;
     75	}
     76
     77	return 0;
     78}
     79
     80/* Start a new process and return the vector length it sees */
     81static int get_child_rdvl(struct vec_data *data)
     82{
     83	FILE *out;
     84	int pipefd[2];
     85	pid_t pid, child;
     86	int read_vl, ret;
     87
     88	ret = pipe(pipefd);
     89	if (ret == -1) {
     90		ksft_print_msg("pipe() failed: %d (%s)\n",
     91			       errno, strerror(errno));
     92		return -1;
     93	}
     94
     95	fflush(stdout);
     96
     97	child = fork();
     98	if (child == -1) {
     99		ksft_print_msg("fork() failed: %d (%s)\n",
    100			       errno, strerror(errno));
    101		close(pipefd[0]);
    102		close(pipefd[1]);
    103		return -1;
    104	}
    105
    106	/* Child: put vector length on the pipe */
    107	if (child == 0) {
    108		/*
    109		 * Replace stdout with the pipe, errors to stderr from
    110		 * here as kselftest prints to stdout.
    111		 */
    112		ret = dup2(pipefd[1], 1);
    113		if (ret == -1) {
    114			fprintf(stderr, "dup2() %d\n", errno);
    115			exit(EXIT_FAILURE);
    116		}
    117
    118		/* exec() a new binary which puts the VL on stdout */
    119		ret = execl(data->rdvl_binary, data->rdvl_binary, NULL);
    120		fprintf(stderr, "execl(%s) failed: %d (%s)\n",
    121			data->rdvl_binary, errno, strerror(errno));
    122
    123		exit(EXIT_FAILURE);
    124	}
    125
    126	close(pipefd[1]);
    127
    128	/* Parent; wait for the exit status from the child & verify it */
    129	do {
    130		pid = wait(&ret);
    131		if (pid == -1) {
    132			ksft_print_msg("wait() failed: %d (%s)\n",
    133				       errno, strerror(errno));
    134			close(pipefd[0]);
    135			return -1;
    136		}
    137	} while (pid != child);
    138
    139	assert(pid == child);
    140
    141	if (!WIFEXITED(ret)) {
    142		ksft_print_msg("child exited abnormally\n");
    143		close(pipefd[0]);
    144		return -1;
    145	}
    146
    147	if (WEXITSTATUS(ret) != 0) {
    148		ksft_print_msg("child returned error %d\n",
    149			       WEXITSTATUS(ret));
    150		close(pipefd[0]);
    151		return -1;
    152	}
    153
    154	out = fdopen(pipefd[0], "r");
    155	if (!out) {
    156		ksft_print_msg("failed to open child stdout\n");
    157		close(pipefd[0]);
    158		return -1;
    159	}
    160
    161	ret = stdio_read_integer(out, "child", &read_vl);
    162	fclose(out);
    163	if (ret != 0)
    164		return ret;
    165
    166	return read_vl;
    167}
    168
    169static int file_read_integer(const char *name, int *val)
    170{
    171	FILE *f;
    172	int ret;
    173
    174	f = fopen(name, "r");
    175	if (!f) {
    176		ksft_test_result_fail("Unable to open %s: %d (%s)\n",
    177				      name, errno,
    178				      strerror(errno));
    179		return -1;
    180	}
    181
    182	ret = stdio_read_integer(f, name, val);
    183	fclose(f);
    184
    185	return ret;
    186}
    187
    188static int file_write_integer(const char *name, int val)
    189{
    190	FILE *f;
    191
    192	f = fopen(name, "w");
    193	if (!f) {
    194		ksft_test_result_fail("Unable to open %s: %d (%s)\n",
    195				      name, errno,
    196				      strerror(errno));
    197		return -1;
    198	}
    199
    200	fprintf(f, "%d", val);
    201	fclose(f);
    202
    203	return 0;
    204}
    205
    206/*
    207 * Verify that we can read the default VL via proc, checking that it
    208 * is set in a freshly spawned child.
    209 */
    210static void proc_read_default(struct vec_data *data)
    211{
    212	int default_vl, child_vl, ret;
    213
    214	ret = file_read_integer(data->default_vl_file, &default_vl);
    215	if (ret != 0)
    216		return;
    217
    218	/* Is this the actual default seen by new processes? */
    219	child_vl = get_child_rdvl(data);
    220	if (child_vl != default_vl) {
    221		ksft_test_result_fail("%s is %d but child VL is %d\n",
    222				      data->default_vl_file,
    223				      default_vl, child_vl);
    224		return;
    225	}
    226
    227	ksft_test_result_pass("%s default vector length %d\n", data->name,
    228			      default_vl);
    229	data->default_vl = default_vl;
    230}
    231
    232/* Verify that we can write a minimum value and have it take effect */
    233static void proc_write_min(struct vec_data *data)
    234{
    235	int ret, new_default, child_vl;
    236
    237	if (geteuid() != 0) {
    238		ksft_test_result_skip("Need to be root to write to /proc\n");
    239		return;
    240	}
    241
    242	ret = file_write_integer(data->default_vl_file, ARCH_MIN_VL);
    243	if (ret != 0)
    244		return;
    245
    246	/* What was the new value? */
    247	ret = file_read_integer(data->default_vl_file, &new_default);
    248	if (ret != 0)
    249		return;
    250
    251	/* Did it take effect in a new process? */
    252	child_vl = get_child_rdvl(data);
    253	if (child_vl != new_default) {
    254		ksft_test_result_fail("%s is %d but child VL is %d\n",
    255				      data->default_vl_file,
    256				      new_default, child_vl);
    257		return;
    258	}
    259
    260	ksft_test_result_pass("%s minimum vector length %d\n", data->name,
    261			      new_default);
    262	data->min_vl = new_default;
    263
    264	file_write_integer(data->default_vl_file, data->default_vl);
    265}
    266
    267/* Verify that we can write a maximum value and have it take effect */
    268static void proc_write_max(struct vec_data *data)
    269{
    270	int ret, new_default, child_vl;
    271
    272	if (geteuid() != 0) {
    273		ksft_test_result_skip("Need to be root to write to /proc\n");
    274		return;
    275	}
    276
    277	/* -1 is accepted by the /proc interface as the maximum VL */
    278	ret = file_write_integer(data->default_vl_file, -1);
    279	if (ret != 0)
    280		return;
    281
    282	/* What was the new value? */
    283	ret = file_read_integer(data->default_vl_file, &new_default);
    284	if (ret != 0)
    285		return;
    286
    287	/* Did it take effect in a new process? */
    288	child_vl = get_child_rdvl(data);
    289	if (child_vl != new_default) {
    290		ksft_test_result_fail("%s is %d but child VL is %d\n",
    291				      data->default_vl_file,
    292				      new_default, child_vl);
    293		return;
    294	}
    295
    296	ksft_test_result_pass("%s maximum vector length %d\n", data->name,
    297			      new_default);
    298	data->max_vl = new_default;
    299
    300	file_write_integer(data->default_vl_file, data->default_vl);
    301}
    302
    303/* Can we read back a VL from prctl? */
    304static void prctl_get(struct vec_data *data)
    305{
    306	int ret;
    307
    308	ret = prctl(data->prctl_get);
    309	if (ret == -1) {
    310		ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
    311				      data->name, errno, strerror(errno));
    312		return;
    313	}
    314
    315	/* Mask out any flags */
    316	ret &= PR_SVE_VL_LEN_MASK;
    317
    318	/* Is that what we can read back directly? */
    319	if (ret == data->rdvl())
    320		ksft_test_result_pass("%s current VL is %d\n",
    321				      data->name, ret);
    322	else
    323		ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n",
    324				      data->name, ret, data->rdvl());
    325}
    326
    327/* Does the prctl let us set the VL we already have? */
    328static void prctl_set_same(struct vec_data *data)
    329{
    330	int cur_vl = data->rdvl();
    331	int ret;
    332
    333	ret = prctl(data->prctl_set, cur_vl);
    334	if (ret < 0) {
    335		ksft_test_result_fail("%s prctl set failed: %d (%s)\n",
    336				      data->name, errno, strerror(errno));
    337		return;
    338	}
    339
    340	ksft_test_result(cur_vl == data->rdvl(),
    341			 "%s set VL %d and have VL %d\n",
    342			 data->name, cur_vl, data->rdvl());
    343}
    344
    345/* Can we set a new VL for this process? */
    346static void prctl_set(struct vec_data *data)
    347{
    348	int ret;
    349
    350	if (data->min_vl == data->max_vl) {
    351		ksft_test_result_skip("%s only one VL supported\n",
    352				      data->name);
    353		return;
    354	}
    355
    356	/* Try to set the minimum VL */
    357	ret = prctl(data->prctl_set, data->min_vl);
    358	if (ret < 0) {
    359		ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
    360				      data->name, data->min_vl,
    361				      errno, strerror(errno));
    362		return;
    363	}
    364
    365	if ((ret & PR_SVE_VL_LEN_MASK) != data->min_vl) {
    366		ksft_test_result_fail("%s prctl set %d but return value is %d\n",
    367				      data->name, data->min_vl, data->rdvl());
    368		return;
    369	}
    370
    371	if (data->rdvl() != data->min_vl) {
    372		ksft_test_result_fail("%s set %d but RDVL is %d\n",
    373				      data->name, data->min_vl, data->rdvl());
    374		return;
    375	}
    376
    377	/* Try to set the maximum VL */
    378	ret = prctl(data->prctl_set, data->max_vl);
    379	if (ret < 0) {
    380		ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
    381				      data->name, data->max_vl,
    382				      errno, strerror(errno));
    383		return;
    384	}
    385
    386	if ((ret & PR_SVE_VL_LEN_MASK) != data->max_vl) {
    387		ksft_test_result_fail("%s prctl() set %d but return value is %d\n",
    388				      data->name, data->max_vl, data->rdvl());
    389		return;
    390	}
    391
    392	/* The _INHERIT flag should not be present when we read the VL */
    393	ret = prctl(data->prctl_get);
    394	if (ret == -1) {
    395		ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
    396				      data->name, errno, strerror(errno));
    397		return;
    398	}
    399
    400	if (ret & PR_SVE_VL_INHERIT) {
    401		ksft_test_result_fail("%s prctl() reports _INHERIT\n",
    402				      data->name);
    403		return;
    404	}
    405
    406	ksft_test_result_pass("%s prctl() set min/max\n", data->name);
    407}
    408
    409/* If we didn't request it a new VL shouldn't affect the child */
    410static void prctl_set_no_child(struct vec_data *data)
    411{
    412	int ret, child_vl;
    413
    414	if (data->min_vl == data->max_vl) {
    415		ksft_test_result_skip("%s only one VL supported\n",
    416				      data->name);
    417		return;
    418	}
    419
    420	ret = prctl(data->prctl_set, data->min_vl);
    421	if (ret < 0) {
    422		ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
    423				      data->name, data->min_vl,
    424				      errno, strerror(errno));
    425		return;
    426	}
    427
    428	/* Ensure the default VL is different */
    429	ret = file_write_integer(data->default_vl_file, data->max_vl);
    430	if (ret != 0)
    431		return;
    432
    433	/* Check that the child has the default we just set */
    434	child_vl = get_child_rdvl(data);
    435	if (child_vl != data->max_vl) {
    436		ksft_test_result_fail("%s is %d but child VL is %d\n",
    437				      data->default_vl_file,
    438				      data->max_vl, child_vl);
    439		return;
    440	}
    441
    442	ksft_test_result_pass("%s vector length used default\n", data->name);
    443
    444	file_write_integer(data->default_vl_file, data->default_vl);
    445}
    446
    447/* If we didn't request it a new VL shouldn't affect the child */
    448static void prctl_set_for_child(struct vec_data *data)
    449{
    450	int ret, child_vl;
    451
    452	if (data->min_vl == data->max_vl) {
    453		ksft_test_result_skip("%s only one VL supported\n",
    454				      data->name);
    455		return;
    456	}
    457
    458	ret = prctl(data->prctl_set, data->min_vl | PR_SVE_VL_INHERIT);
    459	if (ret < 0) {
    460		ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
    461				      data->name, data->min_vl,
    462				      errno, strerror(errno));
    463		return;
    464	}
    465
    466	/* The _INHERIT flag should be present when we read the VL */
    467	ret = prctl(data->prctl_get);
    468	if (ret == -1) {
    469		ksft_test_result_fail("%s prctl() read failed: %d (%s)\n",
    470				      data->name, errno, strerror(errno));
    471		return;
    472	}
    473	if (!(ret & PR_SVE_VL_INHERIT)) {
    474		ksft_test_result_fail("%s prctl() does not report _INHERIT\n",
    475				      data->name);
    476		return;
    477	}
    478
    479	/* Ensure the default VL is different */
    480	ret = file_write_integer(data->default_vl_file, data->max_vl);
    481	if (ret != 0)
    482		return;
    483
    484	/* Check that the child inherited our VL */
    485	child_vl = get_child_rdvl(data);
    486	if (child_vl != data->min_vl) {
    487		ksft_test_result_fail("%s is %d but child VL is %d\n",
    488				      data->default_vl_file,
    489				      data->min_vl, child_vl);
    490		return;
    491	}
    492
    493	ksft_test_result_pass("%s vector length was inherited\n", data->name);
    494
    495	file_write_integer(data->default_vl_file, data->default_vl);
    496}
    497
    498/* _ONEXEC takes effect only in the child process */
    499static void prctl_set_onexec(struct vec_data *data)
    500{
    501	int ret, child_vl;
    502
    503	if (data->min_vl == data->max_vl) {
    504		ksft_test_result_skip("%s only one VL supported\n",
    505				      data->name);
    506		return;
    507	}
    508
    509	/* Set a known value for the default and our current VL */
    510	ret = file_write_integer(data->default_vl_file, data->max_vl);
    511	if (ret != 0)
    512		return;
    513
    514	ret = prctl(data->prctl_set, data->max_vl);
    515	if (ret < 0) {
    516		ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
    517				      data->name, data->min_vl,
    518				      errno, strerror(errno));
    519		return;
    520	}
    521
    522	/* Set a different value for the child to have on exec */
    523	ret = prctl(data->prctl_set, data->min_vl | PR_SVE_SET_VL_ONEXEC);
    524	if (ret < 0) {
    525		ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n",
    526				      data->name, data->min_vl,
    527				      errno, strerror(errno));
    528		return;
    529	}
    530
    531	/* Our current VL should stay the same */
    532	if (data->rdvl() != data->max_vl) {
    533		ksft_test_result_fail("%s VL changed by _ONEXEC prctl()\n",
    534				      data->name);
    535		return;
    536	}
    537
    538	/* Check that the child inherited our VL */
    539	child_vl = get_child_rdvl(data);
    540	if (child_vl != data->min_vl) {
    541		ksft_test_result_fail("Set %d _ONEXEC but child VL is %d\n",
    542				      data->min_vl, child_vl);
    543		return;
    544	}
    545
    546	ksft_test_result_pass("%s vector length set on exec\n", data->name);
    547
    548	file_write_integer(data->default_vl_file, data->default_vl);
    549}
    550
    551/* For each VQ verify that setting via prctl() does the right thing */
    552static void prctl_set_all_vqs(struct vec_data *data)
    553{
    554	int ret, vq, vl, new_vl;
    555	int errors = 0;
    556
    557	if (!data->min_vl || !data->max_vl) {
    558		ksft_test_result_skip("%s Failed to enumerate VLs, not testing VL setting\n",
    559				      data->name);
    560		return;
    561	}
    562
    563	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
    564		vl = sve_vl_from_vq(vq);
    565
    566		/* Attempt to set the VL */
    567		ret = prctl(data->prctl_set, vl);
    568		if (ret < 0) {
    569			errors++;
    570			ksft_print_msg("%s prctl set failed for %d: %d (%s)\n",
    571				       data->name, vl,
    572				       errno, strerror(errno));
    573			continue;
    574		}
    575
    576		new_vl = ret & PR_SVE_VL_LEN_MASK;
    577
    578		/* Check that we actually have the reported new VL */
    579		if (data->rdvl() != new_vl) {
    580			ksft_print_msg("Set %s VL %d but RDVL reports %d\n",
    581				       data->name, new_vl, data->rdvl());
    582			errors++;
    583		}
    584
    585		/* Was that the VL we asked for? */
    586		if (new_vl == vl)
    587			continue;
    588
    589		/* Should round up to the minimum VL if below it */
    590		if (vl < data->min_vl) {
    591			if (new_vl != data->min_vl) {
    592				ksft_print_msg("%s VL %d returned %d not minimum %d\n",
    593					       data->name, vl, new_vl,
    594					       data->min_vl);
    595				errors++;
    596			}
    597
    598			continue;
    599		}
    600
    601		/* Should round down to maximum VL if above it */
    602		if (vl > data->max_vl) {
    603			if (new_vl != data->max_vl) {
    604				ksft_print_msg("%s VL %d returned %d not maximum %d\n",
    605					       data->name, vl, new_vl,
    606					       data->max_vl);
    607				errors++;
    608			}
    609
    610			continue;
    611		}
    612
    613		/* Otherwise we should've rounded down */
    614		if (!(new_vl < vl)) {
    615			ksft_print_msg("%s VL %d returned %d, did not round down\n",
    616				       data->name, vl, new_vl);
    617			errors++;
    618
    619			continue;
    620		}
    621	}
    622
    623	ksft_test_result(errors == 0, "%s prctl() set all VLs, %d errors\n",
    624			 data->name, errors);
    625}
    626
    627typedef void (*test_type)(struct vec_data *);
    628
    629static const test_type tests[] = {
    630	/*
    631	 * The default/min/max tests must be first and in this order
    632	 * to provide data for other tests.
    633	 */
    634	proc_read_default,
    635	proc_write_min,
    636	proc_write_max,
    637
    638	prctl_get,
    639	prctl_set_same,
    640	prctl_set,
    641	prctl_set_no_child,
    642	prctl_set_for_child,
    643	prctl_set_onexec,
    644	prctl_set_all_vqs,
    645};
    646
    647int main(void)
    648{
    649	int i, j;
    650
    651	ksft_print_header();
    652	ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data));
    653
    654	for (i = 0; i < ARRAY_SIZE(vec_data); i++) {
    655		struct vec_data *data = &vec_data[i];
    656		unsigned long supported;
    657
    658		supported = getauxval(data->hwcap_type) & data->hwcap;
    659
    660		for (j = 0; j < ARRAY_SIZE(tests); j++) {
    661			if (supported)
    662				tests[j](data);
    663			else
    664				ksft_test_result_skip("%s not supported\n",
    665						      data->name);
    666		}
    667	}
    668
    669	ksft_exit_pass();
    670}