mirror of https://github.com/torvalds/linux.git
Merge branch 'for-next/selftests' into for-next/core
* for-next/selftests: kselftest/arm64: Add lsfe to the hwcaps test kselftest/arm64: Check that unsupported regsets fail in sve-ptrace kselftest/arm64: Verify that we reject out of bounds VLs in sve-ptrace kselftest/arm64/gcs/basic-gcs: Respect parent directory CFLAGS selftests/arm64: Fix grammatical error in string literals kselftest/arm64: Add parentheses around sizeof for clarity kselftest/arm64: Supress warning and improve readability kselftest/arm64: Remove extra blank line kselftest/arm64/gcs: Use nolibc's getauxval() kselftest/arm64/gcs: Correctly check return value when disabling GCS selftests: arm64: Fix -Waddress warning in tpidr2 test kselftest/arm64: Log error codes in sve-ptrace selftests: arm64: Check fread return value in exec_target
This commit is contained in:
commit
712f4ee70a
|
|
@ -17,6 +17,8 @@
|
|||
#include <asm/sigcontext.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#include <linux/auxvec.h>
|
||||
|
||||
#include "../../kselftest.h"
|
||||
|
||||
#define TESTS_PER_HWCAP 3
|
||||
|
|
@ -55,7 +57,6 @@ static void cmpbr_sigill(void)
|
|||
/* Not implemented, too complicated and unreliable anyway */
|
||||
}
|
||||
|
||||
|
||||
static void crc32_sigill(void)
|
||||
{
|
||||
/* CRC32W W0, W0, W1 */
|
||||
|
|
@ -169,6 +170,18 @@ static void lse128_sigill(void)
|
|||
: "cc", "memory");
|
||||
}
|
||||
|
||||
static void lsfe_sigill(void)
|
||||
{
|
||||
float __attribute__ ((aligned (16))) mem;
|
||||
register float *memp asm ("x0") = &mem;
|
||||
|
||||
/* STFADD H0, [X0] */
|
||||
asm volatile(".inst 0x7c20801f"
|
||||
: "+r" (memp)
|
||||
:
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static void lut_sigill(void)
|
||||
{
|
||||
/* LUTI2 V0.16B, { V0.16B }, V[0] */
|
||||
|
|
@ -762,6 +775,13 @@ static const struct hwcap_data {
|
|||
.cpuinfo = "lse128",
|
||||
.sigill_fn = lse128_sigill,
|
||||
},
|
||||
{
|
||||
.name = "LSFE",
|
||||
.at_hwcap = AT_HWCAP3,
|
||||
.hwcap_bit = HWCAP3_LSFE,
|
||||
.cpuinfo = "lsfe",
|
||||
.sigill_fn = lsfe_sigill,
|
||||
},
|
||||
{
|
||||
.name = "LUT",
|
||||
.at_hwcap = AT_HWCAP2,
|
||||
|
|
|
|||
|
|
@ -227,10 +227,10 @@ int main(int argc, char **argv)
|
|||
ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0);
|
||||
if (ret >= 0) {
|
||||
ksft_test_result(default_value(), "default_value\n");
|
||||
ksft_test_result(write_read, "write_read\n");
|
||||
ksft_test_result(write_sleep_read, "write_sleep_read\n");
|
||||
ksft_test_result(write_fork_read, "write_fork_read\n");
|
||||
ksft_test_result(write_clone_read, "write_clone_read\n");
|
||||
ksft_test_result(write_read(), "write_read\n");
|
||||
ksft_test_result(write_sleep_read(), "write_sleep_read\n");
|
||||
ksft_test_result(write_fork_read(), "write_fork_read\n");
|
||||
ksft_test_result(write_clone_read(), "write_clone_read\n");
|
||||
|
||||
} else {
|
||||
ksft_print_msg("SME support not present\n");
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1U << 0)
|
||||
#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1U << 1)
|
||||
|
||||
|
||||
.macro startfn name:req
|
||||
.globl \name
|
||||
\name:
|
||||
|
|
|
|||
|
|
@ -1568,7 +1568,6 @@ static void run_sve_tests(void)
|
|||
&test_config);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void run_sme_tests(void)
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ static void child_start(struct child_data *child, const char *program)
|
|||
/*
|
||||
* Read from the startup pipe, there should be no data
|
||||
* and we should block until it is closed. We just
|
||||
* carry on on error since this isn't super critical.
|
||||
* carry-on on error since this isn't super critical.
|
||||
*/
|
||||
ret = read(3, &i, sizeof(i));
|
||||
if (ret < 0)
|
||||
|
|
@ -549,7 +549,7 @@ int main(int argc, char **argv)
|
|||
|
||||
evs = calloc(tests, sizeof(*evs));
|
||||
if (!evs)
|
||||
ksft_exit_fail_msg("Failed to allocated %d epoll events\n",
|
||||
ksft_exit_fail_msg("Failed to allocate %d epoll events\n",
|
||||
tests);
|
||||
|
||||
for (i = 0; i < cpus; i++) {
|
||||
|
|
|
|||
|
|
@ -188,13 +188,13 @@ static bool create_socket(void)
|
|||
|
||||
ref = malloc(digest_len);
|
||||
if (!ref) {
|
||||
printf("Failed to allocated %d byte reference\n", digest_len);
|
||||
printf("Failed to allocate %d byte reference\n", digest_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
digest = malloc(digest_len);
|
||||
if (!digest) {
|
||||
printf("Failed to allocated %d byte digest\n", digest_len);
|
||||
printf("Failed to allocate %d byte digest\n", digest_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ static const struct vec_type vec_types[] = {
|
|||
};
|
||||
|
||||
#define VL_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 4)
|
||||
#define FLAG_TESTS 2
|
||||
#define FLAG_TESTS 4
|
||||
#define FPSIMD_TESTS 2
|
||||
|
||||
#define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types))
|
||||
|
|
@ -95,19 +95,27 @@ static int do_child(void)
|
|||
static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
|
||||
{
|
||||
struct iovec iov;
|
||||
int ret;
|
||||
|
||||
iov.iov_base = fpsimd;
|
||||
iov.iov_len = sizeof(*fpsimd);
|
||||
return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
|
||||
ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
|
||||
if (ret == -1)
|
||||
ksft_perror("ptrace(PTRACE_GETREGSET)");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
|
||||
{
|
||||
struct iovec iov;
|
||||
int ret;
|
||||
|
||||
iov.iov_base = fpsimd;
|
||||
iov.iov_len = sizeof(*fpsimd);
|
||||
return ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov);
|
||||
ret = ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov);
|
||||
if (ret == -1)
|
||||
ksft_perror("ptrace(PTRACE_SETREGSET)");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
|
||||
|
|
@ -115,8 +123,9 @@ static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
|
|||
{
|
||||
struct user_sve_header *sve;
|
||||
void *p;
|
||||
size_t sz = sizeof *sve;
|
||||
size_t sz = sizeof(*sve);
|
||||
struct iovec iov;
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
if (*size < sz) {
|
||||
|
|
@ -132,8 +141,11 @@ static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
|
|||
|
||||
iov.iov_base = *buf;
|
||||
iov.iov_len = sz;
|
||||
if (ptrace(PTRACE_GETREGSET, pid, type->regset, &iov))
|
||||
ret = ptrace(PTRACE_GETREGSET, pid, type->regset, &iov);
|
||||
if (ret) {
|
||||
ksft_perror("ptrace(PTRACE_GETREGSET)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
sve = *buf;
|
||||
if (sve->size <= sz)
|
||||
|
|
@ -152,10 +164,46 @@ static int set_sve(pid_t pid, const struct vec_type *type,
|
|||
const struct user_sve_header *sve)
|
||||
{
|
||||
struct iovec iov;
|
||||
int ret;
|
||||
|
||||
iov.iov_base = (void *)sve;
|
||||
iov.iov_len = sve->size;
|
||||
return ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);
|
||||
ret = ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);
|
||||
if (ret == -1)
|
||||
ksft_perror("ptrace(PTRACE_SETREGSET)");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* A read operation fails */
|
||||
static void read_fails(pid_t child, const struct vec_type *type)
|
||||
{
|
||||
struct user_sve_header *new_sve = NULL;
|
||||
size_t new_sve_size = 0;
|
||||
void *ret;
|
||||
|
||||
ret = get_sve(child, type, (void **)&new_sve, &new_sve_size);
|
||||
|
||||
ksft_test_result(ret == NULL, "%s unsupported read fails\n",
|
||||
type->name);
|
||||
|
||||
free(new_sve);
|
||||
}
|
||||
|
||||
/* A write operation fails */
|
||||
static void write_fails(pid_t child, const struct vec_type *type)
|
||||
{
|
||||
struct user_sve_header sve;
|
||||
int ret;
|
||||
|
||||
/* Just the header, no data */
|
||||
memset(&sve, 0, sizeof(sve));
|
||||
sve.size = sizeof(sve);
|
||||
sve.flags = SVE_PT_REGS_SVE;
|
||||
sve.vl = SVE_VL_MIN;
|
||||
ret = set_sve(child, type, &sve);
|
||||
|
||||
ksft_test_result(ret != 0, "%s unsupported write fails\n",
|
||||
type->name);
|
||||
}
|
||||
|
||||
/* Validate setting and getting the inherit flag */
|
||||
|
|
@ -270,6 +318,25 @@ static void check_u32(unsigned int vl, const char *reg,
|
|||
}
|
||||
}
|
||||
|
||||
/* Set out of range VLs */
|
||||
static void ptrace_set_vl_ranges(pid_t child, const struct vec_type *type)
|
||||
{
|
||||
struct user_sve_header sve;
|
||||
int ret;
|
||||
|
||||
memset(&sve, 0, sizeof(sve));
|
||||
sve.flags = SVE_PT_REGS_SVE;
|
||||
sve.size = sizeof(sve);
|
||||
|
||||
ret = set_sve(child, type, &sve);
|
||||
ksft_test_result(ret != 0, "%s Set invalid VL 0\n", type->name);
|
||||
|
||||
sve.vl = SVE_VL_MAX + SVE_VQ_BYTES;
|
||||
ret = set_sve(child, type, &sve);
|
||||
ksft_test_result(ret != 0, "%s Set invalid VL %d\n", type->name,
|
||||
SVE_VL_MAX + SVE_VQ_BYTES);
|
||||
}
|
||||
|
||||
/* Access the FPSIMD registers via the SVE regset */
|
||||
static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
|
||||
{
|
||||
|
|
@ -683,6 +750,20 @@ static int do_parent(pid_t child)
|
|||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vec_types); i++) {
|
||||
/*
|
||||
* If the vector type isn't supported reads and writes
|
||||
* should fail.
|
||||
*/
|
||||
if (!(getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap)) {
|
||||
read_fails(child, &vec_types[i]);
|
||||
write_fails(child, &vec_types[i]);
|
||||
} else {
|
||||
ksft_test_result_skip("%s unsupported read fails\n",
|
||||
vec_types[i].name);
|
||||
ksft_test_result_skip("%s unsupported write fails\n",
|
||||
vec_types[i].name);
|
||||
}
|
||||
|
||||
/* FPSIMD via SVE regset */
|
||||
if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
|
||||
ptrace_sve_fpsimd(child, &vec_types[i]);
|
||||
|
|
@ -703,6 +784,17 @@ static int do_parent(pid_t child)
|
|||
vec_types[i].name);
|
||||
}
|
||||
|
||||
/* Setting out of bounds VLs should fail */
|
||||
if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
|
||||
ptrace_set_vl_ranges(child, &vec_types[i]);
|
||||
} else {
|
||||
ksft_test_result_skip("%s Set invalid VL 0\n",
|
||||
vec_types[i].name);
|
||||
ksft_test_result_skip("%s Set invalid VL %d\n",
|
||||
vec_types[i].name,
|
||||
SVE_VL_MAX + SVE_VQ_BYTES);
|
||||
}
|
||||
|
||||
/* Step through every possible VQ */
|
||||
for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
|
||||
vl = sve_vl_from_vq(vq);
|
||||
|
|
|
|||
|
|
@ -690,7 +690,6 @@ static inline void smstop(void)
|
|||
asm volatile("msr S0_3_C4_C6_3, xzr");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Verify we can change the SVE vector length while SME is active and
|
||||
* continue to use SME afterwards.
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ static int get_zt(pid_t pid, char zt[ZT_SIG_REG_BYTES])
|
|||
return ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZT, &iov);
|
||||
}
|
||||
|
||||
|
||||
static int set_zt(pid_t pid, const char zt[ZT_SIG_REG_BYTES])
|
||||
{
|
||||
struct iovec iov;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ LDLIBS+=-lpthread
|
|||
include ../../lib.mk
|
||||
|
||||
$(OUTPUT)/basic-gcs: basic-gcs.c
|
||||
$(CC) -g -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
|
||||
-static -include ../../../../include/nolibc/nolibc.h \
|
||||
$(CC) $(CFLAGS) -fno-asynchronous-unwind-tables -fno-ident -s -nostdlib -nostdinc \
|
||||
-static -I../../../../include/nolibc -include ../../../../include/nolibc/nolibc.h \
|
||||
-I../../../../../usr/include \
|
||||
-std=gnu99 -I../.. -g \
|
||||
-ffreestanding -Wall $^ -o $@ -lgcc
|
||||
-ffreestanding $^ -o $@ -lgcc
|
||||
|
||||
$(OUTPUT)/gcs-stress-thread: gcs-stress-thread.S
|
||||
$(CC) -nostdlib $^ -o $@
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <sys/mman.h>
|
||||
#include <asm/mman.h>
|
||||
#include <asm/hwcap.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "kselftest.h"
|
||||
|
|
@ -386,14 +387,13 @@ int main(void)
|
|||
|
||||
ksft_print_header();
|
||||
|
||||
/*
|
||||
* We don't have getauxval() with nolibc so treat a failure to
|
||||
* read GCS state as a lack of support and skip.
|
||||
*/
|
||||
if (!(getauxval(AT_HWCAP) & HWCAP_GCS))
|
||||
ksft_exit_skip("SKIP GCS not supported\n");
|
||||
|
||||
ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
|
||||
&gcs_mode, 0, 0, 0);
|
||||
if (ret != 0)
|
||||
ksft_exit_skip("Failed to read GCS state: %d\n", ret);
|
||||
ksft_exit_fail_msg("Failed to read GCS state: %d\n", ret);
|
||||
|
||||
if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) {
|
||||
gcs_mode = PR_SHADOW_STACK_ENABLE;
|
||||
|
|
@ -410,7 +410,7 @@ int main(void)
|
|||
}
|
||||
|
||||
/* One last test: disable GCS, we can do this one time */
|
||||
my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0, 0, 0, 0);
|
||||
ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0, 0, 0, 0);
|
||||
if (ret != 0)
|
||||
ksft_print_msg("Failed to disable GCS: %d\n", ret);
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,6 @@ TEST_F(valid_modes, lock_enable_disable_others)
|
|||
ASSERT_EQ(ret, 0);
|
||||
ASSERT_EQ(mode, PR_SHADOW_STACK_ALL_MODES);
|
||||
|
||||
|
||||
ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
|
||||
variant->mode);
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ int main(int argc, char **argv)
|
|||
|
||||
evs = calloc(tests, sizeof(*evs));
|
||||
if (!evs)
|
||||
ksft_exit_fail_msg("Failed to allocated %d epoll events\n",
|
||||
ksft_exit_fail_msg("Failed to allocate %d epoll events\n",
|
||||
tests);
|
||||
|
||||
for (i = 0; i < gcs_threads; i++)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,12 @@ int main(void)
|
|||
unsigned long hwcaps;
|
||||
size_t val;
|
||||
|
||||
fread(&val, sizeof(size_t), 1, stdin);
|
||||
size_t size = fread(&val, sizeof(size_t), 1, stdin);
|
||||
|
||||
if (size != 1) {
|
||||
fprintf(stderr, "Could not read input from stdin\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* don't try to execute illegal (unimplemented) instructions) caller
|
||||
* should have checked this and keep worker simple
|
||||
|
|
|
|||
Loading…
Reference in New Issue