mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
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
This commit is contained in:
commit
32b4824842
@ -153,7 +153,7 @@ do_syscall:
|
||||
// Only set a non-zero FFR, test patterns must be zero since the
|
||||
// syscall should clear it - this lets us handle FA64.
|
||||
ldr x2, =ffr_in
|
||||
ldr p0, [x2, #0]
|
||||
ldr p0, [x2]
|
||||
ldr x2, [x2, #0]
|
||||
cbz x2, 2f
|
||||
wrffr p0.b
|
||||
@ -298,7 +298,7 @@ do_syscall:
|
||||
cbz x2, 1f
|
||||
ldr x2, =ffr_out
|
||||
rdffr p0.b
|
||||
str p0, [x2, #0]
|
||||
str p0, [x2]
|
||||
1:
|
||||
|
||||
// Restore callee saved registers x19-x30
|
||||
|
@ -39,10 +39,12 @@ struct child_data {
|
||||
|
||||
static int epoll_fd;
|
||||
static struct child_data *children;
|
||||
static struct epoll_event *evs;
|
||||
static int tests;
|
||||
static int num_children;
|
||||
static bool terminate;
|
||||
|
||||
static void drain_output(bool flush);
|
||||
static int startup_pipe[2];
|
||||
|
||||
static int num_processors(void)
|
||||
{
|
||||
@ -81,13 +83,37 @@ static void child_start(struct child_data *child, const char *program)
|
||||
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
|
||||
* stdio. We don't want O_CLOEXEC for the pipes...
|
||||
*/
|
||||
for (i = 3; i < 8192; i++)
|
||||
for (i = 4; i < 8192; 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);
|
||||
fprintf(stderr, "execl(%s) failed: %d (%s)\n",
|
||||
program, errno, strerror(errno));
|
||||
@ -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",
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
child_start(child, "./fpsimd-test");
|
||||
|
||||
ret = asprintf(&child->name, "FPSIMD-%d-%d", cpu, copy);
|
||||
if (ret == -1)
|
||||
ksft_exit_fail_msg("asprintf() failed\n");
|
||||
|
||||
child_start(child, "./fpsimd-test");
|
||||
|
||||
ksft_print_msg("Started %s\n", child->name);
|
||||
}
|
||||
|
||||
@ -307,12 +327,12 @@ static void start_sve(struct child_data *child, int vl, int cpu)
|
||||
if (ret < 0)
|
||||
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);
|
||||
if (ret == -1)
|
||||
ksft_exit_fail_msg("asprintf() failed\n");
|
||||
|
||||
child_start(child, "./sve-test");
|
||||
|
||||
ksft_print_msg("Started %s\n", child->name);
|
||||
}
|
||||
|
||||
@ -320,16 +340,16 @@ static void start_ssve(struct child_data *child, int vl, int cpu)
|
||||
{
|
||||
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);
|
||||
if (ret < 0)
|
||||
ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -341,12 +361,12 @@ static void start_za(struct child_data *child, int vl, int cpu)
|
||||
if (ret < 0)
|
||||
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);
|
||||
if (ret == -1)
|
||||
ksft_exit_fail_msg("asprintf() failed\n");
|
||||
|
||||
child_start(child, "./za-test");
|
||||
|
||||
ksft_print_msg("Started %s\n", child->name);
|
||||
}
|
||||
|
||||
@ -375,11 +395,11 @@ static void probe_vls(int vls[], int *vl_count, int set_vl)
|
||||
/* Handle any pending output without blocking */
|
||||
static void drain_output(bool flush)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int ret = 1;
|
||||
int i;
|
||||
|
||||
while (ret > 0) {
|
||||
ret = epoll_wait(epoll_fd, &ev, 1, 0);
|
||||
ret = epoll_wait(epoll_fd, evs, tests, 0);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
@ -387,8 +407,8 @@ static void drain_output(bool flush)
|
||||
strerror(errno), errno);
|
||||
}
|
||||
|
||||
if (ret == 1)
|
||||
child_output(ev.data.ptr, ev.events, flush);
|
||||
for (i = 0; i < ret; i++)
|
||||
child_output(evs[i].data.ptr, evs[i].events, flush);
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,10 +421,11 @@ int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
int timeout = 10;
|
||||
int cpus, tests, i, j, c;
|
||||
int cpus, i, j, c;
|
||||
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];
|
||||
struct epoll_event ev;
|
||||
struct sigaction sa;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) {
|
||||
@ -465,6 +486,12 @@ int main(int argc, char **argv)
|
||||
strerror(errno), 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 */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = handle_exit_signal;
|
||||
@ -484,6 +511,11 @@ int main(int argc, char **argv)
|
||||
ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n",
|
||||
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 (j = 0; j < fpsimd_per_cpu; j++)
|
||||
start_fpsimd(&children[num_children++], i, j);
|
||||
@ -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 (;;) {
|
||||
/* Did we get a signal asking us to exit? */
|
||||
if (terminate)
|
||||
@ -510,7 +549,7 @@ int main(int argc, char **argv)
|
||||
* useful in emulation where we will both be slow and
|
||||
* 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 (errno == EINTR)
|
||||
continue;
|
||||
@ -519,13 +558,40 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* Output? */
|
||||
if (ret == 1) {
|
||||
child_output(ev.data.ptr, ev.events, false);
|
||||
if (ret > 0) {
|
||||
for (i = 0; i < ret; i++) {
|
||||
child_output(evs[i].data.ptr, evs[i].events,
|
||||
false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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++)
|
||||
child_tickle(&children[i]);
|
||||
|
||||
|
@ -32,7 +32,7 @@ static int check_buffer_by_byte(int mem_type, int mode)
|
||||
bool err;
|
||||
|
||||
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
|
||||
item = sizeof(sizes)/sizeof(int);
|
||||
item = ARRAY_SIZE(sizes);
|
||||
|
||||
for (i = 0; i < item; i++) {
|
||||
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,
|
||||
char *und_ptr = NULL;
|
||||
|
||||
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
|
||||
item = sizeof(sizes)/sizeof(int);
|
||||
item = ARRAY_SIZE(sizes);
|
||||
for (i = 0; i < item; i++) {
|
||||
ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
|
||||
underflow_range, 0);
|
||||
@ -165,7 +165,7 @@ static int check_buffer_overflow_by_byte(int mem_type, int mode,
|
||||
char *over_ptr = NULL;
|
||||
|
||||
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
|
||||
item = sizeof(sizes)/sizeof(int);
|
||||
item = ARRAY_SIZE(sizes);
|
||||
for (i = 0; i < item; i++) {
|
||||
ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
|
||||
0, overflow_range);
|
||||
@ -338,7 +338,7 @@ static int check_buffer_by_block(int mem_type, int mode)
|
||||
int i, item, result = KSFT_PASS;
|
||||
|
||||
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
|
||||
item = sizeof(sizes)/sizeof(int);
|
||||
item = ARRAY_SIZE(sizes);
|
||||
cur_mte_cxt.fault_valid = false;
|
||||
for (i = 0; i < item; 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)
|
||||
{
|
||||
char *ptr;
|
||||
int run, fd;
|
||||
int total = sizeof(sizes)/sizeof(int);
|
||||
int total = ARRAY_SIZE(sizes);
|
||||
|
||||
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
|
||||
for (run = 0; run < total; run++) {
|
||||
@ -404,7 +404,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
size_t page_size = getpagesize();
|
||||
int item = sizeof(sizes)/sizeof(int);
|
||||
int item = ARRAY_SIZE(sizes);
|
||||
|
||||
sizes[item - 3] = page_size - 1;
|
||||
sizes[item - 2] = page_size;
|
||||
|
@ -61,9 +61,8 @@ static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, i
|
||||
{
|
||||
char *ptr, *map_ptr;
|
||||
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);
|
||||
for (run = 0; run < item; run++) {
|
||||
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
|
||||
{
|
||||
char *ptr, *map_ptr;
|
||||
int run, fd, map_size;
|
||||
int total = sizeof(sizes)/sizeof(int);
|
||||
int total = ARRAY_SIZE(sizes);
|
||||
int result = KSFT_PASS;
|
||||
|
||||
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)
|
||||
{
|
||||
char *ptr, *map_ptr;
|
||||
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;
|
||||
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)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
int item = sizeof(sizes)/sizeof(int);
|
||||
int item = ARRAY_SIZE(sizes);
|
||||
|
||||
err = mte_default_setup();
|
||||
if (err)
|
||||
|
@ -1,2 +1 @@
|
||||
- Validate that register contents are saved and restored as expected.
|
||||
- Support and validate extra_context.
|
||||
|
@ -1,5 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (C) 2019 ARM Limited */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "testcases.h"
|
||||
|
||||
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)
|
||||
bool terminated = false;
|
||||
size_t offs = 0;
|
||||
int flags = 0;
|
||||
int new_flags;
|
||||
int new_flags, i;
|
||||
struct extra_context *extra = NULL;
|
||||
struct sve_context *sve = NULL;
|
||||
struct za_context *za = NULL;
|
||||
@ -117,6 +121,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
|
||||
(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
|
||||
void *extra_data = NULL;
|
||||
size_t extra_sz = 0;
|
||||
char magic[4];
|
||||
|
||||
if (!err)
|
||||
return false;
|
||||
@ -194,11 +199,19 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
|
||||
/*
|
||||
* A still unknown Magic: potentially freshly added
|
||||
* 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,
|
||||
"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
|
||||
head->magic);
|
||||
"SKIP Unknown MAGIC: 0x%X (%c%c%c%c) - Is KSFT arm64/signal up to date ?\n",
|
||||
head->magic,
|
||||
magic[3], magic[2], magic[1], magic[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user