/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */ #ifndef NT_ARM_ZA #define NT_ARM_ZA 0x40c #endif
/* * The architecture defines the maximum VQ as 16 but for extensibility * the kernel specifies the SVE_VQ_MAX as 512 resulting in us running * a *lot* more tests than are useful if we use it. Until the * architecture is extended let's limit our coverage to what is * currently allowed, plus one extra to ensure we cover constraining * the VL as expected.
*/ #define TEST_VQ_MAX 17
/* Validate attempting to set the specfied VL via ptrace */ staticvoid ptrace_set_get_vl(pid_t child, unsignedint vl, bool *supported)
{ struct user_za_header za; struct user_za_header *new_za = NULL;
size_t new_za_size = 0; int ret, prctl_vl;
*supported = false;
/* Check if the VL is supported in this process */
prctl_vl = prctl(PR_SME_SET_VL, vl); if (prctl_vl == -1)
ksft_exit_fail_msg("prctl(PR_SME_SET_VL) failed: %s (%d)\n",
strerror(errno), errno);
/* If the VL is not supported then a supported VL will be returned */
*supported = (prctl_vl == vl);
/* Set the VL by doing a set with no register payload */
memset(&za, 0, sizeof(za));
za.size = sizeof(za);
za.vl = vl;
ret = set_za(child, &za); if (ret != 0) {
ksft_test_result_fail("Failed to set VL %u\n", vl); return;
}
/* * Read back the new register state and verify that we have the * same VL that we got from prctl() on ourselves.
*/ if (!get_za(child, (void **)&new_za, &new_za_size)) {
ksft_test_result_fail("Failed to read VL %u\n", vl); return;
}
/* Validate attempting to set no ZA data and read it back */ staticvoid ptrace_set_no_data(pid_t child, unsignedint vl)
{ void *read_buf = NULL; struct user_za_header write_za; struct user_za_header *read_za;
size_t read_za_size = 0; int ret;
/* Set up some data and write it out */
memset(&write_za, 0, sizeof(write_za));
write_za.size = ZA_PT_ZA_OFFSET;
write_za.vl = vl;
ret = set_za(child, &write_za); if (ret != 0) {
ksft_test_result_fail("Failed to set VL %u no data\n", vl); return;
}
/* Read the data back */ if (!get_za(child, (void **)&read_buf, &read_za_size)) {
ksft_test_result_fail("Failed to read VL %u no data\n", vl); return;
}
read_za = read_buf;
/* We might read more data if there's extensions we don't know */ if (read_za->size < write_za.size) {
ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
vl, write_za.size, read_za->size); goto out_read;
}
ksft_test_result(read_za->size == write_za.size, "Disabled ZA for VL %u\n", vl);
out_read:
free(read_buf);
}
/* Validate attempting to set data and read it back */ staticvoid ptrace_set_get_data(pid_t child, unsignedint vl)
{ void *write_buf; void *read_buf = NULL; struct user_za_header *write_za; struct user_za_header *read_za;
size_t read_za_size = 0; unsignedint vq = sve_vq_from_vl(vl); int ret;
size_t data_size;
ret = set_za(child, write_za); if (ret != 0) {
ksft_test_result_fail("Failed to set VL %u data\n", vl); goto out;
}
/* Read the data back */ if (!get_za(child, (void **)&read_buf, &read_za_size)) {
ksft_test_result_fail("Failed to read VL %u data\n", vl); goto out;
}
read_za = read_buf;
/* We might read more data if there's extensions we don't know */ if (read_za->size < write_za->size) {
ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
vl, write_za->size, read_za->size); goto out_read;
}
ksft_test_result(memcmp(write_buf + ZA_PT_ZA_OFFSET,
read_buf + ZA_PT_ZA_OFFSET,
ZA_PT_ZA_SIZE(vq)) == 0, "Data match for VL %u\n", vl);
out_read:
free(read_buf);
out:
free(write_buf);
}
staticint do_parent(pid_t child)
{ int ret = EXIT_FAILURE;
pid_t pid; int status;
siginfo_t si; unsignedint vq, vl; bool vl_supported;
ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
/* Step through every possible VQ */ for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
vl = sve_vl_from_vq(vq);
/* First, try to set this vector length */
ptrace_set_get_vl(child, vl, &vl_supported);
/* If the VL is supported validate data set/get */ if (vl_supported) {
ptrace_set_no_data(child, vl);
ptrace_set_get_data(child, vl);
} else {
ksft_test_result_skip("Disabled ZA for VL %u\n", vl);
ksft_test_result_skip("Get and set data for VL %u\n",
vl);
}
}
ret = EXIT_SUCCESS;
error:
kill(child, SIGKILL);
disappeared: return ret;
}
int main(void)
{ int ret = EXIT_SUCCESS;
pid_t child;
srandom(getpid());
ksft_print_header();
if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
ksft_set_plan(1);
ksft_exit_skip("SME not available\n");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.