Skip to content

Commit

Permalink
kselftest: arm64: mangle_pstate_invalid_compat_toggle and common utils
Browse files Browse the repository at this point in the history
Add some arm64/signal specific boilerplate and utility code to help
further testcases' development.

Introduce also one simple testcase mangle_pstate_invalid_compat_toggle
and some related helpers: it is a simple mangle testcase which messes
with the ucontext_t from within the signal handler, trying to toggle
PSTATE state bits to switch the system between 32bit/64bit execution
state. Expects SIGSEGV on test PASS.

Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
  • Loading branch information
Cristian Marussi authored and Catalin Marinas committed Nov 8, 2019
1 parent 313a4db commit f96bf43
Show file tree
Hide file tree
Showing 11 changed files with 800 additions and 1 deletion.
2 changes: 1 addition & 1 deletion tools/testing/selftests/arm64/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
ARCH ?= $(shell uname -m 2>/dev/null || echo not)

ifneq (,$(filter $(ARCH),aarch64 arm64))
ARM64_SUBTARGETS ?= tags
ARM64_SUBTARGETS ?= tags signal
else
ARM64_SUBTARGETS :=
endif
Expand Down
3 changes: 3 additions & 0 deletions tools/testing/selftests/arm64/signal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mangle_*
fake_sigreturn_*
!*.[ch]
32 changes: 32 additions & 0 deletions tools/testing/selftests/arm64/signal/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2019 ARM Limited

# Additional include paths needed by kselftest.h and local headers
CFLAGS += -D_GNU_SOURCE -std=gnu99 -I.

SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
PROGS := $(patsubst %.c,%,$(SRCS))

# Generated binaries to be installed by top KSFT script
TEST_GEN_PROGS := $(notdir $(PROGS))

# Get Kernel headers installed and use them.
KSFT_KHDR_INSTALL := 1

# Including KSFT lib.mk here will also mangle the TEST_GEN_PROGS list
# to account for any OUTPUT target-dirs optionally provided by
# the toplevel makefile
include ../../lib.mk

$(TEST_GEN_PROGS): $(PROGS)
cp $(PROGS) $(OUTPUT)/

clean:
$(CLEAN)
rm -f $(PROGS)

# Common test-unit targets to build common-layout test-cases executables
# Needs secondary expansion to properly include the testcase c-file in pre-reqs
.SECONDEXPANSION:
$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
$(CC) $(CFLAGS) $^ -o $@
59 changes: 59 additions & 0 deletions tools/testing/selftests/arm64/signal/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
KSelfTest arm64/signal/
=======================

Signals Tests
+++++++++++++

- Tests are built around a common main compilation unit: such shared main
enforces a standard sequence of operations needed to perform a single
signal-test (setup/trigger/run/result/cleanup)

- The above mentioned ops are configurable on a test-by-test basis: each test
is described (and configured) using the descriptor signals.h::struct tdescr

- Each signal testcase is compiled into its own executable: a separate
executable is used for each test since many tests complete successfully
by receiving some kind of fatal signal from the Kernel, so it's safer
to run each test unit in its own standalone process, so as to start each
test from a clean slate.

- New tests can be simply defined in testcases/ dir providing a proper struct
tdescr overriding all the defaults we wish to change (as of now providing a
custom run method is mandatory though)

- Signals' test-cases hereafter defined belong currently to two
principal families:

- 'mangle_' tests: a real signal (SIGUSR1) is raised and used as a trigger
and then the test case code modifies the signal frame from inside the
signal handler itself.

- 'fake_sigreturn_' tests: a brand new custom artificial sigframe structure
is placed on the stack and a sigreturn syscall is called to simulate a
real signal return. This kind of tests does not use a trigger usually and
they are just fired using some simple included assembly trampoline code.

- Most of these tests are successfully passing if the process gets killed by
some fatal signal: usually SIGSEGV or SIGBUS. Since while writing this
kind of tests it is extremely easy in fact to end-up injecting other
unrelated SEGV bugs in the testcases, it becomes extremely tricky to
be really sure that the tests are really addressing what they are meant
to address and they are not instead falling apart due to unplanned bugs
in the test code.
In order to alleviate the misery of the life of such test-developer, a few
helpers are provided:

- a couple of ASSERT_BAD/GOOD_CONTEXT() macros to easily parse a ucontext_t
and verify if it is indeed GOOD or BAD (depending on what we were
expecting), using the same logic/perspective as in the arm64 Kernel signals
routines.

- a sanity mechanism to be used in 'fake_sigreturn_'-alike tests: enabled by
default it takes care to verify that the test-execution had at least
successfully progressed up to the stage of triggering the fake sigreturn
call.

In both cases test results are expected in terms of:
- some fatal signal sent by the Kernel to the test process
or
- analyzing some final regs state
29 changes: 29 additions & 0 deletions tools/testing/selftests/arm64/signal/test_signals.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 ARM Limited
*
* Generic test wrapper for arm64 signal tests.
*
* Each test provides its own tde struct tdescr descriptor to link with
* this wrapper. Framework provides common helpers.
*/
#include <kselftest.h>

#include "test_signals.h"
#include "test_signals_utils.h"

struct tdescr *current;

int main(int argc, char *argv[])
{
current = &tde;

ksft_print_msg("%s :: %s\n", current->name, current->descr);
if (test_setup(current)) {
test_run(current);
test_result(current);
test_cleanup(current);
}

return current->pass ? KSFT_PASS : KSFT_FAIL;
}
93 changes: 93 additions & 0 deletions tools/testing/selftests/arm64/signal/test_signals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2019 ARM Limited */

#ifndef __TEST_SIGNALS_H__
#define __TEST_SIGNALS_H__

#include <signal.h>
#include <stdbool.h>
#include <ucontext.h>

/*
* Using ARCH specific and sanitized Kernel headers installed by KSFT
* framework since we asked for it by setting flag KSFT_KHDR_INSTALL
* in our Makefile.
*/
#include <asm/ptrace.h>
#include <asm/hwcap.h>

#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)

#define get_regval(regname, out) \
{ \
asm volatile("mrs %0, " __stringify(regname) \
: "=r" (out) \
: \
: "memory"); \
}

/*
* Feature flags used in tdescr.feats_required to specify
* any feature by the test
*/
enum {
FSSBS_BIT,
FMAX_END
};

#define FEAT_SSBS (1UL << FSSBS_BIT)

/*
* A descriptor used to describe and configure a test case.
* Fields with a non-trivial meaning are described inline in the following.
*/
struct tdescr {
/* KEEP THIS FIELD FIRST for easier lookup from assembly */
void *token;
/* when disabled token based sanity checking is skipped in handler */
bool sanity_disabled;
/* just a name for the test-case; manadatory field */
char *name;
char *descr;
unsigned long feats_required;
/* bitmask of effectively supported feats: populated at run-time */
unsigned long feats_supported;
bool initialized;
unsigned int minsigstksz;
/* signum used as a test trigger. Zero if no trigger-signal is used */
int sig_trig;
/*
* signum considered as a successful test completion.
* Zero when no signal is expected on success
*/
int sig_ok;
/* signum expected on unsupported CPU features. */
int sig_unsupp;
/* a timeout in second for test completion */
unsigned int timeout;
bool triggered;
bool pass;
/* optional sa_flags for the installed handler */
int sa_flags;
ucontext_t saved_uc;
/* optional test private data */
void *priv;

/* a custom setup function to be called before test starts */
int (*setup)(struct tdescr *td);
/* a custom cleanup function called before test exits */
void (*cleanup)(struct tdescr *td);
/* an optional function to be used as a trigger for test starting */
int (*trigger)(struct tdescr *td);
/*
* the actual test-core: invoked differently depending on the
* presence of the trigger function above; this is mandatory
*/
int (*run)(struct tdescr *td, siginfo_t *si, ucontext_t *uc);
/* an optional function for custom results' processing */
void (*check_result)(struct tdescr *td);
};

extern struct tdescr tde;
#endif
Loading

0 comments on commit f96bf43

Please sign in to comment.