Commit 32b48248 authored by Will Deacon's avatar Will Deacon

Merge branch 'for-next/selftests' into for-next/core

* for-next/selftests:
  kselftest/arm64: Allow epoll_wait() to return more than one result
  kselftest/arm64: Don't drain output while spawning children
  kselftest/arm64: Hold fp-stress children until they're all spawned
  kselftest/arm64: Set test names prior to starting children
  kselftest/arm64: Use preferred form for predicate load/stores
  kselftest/arm64: fix array_size.cocci warning
  kselftest/arm64: fix array_size.cocci warning
  kselftest/arm64: Print ASCII version of unknown signal frame magic values
  kselftest/arm64: Remove validation of extra_context from TODO
  kselftest/arm64: Provide progress messages when signalling children
  kselftest/arm64: Check that all children are producing output in fp-stress
parents 10162e78 c4e8720f
...@@ -153,7 +153,7 @@ do_syscall: ...@@ -153,7 +153,7 @@ do_syscall:
// Only set a non-zero FFR, test patterns must be zero since the // Only set a non-zero FFR, test patterns must be zero since the
// syscall should clear it - this lets us handle FA64. // syscall should clear it - this lets us handle FA64.
ldr x2, =ffr_in ldr x2, =ffr_in
ldr p0, [x2, #0] ldr p0, [x2]
ldr x2, [x2, #0] ldr x2, [x2, #0]
cbz x2, 2f cbz x2, 2f
wrffr p0.b wrffr p0.b
...@@ -298,7 +298,7 @@ do_syscall: ...@@ -298,7 +298,7 @@ do_syscall:
cbz x2, 1f cbz x2, 1f
ldr x2, =ffr_out ldr x2, =ffr_out
rdffr p0.b rdffr p0.b
str p0, [x2, #0] str p0, [x2]
1: 1:
// Restore callee saved registers x19-x30 // Restore callee saved registers x19-x30
......
...@@ -39,10 +39,12 @@ struct child_data { ...@@ -39,10 +39,12 @@ struct child_data {
static int epoll_fd; static int epoll_fd;
static struct child_data *children; static struct child_data *children;
static struct epoll_event *evs;
static int tests;
static int num_children; static int num_children;
static bool terminate; static bool terminate;
static void drain_output(bool flush); static int startup_pipe[2];
static int num_processors(void) static int num_processors(void)
{ {
...@@ -81,13 +83,37 @@ static void child_start(struct child_data *child, const char *program) ...@@ -81,13 +83,37 @@ static void child_start(struct child_data *child, const char *program)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/*
* Duplicate the read side of the startup pipe to
* FD 3 so we can close everything else.
*/
ret = dup2(startup_pipe[0], 3);
if (ret == -1) {
fprintf(stderr, "dup2() %d\n", errno);
exit(EXIT_FAILURE);
}
/* /*
* Very dumb mechanism to clean open FDs other than * Very dumb mechanism to clean open FDs other than
* stdio. We don't want O_CLOEXEC for the pipes... * stdio. We don't want O_CLOEXEC for the pipes...
*/ */
for (i = 3; i < 8192; i++) for (i = 4; i < 8192; i++)
close(i); close(i);
/*
* 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.
*/
ret = read(3, &i, sizeof(i));
if (ret < 0)
fprintf(stderr, "read(startp pipe) failed: %s (%d)\n",
strerror(errno), errno);
if (ret > 0)
fprintf(stderr, "%d bytes of data on startup pipe\n",
ret);
close(3);
ret = execl(program, program, NULL); ret = execl(program, program, NULL);
fprintf(stderr, "execl(%s) failed: %d (%s)\n", fprintf(stderr, "execl(%s) failed: %d (%s)\n",
program, errno, strerror(errno)); program, errno, strerror(errno));
...@@ -112,12 +138,6 @@ static void child_start(struct child_data *child, const char *program) ...@@ -112,12 +138,6 @@ static void child_start(struct child_data *child, const char *program)
ksft_exit_fail_msg("%s EPOLL_CTL_ADD failed: %s (%d)\n", ksft_exit_fail_msg("%s EPOLL_CTL_ADD failed: %s (%d)\n",
child->name, strerror(errno), errno); child->name, strerror(errno), errno);
} }
/*
* Keep output flowing during child startup so logs
* are more timely, can help debugging.
*/
drain_output(false);
} }
} }
...@@ -290,12 +310,12 @@ static void start_fpsimd(struct child_data *child, int cpu, int copy) ...@@ -290,12 +310,12 @@ static void start_fpsimd(struct child_data *child, int cpu, int copy)
{ {
int ret; int ret;
child_start(child, "./fpsimd-test");
ret = asprintf(&child->name, "FPSIMD-%d-%d", cpu, copy); ret = asprintf(&child->name, "FPSIMD-%d-%d", cpu, copy);
if (ret == -1) if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n"); ksft_exit_fail_msg("asprintf() failed\n");
child_start(child, "./fpsimd-test");
ksft_print_msg("Started %s\n", child->name); ksft_print_msg("Started %s\n", child->name);
} }
...@@ -307,12 +327,12 @@ static void start_sve(struct child_data *child, int vl, int cpu) ...@@ -307,12 +327,12 @@ static void start_sve(struct child_data *child, int vl, int cpu)
if (ret < 0) if (ret < 0)
ksft_exit_fail_msg("Failed to set SVE VL %d\n", vl); ksft_exit_fail_msg("Failed to set SVE VL %d\n", vl);
child_start(child, "./sve-test");
ret = asprintf(&child->name, "SVE-VL-%d-%d", vl, cpu); ret = asprintf(&child->name, "SVE-VL-%d-%d", vl, cpu);
if (ret == -1) if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n"); ksft_exit_fail_msg("asprintf() failed\n");
child_start(child, "./sve-test");
ksft_print_msg("Started %s\n", child->name); ksft_print_msg("Started %s\n", child->name);
} }
...@@ -320,16 +340,16 @@ static void start_ssve(struct child_data *child, int vl, int cpu) ...@@ -320,16 +340,16 @@ static void start_ssve(struct child_data *child, int vl, int cpu)
{ {
int ret; int ret;
ret = asprintf(&child->name, "SSVE-VL-%d-%d", vl, cpu);
if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
ret = prctl(PR_SME_SET_VL, vl | PR_SME_VL_INHERIT); ret = prctl(PR_SME_SET_VL, vl | PR_SME_VL_INHERIT);
if (ret < 0) if (ret < 0)
ksft_exit_fail_msg("Failed to set SME VL %d\n", ret); ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
child_start(child, "./ssve-test"); child_start(child, "./ssve-test");
ret = asprintf(&child->name, "SSVE-VL-%d-%d", vl, cpu);
if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
ksft_print_msg("Started %s\n", child->name); ksft_print_msg("Started %s\n", child->name);
} }
...@@ -341,12 +361,12 @@ static void start_za(struct child_data *child, int vl, int cpu) ...@@ -341,12 +361,12 @@ static void start_za(struct child_data *child, int vl, int cpu)
if (ret < 0) if (ret < 0)
ksft_exit_fail_msg("Failed to set SME VL %d\n", ret); ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
child_start(child, "./za-test");
ret = asprintf(&child->name, "ZA-VL-%d-%d", vl, cpu); ret = asprintf(&child->name, "ZA-VL-%d-%d", vl, cpu);
if (ret == -1) if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n"); ksft_exit_fail_msg("asprintf() failed\n");
child_start(child, "./za-test");
ksft_print_msg("Started %s\n", child->name); ksft_print_msg("Started %s\n", child->name);
} }
...@@ -375,11 +395,11 @@ static void probe_vls(int vls[], int *vl_count, int set_vl) ...@@ -375,11 +395,11 @@ static void probe_vls(int vls[], int *vl_count, int set_vl)
/* Handle any pending output without blocking */ /* Handle any pending output without blocking */
static void drain_output(bool flush) static void drain_output(bool flush)
{ {
struct epoll_event ev;
int ret = 1; int ret = 1;
int i;
while (ret > 0) { while (ret > 0) {
ret = epoll_wait(epoll_fd, &ev, 1, 0); ret = epoll_wait(epoll_fd, evs, tests, 0);
if (ret < 0) { if (ret < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
...@@ -387,8 +407,8 @@ static void drain_output(bool flush) ...@@ -387,8 +407,8 @@ static void drain_output(bool flush)
strerror(errno), errno); strerror(errno), errno);
} }
if (ret == 1) for (i = 0; i < ret; i++)
child_output(ev.data.ptr, ev.events, flush); child_output(evs[i].data.ptr, evs[i].events, flush);
} }
} }
...@@ -401,10 +421,11 @@ int main(int argc, char **argv) ...@@ -401,10 +421,11 @@ int main(int argc, char **argv)
{ {
int ret; int ret;
int timeout = 10; int timeout = 10;
int cpus, tests, i, j, c; int cpus, i, j, c;
int sve_vl_count, sme_vl_count, fpsimd_per_cpu; int sve_vl_count, sme_vl_count, fpsimd_per_cpu;
bool all_children_started = false;
int seen_children;
int sve_vls[MAX_VLS], sme_vls[MAX_VLS]; int sve_vls[MAX_VLS], sme_vls[MAX_VLS];
struct epoll_event ev;
struct sigaction sa; struct sigaction sa;
while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) { while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) {
...@@ -465,6 +486,12 @@ int main(int argc, char **argv) ...@@ -465,6 +486,12 @@ int main(int argc, char **argv)
strerror(errno), ret); strerror(errno), ret);
epoll_fd = ret; epoll_fd = ret;
/* Create a pipe which children will block on before execing */
ret = pipe(startup_pipe);
if (ret != 0)
ksft_exit_fail_msg("Failed to create startup pipe: %s (%d)\n",
strerror(errno), errno);
/* Get signal handers ready before we start any children */ /* Get signal handers ready before we start any children */
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handle_exit_signal; sa.sa_sigaction = handle_exit_signal;
...@@ -484,6 +511,11 @@ int main(int argc, char **argv) ...@@ -484,6 +511,11 @@ int main(int argc, char **argv)
ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n", ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n",
strerror(errno), errno); strerror(errno), errno);
evs = calloc(tests, sizeof(*evs));
if (!evs)
ksft_exit_fail_msg("Failed to allocated %d epoll events\n",
tests);
for (i = 0; i < cpus; i++) { for (i = 0; i < cpus; i++) {
for (j = 0; j < fpsimd_per_cpu; j++) for (j = 0; j < fpsimd_per_cpu; j++)
start_fpsimd(&children[num_children++], i, j); start_fpsimd(&children[num_children++], i, j);
...@@ -497,6 +529,13 @@ int main(int argc, char **argv) ...@@ -497,6 +529,13 @@ int main(int argc, char **argv)
} }
} }
/*
* All children started, close the startup pipe and let them
* run.
*/
close(startup_pipe[0]);
close(startup_pipe[1]);
for (;;) { for (;;) {
/* Did we get a signal asking us to exit? */ /* Did we get a signal asking us to exit? */
if (terminate) if (terminate)
...@@ -510,7 +549,7 @@ int main(int argc, char **argv) ...@@ -510,7 +549,7 @@ int main(int argc, char **argv)
* useful in emulation where we will both be slow and * useful in emulation where we will both be slow and
* likely to have a large set of VLs. * likely to have a large set of VLs.
*/ */
ret = epoll_wait(epoll_fd, &ev, 1, 1000); ret = epoll_wait(epoll_fd, evs, tests, 1000);
if (ret < 0) { if (ret < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
...@@ -519,13 +558,40 @@ int main(int argc, char **argv) ...@@ -519,13 +558,40 @@ int main(int argc, char **argv)
} }
/* Output? */ /* Output? */
if (ret == 1) { if (ret > 0) {
child_output(ev.data.ptr, ev.events, false); for (i = 0; i < ret; i++) {
child_output(evs[i].data.ptr, evs[i].events,
false);
}
continue; continue;
} }
/* Otherwise epoll_wait() timed out */ /* Otherwise epoll_wait() timed out */
/*
* If the child processes have not produced output they
* aren't actually running the tests yet .
*/
if (!all_children_started) {
seen_children = 0;
for (i = 0; i < num_children; i++)
if (children[i].output_seen ||
children[i].exited)
seen_children++;
if (seen_children != num_children) {
ksft_print_msg("Waiting for %d children\n",
num_children - seen_children);
continue;
}
all_children_started = true;
}
ksft_print_msg("Sending signals, timeout remaining: %d\n",
timeout);
for (i = 0; i < num_children; i++) for (i = 0; i < num_children; i++)
child_tickle(&children[i]); child_tickle(&children[i]);
......
...@@ -32,7 +32,7 @@ static int check_buffer_by_byte(int mem_type, int mode) ...@@ -32,7 +32,7 @@ static int check_buffer_by_byte(int mem_type, int mode)
bool err; bool err;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
item = sizeof(sizes)/sizeof(int); item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) { for (i = 0; i < item; i++) {
ptr = (char *)mte_allocate_memory(sizes[i], mem_type, 0, true); ptr = (char *)mte_allocate_memory(sizes[i], mem_type, 0, true);
...@@ -69,7 +69,7 @@ static int check_buffer_underflow_by_byte(int mem_type, int mode, ...@@ -69,7 +69,7 @@ static int check_buffer_underflow_by_byte(int mem_type, int mode,
char *und_ptr = NULL; char *und_ptr = NULL;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
item = sizeof(sizes)/sizeof(int); item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) { for (i = 0; i < item; i++) {
ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0, ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
underflow_range, 0); underflow_range, 0);
...@@ -165,7 +165,7 @@ static int check_buffer_overflow_by_byte(int mem_type, int mode, ...@@ -165,7 +165,7 @@ static int check_buffer_overflow_by_byte(int mem_type, int mode,
char *over_ptr = NULL; char *over_ptr = NULL;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
item = sizeof(sizes)/sizeof(int); item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) { for (i = 0; i < item; i++) {
ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0, ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
0, overflow_range); 0, overflow_range);
...@@ -338,7 +338,7 @@ static int check_buffer_by_block(int mem_type, int mode) ...@@ -338,7 +338,7 @@ static int check_buffer_by_block(int mem_type, int mode)
int i, item, result = KSFT_PASS; int i, item, result = KSFT_PASS;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
item = sizeof(sizes)/sizeof(int); item = ARRAY_SIZE(sizes);
cur_mte_cxt.fault_valid = false; cur_mte_cxt.fault_valid = false;
for (i = 0; i < item; i++) { for (i = 0; i < item; i++) {
result = check_buffer_by_block_iterate(mem_type, mode, sizes[i]); result = check_buffer_by_block_iterate(mem_type, mode, sizes[i]);
...@@ -366,7 +366,7 @@ static int check_memory_initial_tags(int mem_type, int mode, int mapping) ...@@ -366,7 +366,7 @@ static int check_memory_initial_tags(int mem_type, int mode, int mapping)
{ {
char *ptr; char *ptr;
int run, fd; int run, fd;
int total = sizeof(sizes)/sizeof(int); int total = ARRAY_SIZE(sizes);
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
for (run = 0; run < total; run++) { for (run = 0; run < total; run++) {
...@@ -404,7 +404,7 @@ int main(int argc, char *argv[]) ...@@ -404,7 +404,7 @@ int main(int argc, char *argv[])
{ {
int err; int err;
size_t page_size = getpagesize(); size_t page_size = getpagesize();
int item = sizeof(sizes)/sizeof(int); int item = ARRAY_SIZE(sizes);
sizes[item - 3] = page_size - 1; sizes[item - 3] = page_size - 1;
sizes[item - 2] = page_size; sizes[item - 2] = page_size;
......
...@@ -61,9 +61,8 @@ static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, i ...@@ -61,9 +61,8 @@ static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, i
{ {
char *ptr, *map_ptr; char *ptr, *map_ptr;
int run, result, map_size; int run, result, map_size;
int item = sizeof(sizes)/sizeof(int); int item = ARRAY_SIZE(sizes);
item = sizeof(sizes)/sizeof(int);
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
for (run = 0; run < item; run++) { for (run = 0; run < item; run++) {
map_size = sizes[run] + OVERFLOW + UNDERFLOW; map_size = sizes[run] + OVERFLOW + UNDERFLOW;
...@@ -93,7 +92,7 @@ static int check_file_memory_mapping(int mem_type, int mode, int mapping, int ta ...@@ -93,7 +92,7 @@ static int check_file_memory_mapping(int mem_type, int mode, int mapping, int ta
{ {
char *ptr, *map_ptr; char *ptr, *map_ptr;
int run, fd, map_size; int run, fd, map_size;
int total = sizeof(sizes)/sizeof(int); int total = ARRAY_SIZE(sizes);
int result = KSFT_PASS; int result = KSFT_PASS;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
...@@ -132,7 +131,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping) ...@@ -132,7 +131,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping)
{ {
char *ptr, *map_ptr; char *ptr, *map_ptr;
int run, prot_flag, result, fd, map_size; int run, prot_flag, result, fd, map_size;
int total = sizeof(sizes)/sizeof(int); int total = ARRAY_SIZE(sizes);
prot_flag = PROT_READ | PROT_WRITE; prot_flag = PROT_READ | PROT_WRITE;
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
...@@ -187,7 +186,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping) ...@@ -187,7 +186,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int err; int err;
int item = sizeof(sizes)/sizeof(int); int item = ARRAY_SIZE(sizes);
err = mte_default_setup(); err = mte_default_setup();
if (err) if (err)
......
- Validate that register contents are saved and restored as expected. - Validate that register contents are saved and restored as expected.
- Support and validate extra_context.
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019 ARM Limited */ /* Copyright (C) 2019 ARM Limited */
#include <ctype.h>
#include <string.h>
#include "testcases.h" #include "testcases.h"
struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic, struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
...@@ -109,7 +113,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -109,7 +113,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
bool terminated = false; bool terminated = false;
size_t offs = 0; size_t offs = 0;
int flags = 0; int flags = 0;
int new_flags; int new_flags, i;
struct extra_context *extra = NULL; struct extra_context *extra = NULL;
struct sve_context *sve = NULL; struct sve_context *sve = NULL;
struct za_context *za = NULL; struct za_context *za = NULL;
...@@ -117,6 +121,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -117,6 +121,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
(struct _aarch64_ctx *)uc->uc_mcontext.__reserved; (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
void *extra_data = NULL; void *extra_data = NULL;
size_t extra_sz = 0; size_t extra_sz = 0;
char magic[4];
if (!err) if (!err)
return false; return false;
...@@ -194,11 +199,19 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) ...@@ -194,11 +199,19 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
/* /*
* A still unknown Magic: potentially freshly added * A still unknown Magic: potentially freshly added
* to the Kernel code and still unknown to the * to the Kernel code and still unknown to the
* tests. * tests. Magic numbers are supposed to be allocated
* as somewhat meaningful ASCII strings so try to
* print as such as well as the raw number.
*/ */
memcpy(magic, &head->magic, sizeof(magic));
for (i = 0; i < sizeof(magic); i++)
if (!isalnum(magic[i]))
magic[i] = '?';
fprintf(stdout, fprintf(stdout,
"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n", "SKIP Unknown MAGIC: 0x%X (%c%c%c%c) - Is KSFT arm64/signal up to date ?\n",
head->magic); head->magic,
magic[3], magic[2], magic[1], magic[0]);
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment