linux-kselftest.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/11] Add arm64/signal initial kselftest support
@ 2019-08-02 17:02 Cristian Marussi
  2019-08-02 17:02 ` [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code Cristian Marussi
                   ` (11 more replies)
  0 siblings, 12 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Hi

this patchset aims to add the initial arch-specific arm64 support to
kselftest starting with signals-related test-cases.
A common internal test-case layout is proposed which then it is anyway
wired-up to the toplevel kselftest Makefile, so that it should be possible
at the end to run it on an arm64 target in the usual way with KSFT.

~/linux# make TARGETS=arm64 kselftest

New KSFT arm64 testcases live inside tools/testing/selftests/arm64 grouped by
family inside subdirectories: arm64/signal is the first family proposed with
this series. arm64/signal tests can be run via KSFT or standalone.

Thanks

Cristian


Notes:
-----
- further details in the included READMEs

- more tests still to be written (current strategy is going through the related
  Kernel signal-handling code and write a test for each possible and sensible code-path)
  A few ideas in testcases/TODO.readme

- a bit of overlap around KSFT arm64/ Makefiles is expected with this:
  https://lore.kernel.org/linux-arm-kernel/c1e6aad230658bc175b42d92daeff2e30050302a.1563904656.git.andreyknvl@google.com/


Changes:
--------

 v2-->v3:
 - rebased on v5.3-rc2
 - better test result characterization looking for
   SEGV_ACCERR in si_code on SIGSEGV
 - using KSFT Framework macros for retvalues
 - removed SAFE_WRITE()/dump_uc: buggy, un-needed and unused
 - reviewed generation process of test_arm64_signals.sh runner script
 - re-added a fixed fake_sigreturn_misaligned_sp testcase and a properly
   extended fake_sigreturn() helper
 - added tests' TODO notes


 v1-->v2:
- rebased on 5.2-rc7
- various makefile's cleanups
- mixed READMEs fixes
- fixed test_arm64_signals.sh runner script
- cleaned up assembly code in signal.S
- improved get_current_context() logic
- fixed SAFE_WRITE()
- common support code splitted into more chunks, each one introduced when
  needed by some new testcases
- fixed some headers validation routines in testcases.c
- removed some still broken/immature tests:
  + fake_sigreturn_misaligned
  + fake_sigreturn_overflow_reserved
  + mangle_pc_invalid
  + mangle_sp_misaligned
- fixed some other testcases:
  + mangle_pstate_ssbs_regs: better checks of SSBS bit when feature unsupported
  + mangle_pstate_invalid_compat_toggle: name fix
  + mangle_pstate_invalid_mode_el[1-3]: precautionary zeroing PSTATE.MODE
  + fake_sigreturn_bad_magic, fake_sigreturn_bad_size,
    fake_sigreturn_bad_size_for_magic0:
    - accounting for available space...dropping extra when needed
    - keeping alignent
- new testcases on FPSMID context:
  + fake_sigreturn_missing_fpsimd
  + fake_sigreturn_duplicated_fpsimd


Cristian Marussi (11):
  kselftest: arm64: introduce new boilerplate code
  kselftest: arm64: adds first test and common utils
  kselftest: arm64: mangle_pstate_invalid_daif_bits
  kselftest: arm64: mangle_pstate_invalid_mode_el
  kselftest: arm64: mangle_pstate_ssbs_regs
  kselftest: arm64: fake_sigreturn_bad_magic
  kselftest: arm64: fake_sigreturn_bad_size_for_magic0
  kselftest: arm64: fake_sigreturn_missing_fpsimd
  kselftest: arm64: fake_sigreturn_duplicated_fpsimd
  kselftest: arm64: fake_sigreturn_bad_size
  kselftest: arm64: fake_sigreturn_misaligned_sp

 tools/testing/selftests/Makefile              |   1 +
 tools/testing/selftests/arm64/Makefile        |  51 +++
 tools/testing/selftests/arm64/README          |  43 +++
 .../testing/selftests/arm64/signal/.gitignore |   6 +
 tools/testing/selftests/arm64/signal/Makefile |  88 +++++
 tools/testing/selftests/arm64/signal/README   |  59 +++
 .../testing/selftests/arm64/signal/signals.S  |  73 ++++
 .../arm64/signal/test_arm64_signals.src_shell |  55 +++
 .../selftests/arm64/signal/test_signals.c     |  26 ++
 .../selftests/arm64/signal/test_signals.h     | 141 +++++++
 .../arm64/signal/test_signals_utils.c         | 354 ++++++++++++++++++
 .../arm64/signal/test_signals_utils.h         |  16 +
 .../arm64/signal/testcases/.gitignore         |  11 +
 .../arm64/signal/testcases/TODO.readme        |   7 +
 .../testcases/fake_sigreturn_bad_magic.c      |  63 ++++
 .../testcases/fake_sigreturn_bad_size.c       |  85 +++++
 .../fake_sigreturn_bad_size_for_magic0.c      |  57 +++
 .../fake_sigreturn_duplicated_fpsimd.c        |  62 +++
 .../testcases/fake_sigreturn_misaligned_sp.c  |  30 ++
 .../testcases/fake_sigreturn_missing_fpsimd.c |  44 +++
 .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
 .../mangle_pstate_invalid_daif_bits.c         |  28 ++
 .../mangle_pstate_invalid_mode_el1.c          |  29 ++
 .../mangle_pstate_invalid_mode_el2.c          |  29 ++
 .../mangle_pstate_invalid_mode_el3.c          |  29 ++
 .../testcases/mangle_pstate_ssbs_regs.c       |  56 +++
 .../arm64/signal/testcases/testcases.c        | 150 ++++++++
 .../arm64/signal/testcases/testcases.h        |  83 ++++
 28 files changed, 1701 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/Makefile
 create mode 100644 tools/testing/selftests/arm64/README
 create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
 create mode 100644 tools/testing/selftests/arm64/signal/Makefile
 create mode 100644 tools/testing/selftests/arm64/signal/README
 create mode 100644 tools/testing/selftests/arm64/signal/signals.S
 create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
 create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
 create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
 create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
 create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:23   ` Dave Martin
  2019-08-02 17:02 ` [PATCH v3 02/11] kselftest: arm64: adds first test and common utils Cristian Marussi
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a new arm64-specific empty subsystem amongst TARGETS of KSFT build
framework; once populated with testcases, it will be possible to build
and invoke the new KSFT TARGETS=arm64 related tests from the toplevel
Makefile in the usual ways.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
Reviewed the build instructions reported in the README, to be more
agnostic regarding user/device etc..
---
 tools/testing/selftests/Makefile       |  1 +
 tools/testing/selftests/arm64/Makefile | 51 ++++++++++++++++++++++++++
 tools/testing/selftests/arm64/README   | 43 ++++++++++++++++++++++
 3 files changed, 95 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/Makefile
 create mode 100644 tools/testing/selftests/arm64/README

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 25b43a8c2b15..1722dae9381a 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 TARGETS = android
+TARGETS += arm64
 TARGETS += bpf
 TARGETS += breakpoints
 TARGETS += capabilities
diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
new file mode 100644
index 000000000000..03a0d4f71218
--- /dev/null
+++ b/tools/testing/selftests/arm64/Makefile
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+# When ARCH not overridden for crosscompiling, lookup machine
+ARCH ?= $(shell uname -m)
+ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
+
+ifeq ("x$(ARCH)", "xarm64")
+SUBDIRS :=
+else
+SUBDIRS :=
+endif
+
+CFLAGS := -Wall -O2 -g
+
+export CC
+export CFLAGS
+
+all:
+	@for DIR in $(SUBDIRS); do				\
+		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
+		mkdir -p $$BUILD_TARGET;			\
+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
+	done
+
+install: all
+	@for DIR in $(SUBDIRS); do				\
+		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
+	done
+
+run_tests: all
+	@for DIR in $(SUBDIRS); do				\
+		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
+	done
+
+# Avoid any output on non arm64 on emit_tests
+emit_tests: all
+	@for DIR in $(SUBDIRS); do				\
+		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
+	done
+
+clean:
+	@for DIR in $(SUBDIRS); do				\
+		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
+		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
+	done
+
+.PHONY: all clean install run_tests emit_tests
diff --git a/tools/testing/selftests/arm64/README b/tools/testing/selftests/arm64/README
new file mode 100644
index 000000000000..dee3306071cc
--- /dev/null
+++ b/tools/testing/selftests/arm64/README
@@ -0,0 +1,43 @@
+KSelfTest ARM64
+===============
+
+- These tests are arm64 specific and so not built or run but just skipped
+  completely when env-variable ARCH is found to be different than 'arm64'
+  and `uname -m` reports other than 'aarch64'.
+
+- Holding true the above, ARM64 KSFT tests can be run:
+
+   + as standalone (example for signal tests)
+
+      $ make -C tools/testing/selftest/arm64/signal \
+		INSTALL_PATH=<your-installation-path> install
+
+      and then launching on the target device inside the installed path:
+
+      $ <your-installed-path>/test_arm64_signals.sh [-k | -v]
+
+   + within the KSelfTest framework using standard Linux top-level-makefile
+     targets:
+
+      $ make TARGETS=arm64 kselftest-clean
+      $ make TARGETS=arm64 kselftest
+
+   Further details on building and running KFST can be found in:
+     Documentation/dev-tools/kselftest.rst
+
+- Tests can depend on some arch-specific definitions which can be found in a
+  standard Kernel Headers installation in $(top_srcdir)/usr/include.
+  Such Kernel Headers are automatically installed (via make headers_install)
+  by KSFT framework itself in a dedicated directory when tests are launched
+  via KSFT itself; when running standalone, instead, a Warning is issued
+  if such headers cannot be found somewhere (we try to guess a few standard
+  locations anyway)
+
+- Some of these tests may be related to possibly not implemented ARMv8
+  features: depending on their implementation status on the effective HW
+  we'll expect different results. The tests' harness will take care to check
+  at run-time if the required features are supported and will act accordingly.
+  Moreover, in order to avoid any kind of compile-time dependency on the
+  toolchain (possibly due to the above mentioned not-implemented features),
+  we make strictly use of direct 'S3_ sysreg' raw-encoding while checking for
+  those features and/or lookin up sysregs.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
  2019-08-02 17:02 ` [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-06 15:50   ` Cristian Marussi
                     ` (4 more replies)
  2019-08-02 17:02 ` [PATCH v3 03/11] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
                   ` (9 subsequent siblings)
  11 siblings, 5 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added some arm64/signal specific boilerplate and utility code to help
further testcase development.

A simple testcase and related helpers are also introduced in this commit:
mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
messes with the ucontext_t from within the sig_handler, trying to toggle
PSTATE state bits to switch the system between 32bit/64bit execution state.
Expects SIGSEGV on test PASS.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
A few fixes:
- test_arm64_signals.sh runner script generation has been reviewed in order to
  be safe against the .gitignore
- using kselftest.h officially provided defines for tests' return values
- removed SAFE_WRITE()/dump_uc()
- looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
  the sigfault had been directly triggered by Kernel
---
 tools/testing/selftests/arm64/Makefile        |   2 +-
 .../testing/selftests/arm64/signal/.gitignore |   6 +
 tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
 tools/testing/selftests/arm64/signal/README   |  59 ++++
 .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
 .../selftests/arm64/signal/test_signals.c     |  26 ++
 .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
 .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
 .../arm64/signal/test_signals_utils.h         |  13 +
 .../arm64/signal/testcases/.gitignore         |   1 +
 .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
 .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
 .../arm64/signal/testcases/testcases.h        |  83 ++++++
 13 files changed, 905 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
 create mode 100644 tools/testing/selftests/arm64/signal/Makefile
 create mode 100644 tools/testing/selftests/arm64/signal/README
 create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
 create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
 create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
 create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
 create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h

diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
index 03a0d4f71218..af59dc74e0dc 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
 ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
 
 ifeq ("x$(ARCH)", "xarm64")
-SUBDIRS :=
+SUBDIRS := signal
 else
 SUBDIRS :=
 endif
diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
new file mode 100644
index 000000000000..434f65c15f03
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/.gitignore
@@ -0,0 +1,6 @@
+# Helper script's internal testcases list (TPROGS) is regenerated
+# each time by Makefile on standalone (non KSFT driven) runs.
+# Committing such list creates a dependency between testcases
+# patches such that they are no more easily revertable. Just ignore.
+test_arm64_signals.src_shell
+test_arm64_signals.sh
diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
new file mode 100644
index 000000000000..8c8d08be4b0d
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+# Supports also standalone invokation out of KSFT-tree
+# Compile standalone and run on your device with:
+#
+#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
+#
+# Run standalone on device with:
+#
+#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
+#
+# If INSTALL_PATH= is NOT provided it will default to ./install
+
+# A proper top_srcdir is needed both by KSFT(lib.mk)
+# and standalone builds
+top_srcdir = ../../../../..
+
+CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
+SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
+PROGS := $(patsubst %.c,%,$(SRCS))
+
+# Guessing as best as we can where the Kernel headers
+# could have been installed depending on ENV config and
+# type of invocation.
+ifeq ($(KBUILD_OUTPUT),)
+khdr_dir = $(top_srcdir)/usr/include
+else
+ifeq (0,$(MAKELEVEL))
+khdr_dir = $(KBUILD_OUTPUT)/usr/include
+else
+# the KSFT preferred location when KBUILD_OUTPUT is set
+khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
+endif
+endif
+
+CFLAGS += -I$(khdr_dir)
+
+# Standalone run
+ifeq (0,$(MAKELEVEL))
+CC := $(CROSS_COMPILE)gcc
+RUNNER_SRC = test_arm64_signals.src_shell
+RUNNER = test_arm64_signals.sh
+INSTALL_PATH ?= install/
+
+all: $(RUNNER)
+
+$(RUNNER): $(PROGS)
+	cp $(RUNNER_SRC) $(RUNNER)
+	sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
+
+install: all
+	mkdir -p $(INSTALL_PATH)/testcases
+	cp $(PROGS) $(INSTALL_PATH)/testcases
+	cp $(RUNNER) $(INSTALL_PATH)/
+
+.PHONY clean:
+	rm -f $(PROGS)
+# KSFT run
+else
+# 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
+
+# This include mk 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)
+endif
+
+# 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
+	@if [ ! -d $(khdr_dir) ]; then \
+		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
+		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
+	fi
+	$(CC) $(CFLAGS) $^ -o $@
diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
new file mode 100644
index 000000000000..53f005f7910a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/README
@@ -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 messes-up with the sigframe ucontext_t from
+    inside the sighandler 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
diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
new file mode 100755
index 000000000000..163e941e2997
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
@@ -0,0 +1,55 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+ret=0
+keep_on_fail=0
+err_out="2> /dev/null"
+
+usage() {
+	echo "Usage: `basename $0` [-v] [-k]"
+	exit 1
+}
+
+# avoiding getopt to avoid compatibility issues on targets
+# with limited resources
+while [ $# -gt 0 ]
+do
+	case $1 in
+		"-k")
+			keep_on_fail=1
+			;;
+		"-v")
+			err_out=
+			;;
+		*)
+			usage
+			;;
+	esac
+	shift
+done
+
+TPROGS=
+
+tot=$(echo $TPROGS | wc -w)
+
+# Tests are expected in testcases/ subdir inside the installation path
+workdir="`dirname $0 2>/dev/null`"
+[ -n $workdir ] && cd $workdir
+
+passed=0
+run=0
+for test in $TPROGS
+do
+	run=$((run + 1))
+	eval ./$test $err_out
+	if [ $? != 0 ]; then
+		[ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
+	else
+		passed=$((passed + 1))
+	fi
+done
+
+echo "==>> PASSED: $passed/$run on $tot available tests."
+
+exit $ret
diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
new file mode 100644
index 000000000000..3447d7011aec
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals.c
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <kselftest.h>
+
+#include "test_signals.h"
+#include "test_signals_utils.h"
+
+struct tdescr *current;
+extern struct tdescr tde;
+
+int main(int argc, char *argv[])
+{
+	current = &tde;
+
+	ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
+		       current->name, current->descr, current->sig_trig,
+		       current->sig_ok, current);
+	if (test_setup(current)) {
+		if (test_run(current))
+			test_result(current);
+		test_cleanup(current);
+	}
+
+	return current->pass ? KSFT_PASS : KSFT_FAIL;
+}
diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
new file mode 100644
index 000000000000..85db3ac44b32
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#ifndef __TEST_SIGNALS_H__
+#define __TEST_SIGNALS_H__
+
+#include <assert.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <ucontext.h>
+#include <stdint.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>
+
+/* pasted from include/linux/stringify.h */
+#define __stringify_1(x...)	#x
+#define __stringify(x...)	__stringify_1(x)
+
+/*
+ * Reads a sysreg using the, possibly provided, S3_ encoding in order to
+ * avoid inject any dependency on the used toolchain regarding possibly
+ * still unsupported ARMv8 extensions.
+ *
+ * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
+ * would introduce a compile-time dependency on possibly unsupported ARMv8
+ * Extensions: you could end-up failing to build the test depending on the
+ * available toolchain.
+ * This is undesirable since some tests, even if specifically targeted at some
+ * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
+ * optional ARM features. (SSBS bit preservation is an example: Kernel handles
+ * it transparently not caring at all about the effective set of supported
+ * features).
+ * On the other side we will expect to observe different behaviours if the
+ * feature is supported or not: usually getting a SIGILL when trying to use
+ * unsupported features. For this reason we have anyway in place some
+ * preliminary run-time checks about the cpu effectively supported features.
+ *
+ * This helper macro is meant to be used for regs readable at EL0, BUT some
+ * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
+ * if the required reg is included in the supported encoding space:
+ *
+ *  Documentation/arm64/cpu-feature-regsiters.txt
+ *
+ *  "The infrastructure emulates only the following system register space:
+ *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
+ */
+#define get_regval(regname, out) \
+	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
+
+/* Regs encoding and masks naming copied in from sysreg.h */
+#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
+#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
+#define ID_AA64MMFR1_PAN_SHIFT	20
+#define ID_AA64MMFR2_UAO_SHIFT	4
+
+/* Local Helpers */
+#define IS_PAN_SUPPORTED(val) \
+	(!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
+#define IS_UAO_SUPPORTED(val) \
+	(!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
+
+#define S3_MRS_SSBS_SYSREG		S3_3_C4_C2_6	/* EL0 supported */
+
+/*
+ * Feature flags used in tdescr.feats_required to specify
+ * any feature by the test
+ */
+enum {
+	FSSBS_BIT,
+	FPAN_BIT,
+	FUAO_BIT,
+	FMAX_END
+};
+
+#define FEAT_SSBS		(1UL << FSSBS_BIT)
+#define FEAT_PAN		(1UL << FPAN_BIT)
+#define FEAT_UAO		(1UL << FUAO_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		feats_ok;
+	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;
+
+	/* a setup function to be called before test starts */
+	int (*setup)(struct tdescr *td);
+	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);
+
+	void *priv;
+};
+#endif
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
new file mode 100644
index 000000000000..ac0055f6340b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/auxv.h>
+#include <linux/auxvec.h>
+#include <ucontext.h>
+
+#include "test_signals.h"
+#include "test_signals_utils.h"
+#include "testcases/testcases.h"
+
+extern struct tdescr *current;
+
+static char *feats_store[FMAX_END] = {
+	"SSBS",
+	"PAN",
+	"UAO"
+};
+
+#define MAX_FEATS_SZ	128
+static inline char *feats_to_string(unsigned long feats)
+{
+	static char feats_string[MAX_FEATS_SZ];
+
+	for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
+		if (feats & 1UL << i)
+			snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
+				 feats_string, feats_store[i]);
+	}
+
+	return feats_string;
+}
+
+static void unblock_signal(int signum)
+{
+	sigset_t sset;
+
+	sigemptyset(&sset);
+	sigaddset(&sset, signum);
+	sigprocmask(SIG_UNBLOCK, &sset, NULL);
+}
+
+static void default_result(struct tdescr *td, bool force_exit)
+{
+	if (td->pass)
+		fprintf(stderr, "==>> completed. PASS(1)\n");
+	else
+		fprintf(stdout, "==>> completed. FAIL(0)\n");
+	if (force_exit)
+		exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+static inline bool are_feats_ok(struct tdescr *td)
+{
+	return td ? td->feats_required == td->feats_supported : 0;
+}
+
+static void default_handler(int signum, siginfo_t *si, void *uc)
+{
+	if (current->sig_trig && signum == current->sig_trig) {
+		fprintf(stderr, "Handling SIG_TRIG\n");
+		current->triggered = 1;
+		/* ->run was asserted NON-NULL in test_setup() already */
+		current->run(current, si, uc);
+	} else if (signum == SIGILL && !current->initialized) {
+		/*
+		 * A SIGILL here while still not initialized means we failed
+		 * even to asses the existence of features during init
+		 */
+		fprintf(stdout,
+			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
+		current->feats_supported = 0;
+	} else if (current->sig_ok && signum == current->sig_ok) {
+		/* it's a bug in the test code when this assert fail */
+		assert(!current->sig_trig || current->triggered);
+		fprintf(stderr,
+			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
+			((ucontext_t *)uc)->uc_mcontext.sp,
+			si->si_addr, si->si_code, current->token,
+			current->token - si->si_addr);
+		/*
+		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
+		 * the very last time, the token field to the SP address used
+		 * to place the fake sigframe: so token==0 means we never made
+		 * it to the end, segfaulting well-before, and the test is
+		 * possibly broken.
+		 */
+		if (!current->sanity_disabled && !current->token) {
+			fprintf(stdout,
+				"current->token ZEROED...test is probably broken!\n");
+			assert(0);
+		}
+		/*
+		 * Trying to narrow down the SEGV to the ones generated by
+		 * Kernel itself via arm64_notify_segfault()
+		 */
+		if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
+			fprintf(stdout,
+				"si_code != SEGV_ACCERR...test is probably broken!\n");
+			assert(0);
+		}
+		fprintf(stderr, "Handling SIG_OK\n");
+		current->pass = 1;
+		/*
+		 * Some tests can lead to SEGV loops: in such a case we want
+		 * to terminate immediately exiting straight away
+		 */
+		default_result(current, 1);
+	} else {
+		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
+			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
+			current->pass = 1;
+		} else if (signum == SIGALRM && current->timeout) {
+			fprintf(stderr, "-- Timeout !\n");
+		} else {
+			fprintf(stderr,
+				"-- RX UNEXPECTED SIGNAL: %d\n", signum);
+		}
+		default_result(current, 1);
+	}
+}
+
+static int default_setup(struct tdescr *td)
+{
+	struct sigaction sa;
+
+	sa.sa_sigaction = default_handler;
+	sa.sa_flags = SA_SIGINFO;
+	if (td->sa_flags)
+		sa.sa_flags |= td->sa_flags;
+	sigemptyset(&sa.sa_mask);
+	/* uncatchable signals naturally skipped ... */
+	for (int sig = 1; sig < 32; sig++)
+		sigaction(sig, &sa, NULL);
+	/*
+	 * RT Signals default disposition is Term but they cannot be
+	 * generated by the Kernel in response to our tests; so just catch
+	 * them all and report them as UNEXPECTED signals.
+	 */
+	for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
+		sigaction(sig, &sa, NULL);
+
+	/* just in case...unblock explicitly all we need */
+	if (td->sig_trig)
+		unblock_signal(td->sig_trig);
+	if (td->sig_ok)
+		unblock_signal(td->sig_ok);
+	if (td->sig_unsupp)
+		unblock_signal(td->sig_unsupp);
+
+	if (td->timeout) {
+		unblock_signal(SIGALRM);
+		alarm(td->timeout);
+	}
+	fprintf(stderr, "Registered handlers for all signals.\n");
+
+	return 1;
+}
+
+static inline int default_trigger(struct tdescr *td)
+{
+	return !raise(td->sig_trig);
+}
+
+static int test_init(struct tdescr *td)
+{
+	td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
+	if (!td->minsigstksz)
+		td->minsigstksz = MINSIGSTKSZ;
+	fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
+
+	if (td->feats_required) {
+		bool feats_ok = false;
+		td->feats_supported = 0;
+		/*
+		 * Checking for CPU required features using both the
+		 * auxval and the arm64 MRS Emulation to read sysregs.
+		 */
+		if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
+			uint64_t val = 0;
+
+			if (td->feats_required & FEAT_SSBS) {
+				/* Uses HWCAP to check capability */
+				if (getauxval(AT_HWCAP) & HWCAP_SSBS)
+					td->feats_supported |= FEAT_SSBS;
+			}
+			if (td->feats_required & FEAT_PAN) {
+				/* Uses MRS emulation to check capability */
+				get_regval(SYS_ID_AA64MMFR1_EL1, val);
+				if (IS_PAN_SUPPORTED(val))
+					td->feats_supported |= FEAT_PAN;
+			}
+			if (td->feats_required & FEAT_UAO) {
+				/* Uses MRS emulation to check capability */
+				get_regval(SYS_ID_AA64MMFR2_EL1 , val);
+				if (IS_UAO_SUPPORTED(val))
+					td->feats_supported |= FEAT_UAO;
+			}
+		} else {
+			fprintf(stderr,
+				"HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
+		}
+		feats_ok = are_feats_ok(td);
+		fprintf(stderr,
+			"Required Features: [%s] %ssupported\n",
+			feats_ok ? feats_to_string(td->feats_supported) :
+		        feats_to_string(td->feats_required ^ td->feats_supported),
+			!feats_ok ? "NOT " : "");
+	}
+
+	td->initialized = 1;
+	return 1;
+}
+
+int test_setup(struct tdescr *td)
+{
+	/* assert core invariants symptom of a rotten testcase */
+	assert(current);
+	assert(td);
+	assert(td->name);
+	assert(td->run);
+
+	if (!test_init(td))
+		return 0;
+
+	if (td->setup)
+		return td->setup(td);
+	else
+		return default_setup(td);
+}
+
+int test_run(struct tdescr *td)
+{
+	if (td->sig_trig) {
+		if (td->trigger)
+			return td->trigger(td);
+		else
+			return default_trigger(td);
+	} else {
+		return td->run(td, NULL, NULL);
+	}
+}
+
+void test_result(struct tdescr *td)
+{
+	if (td->check_result)
+		td->check_result(td);
+	default_result(td, 0);
+}
+
+void test_cleanup(struct tdescr *td)
+{
+	if (td->cleanup)
+		td->cleanup(td);
+}
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
new file mode 100644
index 000000000000..8658d1a7d4b9
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#ifndef __TEST_SIGNALS_UTILS_H__
+#define __TEST_SIGNALS_UTILS_H__
+
+#include "test_signals.h"
+
+int test_setup(struct tdescr *td);
+void test_cleanup(struct tdescr *td);
+int test_run(struct tdescr *td);
+void test_result(struct tdescr *td);
+#endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
new file mode 100644
index 000000000000..8651272e3cfc
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -0,0 +1 @@
+mangle_pstate_invalid_compat_toggle
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
new file mode 100644
index 000000000000..971193e7501b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+				     ucontext_t *uc)
+{
+	ASSERT_GOOD_CONTEXT(uc);
+
+	/* This config should trigger a SIGSEGV by Kernel */
+	uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.sanity_disabled = true,
+		.name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
+		.descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
+		.sig_trig = SIGUSR1,
+		.sig_ok = SIGSEGV,
+		.run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
new file mode 100644
index 000000000000..a59785092e1f
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
@@ -0,0 +1,150 @@
+#include "testcases.h"
+
+struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
+				size_t resv_sz, size_t *offset)
+{
+	size_t offs = 0;
+	struct _aarch64_ctx *found = NULL;
+
+	if (!head || resv_sz < HDR_SZ)
+		return found;
+
+	do {
+		if (head->magic == magic) {
+			found = head;
+			break;
+		}
+		offs += head->size;
+		head = GET_RESV_NEXT_HEAD(head);
+	} while (offs < resv_sz - HDR_SZ);
+
+	if (offset)
+		*offset = offs;
+
+	return found;
+}
+
+bool validate_extra_context(struct extra_context *extra, char **err)
+{
+	struct _aarch64_ctx *term;
+
+	if (!extra || !err)
+		return false;
+
+	fprintf(stderr, "Validating EXTRA...\n");
+	term = GET_RESV_NEXT_HEAD(extra);
+	if (!term || term->magic || term->size) {
+		*err = "UN-Terminated EXTRA context";
+		return false;
+	}
+	if (extra->datap & 0x0fUL)
+		*err = "Extra DATAP misaligned";
+	else if (extra->size & 0x0fUL)
+		*err = "Extra SIZE misaligned";
+	else if (extra->datap != (uint64_t)term + sizeof(*term))
+		*err = "Extra DATAP misplaced (not contiguos)";
+	if (*err)
+		return false;
+
+	return true;
+}
+
+bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
+{
+	bool terminated = false;
+	size_t offs = 0;
+	int flags = 0;
+	struct extra_context *extra = NULL;
+	struct _aarch64_ctx *head =
+		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
+
+	if (!err)
+		return false;
+	/* Walk till the end terminator verifying __reserved contents */
+	while (head && !terminated && offs < resv_sz) {
+		if ((uint64_t)head & 0x0fUL) {
+			*err = "Misaligned HEAD";
+			return false;
+		}
+
+		switch (head->magic) {
+			case 0:
+				if (head->size)
+					*err = "Bad size for MAGIC0";
+				else
+					terminated = true;
+				break;
+			case FPSIMD_MAGIC:
+				if (flags & FPSIMD_CTX)
+					*err = "Multiple FPSIMD_MAGIC";
+				else if (head->size !=
+					 sizeof(struct fpsimd_context))
+					*err = "Bad size for fpsimd_context";
+				flags |= FPSIMD_CTX;
+				break;
+			case ESR_MAGIC:
+				if (head->size != sizeof(struct esr_context))
+					fprintf(stderr,
+						"Bad size for esr_context is not an error...just ignore.\n");
+				break;
+			case SVE_MAGIC:
+				if (flags & SVE_CTX)
+					*err = "Multiple SVE_MAGIC";
+				else if (head->size !=
+					 sizeof(struct sve_context))
+					*err = "Bad size for sve_context";
+				flags |= SVE_CTX;
+				break;
+			case EXTRA_MAGIC:
+				if (flags & EXTRA_CTX)
+					*err = "Multiple EXTRA_MAGIC";
+				else if (head->size !=
+					 sizeof(struct extra_context))
+					*err = "Bad size for extra_context";
+				flags |= EXTRA_CTX;
+				extra = (struct extra_context *)head;
+				break;
+			case KSFT_BAD_MAGIC:
+				/*
+				 * This is a BAD magic header defined
+				 * artificially by a testcase and surely
+				 * unknown to the Kernel parse_user_sigframe().
+				 * It MUST cause a Kernel induced SEGV
+				 */
+				*err = "BAD MAGIC !";
+				break;
+			default:
+				/*
+				 * A still unknown Magic: potentially freshly added
+				 * to the Kernel code and still unknown to the
+				 * tests.
+				 */
+				fprintf(stdout,
+					"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
+					head->magic);
+				break;
+		}
+
+		if (*err)
+			return false;
+
+		offs += head->size;
+		if (resv_sz - offs < sizeof(*head)) {
+			*err = "HEAD Overrun";
+			return false;
+		}
+
+		if (flags & EXTRA_CTX)
+			if (!validate_extra_context(extra, err))
+				return false;
+
+		head = GET_RESV_NEXT_HEAD(head);
+	}
+
+	if (terminated && !(flags & FPSIMD_CTX)) {
+		*err = "Missing FPSIMD";
+		return false;
+	}
+
+	return true;
+}
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
new file mode 100644
index 000000000000..624717c71b1d
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
@@ -0,0 +1,83 @@
+#ifndef __TESTCASES_H__
+#define __TESTCASES_H__
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <ucontext.h>
+#include <assert.h>
+
+/* Architecture specific sigframe definitions */
+#include <asm/sigcontext.h>
+
+#define FPSIMD_CTX	(1 << 0)
+#define SVE_CTX		(1 << 1)
+#define EXTRA_CTX	(1 << 2)
+
+#define KSFT_BAD_MAGIC	0xdeadbeef
+
+#define HDR_SZ \
+	sizeof(struct _aarch64_ctx)
+
+#define GET_SF_RESV_HEAD(sf) \
+	(struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
+
+#define GET_SF_RESV_SIZE(sf) \
+	sizeof((sf).uc.uc_mcontext.__reserved)
+
+#define GET_UCP_RESV_SIZE(ucp) \
+	sizeof((ucp)->uc_mcontext.__reserved)
+
+#define ASSERT_BAD_CONTEXT(uc) do {					\
+	char *err = NULL;						\
+	assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
+	if (err)							\
+		fprintf(stderr,						\
+			"Using badly built context - ERR: %s\n", err);	\
+} while(0)
+
+#define ASSERT_GOOD_CONTEXT(uc) do {					 \
+	char *err = NULL;						 \
+	if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) {	 \
+		if (err)						 \
+			fprintf(stderr,					 \
+				"Detected BAD context - ERR: %s\n", err);\
+		assert(0);						 \
+	} else {							 \
+		fprintf(stderr, "uc context validated.\n");		 \
+	}								 \
+} while(0)
+
+/* head->size accounts both for payload and header _aarch64_ctx size ! */
+#define GET_RESV_NEXT_HEAD(h) \
+	(struct _aarch64_ctx *)((char *)(h) + (h)->size)
+
+struct fake_sigframe {
+	siginfo_t	info;
+	ucontext_t	uc;
+};
+
+
+bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
+
+bool validate_extra_context(struct extra_context *extra, char **err);
+
+struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
+				size_t resv_sz, size_t *offset);
+
+static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
+						  size_t resv_sz,
+						  size_t *offset)
+{
+	return get_header(head, 0, resv_sz, offset);
+}
+
+static inline void write_terminator_record(struct _aarch64_ctx *tail)
+{
+	if (tail) {
+		tail->magic = 0;
+		tail->size = 0;
+	}
+}
+#endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 03/11] kselftest: arm64: mangle_pstate_invalid_daif_bits
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
  2019-08-02 17:02 ` [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code Cristian Marussi
  2019-08-02 17:02 ` [PATCH v3 02/11] kselftest: arm64: adds first test and common utils Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:24   ` Dave Martin
  2019-08-02 17:02 ` [PATCH v3 04/11] kselftest: arm64: mangle_pstate_invalid_mode_el Cristian Marussi
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a simple mangle testcase which messes with the ucontext_t
from within the sig_handler, trying to set PSTATE DAIF bits to an
invalid value (masking everything). Expects SIGSEGV on test PASS.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 .../arm64/signal/testcases/.gitignore         |  1 +
 .../mangle_pstate_invalid_daif_bits.c         | 28 +++++++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c

diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 8651272e3cfc..8a0a29f0cc2a 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -1 +1,2 @@
 mangle_pstate_invalid_compat_toggle
+mangle_pstate_invalid_daif_bits
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
new file mode 100644
index 000000000000..af899d4bb655
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+				     ucontext_t *uc)
+{
+	ASSERT_GOOD_CONTEXT(uc);
+
+	/*
+	 * This config should trigger a SIGSEGV by Kernel when it checks
+	 * the sigframe consistency in valid_user_regs() routine.
+	 */
+	uc->uc_mcontext.pstate |= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT;
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.sanity_disabled = true,
+		.name = "MANGLE_PSTATE_INVALID_DAIF_BITS",
+		.descr = "Mangling uc_mcontext with INVALID DAIF_BITS",
+		.sig_trig = SIGUSR1,
+		.sig_ok = SIGSEGV,
+		.run = mangle_invalid_pstate_run,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 04/11] kselftest: arm64: mangle_pstate_invalid_mode_el
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (2 preceding siblings ...)
  2019-08-02 17:02 ` [PATCH v3 03/11] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:24   ` Dave Martin
  2019-08-02 17:02 ` [PATCH v3 05/11] kselftest: arm64: mangle_pstate_ssbs_regs Cristian Marussi
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added 3 simple mangle testcases that mess with the ucontext_t
from within the sig_handler, trying to toggle PSTATE mode bits to
trick the system into switching to EL1/EL2/EL3. Expects SIGSEGV
on test PASS.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 .../arm64/signal/testcases/.gitignore         |  3 ++
 .../mangle_pstate_invalid_mode_el1.c          | 29 +++++++++++++++++++
 .../mangle_pstate_invalid_mode_el2.c          | 29 +++++++++++++++++++
 .../mangle_pstate_invalid_mode_el3.c          | 29 +++++++++++++++++++
 4 files changed, 90 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c

diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 8a0a29f0cc2a..226bb179b673 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -1,2 +1,5 @@
 mangle_pstate_invalid_compat_toggle
 mangle_pstate_invalid_daif_bits
+mangle_pstate_invalid_mode_el1
+mangle_pstate_invalid_mode_el2
+mangle_pstate_invalid_mode_el3
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
new file mode 100644
index 000000000000..07aed7624383
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+				     ucontext_t *uc)
+{
+	ASSERT_GOOD_CONTEXT(uc);
+
+	/*
+	 * This config should trigger a SIGSEGV by Kernel
+	 * when checking valid_user_regs()
+	 */
+	uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+	uc->uc_mcontext.pstate |= PSR_MODE_EL1t;
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.sanity_disabled = true,
+		.name = "MANGLE_PSTATE_INVALID_MODE_EL1t",
+		.descr = "Mangling uc_mcontext with INVALID MODE EL1t",
+		.sig_trig = SIGUSR1,
+		.sig_ok = SIGSEGV,
+		.run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
new file mode 100644
index 000000000000..0fe7f69efb33
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+				     ucontext_t *uc)
+{
+	ASSERT_GOOD_CONTEXT(uc);
+
+	/*
+	 * This config should trigger a SIGSEGV by Kernel
+	 * when checking valid_user_regs()
+	 */
+	uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+	uc->uc_mcontext.pstate |= PSR_MODE_EL2t;
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.sanity_disabled = true,
+		.name = "MANGLE_PSTATE_INVALID_MODE_EL2t",
+		.descr = "Mangling uc_mcontext with INVALID MODE EL2t",
+		.sig_trig = SIGUSR1,
+		.sig_ok = SIGSEGV,
+		.run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
new file mode 100644
index 000000000000..61131dd6ca0c
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+				     ucontext_t *uc)
+{
+	ASSERT_GOOD_CONTEXT(uc);
+
+	/*
+	 * This config should trigger a SIGSEGV by Kernel
+	 * when checking valid_user_regs()
+	 */
+	uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+	uc->uc_mcontext.pstate |= PSR_MODE_EL3t;
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.sanity_disabled = true,
+		.name = "MANGLE_PSTATE_INVALID_MODE_EL3t",
+		.descr = "Mangling uc_mcontext with INVALID MODE EL3t",
+		.sig_trig = SIGUSR1,
+		.sig_ok = SIGSEGV,
+		.run = mangle_invalid_pstate_run,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 05/11] kselftest: arm64: mangle_pstate_ssbs_regs
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (3 preceding siblings ...)
  2019-08-02 17:02 ` [PATCH v3 04/11] kselftest: arm64: mangle_pstate_invalid_mode_el Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:25   ` Dave Martin
  2019-08-02 17:02 ` [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a simple mangle testcase which messes with the ucontext_t
from within the sig_handler, trying to toggle PSTATE SSBS bit.
Expect SIGILL if SSBS feature unsupported or that the value set in
PSTATE.SSBS is preserved on test PASS.

This commit also introduces a new common utility function:
get_current_context() which can be used to grab a ucontext without
the help of libc, and detect if such ucontext has been actively used
to jump back into it.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 .../selftests/arm64/signal/test_signals.h     |  4 +
 .../arm64/signal/test_signals_utils.c         | 93 +++++++++++++++++++
 .../arm64/signal/test_signals_utils.h         |  2 +
 .../arm64/signal/testcases/.gitignore         |  1 +
 .../testcases/mangle_pstate_ssbs_regs.c       | 56 +++++++++++
 5 files changed, 156 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c

diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
index 85db3ac44b32..37bed0590226 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.h
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -116,6 +116,10 @@ struct tdescr {
 	/* optional sa_flags for the installed handler */
 	int		sa_flags;
 	ucontext_t	saved_uc;
+	/* used by get_current_ctx() */
+	size_t		live_sz;
+	ucontext_t	*live_uc;
+	volatile bool	live_uc_valid;
 
 	/* a setup function to be called before test starts */
 	int (*setup)(struct tdescr *td);
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
index ac0055f6340b..faf55ba99d58 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -11,12 +11,16 @@
 #include <linux/auxvec.h>
 #include <ucontext.h>
 
+#include <asm/unistd.h>
+
 #include "test_signals.h"
 #include "test_signals_utils.h"
 #include "testcases/testcases.h"
 
 extern struct tdescr *current;
 
+static int sig_copyctx = SIGUSR2;
+
 static char *feats_store[FMAX_END] = {
 	"SSBS",
 	"PAN",
@@ -37,6 +41,85 @@ static inline char *feats_to_string(unsigned long feats)
 	return feats_string;
 }
 
+/*
+ * Obtaining a valid and full-blown ucontext_t from userspace is tricky:
+ * libc getcontext does() not save all the regs and messes with some of
+ * them (pstate value in particular is not reliable).
+ * Here we use a service signal to grab the ucontext_t from inside a
+ * dedicated signal handler, since there, it is populated by Kernel
+ * itself in setup_sigframe(). The grabbed context is then stored and
+ * made available in td->live_uc.
+ *
+ * Anyway this function really serves a dual purpose:
+ *
+ * 1. grab a valid sigcontext into td->live_uc for result analysis: in
+ * such case it returns 1.
+ *
+ * 2. detect if somehow a previously grabbed live_uc context has been
+ * used actively with a sigreturn: in such a case the execution would have
+ * magically resumed in the middle of the function itself (seen_already==1):
+ * in such a case return 0, since in fact we have not just simply grabbed
+ * the context.
+ *
+ * This latter case is useful to detect when a fake_sigreturn test-case has
+ * unexpectedly survived without hittig a SEGV.
+ */
+bool get_current_context(struct tdescr *td, ucontext_t *dest_uc)
+{
+	static volatile sig_atomic_t seen_already;
+
+	if (!td || !dest_uc) {
+		fprintf(stdout, "Signal-based Context dumping NOT available\n");
+		return 0;
+	}
+
+	/* it's a genuine invokation..reinit */
+	seen_already = 0;
+	td->live_uc_valid = 0;
+	td->live_sz = sizeof(*dest_uc);
+	memset(dest_uc, 0x00, td->live_sz);
+	td->live_uc = dest_uc;
+	/*
+	 * Grab ucontext_t triggering a signal...
+	 * ASM equivalent of raise(sig_copyctx);
+	 *
+	 * Note that:
+	 * - live_uc_valid is declared volatile in struct tdescr
+	 *   since it will be changed inside the sig_copyctx handler.
+	 * - the kill() syscall invocation returns only after any possible
+	 *   registered sig_handler for the invoked signal has returned,
+	 *   so that live_uc_valid flag is surely up to date when this
+	 *   function return it.
+	 * - the additional 'memory' clobber is there to avoid possible
+	 *   compiler's assumption on the content pointed by dest_uc, which
+	 *   is changed inside the handler, but not referenced here anyway.
+	 */
+	asm volatile ("mov x8, %0\n\t"
+		      "svc #0\n\t"
+		      "mov x1, %1\n\t"
+		      "mov x8, %2\n\t"
+		      "svc #0"
+		      :
+		      : "i" (__NR_getpid),
+		        "r" (sig_copyctx),
+			"i" (__NR_kill)
+		      : "x1","x8","x0","memory");
+	/*
+	 * If we get here with seen_already==1 it implies the td->live_uc
+	 * context has been used to get back here....this probably means
+	 * a test has failed to cause a SEGV...anyway the live_uc has not
+	 * just been acquired...so return 0
+	 */
+	if (seen_already) {
+		fprintf(stdout,
+			"Successful sigreturn detected: live_uc is stale !\n");
+		return 0;
+	}
+	seen_already = 1;
+
+	return td->live_uc_valid;
+}
+
 static void unblock_signal(int signum)
 {
 	sigset_t sset;
@@ -112,6 +195,12 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
 		 * to terminate immediately exiting straight away
 		 */
 		default_result(current, 1);
+	} else if (signum == sig_copyctx && current->live_uc) {
+		memcpy(current->live_uc, uc, current->live_sz);
+		ASSERT_GOOD_CONTEXT(current->live_uc);
+		current->live_uc_valid = 1;
+		fprintf(stderr,
+			"GOOD CONTEXT grabbed from sig_copyctx handler\n");
 	} else {
 		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
 			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
@@ -214,6 +303,10 @@ static int test_init(struct tdescr *td)
 			!feats_ok ? "NOT " : "");
 	}
 
+	if (td->sig_trig == sig_copyctx)
+		sig_copyctx = SIGUSR1;
+	unblock_signal(sig_copyctx);
+
 	td->initialized = 1;
 	return 1;
 }
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index 8658d1a7d4b9..ce35be8ebc8e 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -10,4 +10,6 @@ int test_setup(struct tdescr *td);
 void test_cleanup(struct tdescr *td);
 int test_run(struct tdescr *td);
 void test_result(struct tdescr *td);
+
+bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
 #endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 226bb179b673..a48a118b1a1a 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -3,3 +3,4 @@ mangle_pstate_invalid_daif_bits
 mangle_pstate_invalid_mode_el1
 mangle_pstate_invalid_mode_el2
 mangle_pstate_invalid_mode_el3
+mangle_pstate_ssbs_regs
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
new file mode 100644
index 000000000000..a399d9aa40d5
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_ssbs_run(struct tdescr *td,
+					  siginfo_t *si, ucontext_t *uc)
+{
+	ASSERT_GOOD_CONTEXT(uc);
+
+	/* set bit value */
+	uc->uc_mcontext.pstate |= PSR_SSBS_BIT;
+	fprintf(stderr, "SSBS set to 1 -- PSTATE: 0x%016lX\n",
+		uc->uc_mcontext.pstate);
+	/* Save after mangling...it should be preserved */
+	td->saved_uc = *uc;
+
+	return 1;
+}
+
+static void pstate_ssbs_bit_checks(struct tdescr *td)
+{
+	uint64_t val = 0;
+	ucontext_t uc;
+
+	/* This check reports some result even if MRS SSBS unsupported */
+	if (get_current_context(td, &uc))
+		fprintf(stderr,
+			"INFO: live_uc - got PSTATE: 0x%016lX -> SSBS %s\n",
+			uc.uc_mcontext.pstate,
+			(td->saved_uc.uc_mcontext.pstate & PSR_SSBS_BIT) ==
+			(uc.uc_mcontext.pstate & PSR_SSBS_BIT) ?
+			"PRESERVED" : "CLEARED");
+
+	fprintf(stderr, "Checking with MRS SSBS...\n");
+	get_regval(S3_MRS_SSBS_SYSREG, val);
+	fprintf(stderr, "INFO: MRS SSBS - got: 0x%016lX\n", val);
+	/* pass when preserved */
+	td->pass = (val & PSR_SSBS_BIT) ==
+		   (td->saved_uc.uc_mcontext.pstate & PSR_SSBS_BIT);
+}
+
+struct tdescr tde = {
+		.sanity_disabled = true,
+		.name = "MANGLE_PSTATE_SSBS_REGS",
+		.descr = "Mangling uc_mcontext changing SSBS.(PRESERVE)",
+		.feats_required = FEAT_SSBS,
+		.sig_trig = SIGUSR1,
+		.sig_unsupp = SIGILL,
+		.run = mangle_invalid_pstate_ssbs_run,
+		.check_result = pstate_ssbs_bit_checks,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (4 preceding siblings ...)
  2019-08-02 17:02 ` [PATCH v3 05/11] kselftest: arm64: mangle_pstate_ssbs_regs Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:25   ` Dave Martin
  2019-08-02 17:02 ` [PATCH v3 07/11] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a simple fake_sigreturn testcase which builds a ucontext_t
with a bad magic header and place it onto the stack.
Expects a SIGSEGV on test PASS.
This commit also introduces a common utility assembly function to
invoke a sigreturn using a fake provided sigframe.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 tools/testing/selftests/arm64/signal/Makefile |  2 +-
 .../testing/selftests/arm64/signal/signals.S  | 64 +++++++++++++++++++
 .../arm64/signal/test_signals_utils.h         |  1 +
 .../arm64/signal/testcases/.gitignore         |  1 +
 .../testcases/fake_sigreturn_bad_magic.c      | 63 ++++++++++++++++++
 5 files changed, 130 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/arm64/signal/signals.S
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c

diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
index 8c8d08be4b0d..b3dcf315b5a4 100644
--- a/tools/testing/selftests/arm64/signal/Makefile
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -80,7 +80,7 @@ endif
 # 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
+$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c signals.S $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
 	@if [ ! -d $(khdr_dir) ]; then \
 		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
 		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
new file mode 100644
index 000000000000..6262b877400b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/signals.S
@@ -0,0 +1,64 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright (C) 2019 ARM Limited
+ */
+
+#include <asm/unistd.h>
+
+.section        ".rodata", "a"
+call_fmt:
+	.asciz "Calling sigreturn with fake sigframe sized:%zd at calculated SP @%08lX\n"
+
+.text
+
+.globl fake_sigreturn
+
+/*	fake_sigreturn	x0:&sigframe,  x1:sigframe_size,  x2:alignment_SP */
+fake_sigreturn:
+	mov x20, x0
+	mov x21, x1
+	mov x22, x2
+	mov x23, sp
+
+	/* create space on the stack for fake sigframe..."x22"-aligned */
+	mov x0, #0
+	add x0, x21, x22
+	sub x22, x22, #1
+	bic x0, x0, x22
+	sub x23, x23, x0
+
+	ldr x0, =call_fmt
+	mov x1, x21
+	mov x2, x23
+	bl printf
+
+	mov sp, x23
+
+	/* now fill it with the provided content... */
+	mov x0, sp
+	mov x1, x20
+	mov x2, x21
+	bl memcpy
+
+	/*
+	 * Here saving a last minute SP to current->token acts as a marker:
+	 * if we got here, we are successfully faking a sigreturn; in other
+	 * words we are sure no bad fatal signal has been raised till now
+	 * for unrelated reasons, so we should consider the possibl observed
+	 * fatal signal like SEGV coming from Kernel restore_sigframe() and
+	 * triggered as expected from our test-case.
+	 * For simplicity this assumes that current field 'token' is laid out
+	 * as first in struct tdescr
+	 */
+	ldr x0, current
+	str x23, [x0]
+	/* SP is already pointing back to the just built fake sigframe here */
+	mov x8, #__NR_rt_sigreturn
+	svc #0
+
+	/*
+	 * Above sigreturn should not return...looping here leads to a timeout
+	 * and ensure proper and clean test failure, instead of jumping around
+	 * on a potentially corrupted stack.
+	 */
+	b .
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index ce35be8ebc8e..2a71da7e6695 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -12,4 +12,5 @@ int test_run(struct tdescr *td);
 void test_result(struct tdescr *td);
 
 bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
+int fake_sigreturn(void *sigframe, size_t sz, int alignment);
 #endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index a48a118b1a1a..0ea6fdc3765c 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -4,3 +4,4 @@ mangle_pstate_invalid_mode_el1
 mangle_pstate_invalid_mode_el2
 mangle_pstate_invalid_mode_el3
 mangle_pstate_ssbs_regs
+fake_sigreturn_bad_magic
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
new file mode 100644
index 000000000000..b4c063e02a7a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_bad_magic_run(struct tdescr *td,
+					siginfo_t *si, ucontext_t *uc)
+{
+	size_t resv_sz, offset;
+	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+	/* just to fill the ucontext_t with something real */
+	if (!get_current_context(td, &sf.uc))
+		return 1;
+
+	resv_sz = GET_SF_RESV_SIZE(sf);
+	/*
+	 * find the terminator, preserving existing headers
+	 * and verify amount of spare room in __reserved area.
+	 */
+	head = get_terminator(shead, resv_sz, &offset);
+	/*
+	 * try stripping extra_context header when low on space:
+	 * we need at least 2*HDR_SZ space ... one for the KSFT_BAD_MAGIC
+	 * and the other for the usual terminator.
+	 */
+	if (head && resv_sz - offset < HDR_SZ * 2) {
+		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+			resv_sz - offset);
+		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+	}
+	/* just give up and timeout if still not enough space */
+	if (head && resv_sz - offset >= HDR_SZ) {
+		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+			resv_sz - offset);
+		/*
+		 * use a well known NON existent bad magic...something
+		 * we should pretty sure won't be ever defined in Kernel
+		 */
+		head->magic = KSFT_BAD_MAGIC;
+		head->size = HDR_SZ;
+		write_terminator_record(GET_RESV_NEXT_HEAD(head));
+
+		ASSERT_BAD_CONTEXT(&sf.uc);
+		fake_sigreturn(&sf, sizeof(sf), 16);
+	}
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.name = "FAKE_SIGRETURN_BAD_MAGIC",
+		.descr = "Triggers a fake sigreturn with a sigframe including a bad non-existent magic",
+		.sig_ok = SIGSEGV,
+		.timeout = 3,
+		.run = fake_sigreturn_bad_magic_run,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 07/11] kselftest: arm64: fake_sigreturn_bad_size_for_magic0
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (5 preceding siblings ...)
  2019-08-02 17:02 ` [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:25   ` Dave Martin
  2019-08-02 17:02 ` [PATCH v3 08/11] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a simple fake_sigreturn testcase which builds a ucontext_t
with a badly sized magic0 header and place it onto the stack.
Expects a SIGSEGV on test PASS.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 .../arm64/signal/testcases/.gitignore         |  1 +
 .../fake_sigreturn_bad_size_for_magic0.c      | 57 +++++++++++++++++++
 2 files changed, 58 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c

diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 0ea6fdc3765c..cf2a73599818 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -5,3 +5,4 @@ mangle_pstate_invalid_mode_el2
 mangle_pstate_invalid_mode_el3
 mangle_pstate_ssbs_regs
 fake_sigreturn_bad_magic
+fake_sigreturn_bad_size_for_magic0
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
new file mode 100644
index 000000000000..2f53c4740c85
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+#define MIN_SZ_ALIGN	16
+
+static int fake_sigreturn_bad_size_for_magic0_run(struct tdescr *td,
+						  siginfo_t *si, ucontext_t *uc)
+{
+	size_t resv_sz, offset;
+	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+	/* just to fill the ucontext_t with something real */
+	if (!get_current_context(td, &sf.uc))
+		return 1;
+
+	resv_sz = GET_SF_RESV_SIZE(sf);
+	/*
+	 * find the terminator, preserving existing headers
+	 * and verify amount of spare room in __reserved area.
+	 */
+	head = get_terminator(shead, resv_sz, &offset);
+	/*
+	 * try stripping extra_context header when low on space:
+	 * we need at least HDR_SZ + 16 space for the bad sized terminator.
+	 */
+	if (head && resv_sz - offset < HDR_SZ + MIN_SZ_ALIGN) {
+		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+			resv_sz - offset);
+		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+	}
+	/* just give up and timeout if still not enough space */
+	if (head && resv_sz - offset >= HDR_SZ + MIN_SZ_ALIGN) {
+		head->magic = 0;
+		head->size = MIN_SZ_ALIGN;
+
+		ASSERT_BAD_CONTEXT(&sf.uc);
+		fake_sigreturn(&sf, sizeof(sf), 16);
+	}
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.name = "FAKE_SIGRETURN_BAD_SIZE_FOR_MAGIC0",
+		.descr = "Triggers a fake sigreturn with a sigframe including a bad non-zero size magic0",
+		.sig_ok = SIGSEGV,
+		.timeout = 3,
+		.run = fake_sigreturn_bad_size_for_magic0_run,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 08/11] kselftest: arm64: fake_sigreturn_missing_fpsimd
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (6 preceding siblings ...)
  2019-08-02 17:02 ` [PATCH v3 07/11] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:26   ` Dave Martin
  2019-08-02 17:02 ` [PATCH v3 09/11] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a simple fake_sigreturn testcase which builds a ucontext_t
without the required fpsimd_context and place it onto the stack.
Expects a SIGSEGV on test PASS.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 .../arm64/signal/testcases/.gitignore         |  1 +
 .../testcases/fake_sigreturn_missing_fpsimd.c | 44 +++++++++++++++++++
 2 files changed, 45 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c

diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index cf2a73599818..17d1c5e73319 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -6,3 +6,4 @@ mangle_pstate_invalid_mode_el3
 mangle_pstate_ssbs_regs
 fake_sigreturn_bad_magic
 fake_sigreturn_bad_size_for_magic0
+fake_sigreturn_missing_fpsimd
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
new file mode 100644
index 000000000000..b8dd57ce6844
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_missing_fpsimd_run(struct tdescr *td,
+					     siginfo_t *si, ucontext_t *uc)
+{
+	size_t resv_sz, offset;
+	struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
+
+	/* just to fill the ucontext_t with something real */
+	if (!get_current_context(td, &sf.uc))
+		return 1;
+
+	resv_sz = GET_SF_RESV_SIZE(sf);
+	head = get_header(head, FPSIMD_MAGIC, resv_sz, &offset);
+	/* just give up and timeout if still not enough space */
+	if (head && resv_sz - offset >= HDR_SZ) {
+		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+			resv_sz - offset);
+		/* Just overwrite fpsmid_context */
+		write_terminator_record(head);
+
+		ASSERT_BAD_CONTEXT(&sf.uc);
+		fake_sigreturn(&sf, sizeof(sf), 16);
+	}
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.name = "FAKE_SIGRETURN_MISSING_FPSIMD",
+		.descr = "Triggers a fake sigreturn with a sigframe missing the mandatory fpsimd_context",
+		.sig_ok = SIGSEGV,
+		.timeout = 3,
+		.run = fake_sigreturn_missing_fpsimd_run,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 09/11] kselftest: arm64: fake_sigreturn_duplicated_fpsimd
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (7 preceding siblings ...)
  2019-08-02 17:02 ` [PATCH v3 08/11] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:26   ` Dave Martin
  2019-08-02 17:02 ` [PATCH v3 10/11] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a simple fake_sigreturn testcase which builds a ucontext_t
with an anomalous additional fpsimd_context and place it onto the stack.
Expects a SIGSEGV on test PASS.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 .../arm64/signal/testcases/.gitignore         |  1 +
 .../fake_sigreturn_duplicated_fpsimd.c        | 62 +++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c

diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 17d1c5e73319..94f9baaf638c 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -7,3 +7,4 @@ mangle_pstate_ssbs_regs
 fake_sigreturn_bad_magic
 fake_sigreturn_bad_size_for_magic0
 fake_sigreturn_missing_fpsimd
+fake_sigreturn_duplicated_fpsimd
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
new file mode 100644
index 000000000000..09af7a0f8776
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_duplicated_fpsimd_run(struct tdescr *td,
+						siginfo_t *si, ucontext_t *uc)
+{
+	size_t resv_sz, offset;
+	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+	/* just to fill the ucontext_t with something real */
+	if (!get_current_context(td, &sf.uc))
+		return 1;
+
+	resv_sz = GET_SF_RESV_SIZE(sf);
+	/*
+	 * find the terminator, preserving existing headers
+	 * and verify amount of spare room in __reserved area.
+	 */
+	head = get_terminator(shead, resv_sz, &offset);
+	/*
+	 * try stripping extra_context header when low on space:
+	 * we need at least space for one additional fpsimd_context
+	 */
+	if (head && resv_sz - offset < sizeof(struct fpsimd_context)) {
+		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+			resv_sz - offset);
+		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+	}
+
+	/* just give up and timeout if still not enough space */
+	if (head &&
+	    resv_sz - offset >= sizeof(struct fpsimd_context) + HDR_SZ) {
+		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+			resv_sz - offset);
+		/* Add a spurios fpsimd_context */
+		head->magic = FPSIMD_MAGIC;
+		head->size = sizeof(struct fpsimd_context);
+		/* and terminate */
+		write_terminator_record(GET_RESV_NEXT_HEAD(head));
+
+		ASSERT_BAD_CONTEXT(&sf.uc);
+		fake_sigreturn(&sf, sizeof(sf), 16);
+	}
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.name = "FAKE_SIGRETURN_DUPLICATED_FPSIMD",
+		.descr = "Triggers a fake sigreturn with a sigframe including two fpsimd_context",
+		.sig_ok = SIGSEGV,
+		.timeout = 3,
+		.run = fake_sigreturn_duplicated_fpsimd_run,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 10/11] kselftest: arm64: fake_sigreturn_bad_size
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (8 preceding siblings ...)
  2019-08-02 17:02 ` [PATCH v3 09/11] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
@ 2019-08-02 17:02 ` Cristian Marussi
  2019-08-13 16:26   ` Dave Martin
  2019-08-02 17:03 ` [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp Cristian Marussi
  2019-08-13 16:22 ` [PATCH v3 00/11] Add arm64/signal initial kselftest support Dave Martin
  11 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a simple fake_sigreturn testcase which builds a ucontext_t
with a badly sized header that causes a overrun in the __reserved
area and place it onto the stack. Expects a SIGSEGV on test PASS.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
 .../arm64/signal/testcases/.gitignore         |  1 +
 .../testcases/fake_sigreturn_bad_size.c       | 85 +++++++++++++++++++
 2 files changed, 86 insertions(+)
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c

diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 94f9baaf638c..3408e0f5ba98 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -8,3 +8,4 @@ fake_sigreturn_bad_magic
 fake_sigreturn_bad_size_for_magic0
 fake_sigreturn_missing_fpsimd
 fake_sigreturn_duplicated_fpsimd
+fake_sigreturn_bad_size
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
new file mode 100644
index 000000000000..1467fb534d8b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+#define MIN_SZ_ALIGN	16
+
+static int fake_sigreturn_bad_size_run(struct tdescr *td,
+				       siginfo_t *si, ucontext_t *uc)
+{
+	size_t resv_sz, need_sz, offset;
+	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+	/* just to fill the ucontext_t with something real */
+	if (!get_current_context(td, &sf.uc))
+		return 1;
+
+	resv_sz = GET_SF_RESV_SIZE(sf);
+	/*
+	 * find the terminator, preserving existing headers
+	 * and verify amount of spare room in __reserved area.
+	 */
+	head = get_terminator(shead, resv_sz, &offset);
+	/*
+	 * try stripping extra_context header when low on space:
+	 * we need at least  for the bad sized esr_context.
+	 */
+	need_sz = HDR_SZ + sizeof(struct esr_context);
+	if (head && resv_sz - offset < need_sz) {
+		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+			resv_sz - offset);
+		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+	}
+	/* just give up and timeout if still not enough space */
+	if (head && resv_sz - offset >= need_sz) {
+		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+			resv_sz - offset);
+		/*
+		 * Use an esr_context to build a fake header with a
+		 * size greater then the free __reserved area minus HDR_SZ;
+		 * using ESR_MAGIC here since it is not checked for size nor
+		 * is limited to one instance.
+		 *
+		 * At first inject an additional normal esr_context
+		 */
+		head->magic = ESR_MAGIC;
+		head->size = sizeof(struct esr_context);
+		/* and terminate properly */
+		write_terminator_record(GET_RESV_NEXT_HEAD(head));
+		ASSERT_GOOD_CONTEXT(&sf.uc);
+
+		/*
+		 * now mess with fake esr_context size: leaving less space than
+		 * neededwhile keeping size value 16-aligned
+		 *
+		 * It must trigger a SEGV from Kernel on:
+		 *
+		 *	resv_sz - offset < sizeof(*head)
+		 */
+		/* at first set the maximum good 16-aligned size */
+		head->size = (resv_sz - offset - need_sz + MIN_SZ_ALIGN) & ~0xfUL;
+		/* plus a bit more of 16-aligned sized stuff */
+		head->size += MIN_SZ_ALIGN;
+		/* and terminate properly */
+		write_terminator_record(GET_RESV_NEXT_HEAD(head));
+		ASSERT_BAD_CONTEXT(&sf.uc);
+		fake_sigreturn(&sf, sizeof(sf), 16);
+	}
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.name = "FAKE_SIGRETURN_BAD_SIZE",
+		.descr = "Triggers a fake sigreturn with a sigframe including a badly sized header which overruns the __reserved area",
+		.sig_ok = SIGSEGV,
+		.timeout = 3,
+		.run = fake_sigreturn_bad_size_run,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (9 preceding siblings ...)
  2019-08-02 17:02 ` [PATCH v3 10/11] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
@ 2019-08-02 17:03 ` Cristian Marussi
  2019-08-07 16:04   ` Cristian Marussi
  2019-08-13 16:27   ` Dave Martin
  2019-08-13 16:22 ` [PATCH v3 00/11] Add arm64/signal initial kselftest support Dave Martin
  11 siblings, 2 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-02 17:03 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin

Added a simple fake_sigreturn testcase which places a valid
sigframe on a non-16 bytes aligned SP.
fake_sigretrun() helper function has been patched accordingly
to support placing a sigframe on a non-16 bytes aligned address.
Expects a SIGSEGV on test PASS.

Adds also a test TODO lists holding some further test ideas.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
Re-added this text after fixing the forced misaglinment procedure in
fake_sigreturn() itself: require a ZERO alignment and you'll get
your sigframe placed on a misaligned SP (2-bytes off the 16-align)
---
 .../testing/selftests/arm64/signal/signals.S  | 21 +++++++++----
 .../arm64/signal/testcases/TODO.readme        |  8 +++++
 .../testcases/fake_sigreturn_misaligned_sp.c  | 30 +++++++++++++++++++
 3 files changed, 53 insertions(+), 6 deletions(-)
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
 create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c

diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
index 6262b877400b..2099871176ed 100644
--- a/tools/testing/selftests/arm64/signal/signals.S
+++ b/tools/testing/selftests/arm64/signal/signals.S
@@ -13,19 +13,28 @@ call_fmt:
 
 .globl fake_sigreturn
 
-/*	fake_sigreturn	x0:&sigframe,  x1:sigframe_size,  x2:alignment_SP */
+/*	fake_sigreturn	x0:&sigframe, x1:sigframe_sz, x2:align */
 fake_sigreturn:
-	mov x20, x0
-	mov x21, x1
-	mov x22, x2
-	mov x23, sp
 
-	/* create space on the stack for fake sigframe..."x22"-aligned */
+	/* Save args and decide which aligment to enforce */
+	mov 	x23, sp
+	mov	x20, x0
+	mov 	x21, x1
+	/* x22 and x24 used for forcing alignment or misalignment */
+	mov	x22, x2
+	mov	x24, #0
+	cbnz	x22, 1f
+	mov	x22, #16
+	mov	x24, #2
+
+1:	/* create space on the stack for fake sigframe..."x22"-aligned */
 	mov x0, #0
 	add x0, x21, x22
 	sub x22, x22, #1
 	bic x0, x0, x22
 	sub x23, x23, x0
+	/* force misaligned by x24 bytes if required alignment was zero */
+	add x23, x23, x24
 
 	ldr x0, =call_fmt
 	mov x1, x21
diff --git a/tools/testing/selftests/arm64/signal/testcases/TODO.readme b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
new file mode 100644
index 000000000000..5c949492e7ab
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
@@ -0,0 +1,8 @@
+Some more possible ideas for signals tests:
+
+- fake_sigreturn_unmapped_sp
+- fake_sigreturn_kernelspace_sp
+- fake_sigreturn_sve_bad_extra_context
+- mangle_sve_invalid_extra_context
+- mangle_pstate_invalid_el for H modes (+ macroization ?)
+- fake_sigreturn_overflow_reserved
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
new file mode 100644
index 000000000000..3ee8c500c7d1
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_misaligned_run(struct tdescr *td,
+				         siginfo_t *si, ucontext_t *uc)
+{
+	/* just to fill the ucontext_t with something real */
+	if (!get_current_context(td, &sf.uc))
+		return 1;
+
+	/* Forcing sigframe on misaligned (=!16) SP */
+	fake_sigreturn(&sf, sizeof(sf), 0);
+
+	return 1;
+}
+
+struct tdescr tde = {
+		.name = "FAKE_SIGRETURN_MISALIGNED_SP",
+		.descr = "Triggers a fake sigreturn with a misaligned sigframe on SP",
+		.sig_ok = SIGSEGV,
+		.timeout = 3,
+		.run = fake_sigreturn_misaligned_run,
+};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-02 17:02 ` [PATCH v3 02/11] kselftest: arm64: adds first test and common utils Cristian Marussi
@ 2019-08-06 15:50   ` Cristian Marussi
  2019-08-07 15:42   ` Cristian Marussi
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-06 15:50 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel; +Cc: dave.martin

Hi

On 02/08/2019 18:02, Cristian Marussi wrote:
> Added some arm64/signal specific boilerplate and utility code to help
> further testcase development.
> 
> A simple testcase and related helpers are also introduced in this commit:
> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
> messes with the ucontext_t from within the sig_handler, trying to toggle
> PSTATE state bits to switch the system between 32bit/64bit execution state.
> Expects SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> A few fixes:
> - test_arm64_signals.sh runner script generation has been reviewed in order to
>   be safe against the .gitignore
> - using kselftest.h officially provided defines for tests' return values
> - removed SAFE_WRITE()/dump_uc()
> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>   the sigfault had been directly triggered by Kernel
> ---
>  tools/testing/selftests/arm64/Makefile        |   2 +-
>  .../testing/selftests/arm64/signal/.gitignore |   6 +
>  tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>  tools/testing/selftests/arm64/signal/README   |  59 ++++
>  .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>  .../selftests/arm64/signal/test_signals.c     |  26 ++
>  .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>  .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>  .../arm64/signal/test_signals_utils.h         |  13 +
>  .../arm64/signal/testcases/.gitignore         |   1 +
>  .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>  .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>  .../arm64/signal/testcases/testcases.h        |  83 ++++++
>  13 files changed, 905 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>  create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>  create mode 100644 tools/testing/selftests/arm64/signal/README
>  create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
> 

One known issue with this patch, which I've just discovered once I upgraded my local toolchain,
is a missing include and a feature_test_macros needed by testcases.h (related to to siginfo_t)
like in:

diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
index 624717c71b1d..80831ffc0bbd 100644
--- a/tools/testing/selftests/arm64/signal/testcases/testcases.h
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
@@ -7,6 +7,7 @@
 #include <unistd.h>
 #include <ucontext.h>
 #include <assert.h>
+#include <signal.h>
 
 /* Architecture specific sigframe definitions */
 #include <asm/sigcontext.h>


diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
index b3dcf315b5a4..a32d5656bb20 100644
--- a/tools/testing/selftests/arm64/signal/Makefile
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -16,7 +16,7 @@
 # and standalone builds
 top_srcdir = ../../../../..
 
-CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
+CFLAGS += -D_GNU_SOURCE -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
 SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
 PROGS := $(patsubst %.c,%,$(SRCS))

Cheers

Cristian


> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
> index 03a0d4f71218..af59dc74e0dc 100644
> --- a/tools/testing/selftests/arm64/Makefile
> +++ b/tools/testing/selftests/arm64/Makefile
> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>  ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>  
>  ifeq ("x$(ARCH)", "xarm64")
> -SUBDIRS :=
> +SUBDIRS := signal
>  else
>  SUBDIRS :=
>  endif
> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
> new file mode 100644
> index 000000000000..434f65c15f03
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/.gitignore
> @@ -0,0 +1,6 @@
> +# Helper script's internal testcases list (TPROGS) is regenerated
> +# each time by Makefile on standalone (non KSFT driven) runs.
> +# Committing such list creates a dependency between testcases
> +# patches such that they are no more easily revertable. Just ignore.
> +test_arm64_signals.src_shell
> +test_arm64_signals.sh
> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
> new file mode 100644
> index 000000000000..8c8d08be4b0d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/Makefile
> @@ -0,0 +1,88 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +# Supports also standalone invokation out of KSFT-tree
> +# Compile standalone and run on your device with:
> +#
> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
> +#
> +# Run standalone on device with:
> +#
> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
> +#
> +# If INSTALL_PATH= is NOT provided it will default to ./install
> +
> +# A proper top_srcdir is needed both by KSFT(lib.mk)
> +# and standalone builds
> +top_srcdir = ../../../../..
> +
> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
> +PROGS := $(patsubst %.c,%,$(SRCS))
> +
> +# Guessing as best as we can where the Kernel headers
> +# could have been installed depending on ENV config and
> +# type of invocation.
> +ifeq ($(KBUILD_OUTPUT),)
> +khdr_dir = $(top_srcdir)/usr/include
> +else
> +ifeq (0,$(MAKELEVEL))
> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
> +else
> +# the KSFT preferred location when KBUILD_OUTPUT is set
> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
> +endif
> +endif
> +
> +CFLAGS += -I$(khdr_dir)
> +
> +# Standalone run
> +ifeq (0,$(MAKELEVEL))
> +CC := $(CROSS_COMPILE)gcc
> +RUNNER_SRC = test_arm64_signals.src_shell
> +RUNNER = test_arm64_signals.sh
> +INSTALL_PATH ?= install/
> +
> +all: $(RUNNER)
> +
> +$(RUNNER): $(PROGS)
> +	cp $(RUNNER_SRC) $(RUNNER)
> +	sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
> +
> +install: all
> +	mkdir -p $(INSTALL_PATH)/testcases
> +	cp $(PROGS) $(INSTALL_PATH)/testcases
> +	cp $(RUNNER) $(INSTALL_PATH)/
> +
> +.PHONY clean:
> +	rm -f $(PROGS)
> +# KSFT run
> +else
> +# 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
> +
> +# This include mk 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)
> +endif
> +
> +# 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
> +	@if [ ! -d $(khdr_dir) ]; then \
> +		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
> +		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
> +	fi
> +	$(CC) $(CFLAGS) $^ -o $@
> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
> new file mode 100644
> index 000000000000..53f005f7910a
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/README
> @@ -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 messes-up with the sigframe ucontext_t from
> +    inside the sighandler 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
> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> new file mode 100755
> index 000000000000..163e941e2997
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> @@ -0,0 +1,55 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +ret=0
> +keep_on_fail=0
> +err_out="2> /dev/null"
> +
> +usage() {
> +	echo "Usage: `basename $0` [-v] [-k]"
> +	exit 1
> +}
> +
> +# avoiding getopt to avoid compatibility issues on targets
> +# with limited resources
> +while [ $# -gt 0 ]
> +do
> +	case $1 in
> +		"-k")
> +			keep_on_fail=1
> +			;;
> +		"-v")
> +			err_out=
> +			;;
> +		*)
> +			usage
> +			;;
> +	esac
> +	shift
> +done
> +
> +TPROGS=
> +
> +tot=$(echo $TPROGS | wc -w)
> +
> +# Tests are expected in testcases/ subdir inside the installation path
> +workdir="`dirname $0 2>/dev/null`"
> +[ -n $workdir ] && cd $workdir
> +
> +passed=0
> +run=0
> +for test in $TPROGS
> +do
> +	run=$((run + 1))
> +	eval ./$test $err_out
> +	if [ $? != 0 ]; then
> +		[ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
> +	else
> +		passed=$((passed + 1))
> +	fi
> +done
> +
> +echo "==>> PASSED: $passed/$run on $tot available tests."
> +
> +exit $ret
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
> new file mode 100644
> index 000000000000..3447d7011aec
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <kselftest.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +
> +struct tdescr *current;
> +extern struct tdescr tde;
> +
> +int main(int argc, char *argv[])
> +{
> +	current = &tde;
> +
> +	ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
> +		       current->name, current->descr, current->sig_trig,
> +		       current->sig_ok, current);
> +	if (test_setup(current)) {
> +		if (test_run(current))
> +			test_result(current);
> +		test_cleanup(current);
> +	}
> +
> +	return current->pass ? KSFT_PASS : KSFT_FAIL;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> new file mode 100644
> index 000000000000..85db3ac44b32
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
> @@ -0,0 +1,137 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_H__
> +#define __TEST_SIGNALS_H__
> +
> +#include <assert.h>
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <ucontext.h>
> +#include <stdint.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>
> +
> +/* pasted from include/linux/stringify.h */
> +#define __stringify_1(x...)	#x
> +#define __stringify(x...)	__stringify_1(x)
> +
> +/*
> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
> + * avoid inject any dependency on the used toolchain regarding possibly
> + * still unsupported ARMv8 extensions.
> + *
> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
> + * would introduce a compile-time dependency on possibly unsupported ARMv8
> + * Extensions: you could end-up failing to build the test depending on the
> + * available toolchain.
> + * This is undesirable since some tests, even if specifically targeted at some
> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
> + * it transparently not caring at all about the effective set of supported
> + * features).
> + * On the other side we will expect to observe different behaviours if the
> + * feature is supported or not: usually getting a SIGILL when trying to use
> + * unsupported features. For this reason we have anyway in place some
> + * preliminary run-time checks about the cpu effectively supported features.
> + *
> + * This helper macro is meant to be used for regs readable at EL0, BUT some
> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
> + * if the required reg is included in the supported encoding space:
> + *
> + *  Documentation/arm64/cpu-feature-regsiters.txt
> + *
> + *  "The infrastructure emulates only the following system register space:
> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
> + */
> +#define get_regval(regname, out) \
> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
> +
> +/* Regs encoding and masks naming copied in from sysreg.h */
> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
> +#define ID_AA64MMFR1_PAN_SHIFT	20
> +#define ID_AA64MMFR2_UAO_SHIFT	4
> +
> +/* Local Helpers */
> +#define IS_PAN_SUPPORTED(val) \
> +	(!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
> +#define IS_UAO_SUPPORTED(val) \
> +	(!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
> +
> +#define S3_MRS_SSBS_SYSREG		S3_3_C4_C2_6	/* EL0 supported */
> +
> +/*
> + * Feature flags used in tdescr.feats_required to specify
> + * any feature by the test
> + */
> +enum {
> +	FSSBS_BIT,
> +	FPAN_BIT,
> +	FUAO_BIT,
> +	FMAX_END
> +};
> +
> +#define FEAT_SSBS		(1UL << FSSBS_BIT)
> +#define FEAT_PAN		(1UL << FPAN_BIT)
> +#define FEAT_UAO		(1UL << FUAO_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		feats_ok;
> +	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;
> +
> +	/* a setup function to be called before test starts */
> +	int (*setup)(struct tdescr *td);
> +	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);
> +
> +	void *priv;
> +};
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> new file mode 100644
> index 000000000000..ac0055f6340b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -0,0 +1,261 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <assert.h>
> +#include <sys/auxv.h>
> +#include <linux/auxvec.h>
> +#include <ucontext.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +#include "testcases/testcases.h"
> +
> +extern struct tdescr *current;
> +
> +static char *feats_store[FMAX_END] = {
> +	"SSBS",
> +	"PAN",
> +	"UAO"
> +};
> +
> +#define MAX_FEATS_SZ	128
> +static inline char *feats_to_string(unsigned long feats)
> +{
> +	static char feats_string[MAX_FEATS_SZ];
> +
> +	for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
> +		if (feats & 1UL << i)
> +			snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
> +				 feats_string, feats_store[i]);
> +	}
> +
> +	return feats_string;
> +}
> +
> +static void unblock_signal(int signum)
> +{
> +	sigset_t sset;
> +
> +	sigemptyset(&sset);
> +	sigaddset(&sset, signum);
> +	sigprocmask(SIG_UNBLOCK, &sset, NULL);
> +}
> +
> +static void default_result(struct tdescr *td, bool force_exit)
> +{
> +	if (td->pass)
> +		fprintf(stderr, "==>> completed. PASS(1)\n");
> +	else
> +		fprintf(stdout, "==>> completed. FAIL(0)\n");
> +	if (force_exit)
> +		exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
> +}
> +
> +static inline bool are_feats_ok(struct tdescr *td)
> +{
> +	return td ? td->feats_required == td->feats_supported : 0;
> +}
> +
> +static void default_handler(int signum, siginfo_t *si, void *uc)
> +{
> +	if (current->sig_trig && signum == current->sig_trig) {
> +		fprintf(stderr, "Handling SIG_TRIG\n");
> +		current->triggered = 1;
> +		/* ->run was asserted NON-NULL in test_setup() already */
> +		current->run(current, si, uc);
> +	} else if (signum == SIGILL && !current->initialized) {
> +		/*
> +		 * A SIGILL here while still not initialized means we failed
> +		 * even to asses the existence of features during init
> +		 */
> +		fprintf(stdout,
> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
> +		current->feats_supported = 0;
> +	} else if (current->sig_ok && signum == current->sig_ok) {
> +		/* it's a bug in the test code when this assert fail */
> +		assert(!current->sig_trig || current->triggered);
> +		fprintf(stderr,
> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> +			((ucontext_t *)uc)->uc_mcontext.sp,
> +			si->si_addr, si->si_code, current->token,
> +			current->token - si->si_addr);
> +		/*
> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
> +		 * the very last time, the token field to the SP address used
> +		 * to place the fake sigframe: so token==0 means we never made
> +		 * it to the end, segfaulting well-before, and the test is
> +		 * possibly broken.
> +		 */
> +		if (!current->sanity_disabled && !current->token) {
> +			fprintf(stdout,
> +				"current->token ZEROED...test is probably broken!\n");
> +			assert(0);
> +		}
> +		/*
> +		 * Trying to narrow down the SEGV to the ones generated by
> +		 * Kernel itself via arm64_notify_segfault()
> +		 */
> +		if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
> +			fprintf(stdout,
> +				"si_code != SEGV_ACCERR...test is probably broken!\n");
> +			assert(0);
> +		}
> +		fprintf(stderr, "Handling SIG_OK\n");
> +		current->pass = 1;
> +		/*
> +		 * Some tests can lead to SEGV loops: in such a case we want
> +		 * to terminate immediately exiting straight away
> +		 */
> +		default_result(current, 1);
> +	} else {
> +		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
> +			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
> +			current->pass = 1;
> +		} else if (signum == SIGALRM && current->timeout) {
> +			fprintf(stderr, "-- Timeout !\n");
> +		} else {
> +			fprintf(stderr,
> +				"-- RX UNEXPECTED SIGNAL: %d\n", signum);
> +		}
> +		default_result(current, 1);
> +	}
> +}
> +
> +static int default_setup(struct tdescr *td)
> +{
> +	struct sigaction sa;
> +
> +	sa.sa_sigaction = default_handler;
> +	sa.sa_flags = SA_SIGINFO;
> +	if (td->sa_flags)
> +		sa.sa_flags |= td->sa_flags;
> +	sigemptyset(&sa.sa_mask);
> +	/* uncatchable signals naturally skipped ... */
> +	for (int sig = 1; sig < 32; sig++)
> +		sigaction(sig, &sa, NULL);
> +	/*
> +	 * RT Signals default disposition is Term but they cannot be
> +	 * generated by the Kernel in response to our tests; so just catch
> +	 * them all and report them as UNEXPECTED signals.
> +	 */
> +	for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
> +		sigaction(sig, &sa, NULL);
> +
> +	/* just in case...unblock explicitly all we need */
> +	if (td->sig_trig)
> +		unblock_signal(td->sig_trig);
> +	if (td->sig_ok)
> +		unblock_signal(td->sig_ok);
> +	if (td->sig_unsupp)
> +		unblock_signal(td->sig_unsupp);
> +
> +	if (td->timeout) {
> +		unblock_signal(SIGALRM);
> +		alarm(td->timeout);
> +	}
> +	fprintf(stderr, "Registered handlers for all signals.\n");
> +
> +	return 1;
> +}
> +
> +static inline int default_trigger(struct tdescr *td)
> +{
> +	return !raise(td->sig_trig);
> +}
> +
> +static int test_init(struct tdescr *td)
> +{
> +	td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
> +	if (!td->minsigstksz)
> +		td->minsigstksz = MINSIGSTKSZ;
> +	fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
> +
> +	if (td->feats_required) {
> +		bool feats_ok = false;
> +		td->feats_supported = 0;
> +		/*
> +		 * Checking for CPU required features using both the
> +		 * auxval and the arm64 MRS Emulation to read sysregs.
> +		 */
> +		if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
> +			uint64_t val = 0;
> +
> +			if (td->feats_required & FEAT_SSBS) {
> +				/* Uses HWCAP to check capability */
> +				if (getauxval(AT_HWCAP) & HWCAP_SSBS)
> +					td->feats_supported |= FEAT_SSBS;
> +			}
> +			if (td->feats_required & FEAT_PAN) {
> +				/* Uses MRS emulation to check capability */
> +				get_regval(SYS_ID_AA64MMFR1_EL1, val);
> +				if (IS_PAN_SUPPORTED(val))
> +					td->feats_supported |= FEAT_PAN;
> +			}
> +			if (td->feats_required & FEAT_UAO) {
> +				/* Uses MRS emulation to check capability */
> +				get_regval(SYS_ID_AA64MMFR2_EL1 , val);
> +				if (IS_UAO_SUPPORTED(val))
> +					td->feats_supported |= FEAT_UAO;
> +			}
> +		} else {
> +			fprintf(stderr,
> +				"HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
> +		}
> +		feats_ok = are_feats_ok(td);
> +		fprintf(stderr,
> +			"Required Features: [%s] %ssupported\n",
> +			feats_ok ? feats_to_string(td->feats_supported) :
> +		        feats_to_string(td->feats_required ^ td->feats_supported),
> +			!feats_ok ? "NOT " : "");
> +	}
> +
> +	td->initialized = 1;
> +	return 1;
> +}
> +
> +int test_setup(struct tdescr *td)
> +{
> +	/* assert core invariants symptom of a rotten testcase */
> +	assert(current);
> +	assert(td);
> +	assert(td->name);
> +	assert(td->run);
> +
> +	if (!test_init(td))
> +		return 0;
> +
> +	if (td->setup)
> +		return td->setup(td);
> +	else
> +		return default_setup(td);
> +}
> +
> +int test_run(struct tdescr *td)
> +{
> +	if (td->sig_trig) {
> +		if (td->trigger)
> +			return td->trigger(td);
> +		else
> +			return default_trigger(td);
> +	} else {
> +		return td->run(td, NULL, NULL);
> +	}
> +}
> +
> +void test_result(struct tdescr *td)
> +{
> +	if (td->check_result)
> +		td->check_result(td);
> +	default_result(td, 0);
> +}
> +
> +void test_cleanup(struct tdescr *td)
> +{
> +	if (td->cleanup)
> +		td->cleanup(td);
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> new file mode 100644
> index 000000000000..8658d1a7d4b9
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_UTILS_H__
> +#define __TEST_SIGNALS_UTILS_H__
> +
> +#include "test_signals.h"
> +
> +int test_setup(struct tdescr *td);
> +void test_cleanup(struct tdescr *td);
> +int test_run(struct tdescr *td);
> +void test_result(struct tdescr *td);
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> new file mode 100644
> index 000000000000..8651272e3cfc
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -0,0 +1 @@
> +mangle_pstate_invalid_compat_toggle
> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> new file mode 100644
> index 000000000000..971193e7501b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
> +				     ucontext_t *uc)
> +{
> +	ASSERT_GOOD_CONTEXT(uc);
> +
> +	/* This config should trigger a SIGSEGV by Kernel */
> +	uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
> +
> +	return 1;
> +}
> +
> +struct tdescr tde = {
> +		.sanity_disabled = true,
> +		.name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
> +		.descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
> +		.sig_trig = SIGUSR1,
> +		.sig_ok = SIGSEGV,
> +		.run = mangle_invalid_pstate_run,
> +};
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> new file mode 100644
> index 000000000000..a59785092e1f
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> @@ -0,0 +1,150 @@
> +#include "testcases.h"
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +				size_t resv_sz, size_t *offset)
> +{
> +	size_t offs = 0;
> +	struct _aarch64_ctx *found = NULL;
> +
> +	if (!head || resv_sz < HDR_SZ)
> +		return found;
> +
> +	do {
> +		if (head->magic == magic) {
> +			found = head;
> +			break;
> +		}
> +		offs += head->size;
> +		head = GET_RESV_NEXT_HEAD(head);
> +	} while (offs < resv_sz - HDR_SZ);
> +
> +	if (offset)
> +		*offset = offs;
> +
> +	return found;
> +}
> +
> +bool validate_extra_context(struct extra_context *extra, char **err)
> +{
> +	struct _aarch64_ctx *term;
> +
> +	if (!extra || !err)
> +		return false;
> +
> +	fprintf(stderr, "Validating EXTRA...\n");
> +	term = GET_RESV_NEXT_HEAD(extra);
> +	if (!term || term->magic || term->size) {
> +		*err = "UN-Terminated EXTRA context";
> +		return false;
> +	}
> +	if (extra->datap & 0x0fUL)
> +		*err = "Extra DATAP misaligned";
> +	else if (extra->size & 0x0fUL)
> +		*err = "Extra SIZE misaligned";
> +	else if (extra->datap != (uint64_t)term + sizeof(*term))
> +		*err = "Extra DATAP misplaced (not contiguos)";
> +	if (*err)
> +		return false;
> +
> +	return true;
> +}
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
> +{
> +	bool terminated = false;
> +	size_t offs = 0;
> +	int flags = 0;
> +	struct extra_context *extra = NULL;
> +	struct _aarch64_ctx *head =
> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
> +
> +	if (!err)
> +		return false;
> +	/* Walk till the end terminator verifying __reserved contents */
> +	while (head && !terminated && offs < resv_sz) {
> +		if ((uint64_t)head & 0x0fUL) {
> +			*err = "Misaligned HEAD";
> +			return false;
> +		}
> +
> +		switch (head->magic) {
> +			case 0:
> +				if (head->size)
> +					*err = "Bad size for MAGIC0";
> +				else
> +					terminated = true;
> +				break;
> +			case FPSIMD_MAGIC:
> +				if (flags & FPSIMD_CTX)
> +					*err = "Multiple FPSIMD_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct fpsimd_context))
> +					*err = "Bad size for fpsimd_context";
> +				flags |= FPSIMD_CTX;
> +				break;
> +			case ESR_MAGIC:
> +				if (head->size != sizeof(struct esr_context))
> +					fprintf(stderr,
> +						"Bad size for esr_context is not an error...just ignore.\n");
> +				break;
> +			case SVE_MAGIC:
> +				if (flags & SVE_CTX)
> +					*err = "Multiple SVE_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct sve_context))
> +					*err = "Bad size for sve_context";
> +				flags |= SVE_CTX;
> +				break;
> +			case EXTRA_MAGIC:
> +				if (flags & EXTRA_CTX)
> +					*err = "Multiple EXTRA_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct extra_context))
> +					*err = "Bad size for extra_context";
> +				flags |= EXTRA_CTX;
> +				extra = (struct extra_context *)head;
> +				break;
> +			case KSFT_BAD_MAGIC:
> +				/*
> +				 * This is a BAD magic header defined
> +				 * artificially by a testcase and surely
> +				 * unknown to the Kernel parse_user_sigframe().
> +				 * It MUST cause a Kernel induced SEGV
> +				 */
> +				*err = "BAD MAGIC !";
> +				break;
> +			default:
> +				/*
> +				 * A still unknown Magic: potentially freshly added
> +				 * to the Kernel code and still unknown to the
> +				 * tests.
> +				 */
> +				fprintf(stdout,
> +					"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
> +					head->magic);
> +				break;
> +		}
> +
> +		if (*err)
> +			return false;
> +
> +		offs += head->size;
> +		if (resv_sz - offs < sizeof(*head)) {
> +			*err = "HEAD Overrun";
> +			return false;
> +		}
> +
> +		if (flags & EXTRA_CTX)
> +			if (!validate_extra_context(extra, err))
> +				return false;
> +
> +		head = GET_RESV_NEXT_HEAD(head);
> +	}
> +
> +	if (terminated && !(flags & FPSIMD_CTX)) {
> +		*err = "Missing FPSIMD";
> +		return false;
> +	}
> +
> +	return true;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> new file mode 100644
> index 000000000000..624717c71b1d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> @@ -0,0 +1,83 @@
> +#ifndef __TESTCASES_H__
> +#define __TESTCASES_H__
> +
> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <ucontext.h>
> +#include <assert.h>
> +
> +/* Architecture specific sigframe definitions */
> +#include <asm/sigcontext.h>
> +
> +#define FPSIMD_CTX	(1 << 0)
> +#define SVE_CTX		(1 << 1)
> +#define EXTRA_CTX	(1 << 2)
> +
> +#define KSFT_BAD_MAGIC	0xdeadbeef
> +
> +#define HDR_SZ \
> +	sizeof(struct _aarch64_ctx)
> +
> +#define GET_SF_RESV_HEAD(sf) \
> +	(struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
> +
> +#define GET_SF_RESV_SIZE(sf) \
> +	sizeof((sf).uc.uc_mcontext.__reserved)
> +
> +#define GET_UCP_RESV_SIZE(ucp) \
> +	sizeof((ucp)->uc_mcontext.__reserved)
> +
> +#define ASSERT_BAD_CONTEXT(uc) do {					\
> +	char *err = NULL;						\
> +	assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
> +	if (err)							\
> +		fprintf(stderr,						\
> +			"Using badly built context - ERR: %s\n", err);	\
> +} while(0)
> +
> +#define ASSERT_GOOD_CONTEXT(uc) do {					 \
> +	char *err = NULL;						 \
> +	if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) {	 \
> +		if (err)						 \
> +			fprintf(stderr,					 \
> +				"Detected BAD context - ERR: %s\n", err);\
> +		assert(0);						 \
> +	} else {							 \
> +		fprintf(stderr, "uc context validated.\n");		 \
> +	}								 \
> +} while(0)
> +
> +/* head->size accounts both for payload and header _aarch64_ctx size ! */
> +#define GET_RESV_NEXT_HEAD(h) \
> +	(struct _aarch64_ctx *)((char *)(h) + (h)->size)
> +
> +struct fake_sigframe {
> +	siginfo_t	info;
> +	ucontext_t	uc;
> +};
> +
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
> +
> +bool validate_extra_context(struct extra_context *extra, char **err);
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +				size_t resv_sz, size_t *offset);
> +
> +static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
> +						  size_t resv_sz,
> +						  size_t *offset)
> +{
> +	return get_header(head, 0, resv_sz, offset);
> +}
> +
> +static inline void write_terminator_record(struct _aarch64_ctx *tail)
> +{
> +	if (tail) {
> +		tail->magic = 0;
> +		tail->size = 0;
> +	}
> +}
> +#endif
> 


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-02 17:02 ` [PATCH v3 02/11] kselftest: arm64: adds first test and common utils Cristian Marussi
  2019-08-06 15:50   ` Cristian Marussi
@ 2019-08-07 15:42   ` Cristian Marussi
  2019-08-09 10:54   ` Cristian Marussi
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-07 15:42 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel; +Cc: dave.martin

Hi

On 02/08/2019 18:02, Cristian Marussi wrote:
> Added some arm64/signal specific boilerplate and utility code to help
> further testcase development.
> 
> A simple testcase and related helpers are also introduced in this commit:
> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
> messes with the ucontext_t from within the sig_handler, trying to toggle
> PSTATE state bits to switch the system between 32bit/64bit execution state.
> Expects SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> A few fixes:
> - test_arm64_signals.sh runner script generation has been reviewed in order to
>   be safe against the .gitignore
> - using kselftest.h officially provided defines for tests' return values
> - removed SAFE_WRITE()/dump_uc()
> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>   the sigfault had been directly triggered by Kernel
> ---
>  tools/testing/selftests/arm64/Makefile        |   2 +-
>  .../testing/selftests/arm64/signal/.gitignore |   6 +
>  tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>  tools/testing/selftests/arm64/signal/README   |  59 ++++
>  .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>  .../selftests/arm64/signal/test_signals.c     |  26 ++
>  .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>  .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>  .../arm64/signal/test_signals_utils.h         |  13 +
>  .../arm64/signal/testcases/.gitignore         |   1 +
>  .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>  .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>  .../arm64/signal/testcases/testcases.h        |  83 ++++++
>  13 files changed, 905 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>  create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>  create mode 100644 tools/testing/selftests/arm64/signal/README
>  create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
> 

I discovered an additional issue with this patch while building
some additional SVE related arm64/signal testcases (ofr a different patch series),
which is related to the logic of the helper get_header() that is flawed under some
specific conditions (not exposed by the test-cases included in this series).

A fix like the one below will go into V4, once reviews have settled.

diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
index a59785092e1f..0727b3987bbd 100644
--- a/tools/testing/selftests/arm64/signal/testcases/testcases.c
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
@@ -10,9 +10,16 @@ struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
                return found;
 
        do {
+               /*
+                * account for the fact that:
+                * - we could be in search of the terminator itself
+                * - a terminator should anyway terminate the loop
+                */
                if (head->magic == magic) {
                        found = head;
                        break;
+               } else if (!head->magic) {
+                       break;
                }
                offs += head->size;
                head = GET_RESV_NEXT_HEAD(head);

Cheers

Cristian

> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
> index 03a0d4f71218..af59dc74e0dc 100644
> --- a/tools/testing/selftests/arm64/Makefile
> +++ b/tools/testing/selftests/arm64/Makefile
> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>  ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>  
>  ifeq ("x$(ARCH)", "xarm64")
> -SUBDIRS :=
> +SUBDIRS := signal
>  else
>  SUBDIRS :=
>  endif
> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
> new file mode 100644
> index 000000000000..434f65c15f03
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/.gitignore
> @@ -0,0 +1,6 @@
> +# Helper script's internal testcases list (TPROGS) is regenerated
> +# each time by Makefile on standalone (non KSFT driven) runs.
> +# Committing such list creates a dependency between testcases
> +# patches such that they are no more easily revertable. Just ignore.
> +test_arm64_signals.src_shell
> +test_arm64_signals.sh
> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
> new file mode 100644
> index 000000000000..8c8d08be4b0d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/Makefile
> @@ -0,0 +1,88 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +# Supports also standalone invokation out of KSFT-tree
> +# Compile standalone and run on your device with:
> +#
> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
> +#
> +# Run standalone on device with:
> +#
> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
> +#
> +# If INSTALL_PATH= is NOT provided it will default to ./install
> +
> +# A proper top_srcdir is needed both by KSFT(lib.mk)
> +# and standalone builds
> +top_srcdir = ../../../../..
> +
> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
> +PROGS := $(patsubst %.c,%,$(SRCS))
> +
> +# Guessing as best as we can where the Kernel headers
> +# could have been installed depending on ENV config and
> +# type of invocation.
> +ifeq ($(KBUILD_OUTPUT),)
> +khdr_dir = $(top_srcdir)/usr/include
> +else
> +ifeq (0,$(MAKELEVEL))
> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
> +else
> +# the KSFT preferred location when KBUILD_OUTPUT is set
> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
> +endif
> +endif
> +
> +CFLAGS += -I$(khdr_dir)
> +
> +# Standalone run
> +ifeq (0,$(MAKELEVEL))
> +CC := $(CROSS_COMPILE)gcc
> +RUNNER_SRC = test_arm64_signals.src_shell
> +RUNNER = test_arm64_signals.sh
> +INSTALL_PATH ?= install/
> +
> +all: $(RUNNER)
> +
> +$(RUNNER): $(PROGS)
> +	cp $(RUNNER_SRC) $(RUNNER)
> +	sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
> +
> +install: all
> +	mkdir -p $(INSTALL_PATH)/testcases
> +	cp $(PROGS) $(INSTALL_PATH)/testcases
> +	cp $(RUNNER) $(INSTALL_PATH)/
> +
> +.PHONY clean:
> +	rm -f $(PROGS)
> +# KSFT run
> +else
> +# 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
> +
> +# This include mk 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)
> +endif
> +
> +# 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
> +	@if [ ! -d $(khdr_dir) ]; then \
> +		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
> +		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
> +	fi
> +	$(CC) $(CFLAGS) $^ -o $@
> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
> new file mode 100644
> index 000000000000..53f005f7910a
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/README
> @@ -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 messes-up with the sigframe ucontext_t from
> +    inside the sighandler 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
> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> new file mode 100755
> index 000000000000..163e941e2997
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> @@ -0,0 +1,55 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +ret=0
> +keep_on_fail=0
> +err_out="2> /dev/null"
> +
> +usage() {
> +	echo "Usage: `basename $0` [-v] [-k]"
> +	exit 1
> +}
> +
> +# avoiding getopt to avoid compatibility issues on targets
> +# with limited resources
> +while [ $# -gt 0 ]
> +do
> +	case $1 in
> +		"-k")
> +			keep_on_fail=1
> +			;;
> +		"-v")
> +			err_out=
> +			;;
> +		*)
> +			usage
> +			;;
> +	esac
> +	shift
> +done
> +
> +TPROGS=
> +
> +tot=$(echo $TPROGS | wc -w)
> +
> +# Tests are expected in testcases/ subdir inside the installation path
> +workdir="`dirname $0 2>/dev/null`"
> +[ -n $workdir ] && cd $workdir
> +
> +passed=0
> +run=0
> +for test in $TPROGS
> +do
> +	run=$((run + 1))
> +	eval ./$test $err_out
> +	if [ $? != 0 ]; then
> +		[ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
> +	else
> +		passed=$((passed + 1))
> +	fi
> +done
> +
> +echo "==>> PASSED: $passed/$run on $tot available tests."
> +
> +exit $ret
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
> new file mode 100644
> index 000000000000..3447d7011aec
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <kselftest.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +
> +struct tdescr *current;
> +extern struct tdescr tde;
> +
> +int main(int argc, char *argv[])
> +{
> +	current = &tde;
> +
> +	ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
> +		       current->name, current->descr, current->sig_trig,
> +		       current->sig_ok, current);
> +	if (test_setup(current)) {
> +		if (test_run(current))
> +			test_result(current);
> +		test_cleanup(current);
> +	}
> +
> +	return current->pass ? KSFT_PASS : KSFT_FAIL;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> new file mode 100644
> index 000000000000..85db3ac44b32
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
> @@ -0,0 +1,137 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_H__
> +#define __TEST_SIGNALS_H__
> +
> +#include <assert.h>
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <ucontext.h>
> +#include <stdint.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>
> +
> +/* pasted from include/linux/stringify.h */
> +#define __stringify_1(x...)	#x
> +#define __stringify(x...)	__stringify_1(x)
> +
> +/*
> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
> + * avoid inject any dependency on the used toolchain regarding possibly
> + * still unsupported ARMv8 extensions.
> + *
> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
> + * would introduce a compile-time dependency on possibly unsupported ARMv8
> + * Extensions: you could end-up failing to build the test depending on the
> + * available toolchain.
> + * This is undesirable since some tests, even if specifically targeted at some
> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
> + * it transparently not caring at all about the effective set of supported
> + * features).
> + * On the other side we will expect to observe different behaviours if the
> + * feature is supported or not: usually getting a SIGILL when trying to use
> + * unsupported features. For this reason we have anyway in place some
> + * preliminary run-time checks about the cpu effectively supported features.
> + *
> + * This helper macro is meant to be used for regs readable at EL0, BUT some
> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
> + * if the required reg is included in the supported encoding space:
> + *
> + *  Documentation/arm64/cpu-feature-regsiters.txt
> + *
> + *  "The infrastructure emulates only the following system register space:
> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
> + */
> +#define get_regval(regname, out) \
> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
> +
> +/* Regs encoding and masks naming copied in from sysreg.h */
> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
> +#define ID_AA64MMFR1_PAN_SHIFT	20
> +#define ID_AA64MMFR2_UAO_SHIFT	4
> +
> +/* Local Helpers */
> +#define IS_PAN_SUPPORTED(val) \
> +	(!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
> +#define IS_UAO_SUPPORTED(val) \
> +	(!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
> +
> +#define S3_MRS_SSBS_SYSREG		S3_3_C4_C2_6	/* EL0 supported */
> +
> +/*
> + * Feature flags used in tdescr.feats_required to specify
> + * any feature by the test
> + */
> +enum {
> +	FSSBS_BIT,
> +	FPAN_BIT,
> +	FUAO_BIT,
> +	FMAX_END
> +};
> +
> +#define FEAT_SSBS		(1UL << FSSBS_BIT)
> +#define FEAT_PAN		(1UL << FPAN_BIT)
> +#define FEAT_UAO		(1UL << FUAO_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		feats_ok;
> +	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;
> +
> +	/* a setup function to be called before test starts */
> +	int (*setup)(struct tdescr *td);
> +	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);
> +
> +	void *priv;
> +};
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> new file mode 100644
> index 000000000000..ac0055f6340b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -0,0 +1,261 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <assert.h>
> +#include <sys/auxv.h>
> +#include <linux/auxvec.h>
> +#include <ucontext.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +#include "testcases/testcases.h"
> +
> +extern struct tdescr *current;
> +
> +static char *feats_store[FMAX_END] = {
> +	"SSBS",
> +	"PAN",
> +	"UAO"
> +};
> +
> +#define MAX_FEATS_SZ	128
> +static inline char *feats_to_string(unsigned long feats)
> +{
> +	static char feats_string[MAX_FEATS_SZ];
> +
> +	for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
> +		if (feats & 1UL << i)
> +			snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
> +				 feats_string, feats_store[i]);
> +	}
> +
> +	return feats_string;
> +}
> +
> +static void unblock_signal(int signum)
> +{
> +	sigset_t sset;
> +
> +	sigemptyset(&sset);
> +	sigaddset(&sset, signum);
> +	sigprocmask(SIG_UNBLOCK, &sset, NULL);
> +}
> +
> +static void default_result(struct tdescr *td, bool force_exit)
> +{
> +	if (td->pass)
> +		fprintf(stderr, "==>> completed. PASS(1)\n");
> +	else
> +		fprintf(stdout, "==>> completed. FAIL(0)\n");
> +	if (force_exit)
> +		exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
> +}
> +
> +static inline bool are_feats_ok(struct tdescr *td)
> +{
> +	return td ? td->feats_required == td->feats_supported : 0;
> +}
> +
> +static void default_handler(int signum, siginfo_t *si, void *uc)
> +{
> +	if (current->sig_trig && signum == current->sig_trig) {
> +		fprintf(stderr, "Handling SIG_TRIG\n");
> +		current->triggered = 1;
> +		/* ->run was asserted NON-NULL in test_setup() already */
> +		current->run(current, si, uc);
> +	} else if (signum == SIGILL && !current->initialized) {
> +		/*
> +		 * A SIGILL here while still not initialized means we failed
> +		 * even to asses the existence of features during init
> +		 */
> +		fprintf(stdout,
> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
> +		current->feats_supported = 0;
> +	} else if (current->sig_ok && signum == current->sig_ok) {
> +		/* it's a bug in the test code when this assert fail */
> +		assert(!current->sig_trig || current->triggered);
> +		fprintf(stderr,
> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> +			((ucontext_t *)uc)->uc_mcontext.sp,
> +			si->si_addr, si->si_code, current->token,
> +			current->token - si->si_addr);
> +		/*
> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
> +		 * the very last time, the token field to the SP address used
> +		 * to place the fake sigframe: so token==0 means we never made
> +		 * it to the end, segfaulting well-before, and the test is
> +		 * possibly broken.
> +		 */
> +		if (!current->sanity_disabled && !current->token) {
> +			fprintf(stdout,
> +				"current->token ZEROED...test is probably broken!\n");
> +			assert(0);
> +		}
> +		/*
> +		 * Trying to narrow down the SEGV to the ones generated by
> +		 * Kernel itself via arm64_notify_segfault()
> +		 */
> +		if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
> +			fprintf(stdout,
> +				"si_code != SEGV_ACCERR...test is probably broken!\n");
> +			assert(0);
> +		}
> +		fprintf(stderr, "Handling SIG_OK\n");
> +		current->pass = 1;
> +		/*
> +		 * Some tests can lead to SEGV loops: in such a case we want
> +		 * to terminate immediately exiting straight away
> +		 */
> +		default_result(current, 1);
> +	} else {
> +		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
> +			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
> +			current->pass = 1;
> +		} else if (signum == SIGALRM && current->timeout) {
> +			fprintf(stderr, "-- Timeout !\n");
> +		} else {
> +			fprintf(stderr,
> +				"-- RX UNEXPECTED SIGNAL: %d\n", signum);
> +		}
> +		default_result(current, 1);
> +	}
> +}
> +
> +static int default_setup(struct tdescr *td)
> +{
> +	struct sigaction sa;
> +
> +	sa.sa_sigaction = default_handler;
> +	sa.sa_flags = SA_SIGINFO;
> +	if (td->sa_flags)
> +		sa.sa_flags |= td->sa_flags;
> +	sigemptyset(&sa.sa_mask);
> +	/* uncatchable signals naturally skipped ... */
> +	for (int sig = 1; sig < 32; sig++)
> +		sigaction(sig, &sa, NULL);
> +	/*
> +	 * RT Signals default disposition is Term but they cannot be
> +	 * generated by the Kernel in response to our tests; so just catch
> +	 * them all and report them as UNEXPECTED signals.
> +	 */
> +	for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
> +		sigaction(sig, &sa, NULL);
> +
> +	/* just in case...unblock explicitly all we need */
> +	if (td->sig_trig)
> +		unblock_signal(td->sig_trig);
> +	if (td->sig_ok)
> +		unblock_signal(td->sig_ok);
> +	if (td->sig_unsupp)
> +		unblock_signal(td->sig_unsupp);
> +
> +	if (td->timeout) {
> +		unblock_signal(SIGALRM);
> +		alarm(td->timeout);
> +	}
> +	fprintf(stderr, "Registered handlers for all signals.\n");
> +
> +	return 1;
> +}
> +
> +static inline int default_trigger(struct tdescr *td)
> +{
> +	return !raise(td->sig_trig);
> +}
> +
> +static int test_init(struct tdescr *td)
> +{
> +	td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
> +	if (!td->minsigstksz)
> +		td->minsigstksz = MINSIGSTKSZ;
> +	fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
> +
> +	if (td->feats_required) {
> +		bool feats_ok = false;
> +		td->feats_supported = 0;
> +		/*
> +		 * Checking for CPU required features using both the
> +		 * auxval and the arm64 MRS Emulation to read sysregs.
> +		 */
> +		if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
> +			uint64_t val = 0;
> +
> +			if (td->feats_required & FEAT_SSBS) {
> +				/* Uses HWCAP to check capability */
> +				if (getauxval(AT_HWCAP) & HWCAP_SSBS)
> +					td->feats_supported |= FEAT_SSBS;
> +			}
> +			if (td->feats_required & FEAT_PAN) {
> +				/* Uses MRS emulation to check capability */
> +				get_regval(SYS_ID_AA64MMFR1_EL1, val);
> +				if (IS_PAN_SUPPORTED(val))
> +					td->feats_supported |= FEAT_PAN;
> +			}
> +			if (td->feats_required & FEAT_UAO) {
> +				/* Uses MRS emulation to check capability */
> +				get_regval(SYS_ID_AA64MMFR2_EL1 , val);
> +				if (IS_UAO_SUPPORTED(val))
> +					td->feats_supported |= FEAT_UAO;
> +			}
> +		} else {
> +			fprintf(stderr,
> +				"HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
> +		}
> +		feats_ok = are_feats_ok(td);
> +		fprintf(stderr,
> +			"Required Features: [%s] %ssupported\n",
> +			feats_ok ? feats_to_string(td->feats_supported) :
> +		        feats_to_string(td->feats_required ^ td->feats_supported),
> +			!feats_ok ? "NOT " : "");
> +	}
> +
> +	td->initialized = 1;
> +	return 1;
> +}
> +
> +int test_setup(struct tdescr *td)
> +{
> +	/* assert core invariants symptom of a rotten testcase */
> +	assert(current);
> +	assert(td);
> +	assert(td->name);
> +	assert(td->run);
> +
> +	if (!test_init(td))
> +		return 0;
> +
> +	if (td->setup)
> +		return td->setup(td);
> +	else
> +		return default_setup(td);
> +}
> +
> +int test_run(struct tdescr *td)
> +{
> +	if (td->sig_trig) {
> +		if (td->trigger)
> +			return td->trigger(td);
> +		else
> +			return default_trigger(td);
> +	} else {
> +		return td->run(td, NULL, NULL);
> +	}
> +}
> +
> +void test_result(struct tdescr *td)
> +{
> +	if (td->check_result)
> +		td->check_result(td);
> +	default_result(td, 0);
> +}
> +
> +void test_cleanup(struct tdescr *td)
> +{
> +	if (td->cleanup)
> +		td->cleanup(td);
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> new file mode 100644
> index 000000000000..8658d1a7d4b9
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_UTILS_H__
> +#define __TEST_SIGNALS_UTILS_H__
> +
> +#include "test_signals.h"
> +
> +int test_setup(struct tdescr *td);
> +void test_cleanup(struct tdescr *td);
> +int test_run(struct tdescr *td);
> +void test_result(struct tdescr *td);
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> new file mode 100644
> index 000000000000..8651272e3cfc
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -0,0 +1 @@
> +mangle_pstate_invalid_compat_toggle
> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> new file mode 100644
> index 000000000000..971193e7501b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
> +				     ucontext_t *uc)
> +{
> +	ASSERT_GOOD_CONTEXT(uc);
> +
> +	/* This config should trigger a SIGSEGV by Kernel */
> +	uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
> +
> +	return 1;
> +}
> +
> +struct tdescr tde = {
> +		.sanity_disabled = true,
> +		.name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
> +		.descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
> +		.sig_trig = SIGUSR1,
> +		.sig_ok = SIGSEGV,
> +		.run = mangle_invalid_pstate_run,
> +};
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> new file mode 100644
> index 000000000000..a59785092e1f
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> @@ -0,0 +1,150 @@
> +#include "testcases.h"
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +				size_t resv_sz, size_t *offset)
> +{
> +	size_t offs = 0;
> +	struct _aarch64_ctx *found = NULL;
> +
> +	if (!head || resv_sz < HDR_SZ)
> +		return found;
> +
> +	do {
> +		if (head->magic == magic) {
> +			found = head;
> +			break;
> +		}
> +		offs += head->size;
> +		head = GET_RESV_NEXT_HEAD(head);
> +	} while (offs < resv_sz - HDR_SZ);
> +
> +	if (offset)
> +		*offset = offs;
> +
> +	return found;
> +}
> +
> +bool validate_extra_context(struct extra_context *extra, char **err)
> +{
> +	struct _aarch64_ctx *term;
> +
> +	if (!extra || !err)
> +		return false;
> +
> +	fprintf(stderr, "Validating EXTRA...\n");
> +	term = GET_RESV_NEXT_HEAD(extra);
> +	if (!term || term->magic || term->size) {
> +		*err = "UN-Terminated EXTRA context";
> +		return false;
> +	}
> +	if (extra->datap & 0x0fUL)
> +		*err = "Extra DATAP misaligned";
> +	else if (extra->size & 0x0fUL)
> +		*err = "Extra SIZE misaligned";
> +	else if (extra->datap != (uint64_t)term + sizeof(*term))
> +		*err = "Extra DATAP misplaced (not contiguos)";
> +	if (*err)
> +		return false;
> +
> +	return true;
> +}
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
> +{
> +	bool terminated = false;
> +	size_t offs = 0;
> +	int flags = 0;
> +	struct extra_context *extra = NULL;
> +	struct _aarch64_ctx *head =
> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
> +
> +	if (!err)
> +		return false;
> +	/* Walk till the end terminator verifying __reserved contents */
> +	while (head && !terminated && offs < resv_sz) {
> +		if ((uint64_t)head & 0x0fUL) {
> +			*err = "Misaligned HEAD";
> +			return false;
> +		}
> +
> +		switch (head->magic) {
> +			case 0:
> +				if (head->size)
> +					*err = "Bad size for MAGIC0";
> +				else
> +					terminated = true;
> +				break;
> +			case FPSIMD_MAGIC:
> +				if (flags & FPSIMD_CTX)
> +					*err = "Multiple FPSIMD_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct fpsimd_context))
> +					*err = "Bad size for fpsimd_context";
> +				flags |= FPSIMD_CTX;
> +				break;
> +			case ESR_MAGIC:
> +				if (head->size != sizeof(struct esr_context))
> +					fprintf(stderr,
> +						"Bad size for esr_context is not an error...just ignore.\n");
> +				break;
> +			case SVE_MAGIC:
> +				if (flags & SVE_CTX)
> +					*err = "Multiple SVE_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct sve_context))
> +					*err = "Bad size for sve_context";
> +				flags |= SVE_CTX;
> +				break;
> +			case EXTRA_MAGIC:
> +				if (flags & EXTRA_CTX)
> +					*err = "Multiple EXTRA_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct extra_context))
> +					*err = "Bad size for extra_context";
> +				flags |= EXTRA_CTX;
> +				extra = (struct extra_context *)head;
> +				break;
> +			case KSFT_BAD_MAGIC:
> +				/*
> +				 * This is a BAD magic header defined
> +				 * artificially by a testcase and surely
> +				 * unknown to the Kernel parse_user_sigframe().
> +				 * It MUST cause a Kernel induced SEGV
> +				 */
> +				*err = "BAD MAGIC !";
> +				break;
> +			default:
> +				/*
> +				 * A still unknown Magic: potentially freshly added
> +				 * to the Kernel code and still unknown to the
> +				 * tests.
> +				 */
> +				fprintf(stdout,
> +					"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
> +					head->magic);
> +				break;
> +		}
> +
> +		if (*err)
> +			return false;
> +
> +		offs += head->size;
> +		if (resv_sz - offs < sizeof(*head)) {
> +			*err = "HEAD Overrun";
> +			return false;
> +		}
> +
> +		if (flags & EXTRA_CTX)
> +			if (!validate_extra_context(extra, err))
> +				return false;
> +
> +		head = GET_RESV_NEXT_HEAD(head);
> +	}
> +
> +	if (terminated && !(flags & FPSIMD_CTX)) {
> +		*err = "Missing FPSIMD";
> +		return false;
> +	}
> +
> +	return true;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> new file mode 100644
> index 000000000000..624717c71b1d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> @@ -0,0 +1,83 @@
> +#ifndef __TESTCASES_H__
> +#define __TESTCASES_H__
> +
> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <ucontext.h>
> +#include <assert.h>
> +
> +/* Architecture specific sigframe definitions */
> +#include <asm/sigcontext.h>
> +
> +#define FPSIMD_CTX	(1 << 0)
> +#define SVE_CTX		(1 << 1)
> +#define EXTRA_CTX	(1 << 2)
> +
> +#define KSFT_BAD_MAGIC	0xdeadbeef
> +
> +#define HDR_SZ \
> +	sizeof(struct _aarch64_ctx)
> +
> +#define GET_SF_RESV_HEAD(sf) \
> +	(struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
> +
> +#define GET_SF_RESV_SIZE(sf) \
> +	sizeof((sf).uc.uc_mcontext.__reserved)
> +
> +#define GET_UCP_RESV_SIZE(ucp) \
> +	sizeof((ucp)->uc_mcontext.__reserved)
> +
> +#define ASSERT_BAD_CONTEXT(uc) do {					\
> +	char *err = NULL;						\
> +	assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
> +	if (err)							\
> +		fprintf(stderr,						\
> +			"Using badly built context - ERR: %s\n", err);	\
> +} while(0)
> +
> +#define ASSERT_GOOD_CONTEXT(uc) do {					 \
> +	char *err = NULL;						 \
> +	if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) {	 \
> +		if (err)						 \
> +			fprintf(stderr,					 \
> +				"Detected BAD context - ERR: %s\n", err);\
> +		assert(0);						 \
> +	} else {							 \
> +		fprintf(stderr, "uc context validated.\n");		 \
> +	}								 \
> +} while(0)
> +
> +/* head->size accounts both for payload and header _aarch64_ctx size ! */
> +#define GET_RESV_NEXT_HEAD(h) \
> +	(struct _aarch64_ctx *)((char *)(h) + (h)->size)
> +
> +struct fake_sigframe {
> +	siginfo_t	info;
> +	ucontext_t	uc;
> +};
> +
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
> +
> +bool validate_extra_context(struct extra_context *extra, char **err);
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +				size_t resv_sz, size_t *offset);
> +
> +static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
> +						  size_t resv_sz,
> +						  size_t *offset)
> +{
> +	return get_header(head, 0, resv_sz, offset);
> +}
> +
> +static inline void write_terminator_record(struct _aarch64_ctx *tail)
> +{
> +	if (tail) {
> +		tail->magic = 0;
> +		tail->size = 0;
> +	}
> +}
> +#endif
> 


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp
  2019-08-02 17:03 ` [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp Cristian Marussi
@ 2019-08-07 16:04   ` Cristian Marussi
  2019-08-13 16:28     ` Dave Martin
  2019-08-13 16:27   ` Dave Martin
  1 sibling, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-07 16:04 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel; +Cc: Dave P Martin

On 02/08/2019 18:03, Cristian Marussi wrote:
> Added a simple fake_sigreturn testcase which places a valid
> sigframe on a non-16 bytes aligned SP.
> fake_sigretrun() helper function has been patched accordingly
> to support placing a sigframe on a non-16 bytes aligned address.
> Expects a SIGSEGV on test PASS.
> 
> Adds also a test TODO lists holding some further test ideas.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> Re-added this text after fixing the forced misaglinment procedure in
> fake_sigreturn() itself: require a ZERO alignment and you'll get
> your sigframe placed on a misaligned SP (2-bytes off the 16-align)
> ---
>  .../testing/selftests/arm64/signal/signals.S  | 21 +++++++++----
>  .../arm64/signal/testcases/TODO.readme        |  8 +++++
>  .../testcases/fake_sigreturn_misaligned_sp.c  | 30 +++++++++++++++++++
>  3 files changed, 53 insertions(+), 6 deletions(-)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
> 

When this test was re-added in V3, the related .gitignore was missed.
It will go in V4

Cheers

Cristian
> diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
> index 6262b877400b..2099871176ed 100644
> --- a/tools/testing/selftests/arm64/signal/signals.S
> +++ b/tools/testing/selftests/arm64/signal/signals.S
> @@ -13,19 +13,28 @@ call_fmt:
>  
>  .globl fake_sigreturn
>  
> -/*	fake_sigreturn	x0:&sigframe,  x1:sigframe_size,  x2:alignment_SP */
> +/*	fake_sigreturn	x0:&sigframe, x1:sigframe_sz, x2:align */
>  fake_sigreturn:
> -	mov x20, x0
> -	mov x21, x1
> -	mov x22, x2
> -	mov x23, sp
>  
> -	/* create space on the stack for fake sigframe..."x22"-aligned */
> +	/* Save args and decide which aligment to enforce */
> +	mov 	x23, sp
> +	mov	x20, x0
> +	mov 	x21, x1
> +	/* x22 and x24 used for forcing alignment or misalignment */
> +	mov	x22, x2
> +	mov	x24, #0
> +	cbnz	x22, 1f
> +	mov	x22, #16
> +	mov	x24, #2
> +
> +1:	/* create space on the stack for fake sigframe..."x22"-aligned */
>  	mov x0, #0
>  	add x0, x21, x22
>  	sub x22, x22, #1
>  	bic x0, x0, x22
>  	sub x23, x23, x0
> +	/* force misaligned by x24 bytes if required alignment was zero */
> +	add x23, x23, x24
>  
>  	ldr x0, =call_fmt
>  	mov x1, x21
> diff --git a/tools/testing/selftests/arm64/signal/testcases/TODO.readme b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
> new file mode 100644
> index 000000000000..5c949492e7ab
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
> @@ -0,0 +1,8 @@
> +Some more possible ideas for signals tests:
> +
> +- fake_sigreturn_unmapped_sp
> +- fake_sigreturn_kernelspace_sp
> +- fake_sigreturn_sve_bad_extra_context
> +- mangle_sve_invalid_extra_context
> +- mangle_pstate_invalid_el for H modes (+ macroization ?)
> +- fake_sigreturn_overflow_reserved
> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
> new file mode 100644
> index 000000000000..3ee8c500c7d1
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <ucontext.h>
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +struct fake_sigframe sf;
> +
> +static int fake_sigreturn_misaligned_run(struct tdescr *td,
> +				         siginfo_t *si, ucontext_t *uc)
> +{
> +	/* just to fill the ucontext_t with something real */
> +	if (!get_current_context(td, &sf.uc))
> +		return 1;
> +
> +	/* Forcing sigframe on misaligned (=!16) SP */
> +	fake_sigreturn(&sf, sizeof(sf), 0);
> +
> +	return 1;
> +}
> +
> +struct tdescr tde = {
> +		.name = "FAKE_SIGRETURN_MISALIGNED_SP",
> +		.descr = "Triggers a fake sigreturn with a misaligned sigframe on SP",
> +		.sig_ok = SIGSEGV,
> +		.timeout = 3,
> +		.run = fake_sigreturn_misaligned_run,
> +};
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-02 17:02 ` [PATCH v3 02/11] kselftest: arm64: adds first test and common utils Cristian Marussi
  2019-08-06 15:50   ` Cristian Marussi
  2019-08-07 15:42   ` Cristian Marussi
@ 2019-08-09 10:54   ` Cristian Marussi
  2019-08-09 11:16     ` Dave Martin
  2019-08-12 12:43   ` Amit Kachhap
  2019-08-13 16:24   ` Dave Martin
  4 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-09 10:54 UTC (permalink / raw)
  To: linux-kselftest, linux-arm-kernel; +Cc: Dave P Martin

Hi

On 8/2/19 6:02 PM, Cristian Marussi wrote:
> Added some arm64/signal specific boilerplate and utility code to help
> further testcase development.
> 
> A simple testcase and related helpers are also introduced in this commit:
> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
> messes with the ucontext_t from within the sig_handler, trying to toggle
> PSTATE state bits to switch the system between 32bit/64bit execution state.
> Expects SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> A few fixes:
> - test_arm64_signals.sh runner script generation has been reviewed in order to
>    be safe against the .gitignore
> - using kselftest.h officially provided defines for tests' return values
> - removed SAFE_WRITE()/dump_uc()
> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>    the sigfault had been directly triggered by Kernel
> ---
>   tools/testing/selftests/arm64/Makefile        |   2 +-
>   .../testing/selftests/arm64/signal/.gitignore |   6 +
>   tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>   tools/testing/selftests/arm64/signal/README   |  59 ++++
>   .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>   .../selftests/arm64/signal/test_signals.c     |  26 ++
>   .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>   .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>   .../arm64/signal/test_signals_utils.h         |  13 +
>   .../arm64/signal/testcases/.gitignore         |   1 +
>   .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>   .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>   .../arm64/signal/testcases/testcases.h        |  83 ++++++
>   13 files changed, 905 insertions(+), 1 deletion(-)
>   create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>   create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>   create mode 100644 tools/testing/selftests/arm64/signal/README
>   create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
> 

A few more compilation warnings triggered by GCC-8 ONLY when compiling via the top kselftest Makefile/target
(due to some additional -W passed down and an awkward use of snprintf on my side...)


test_signals_utils.c: In function ‘feats_to_string’:
test_signals_utils.c:38:13: warning: passing argument 1 to restrict-qualified parameter aliases with argument 4 [-Wrestrict]
     snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
              ^~~~~~~~~~~~
            
test_signals_utils.c: In function ‘default_handler’:
test_signals_utils.c:192:19: warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘long long unsigned int’ [-Wformat=]
     "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
                   ~^

will be fixed in V4 as:


diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
index 31788a1d33a4..c0f3cd1b560a 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -23,21 +23,25 @@ extern struct tdescr *current;
  static int sig_copyctx = SIGTRAP;
  
  static char *feats_store[FMAX_END] = {
-       "SSBS",
-       "PAN",
-       "UAO",
+       " SSBS ",
+       " PAN ",
+       " UAO ",
  };
  
  #define MAX_FEATS_SZ   128
+static char feats_string[MAX_FEATS_SZ];
+
  static inline char *feats_to_string(unsigned long feats)
  {
-       static char feats_string[MAX_FEATS_SZ];
+       for (int i = 0; i < FMAX_END; i++) {
+               size_t tlen = 0;
  
-       for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
-               if (feats & 1UL << i)
-                       snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
-                                feats_string, feats_store[i]);
+               if (feats & 1UL << i) {
+                       strncat(feats_string, feats_store[i],
+                               MAX_FEATS_SZ - 1 - tlen);
+                       tlen += strlen(feats_store[i]);
+               }
         }
  
         return feats_string;
@@ -190,7 +194,7 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
                 /* it's a bug in the test code when this assert fail */
                 assert(!current->sig_trig || current->triggered);
                 fprintf(stderr,
-                       "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
+                       "SIG_OK -- SP:%llX  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
                         ((ucontext_t *)uc)->uc_mcontext.sp,
                         si->si_addr, si->si_code, current->token,
                         current->token - si->si_addr);


Cheers

Cristian





> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
> index 03a0d4f71218..af59dc74e0dc 100644
> --- a/tools/testing/selftests/arm64/Makefile
> +++ b/tools/testing/selftests/arm64/Makefile
> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>   ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>   
>   ifeq ("x$(ARCH)", "xarm64")
> -SUBDIRS :=
> +SUBDIRS := signal
>   else
>   SUBDIRS :=
>   endif
> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
> new file mode 100644
> index 000000000000..434f65c15f03
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/.gitignore
> @@ -0,0 +1,6 @@
> +# Helper script's internal testcases list (TPROGS) is regenerated
> +# each time by Makefile on standalone (non KSFT driven) runs.
> +# Committing such list creates a dependency between testcases
> +# patches such that they are no more easily revertable. Just ignore.
> +test_arm64_signals.src_shell
> +test_arm64_signals.sh
> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
> new file mode 100644
> index 000000000000..8c8d08be4b0d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/Makefile
> @@ -0,0 +1,88 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +# Supports also standalone invokation out of KSFT-tree
> +# Compile standalone and run on your device with:
> +#
> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
> +#
> +# Run standalone on device with:
> +#
> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
> +#
> +# If INSTALL_PATH= is NOT provided it will default to ./install
> +
> +# A proper top_srcdir is needed both by KSFT(lib.mk)
> +# and standalone builds
> +top_srcdir = ../../../../..
> +
> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
> +PROGS := $(patsubst %.c,%,$(SRCS))
> +
> +# Guessing as best as we can where the Kernel headers
> +# could have been installed depending on ENV config and
> +# type of invocation.
> +ifeq ($(KBUILD_OUTPUT),)
> +khdr_dir = $(top_srcdir)/usr/include
> +else
> +ifeq (0,$(MAKELEVEL))
> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
> +else
> +# the KSFT preferred location when KBUILD_OUTPUT is set
> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
> +endif
> +endif
> +
> +CFLAGS += -I$(khdr_dir)
> +
> +# Standalone run
> +ifeq (0,$(MAKELEVEL))
> +CC := $(CROSS_COMPILE)gcc
> +RUNNER_SRC = test_arm64_signals.src_shell
> +RUNNER = test_arm64_signals.sh
> +INSTALL_PATH ?= install/
> +
> +all: $(RUNNER)
> +
> +$(RUNNER): $(PROGS)
> +	cp $(RUNNER_SRC) $(RUNNER)
> +	sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
> +
> +install: all
> +	mkdir -p $(INSTALL_PATH)/testcases
> +	cp $(PROGS) $(INSTALL_PATH)/testcases
> +	cp $(RUNNER) $(INSTALL_PATH)/
> +
> +.PHONY clean:
> +	rm -f $(PROGS)
> +# KSFT run
> +else
> +# 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
> +
> +# This include mk 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)
> +endif
> +
> +# 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
> +	@if [ ! -d $(khdr_dir) ]; then \
> +		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
> +		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
> +	fi
> +	$(CC) $(CFLAGS) $^ -o $@
> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
> new file mode 100644
> index 000000000000..53f005f7910a
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/README
> @@ -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 messes-up with the sigframe ucontext_t from
> +    inside the sighandler 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
> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> new file mode 100755
> index 000000000000..163e941e2997
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> @@ -0,0 +1,55 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +ret=0
> +keep_on_fail=0
> +err_out="2> /dev/null"
> +
> +usage() {
> +	echo "Usage: `basename $0` [-v] [-k]"
> +	exit 1
> +}
> +
> +# avoiding getopt to avoid compatibility issues on targets
> +# with limited resources
> +while [ $# -gt 0 ]
> +do
> +	case $1 in
> +		"-k")
> +			keep_on_fail=1
> +			;;
> +		"-v")
> +			err_out=
> +			;;
> +		*)
> +			usage
> +			;;
> +	esac
> +	shift
> +done
> +
> +TPROGS=
> +
> +tot=$(echo $TPROGS | wc -w)
> +
> +# Tests are expected in testcases/ subdir inside the installation path
> +workdir="`dirname $0 2>/dev/null`"
> +[ -n $workdir ] && cd $workdir
> +
> +passed=0
> +run=0
> +for test in $TPROGS
> +do
> +	run=$((run + 1))
> +	eval ./$test $err_out
> +	if [ $? != 0 ]; then
> +		[ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
> +	else
> +		passed=$((passed + 1))
> +	fi
> +done
> +
> +echo "==>> PASSED: $passed/$run on $tot available tests."
> +
> +exit $ret
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
> new file mode 100644
> index 000000000000..3447d7011aec
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <kselftest.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +
> +struct tdescr *current;
> +extern struct tdescr tde;
> +
> +int main(int argc, char *argv[])
> +{
> +	current = &tde;
> +
> +	ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
> +		       current->name, current->descr, current->sig_trig,
> +		       current->sig_ok, current);
> +	if (test_setup(current)) {
> +		if (test_run(current))
> +			test_result(current);
> +		test_cleanup(current);
> +	}
> +
> +	return current->pass ? KSFT_PASS : KSFT_FAIL;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> new file mode 100644
> index 000000000000..85db3ac44b32
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
> @@ -0,0 +1,137 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_H__
> +#define __TEST_SIGNALS_H__
> +
> +#include <assert.h>
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <ucontext.h>
> +#include <stdint.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>
> +
> +/* pasted from include/linux/stringify.h */
> +#define __stringify_1(x...)	#x
> +#define __stringify(x...)	__stringify_1(x)
> +
> +/*
> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
> + * avoid inject any dependency on the used toolchain regarding possibly
> + * still unsupported ARMv8 extensions.
> + *
> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
> + * would introduce a compile-time dependency on possibly unsupported ARMv8
> + * Extensions: you could end-up failing to build the test depending on the
> + * available toolchain.
> + * This is undesirable since some tests, even if specifically targeted at some
> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
> + * it transparently not caring at all about the effective set of supported
> + * features).
> + * On the other side we will expect to observe different behaviours if the
> + * feature is supported or not: usually getting a SIGILL when trying to use
> + * unsupported features. For this reason we have anyway in place some
> + * preliminary run-time checks about the cpu effectively supported features.
> + *
> + * This helper macro is meant to be used for regs readable at EL0, BUT some
> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
> + * if the required reg is included in the supported encoding space:
> + *
> + *  Documentation/arm64/cpu-feature-regsiters.txt
> + *
> + *  "The infrastructure emulates only the following system register space:
> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
> + */
> +#define get_regval(regname, out) \
> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
> +
> +/* Regs encoding and masks naming copied in from sysreg.h */
> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
> +#define ID_AA64MMFR1_PAN_SHIFT	20
> +#define ID_AA64MMFR2_UAO_SHIFT	4
> +
> +/* Local Helpers */
> +#define IS_PAN_SUPPORTED(val) \
> +	(!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
> +#define IS_UAO_SUPPORTED(val) \
> +	(!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
> +
> +#define S3_MRS_SSBS_SYSREG		S3_3_C4_C2_6	/* EL0 supported */
> +
> +/*
> + * Feature flags used in tdescr.feats_required to specify
> + * any feature by the test
> + */
> +enum {
> +	FSSBS_BIT,
> +	FPAN_BIT,
> +	FUAO_BIT,
> +	FMAX_END
> +};
> +
> +#define FEAT_SSBS		(1UL << FSSBS_BIT)
> +#define FEAT_PAN		(1UL << FPAN_BIT)
> +#define FEAT_UAO		(1UL << FUAO_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		feats_ok;
> +	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;
> +
> +	/* a setup function to be called before test starts */
> +	int (*setup)(struct tdescr *td);
> +	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);
> +
> +	void *priv;
> +};
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> new file mode 100644
> index 000000000000..ac0055f6340b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -0,0 +1,261 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <assert.h>
> +#include <sys/auxv.h>
> +#include <linux/auxvec.h>
> +#include <ucontext.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +#include "testcases/testcases.h"
> +
> +extern struct tdescr *current;
> +
> +static char *feats_store[FMAX_END] = {
> +	"SSBS",
> +	"PAN",
> +	"UAO"
> +};
> +
> +#define MAX_FEATS_SZ	128
> +static inline char *feats_to_string(unsigned long feats)
> +{
> +	static char feats_string[MAX_FEATS_SZ];
> +
> +	for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
> +		if (feats & 1UL << i)
> +			snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
> +				 feats_string, feats_store[i]);
> +	}
> +
> +	return feats_string;
> +}
> +
> +static void unblock_signal(int signum)
> +{
> +	sigset_t sset;
> +
> +	sigemptyset(&sset);
> +	sigaddset(&sset, signum);
> +	sigprocmask(SIG_UNBLOCK, &sset, NULL);
> +}
> +
> +static void default_result(struct tdescr *td, bool force_exit)
> +{
> +	if (td->pass)
> +		fprintf(stderr, "==>> completed. PASS(1)\n");
> +	else
> +		fprintf(stdout, "==>> completed. FAIL(0)\n");
> +	if (force_exit)
> +		exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
> +}
> +
> +static inline bool are_feats_ok(struct tdescr *td)
> +{
> +	return td ? td->feats_required == td->feats_supported : 0;
> +}
> +
> +static void default_handler(int signum, siginfo_t *si, void *uc)
> +{
> +	if (current->sig_trig && signum == current->sig_trig) {
> +		fprintf(stderr, "Handling SIG_TRIG\n");
> +		current->triggered = 1;
> +		/* ->run was asserted NON-NULL in test_setup() already */
> +		current->run(current, si, uc);
> +	} else if (signum == SIGILL && !current->initialized) {
> +		/*
> +		 * A SIGILL here while still not initialized means we failed
> +		 * even to asses the existence of features during init
> +		 */
> +		fprintf(stdout,
> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
> +		current->feats_supported = 0;
> +	} else if (current->sig_ok && signum == current->sig_ok) {
> +		/* it's a bug in the test code when this assert fail */
> +		assert(!current->sig_trig || current->triggered);
> +		fprintf(stderr,
> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> +			((ucontext_t *)uc)->uc_mcontext.sp,
> +			si->si_addr, si->si_code, current->token,
> +			current->token - si->si_addr);
> +		/*
> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
> +		 * the very last time, the token field to the SP address used
> +		 * to place the fake sigframe: so token==0 means we never made
> +		 * it to the end, segfaulting well-before, and the test is
> +		 * possibly broken.
> +		 */
> +		if (!current->sanity_disabled && !current->token) {
> +			fprintf(stdout,
> +				"current->token ZEROED...test is probably broken!\n");
> +			assert(0);
> +		}
> +		/*
> +		 * Trying to narrow down the SEGV to the ones generated by
> +		 * Kernel itself via arm64_notify_segfault()
> +		 */
> +		if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
> +			fprintf(stdout,
> +				"si_code != SEGV_ACCERR...test is probably broken!\n");
> +			assert(0);
> +		}
> +		fprintf(stderr, "Handling SIG_OK\n");
> +		current->pass = 1;
> +		/*
> +		 * Some tests can lead to SEGV loops: in such a case we want
> +		 * to terminate immediately exiting straight away
> +		 */
> +		default_result(current, 1);
> +	} else {
> +		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
> +			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
> +			current->pass = 1;
> +		} else if (signum == SIGALRM && current->timeout) {
> +			fprintf(stderr, "-- Timeout !\n");
> +		} else {
> +			fprintf(stderr,
> +				"-- RX UNEXPECTED SIGNAL: %d\n", signum);
> +		}
> +		default_result(current, 1);
> +	}
> +}
> +
> +static int default_setup(struct tdescr *td)
> +{
> +	struct sigaction sa;
> +
> +	sa.sa_sigaction = default_handler;
> +	sa.sa_flags = SA_SIGINFO;
> +	if (td->sa_flags)
> +		sa.sa_flags |= td->sa_flags;
> +	sigemptyset(&sa.sa_mask);
> +	/* uncatchable signals naturally skipped ... */
> +	for (int sig = 1; sig < 32; sig++)
> +		sigaction(sig, &sa, NULL);
> +	/*
> +	 * RT Signals default disposition is Term but they cannot be
> +	 * generated by the Kernel in response to our tests; so just catch
> +	 * them all and report them as UNEXPECTED signals.
> +	 */
> +	for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
> +		sigaction(sig, &sa, NULL);
> +
> +	/* just in case...unblock explicitly all we need */
> +	if (td->sig_trig)
> +		unblock_signal(td->sig_trig);
> +	if (td->sig_ok)
> +		unblock_signal(td->sig_ok);
> +	if (td->sig_unsupp)
> +		unblock_signal(td->sig_unsupp);
> +
> +	if (td->timeout) {
> +		unblock_signal(SIGALRM);
> +		alarm(td->timeout);
> +	}
> +	fprintf(stderr, "Registered handlers for all signals.\n");
> +
> +	return 1;
> +}
> +
> +static inline int default_trigger(struct tdescr *td)
> +{
> +	return !raise(td->sig_trig);
> +}
> +
> +static int test_init(struct tdescr *td)
> +{
> +	td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
> +	if (!td->minsigstksz)
> +		td->minsigstksz = MINSIGSTKSZ;
> +	fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
> +
> +	if (td->feats_required) {
> +		bool feats_ok = false;
> +		td->feats_supported = 0;
> +		/*
> +		 * Checking for CPU required features using both the
> +		 * auxval and the arm64 MRS Emulation to read sysregs.
> +		 */
> +		if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
> +			uint64_t val = 0;
> +
> +			if (td->feats_required & FEAT_SSBS) {
> +				/* Uses HWCAP to check capability */
> +				if (getauxval(AT_HWCAP) & HWCAP_SSBS)
> +					td->feats_supported |= FEAT_SSBS;
> +			}
> +			if (td->feats_required & FEAT_PAN) {
> +				/* Uses MRS emulation to check capability */
> +				get_regval(SYS_ID_AA64MMFR1_EL1, val);
> +				if (IS_PAN_SUPPORTED(val))
> +					td->feats_supported |= FEAT_PAN;
> +			}
> +			if (td->feats_required & FEAT_UAO) {
> +				/* Uses MRS emulation to check capability */
> +				get_regval(SYS_ID_AA64MMFR2_EL1 , val);
> +				if (IS_UAO_SUPPORTED(val))
> +					td->feats_supported |= FEAT_UAO;
> +			}
> +		} else {
> +			fprintf(stderr,
> +				"HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
> +		}
> +		feats_ok = are_feats_ok(td);
> +		fprintf(stderr,
> +			"Required Features: [%s] %ssupported\n",
> +			feats_ok ? feats_to_string(td->feats_supported) :
> +		        feats_to_string(td->feats_required ^ td->feats_supported),
> +			!feats_ok ? "NOT " : "");
> +	}
> +
> +	td->initialized = 1;
> +	return 1;
> +}
> +
> +int test_setup(struct tdescr *td)
> +{
> +	/* assert core invariants symptom of a rotten testcase */
> +	assert(current);
> +	assert(td);
> +	assert(td->name);
> +	assert(td->run);
> +
> +	if (!test_init(td))
> +		return 0;
> +
> +	if (td->setup)
> +		return td->setup(td);
> +	else
> +		return default_setup(td);
> +}
> +
> +int test_run(struct tdescr *td)
> +{
> +	if (td->sig_trig) {
> +		if (td->trigger)
> +			return td->trigger(td);
> +		else
> +			return default_trigger(td);
> +	} else {
> +		return td->run(td, NULL, NULL);
> +	}
> +}
> +
> +void test_result(struct tdescr *td)
> +{
> +	if (td->check_result)
> +		td->check_result(td);
> +	default_result(td, 0);
> +}
> +
> +void test_cleanup(struct tdescr *td)
> +{
> +	if (td->cleanup)
> +		td->cleanup(td);
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> new file mode 100644
> index 000000000000..8658d1a7d4b9
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_UTILS_H__
> +#define __TEST_SIGNALS_UTILS_H__
> +
> +#include "test_signals.h"
> +
> +int test_setup(struct tdescr *td);
> +void test_cleanup(struct tdescr *td);
> +int test_run(struct tdescr *td);
> +void test_result(struct tdescr *td);
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> new file mode 100644
> index 000000000000..8651272e3cfc
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -0,0 +1 @@
> +mangle_pstate_invalid_compat_toggle
> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> new file mode 100644
> index 000000000000..971193e7501b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
> +				     ucontext_t *uc)
> +{
> +	ASSERT_GOOD_CONTEXT(uc);
> +
> +	/* This config should trigger a SIGSEGV by Kernel */
> +	uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
> +
> +	return 1;
> +}
> +
> +struct tdescr tde = {
> +		.sanity_disabled = true,
> +		.name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
> +		.descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
> +		.sig_trig = SIGUSR1,
> +		.sig_ok = SIGSEGV,
> +		.run = mangle_invalid_pstate_run,
> +};
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> new file mode 100644
> index 000000000000..a59785092e1f
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> @@ -0,0 +1,150 @@
> +#include "testcases.h"
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +				size_t resv_sz, size_t *offset)
> +{
> +	size_t offs = 0;
> +	struct _aarch64_ctx *found = NULL;
> +
> +	if (!head || resv_sz < HDR_SZ)
> +		return found;
> +
> +	do {
> +		if (head->magic == magic) {
> +			found = head;
> +			break;
> +		}
> +		offs += head->size;
> +		head = GET_RESV_NEXT_HEAD(head);
> +	} while (offs < resv_sz - HDR_SZ);
> +
> +	if (offset)
> +		*offset = offs;
> +
> +	return found;
> +}
> +
> +bool validate_extra_context(struct extra_context *extra, char **err)
> +{
> +	struct _aarch64_ctx *term;
> +
> +	if (!extra || !err)
> +		return false;
> +
> +	fprintf(stderr, "Validating EXTRA...\n");
> +	term = GET_RESV_NEXT_HEAD(extra);
> +	if (!term || term->magic || term->size) {
> +		*err = "UN-Terminated EXTRA context";
> +		return false;
> +	}
> +	if (extra->datap & 0x0fUL)
> +		*err = "Extra DATAP misaligned";
> +	else if (extra->size & 0x0fUL)
> +		*err = "Extra SIZE misaligned";
> +	else if (extra->datap != (uint64_t)term + sizeof(*term))
> +		*err = "Extra DATAP misplaced (not contiguos)";
> +	if (*err)
> +		return false;
> +
> +	return true;
> +}
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
> +{
> +	bool terminated = false;
> +	size_t offs = 0;
> +	int flags = 0;
> +	struct extra_context *extra = NULL;
> +	struct _aarch64_ctx *head =
> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
> +
> +	if (!err)
> +		return false;
> +	/* Walk till the end terminator verifying __reserved contents */
> +	while (head && !terminated && offs < resv_sz) {
> +		if ((uint64_t)head & 0x0fUL) {
> +			*err = "Misaligned HEAD";
> +			return false;
> +		}
> +
> +		switch (head->magic) {
> +			case 0:
> +				if (head->size)
> +					*err = "Bad size for MAGIC0";
> +				else
> +					terminated = true;
> +				break;
> +			case FPSIMD_MAGIC:
> +				if (flags & FPSIMD_CTX)
> +					*err = "Multiple FPSIMD_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct fpsimd_context))
> +					*err = "Bad size for fpsimd_context";
> +				flags |= FPSIMD_CTX;
> +				break;
> +			case ESR_MAGIC:
> +				if (head->size != sizeof(struct esr_context))
> +					fprintf(stderr,
> +						"Bad size for esr_context is not an error...just ignore.\n");
> +				break;
> +			case SVE_MAGIC:
> +				if (flags & SVE_CTX)
> +					*err = "Multiple SVE_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct sve_context))
> +					*err = "Bad size for sve_context";
> +				flags |= SVE_CTX;
> +				break;
> +			case EXTRA_MAGIC:
> +				if (flags & EXTRA_CTX)
> +					*err = "Multiple EXTRA_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct extra_context))
> +					*err = "Bad size for extra_context";
> +				flags |= EXTRA_CTX;
> +				extra = (struct extra_context *)head;
> +				break;
> +			case KSFT_BAD_MAGIC:
> +				/*
> +				 * This is a BAD magic header defined
> +				 * artificially by a testcase and surely
> +				 * unknown to the Kernel parse_user_sigframe().
> +				 * It MUST cause a Kernel induced SEGV
> +				 */
> +				*err = "BAD MAGIC !";
> +				break;
> +			default:
> +				/*
> +				 * A still unknown Magic: potentially freshly added
> +				 * to the Kernel code and still unknown to the
> +				 * tests.
> +				 */
> +				fprintf(stdout,
> +					"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
> +					head->magic);
> +				break;
> +		}
> +
> +		if (*err)
> +			return false;
> +
> +		offs += head->size;
> +		if (resv_sz - offs < sizeof(*head)) {
> +			*err = "HEAD Overrun";
> +			return false;
> +		}
> +
> +		if (flags & EXTRA_CTX)
> +			if (!validate_extra_context(extra, err))
> +				return false;
> +
> +		head = GET_RESV_NEXT_HEAD(head);
> +	}
> +
> +	if (terminated && !(flags & FPSIMD_CTX)) {
> +		*err = "Missing FPSIMD";
> +		return false;
> +	}
> +
> +	return true;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> new file mode 100644
> index 000000000000..624717c71b1d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> @@ -0,0 +1,83 @@
> +#ifndef __TESTCASES_H__
> +#define __TESTCASES_H__
> +
> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <ucontext.h>
> +#include <assert.h>
> +
> +/* Architecture specific sigframe definitions */
> +#include <asm/sigcontext.h>
> +
> +#define FPSIMD_CTX	(1 << 0)
> +#define SVE_CTX		(1 << 1)
> +#define EXTRA_CTX	(1 << 2)
> +
> +#define KSFT_BAD_MAGIC	0xdeadbeef
> +
> +#define HDR_SZ \
> +	sizeof(struct _aarch64_ctx)
> +
> +#define GET_SF_RESV_HEAD(sf) \
> +	(struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
> +
> +#define GET_SF_RESV_SIZE(sf) \
> +	sizeof((sf).uc.uc_mcontext.__reserved)
> +
> +#define GET_UCP_RESV_SIZE(ucp) \
> +	sizeof((ucp)->uc_mcontext.__reserved)
> +
> +#define ASSERT_BAD_CONTEXT(uc) do {					\
> +	char *err = NULL;						\
> +	assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
> +	if (err)							\
> +		fprintf(stderr,						\
> +			"Using badly built context - ERR: %s\n", err);	\
> +} while(0)
> +
> +#define ASSERT_GOOD_CONTEXT(uc) do {					 \
> +	char *err = NULL;						 \
> +	if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) {	 \
> +		if (err)						 \
> +			fprintf(stderr,					 \
> +				"Detected BAD context - ERR: %s\n", err);\
> +		assert(0);						 \
> +	} else {							 \
> +		fprintf(stderr, "uc context validated.\n");		 \
> +	}								 \
> +} while(0)
> +
> +/* head->size accounts both for payload and header _aarch64_ctx size ! */
> +#define GET_RESV_NEXT_HEAD(h) \
> +	(struct _aarch64_ctx *)((char *)(h) + (h)->size)
> +
> +struct fake_sigframe {
> +	siginfo_t	info;
> +	ucontext_t	uc;
> +};
> +
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
> +
> +bool validate_extra_context(struct extra_context *extra, char **err);
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +				size_t resv_sz, size_t *offset);
> +
> +static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
> +						  size_t resv_sz,
> +						  size_t *offset)
> +{
> +	return get_header(head, 0, resv_sz, offset);
> +}
> +
> +static inline void write_terminator_record(struct _aarch64_ctx *tail)
> +{
> +	if (tail) {
> +		tail->magic = 0;
> +		tail->size = 0;
> +	}
> +}
> +#endif
> 

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-09 10:54   ` Cristian Marussi
@ 2019-08-09 11:16     ` Dave Martin
  2019-08-09 12:20       ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-09 11:16 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel

On Fri, Aug 09, 2019 at 11:54:06AM +0100, Cristian Marussi wrote:
> Hi
> 
> On 8/2/19 6:02 PM, Cristian Marussi wrote:
> >Added some arm64/signal specific boilerplate and utility code to help
> >further testcase development.
> >
> >A simple testcase and related helpers are also introduced in this commit:
> >mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
> >messes with the ucontext_t from within the sig_handler, trying to toggle
> >PSTATE state bits to switch the system between 32bit/64bit execution state.
> >Expects SIGSEGV on test PASS.
> >
> >Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> >---
> >A few fixes:
> >- test_arm64_signals.sh runner script generation has been reviewed in order to
> >   be safe against the .gitignore
> >- using kselftest.h officially provided defines for tests' return values
> >- removed SAFE_WRITE()/dump_uc()
> >- looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
> >   the sigfault had been directly triggered by Kernel
> >---
> >  tools/testing/selftests/arm64/Makefile        |   2 +-
> >  .../testing/selftests/arm64/signal/.gitignore |   6 +
> >  tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
> >  tools/testing/selftests/arm64/signal/README   |  59 ++++
> >  .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
> >  .../selftests/arm64/signal/test_signals.c     |  26 ++
> >  .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
> >  .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
> >  .../arm64/signal/test_signals_utils.h         |  13 +
> >  .../arm64/signal/testcases/.gitignore         |   1 +
> >  .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
> >  .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
> >  .../arm64/signal/testcases/testcases.h        |  83 ++++++
> >  13 files changed, 905 insertions(+), 1 deletion(-)
> >  create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
> >  create mode 100644 tools/testing/selftests/arm64/signal/Makefile
> >  create mode 100644 tools/testing/selftests/arm64/signal/README
> >  create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> >  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
> >  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
> >  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
> >  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
> >  create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
> >  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> >  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
> >  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
> >
> 
> A few more compilation warnings triggered by GCC-8 ONLY when compiling via the top kselftest Makefile/target
> (due to some additional -W passed down and an awkward use of snprintf on my side...)
> 
> 
> test_signals_utils.c: In function ‘feats_to_string’:
> test_signals_utils.c:38:13: warning: passing argument 1 to restrict-qualified parameter aliases with argument 4 [-Wrestrict]
>     snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
>              ^~~~~~~~~~~~
> test_signals_utils.c: In function ‘default_handler’:
> test_signals_utils.c:192:19: warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘long long unsigned int’ [-Wformat=]
>     "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
>                   ~^
> 
> will be fixed in V4 as:
> 
> 
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> index 31788a1d33a4..c0f3cd1b560a 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -23,21 +23,25 @@ extern struct tdescr *current;
>  static int sig_copyctx = SIGTRAP;
>  static char *feats_store[FMAX_END] = {
> -       "SSBS",
> -       "PAN",
> -       "UAO",
> +       " SSBS ",
> +       " PAN ",
> +       " UAO ",
>  };
>  #define MAX_FEATS_SZ   128
> +static char feats_string[MAX_FEATS_SZ];
> +
>  static inline char *feats_to_string(unsigned long feats)
>  {
> -       static char feats_string[MAX_FEATS_SZ];
> +       for (int i = 0; i < FMAX_END; i++) {
> +               size_t tlen = 0;
> -       for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
> -               if (feats & 1UL << i)
> -                       snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
> -                                feats_string, feats_store[i]);
> +               if (feats & 1UL << i) {
> +                       strncat(feats_string, feats_store[i],

Should this be feats_string + tlen?

> +                               MAX_FEATS_SZ - 1 - tlen);

An assert(tlen <= MAX_FEATS_SZ - 1) is probably a good idea here,
in case more features are added to feats_store[] someday.

> +                       tlen += strlen(feats_store[i]);
> +               }

Don't we need to initialise tlen outside the loop?  Otherwise we just
zero it again after the +=.

>         }
>         return feats_string;
> @@ -190,7 +194,7 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
>                 /* it's a bug in the test code when this assert fail */
>                 assert(!current->sig_trig || current->triggered);
>                 fprintf(stderr,
> -                       "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> +                       "SIG_OK -- SP:%llX  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",

For consistency, can we have a "0x" prefix?

I think %p usually generates a "0x" prefix by itself, so 0x%p might give
a double prefix.

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-09 11:16     ` Dave Martin
@ 2019-08-09 12:20       ` Cristian Marussi
  2019-08-09 12:32         ` Dave Martin
  0 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-09 12:20 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel


Hi

On 8/9/19 12:16 PM, Dave Martin wrote:
> On Fri, Aug 09, 2019 at 11:54:06AM +0100, Cristian Marussi wrote:
>> Hi
>>
>> On 8/2/19 6:02 PM, Cristian Marussi wrote:
>>> Added some arm64/signal specific boilerplate and utility code to help
>>> further testcase development.
>>>
>>> A simple testcase and related helpers are also introduced in this commit:
>>> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
>>> messes with the ucontext_t from within the sig_handler, trying to toggle
>>> PSTATE state bits to switch the system between 32bit/64bit execution state.
>>> Expects SIGSEGV on test PASS.
>>>
>>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>>> ---
>>> A few fixes:
>>> - test_arm64_signals.sh runner script generation has been reviewed in order to
>>>    be safe against the .gitignore
>>> - using kselftest.h officially provided defines for tests' return values
>>> - removed SAFE_WRITE()/dump_uc()
>>> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>>>    the sigfault had been directly triggered by Kernel
>>> ---
>>>   tools/testing/selftests/arm64/Makefile        |   2 +-
>>>   .../testing/selftests/arm64/signal/.gitignore |   6 +
>>>   tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>>>   tools/testing/selftests/arm64/signal/README   |  59 ++++
>>>   .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>>>   .../selftests/arm64/signal/test_signals.c     |  26 ++
>>>   .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>>>   .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>>>   .../arm64/signal/test_signals_utils.h         |  13 +
>>>   .../arm64/signal/testcases/.gitignore         |   1 +
>>>   .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>>>   .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>>>   .../arm64/signal/testcases/testcases.h        |  83 ++++++
>>>   13 files changed, 905 insertions(+), 1 deletion(-)
>>>   create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>>>   create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>>>   create mode 100644 tools/testing/selftests/arm64/signal/README
>>>   create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>>>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>>>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>>>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>>>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>>>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>>>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
>>>
>>
>> A few more compilation warnings triggered by GCC-8 ONLY when compiling via the top kselftest Makefile/target
>> (due to some additional -W passed down and an awkward use of snprintf on my side...)
>>
>>
>> test_signals_utils.c: In function ‘feats_to_string’:
>> test_signals_utils.c:38:13: warning: passing argument 1 to restrict-qualified parameter aliases with argument 4 [-Wrestrict]
>>      snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
>>               ^~~~~~~~~~~~
>> test_signals_utils.c: In function ‘default_handler’:
>> test_signals_utils.c:192:19: warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘long long unsigned int’ [-Wformat=]
>>      "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
>>                    ~^
>>
>> will be fixed in V4 as:
>>
>>
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> index 31788a1d33a4..c0f3cd1b560a 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> @@ -23,21 +23,25 @@ extern struct tdescr *current;
>>   static int sig_copyctx = SIGTRAP;
>>   static char *feats_store[FMAX_END] = {
>> -       "SSBS",
>> -       "PAN",
>> -       "UAO",
>> +       " SSBS ",
>> +       " PAN ",
>> +       " UAO ",
>>   };
>>   #define MAX_FEATS_SZ   128
>> +static char feats_string[MAX_FEATS_SZ];
>> +
>>   static inline char *feats_to_string(unsigned long feats)
>>   {
>> -       static char feats_string[MAX_FEATS_SZ];
>> +       for (int i = 0; i < FMAX_END; i++) {
>> +               size_t tlen = 0;
>> -       for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
>> -               if (feats & 1UL << i)
>> -                       snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
>> -                                feats_string, feats_store[i]);
>> +               if (feats & 1UL << i) {
>> +                       strncat(feats_string, feats_store[i],
> 
> Should this be feats_string + tlen?
>

strncat appends to the end of a NULL terminated string overwriting the NULL itself and
appending its own NULL (as long as dest and src do not overlap and fits the max size param),
so it must be fed the start of the dest string to which we are appending
  
>> +                               MAX_FEATS_SZ - 1 - tlen);
> 
> An assert(tlen <= MAX_FEATS_SZ - 1) is probably a good idea here,
> in case more features are added to feats_store[] someday.
> 

Yes in fact...if not it would be simply truncated silently

>> +                       tlen += strlen(feats_store[i]);
>> +               }
> 
> Don't we need to initialise tlen outside the loop?  Otherwise we just
> zero it again after the +=.

..and that's a bug :<

> 
>>          }
>>          return feats_string;
>> @@ -190,7 +194,7 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
>>                  /* it's a bug in the test code when this assert fail */
>>                  assert(!current->sig_trig || current->triggered);
>>                  fprintf(stderr,
>> -                       "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
>> +                       "SIG_OK -- SP:%llX  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> 
> For consistency, can we have a "0x" prefix?
> 
> I think %p usually generates a "0x" prefix by itself, so 0x%p might give
> a double prefix.
> 

Yes you are right.

Moreover I'm in doubt what to do generally with all these stderr output, because I optionally discard to null
testing standalone, but this is not what the KSFT framework runner script does, so arm64/signal tests
end up being overly verbose when run from the framework (even if tests use anyway the KSFT exit codes
conventions so all the results are correctly reported); but I suppose I'll receive a clear indication on this matter
from the maintainers at the end...
  
Cheers

Cristian

> [...]
> 
> Cheers
> ---Dave
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-09 12:20       ` Cristian Marussi
@ 2019-08-09 12:32         ` Dave Martin
  0 siblings, 0 replies; 56+ messages in thread
From: Dave Martin @ 2019-08-09 12:32 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-arm-kernel, linux-kselftest

On Fri, Aug 09, 2019 at 01:20:45PM +0100, Cristian Marussi wrote:
> 
> Hi
> 
> On 8/9/19 12:16 PM, Dave Martin wrote:
> >On Fri, Aug 09, 2019 at 11:54:06AM +0100, Cristian Marussi wrote:
> >>Hi
> >>
> >>On 8/2/19 6:02 PM, Cristian Marussi wrote:
> >>>Added some arm64/signal specific boilerplate and utility code to help
> >>>further testcase development.
> >>>
> >>>A simple testcase and related helpers are also introduced in this commit:
> >>>mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
> >>>messes with the ucontext_t from within the sig_handler, trying to toggle
> >>>PSTATE state bits to switch the system between 32bit/64bit execution state.
> >>>Expects SIGSEGV on test PASS.
> >>>
> >>>Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> >>>---

[...]

> >>diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> >>index 31788a1d33a4..c0f3cd1b560a 100644
> >>--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
> >>+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> >>@@ -23,21 +23,25 @@ extern struct tdescr *current;
> >>  static int sig_copyctx = SIGTRAP;
> >>  static char *feats_store[FMAX_END] = {
> >>-       "SSBS",
> >>-       "PAN",
> >>-       "UAO",
> >>+       " SSBS ",
> >>+       " PAN ",
> >>+       " UAO ",
> >>  };
> >>  #define MAX_FEATS_SZ   128
> >>+static char feats_string[MAX_FEATS_SZ];
> >>+
> >>  static inline char *feats_to_string(unsigned long feats)
> >>  {
> >>-       static char feats_string[MAX_FEATS_SZ];
> >>+       for (int i = 0; i < FMAX_END; i++) {
> >>+               size_t tlen = 0;
> >>-       for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
> >>-               if (feats & 1UL << i)
> >>-                       snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
> >>-                                feats_string, feats_store[i]);
> >>+               if (feats & 1UL << i) {
> >>+                       strncat(feats_string, feats_store[i],
> >
> >Should this be feats_string + tlen?
> >
> 
> strncat appends to the end of a NULL terminated string overwriting the NULL itself and
> appending its own NULL (as long as dest and src do not overlap and fits the max size param),
> so it must be fed the start of the dest string to which we are appending
>
> >>+                               MAX_FEATS_SZ - 1 - tlen);

I see.  Yes, you're right -- I was confusing strncat() with strncpy().

> >An assert(tlen <= MAX_FEATS_SZ - 1) is probably a good idea here,
> >in case more features are added to feats_store[] someday.
> >
> 
> Yes in fact...if not it would be simply truncated silently

I think MAX_FEATS - 1 - tlen would overflow.  tlen is a size_t, so the
result would might be a giant unsigned number in this case, leading to a
potential buffer overrun in strncat().

> 
> >>+                       tlen += strlen(feats_store[i]);
> >>+               }
> >
> >Don't we need to initialise tlen outside the loop?  Otherwise we just
> >zero it again after the +=.
> 
> ..and that's a bug :<

OK

> >
> >>         }
> >>         return feats_string;
> >>@@ -190,7 +194,7 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
> >>                 /* it's a bug in the test code when this assert fail */
> >>                 assert(!current->sig_trig || current->triggered);
> >>                 fprintf(stderr,
> >>-                       "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> >>+                       "SIG_OK -- SP:%llX  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> >
> >For consistency, can we have a "0x" prefix?
> >
> >I think %p usually generates a "0x" prefix by itself, so 0x%p might give
> >a double prefix.
> >
> 
> Yes you are right.
> 
> Moreover I'm in doubt what to do generally with all these stderr
> output, because I optionally discard to null testing standalone, but
> this is not what the KSFT framework runner script does, so
> arm64/signal tests end up being overly verbose when run from the
> framework (even if tests use anyway the KSFT exit codes conventions
> so all the results are correctly reported); but I suppose I'll
> receive a clear indication on this matter from the maintainers at the
> end...

Sure, keep the prints for now.  If they're potentially useful we can
always find a way to make them optional.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-02 17:02 ` [PATCH v3 02/11] kselftest: arm64: adds first test and common utils Cristian Marussi
                     ` (2 preceding siblings ...)
  2019-08-09 10:54   ` Cristian Marussi
@ 2019-08-12 12:43   ` Amit Kachhap
  2019-08-13 13:22     ` Cristian Marussi
  2019-08-13 16:24   ` Dave Martin
  4 siblings, 1 reply; 56+ messages in thread
From: Amit Kachhap @ 2019-08-12 12:43 UTC (permalink / raw)
  To: Cristian Marussi, linux-kselftest, linux-arm-kernel, shuah
  Cc: andreyknvl, Dave P Martin

Hi Cristian,

On 8/2/19 10:32 PM, Cristian Marussi wrote:
> Added some arm64/signal specific boilerplate and utility code to help
> further testcase development.
>
> A simple testcase and related helpers are also introduced in this commit:
> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
> messes with the ucontext_t from within the sig_handler, trying to toggle
> PSTATE state bits to switch the system between 32bit/64bit execution state.
> Expects SIGSEGV on test PASS.
>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> A few fixes:
> - test_arm64_signals.sh runner script generation has been reviewed in order to
>    be safe against the .gitignore
> - using kselftest.h officially provided defines for tests' return values
> - removed SAFE_WRITE()/dump_uc()
> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>    the sigfault had been directly triggered by Kernel
> ---
>   tools/testing/selftests/arm64/Makefile        |   2 +-
>   .../testing/selftests/arm64/signal/.gitignore |   6 +
>   tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>   tools/testing/selftests/arm64/signal/README   |  59 ++++
>   .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>   .../selftests/arm64/signal/test_signals.c     |  26 ++
>   .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>   .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>   .../arm64/signal/test_signals_utils.h         |  13 +
>   .../arm64/signal/testcases/.gitignore         |   1 +
>   .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>   .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>   .../arm64/signal/testcases/testcases.h        |  83 ++++++
>   13 files changed, 905 insertions(+), 1 deletion(-)
>   create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>   create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>   create mode 100644 tools/testing/selftests/arm64/signal/README
>   create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
>
> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
> index 03a0d4f71218..af59dc74e0dc 100644
> --- a/tools/testing/selftests/arm64/Makefile
> +++ b/tools/testing/selftests/arm64/Makefile
> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>   ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>
>   ifeq ("x$(ARCH)", "xarm64")
> -SUBDIRS :=
> +SUBDIRS := signal
>   else
>   SUBDIRS :=
>   endif
> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
> new file mode 100644
> index 000000000000..434f65c15f03
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/.gitignore
> @@ -0,0 +1,6 @@
> +# Helper script's internal testcases list (TPROGS) is regenerated
> +# each time by Makefile on standalone (non KSFT driven) runs.
> +# Committing such list creates a dependency between testcases
> +# patches such that they are no more easily revertable. Just ignore.
> +test_arm64_signals.src_shell
> +test_arm64_signals.sh
> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
> new file mode 100644
> index 000000000000..8c8d08be4b0d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/Makefile
> @@ -0,0 +1,88 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +# Supports also standalone invokation out of KSFT-tree
> +# Compile standalone and run on your device with:
> +#
> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
> +#
> +# Run standalone on device with:
> +#
> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
> +#
> +# If INSTALL_PATH= is NOT provided it will default to ./install
> +
> +# A proper top_srcdir is needed both by KSFT(lib.mk)
> +# and standalone builds
> +top_srcdir = ../../../../..
> +
> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
> +PROGS := $(patsubst %.c,%,$(SRCS))
> +
> +# Guessing as best as we can where the Kernel headers
> +# could have been installed depending on ENV config and
> +# type of invocation.
> +ifeq ($(KBUILD_OUTPUT),)
> +khdr_dir = $(top_srcdir)/usr/include
> +else
> +ifeq (0,$(MAKELEVEL))
> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
> +else
> +# the KSFT preferred location when KBUILD_OUTPUT is set
> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
> +endif
> +endif
> +
> +CFLAGS += -I$(khdr_dir)
> +
> +# Standalone run
> +ifeq (0,$(MAKELEVEL))
> +CC := $(CROSS_COMPILE)gcc
> +RUNNER_SRC = test_arm64_signals.src_shell
> +RUNNER = test_arm64_signals.sh
> +INSTALL_PATH ?= install/
> +
> +all: $(RUNNER)
> +
> +$(RUNNER): $(PROGS)
> +     cp $(RUNNER_SRC) $(RUNNER)
> +     sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
> +
> +install: all
> +     mkdir -p $(INSTALL_PATH)/testcases
> +     cp $(PROGS) $(INSTALL_PATH)/testcases
> +     cp $(RUNNER) $(INSTALL_PATH)/
> +
> +.PHONY clean:
> +     rm -f $(PROGS)
> +# KSFT run
> +else
> +# 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
> +
> +# This include mk 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)
> +endif
> +
> +# 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

I suppose *.h can be removed from the targets here.


> +     @if [ ! -d $(khdr_dir) ]; then \
> +             echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
> +             echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
> +     fi
> +     $(CC) $(CFLAGS) $^ -o $@
> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
> new file mode 100644
> index 000000000000..53f005f7910a
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/README
> @@ -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 messes-up with the sigframe ucontext_t from
> +    inside the sighandler 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
> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> new file mode 100755
> index 000000000000..163e941e2997
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> @@ -0,0 +1,55 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +ret=0
> +keep_on_fail=0
> +err_out="2> /dev/null"
> +
> +usage() {
> +     echo "Usage: `basename $0` [-v] [-k]"
> +     exit 1
> +}
> +
> +# avoiding getopt to avoid compatibility issues on targets
> +# with limited resources
> +while [ $# -gt 0 ]
> +do
> +     case $1 in
> +             "-k")
> +                     keep_on_fail=1
> +                     ;;
> +             "-v")
> +                     err_out=
> +                     ;;
> +             *)
> +                     usage
> +                     ;;
> +     esac
> +     shift
> +done
> +
> +TPROGS=
> +
> +tot=$(echo $TPROGS | wc -w)
> +
> +# Tests are expected in testcases/ subdir inside the installation path
> +workdir="`dirname $0 2>/dev/null`"
> +[ -n $workdir ] && cd $workdir
> +
> +passed=0
> +run=0
> +for test in $TPROGS
> +do
> +     run=$((run + 1))
> +     eval ./$test $err_out
> +     if [ $? != 0 ]; then
> +             [ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
> +     else
> +             passed=$((passed + 1))
> +     fi
> +done
> +
> +echo "==>> PASSED: $passed/$run on $tot available tests."
> +
> +exit $ret
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
> new file mode 100644
> index 000000000000..3447d7011aec
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <kselftest.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +
> +struct tdescr *current;
> +extern struct tdescr tde;
> +
> +int main(int argc, char *argv[])
> +{
> +     current = &tde;
> +
> +     ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
> +                    current->name, current->descr, current->sig_trig,
> +                    current->sig_ok, current);
> +     if (test_setup(current)) {
> +             if (test_run(current))
> +                     test_result(current);
> +             test_cleanup(current);
> +     }
> +
> +     return current->pass ? KSFT_PASS : KSFT_FAIL;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> new file mode 100644
> index 000000000000..85db3ac44b32
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
> @@ -0,0 +1,137 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_H__
> +#define __TEST_SIGNALS_H__
> +
> +#include <assert.h>
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <ucontext.h>
> +#include <stdint.h>
Headers can be added in alphabetically order.

Thanks,
Amit D
> +
> +/*
> + * 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>
> +
> +/* pasted from include/linux/stringify.h */
> +#define __stringify_1(x...)  #x
> +#define __stringify(x...)    __stringify_1(x)
> +
> +/*
> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
> + * avoid inject any dependency on the used toolchain regarding possibly
> + * still unsupported ARMv8 extensions.
> + *
> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
> + * would introduce a compile-time dependency on possibly unsupported ARMv8
> + * Extensions: you could end-up failing to build the test depending on the
> + * available toolchain.
> + * This is undesirable since some tests, even if specifically targeted at some
> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
> + * it transparently not caring at all about the effective set of supported
> + * features).
> + * On the other side we will expect to observe different behaviours if the
> + * feature is supported or not: usually getting a SIGILL when trying to use
> + * unsupported features. For this reason we have anyway in place some
> + * preliminary run-time checks about the cpu effectively supported features.
> + *
> + * This helper macro is meant to be used for regs readable at EL0, BUT some
> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
> + * if the required reg is included in the supported encoding space:
> + *
> + *  Documentation/arm64/cpu-feature-regsiters.txt
> + *
> + *  "The infrastructure emulates only the following system register space:
> + *           Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
> + */
> +#define get_regval(regname, out) \
> +     asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
> +
> +/* Regs encoding and masks naming copied in from sysreg.h */
> +#define SYS_ID_AA64MMFR1_EL1 S3_0_C0_C7_1    /* MRS Emulated */
> +#define SYS_ID_AA64MMFR2_EL1 S3_0_C0_C7_2    /* MRS Emulated */
> +#define ID_AA64MMFR1_PAN_SHIFT       20
> +#define ID_AA64MMFR2_UAO_SHIFT       4
> +
> +/* Local Helpers */
> +#define IS_PAN_SUPPORTED(val) \
> +     (!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
> +#define IS_UAO_SUPPORTED(val) \
> +     (!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
> +
> +#define S3_MRS_SSBS_SYSREG           S3_3_C4_C2_6    /* EL0 supported */
> +
> +/*
> + * Feature flags used in tdescr.feats_required to specify
> + * any feature by the test
> + */
> +enum {
> +     FSSBS_BIT,
> +     FPAN_BIT,
> +     FUAO_BIT,
> +     FMAX_END
> +};
> +
> +#define FEAT_SSBS            (1UL << FSSBS_BIT)
> +#define FEAT_PAN             (1UL << FPAN_BIT)
> +#define FEAT_UAO             (1UL << FUAO_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            feats_ok;
> +     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;
> +
> +     /* a setup function to be called before test starts */
> +     int (*setup)(struct tdescr *td);
> +     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);
> +
> +     void *priv;
> +};
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> new file mode 100644
> index 000000000000..ac0055f6340b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -0,0 +1,261 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <assert.h>
> +#include <sys/auxv.h>
> +#include <linux/auxvec.h>
> +#include <ucontext.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +#include "testcases/testcases.h"
> +
> +extern struct tdescr *current;
> +
> +static char *feats_store[FMAX_END] = {
> +     "SSBS",
> +     "PAN",
> +     "UAO"
> +};
> +
> +#define MAX_FEATS_SZ 128
> +static inline char *feats_to_string(unsigned long feats)
> +{
> +     static char feats_string[MAX_FEATS_SZ];
> +
> +     for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
> +             if (feats & 1UL << i)
> +                     snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
> +                              feats_string, feats_store[i]);
> +     }
> +
> +     return feats_string;
> +}
> +
> +static void unblock_signal(int signum)
> +{
> +     sigset_t sset;
> +
> +     sigemptyset(&sset);
> +     sigaddset(&sset, signum);
> +     sigprocmask(SIG_UNBLOCK, &sset, NULL);
> +}
> +
> +static void default_result(struct tdescr *td, bool force_exit)
> +{
> +     if (td->pass)
> +             fprintf(stderr, "==>> completed. PASS(1)\n");
> +     else
> +             fprintf(stdout, "==>> completed. FAIL(0)\n");
> +     if (force_exit)
> +             exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
> +}
> +
> +static inline bool are_feats_ok(struct tdescr *td)
> +{
> +     return td ? td->feats_required == td->feats_supported : 0;
> +}
> +
> +static void default_handler(int signum, siginfo_t *si, void *uc)
> +{
> +     if (current->sig_trig && signum == current->sig_trig) {
> +             fprintf(stderr, "Handling SIG_TRIG\n");
> +             current->triggered = 1;
> +             /* ->run was asserted NON-NULL in test_setup() already */
> +             current->run(current, si, uc);
> +     } else if (signum == SIGILL && !current->initialized) {
> +             /*
> +              * A SIGILL here while still not initialized means we failed
> +              * even to asses the existence of features during init
> +              */
> +             fprintf(stdout,
> +                     "Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
> +             current->feats_supported = 0;
> +     } else if (current->sig_ok && signum == current->sig_ok) {
> +             /* it's a bug in the test code when this assert fail */
> +             assert(!current->sig_trig || current->triggered);
> +             fprintf(stderr,
> +                     "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> +                     ((ucontext_t *)uc)->uc_mcontext.sp,
> +                     si->si_addr, si->si_code, current->token,
> +                     current->token - si->si_addr);
> +             /*
> +              * fake_sigreturn tests, which have sanity_enabled=1, set, at
> +              * the very last time, the token field to the SP address used
> +              * to place the fake sigframe: so token==0 means we never made
> +              * it to the end, segfaulting well-before, and the test is
> +              * possibly broken.
> +              */
> +             if (!current->sanity_disabled && !current->token) {
> +                     fprintf(stdout,
> +                             "current->token ZEROED...test is probably broken!\n");
> +                     assert(0);
> +             }
> +             /*
> +              * Trying to narrow down the SEGV to the ones generated by
> +              * Kernel itself via arm64_notify_segfault()
> +              */
> +             if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
> +                     fprintf(stdout,
> +                             "si_code != SEGV_ACCERR...test is probably broken!\n");
> +                     assert(0);
> +             }
> +             fprintf(stderr, "Handling SIG_OK\n");
> +             current->pass = 1;
> +             /*
> +              * Some tests can lead to SEGV loops: in such a case we want
> +              * to terminate immediately exiting straight away
> +              */
> +             default_result(current, 1);
> +     } else {
> +             if (signum == current->sig_unsupp && !are_feats_ok(current)) {
> +                     fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
> +                     current->pass = 1;
> +             } else if (signum == SIGALRM && current->timeout) {
> +                     fprintf(stderr, "-- Timeout !\n");
> +             } else {
> +                     fprintf(stderr,
> +                             "-- RX UNEXPECTED SIGNAL: %d\n", signum);
> +             }
> +             default_result(current, 1);
> +     }
> +}
> +
> +static int default_setup(struct tdescr *td)
> +{
> +     struct sigaction sa;
> +
> +     sa.sa_sigaction = default_handler;
> +     sa.sa_flags = SA_SIGINFO;
> +     if (td->sa_flags)
> +             sa.sa_flags |= td->sa_flags;
> +     sigemptyset(&sa.sa_mask);
> +     /* uncatchable signals naturally skipped ... */
> +     for (int sig = 1; sig < 32; sig++)
> +             sigaction(sig, &sa, NULL);
> +     /*
> +      * RT Signals default disposition is Term but they cannot be
> +      * generated by the Kernel in response to our tests; so just catch
> +      * them all and report them as UNEXPECTED signals.
> +      */
> +     for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
> +             sigaction(sig, &sa, NULL);
> +
> +     /* just in case...unblock explicitly all we need */
> +     if (td->sig_trig)
> +             unblock_signal(td->sig_trig);
> +     if (td->sig_ok)
> +             unblock_signal(td->sig_ok);
> +     if (td->sig_unsupp)
> +             unblock_signal(td->sig_unsupp);
> +
> +     if (td->timeout) {
> +             unblock_signal(SIGALRM);
> +             alarm(td->timeout);
> +     }
> +     fprintf(stderr, "Registered handlers for all signals.\n");
> +
> +     return 1;
> +}
> +
> +static inline int default_trigger(struct tdescr *td)
> +{
> +     return !raise(td->sig_trig);
> +}
> +
> +static int test_init(struct tdescr *td)
> +{
> +     td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
> +     if (!td->minsigstksz)
> +             td->minsigstksz = MINSIGSTKSZ;
> +     fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
> +
> +     if (td->feats_required) {
> +             bool feats_ok = false;
> +             td->feats_supported = 0;
> +             /*
> +              * Checking for CPU required features using both the
> +              * auxval and the arm64 MRS Emulation to read sysregs.
> +              */
> +             if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
> +                     uint64_t val = 0;
> +
> +                     if (td->feats_required & FEAT_SSBS) {
> +                             /* Uses HWCAP to check capability */
> +                             if (getauxval(AT_HWCAP) & HWCAP_SSBS)
> +                                     td->feats_supported |= FEAT_SSBS;
> +                     }
> +                     if (td->feats_required & FEAT_PAN) {
> +                             /* Uses MRS emulation to check capability */
> +                             get_regval(SYS_ID_AA64MMFR1_EL1, val);
> +                             if (IS_PAN_SUPPORTED(val))
> +                                     td->feats_supported |= FEAT_PAN;
> +                     }
> +                     if (td->feats_required & FEAT_UAO) {
> +                             /* Uses MRS emulation to check capability */
> +                             get_regval(SYS_ID_AA64MMFR2_EL1 , val);
> +                             if (IS_UAO_SUPPORTED(val))
> +                                     td->feats_supported |= FEAT_UAO;
> +                     }
> +             } else {
> +                     fprintf(stderr,
> +                             "HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
> +             }
> +             feats_ok = are_feats_ok(td);
> +             fprintf(stderr,
> +                     "Required Features: [%s] %ssupported\n",
> +                     feats_ok ? feats_to_string(td->feats_supported) :
> +                     feats_to_string(td->feats_required ^ td->feats_supported),
> +                     !feats_ok ? "NOT " : "");
> +     }
> +
> +     td->initialized = 1;
> +     return 1;
> +}
> +
> +int test_setup(struct tdescr *td)
> +{
> +     /* assert core invariants symptom of a rotten testcase */
> +     assert(current);
> +     assert(td);
> +     assert(td->name);
> +     assert(td->run);
> +
> +     if (!test_init(td))
> +             return 0;
> +
> +     if (td->setup)
> +             return td->setup(td);
> +     else
> +             return default_setup(td);
> +}
> +
> +int test_run(struct tdescr *td)
> +{
> +     if (td->sig_trig) {
> +             if (td->trigger)
> +                     return td->trigger(td);
> +             else
> +                     return default_trigger(td);
> +     } else {
> +             return td->run(td, NULL, NULL);
> +     }
> +}
> +
> +void test_result(struct tdescr *td)
> +{
> +     if (td->check_result)
> +             td->check_result(td);
> +     default_result(td, 0);
> +}
> +
> +void test_cleanup(struct tdescr *td)
> +{
> +     if (td->cleanup)
> +             td->cleanup(td);
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> new file mode 100644
> index 000000000000..8658d1a7d4b9
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_UTILS_H__
> +#define __TEST_SIGNALS_UTILS_H__
> +
> +#include "test_signals.h"
> +
> +int test_setup(struct tdescr *td);
> +void test_cleanup(struct tdescr *td);
> +int test_run(struct tdescr *td);
> +void test_result(struct tdescr *td);
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> new file mode 100644
> index 000000000000..8651272e3cfc
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -0,0 +1 @@
> +mangle_pstate_invalid_compat_toggle
> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> new file mode 100644
> index 000000000000..971193e7501b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
> +                                  ucontext_t *uc)
> +{
> +     ASSERT_GOOD_CONTEXT(uc);
> +
> +     /* This config should trigger a SIGSEGV by Kernel */
> +     uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
> +
> +     return 1;
> +}
> +
> +struct tdescr tde = {
> +             .sanity_disabled = true,
> +             .name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
> +             .descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
> +             .sig_trig = SIGUSR1,
> +             .sig_ok = SIGSEGV,
> +             .run = mangle_invalid_pstate_run,
> +};
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> new file mode 100644
> index 000000000000..a59785092e1f
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> @@ -0,0 +1,150 @@
> +#include "testcases.h"
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +                             size_t resv_sz, size_t *offset)
> +{
> +     size_t offs = 0;
> +     struct _aarch64_ctx *found = NULL;
> +
> +     if (!head || resv_sz < HDR_SZ)
> +             return found;
> +
> +     do {
> +             if (head->magic == magic) {
> +                     found = head;
> +                     break;
> +             }
> +             offs += head->size;
> +             head = GET_RESV_NEXT_HEAD(head);
> +     } while (offs < resv_sz - HDR_SZ);
> +
> +     if (offset)
> +             *offset = offs;
> +
> +     return found;
> +}
> +
> +bool validate_extra_context(struct extra_context *extra, char **err)
> +{
> +     struct _aarch64_ctx *term;
> +
> +     if (!extra || !err)
> +             return false;
> +
> +     fprintf(stderr, "Validating EXTRA...\n");
> +     term = GET_RESV_NEXT_HEAD(extra);
> +     if (!term || term->magic || term->size) {
> +             *err = "UN-Terminated EXTRA context";
> +             return false;
> +     }
> +     if (extra->datap & 0x0fUL)
> +             *err = "Extra DATAP misaligned";
> +     else if (extra->size & 0x0fUL)
> +             *err = "Extra SIZE misaligned";
> +     else if (extra->datap != (uint64_t)term + sizeof(*term))
> +             *err = "Extra DATAP misplaced (not contiguos)";
> +     if (*err)
> +             return false;
> +
> +     return true;
> +}
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
> +{
> +     bool terminated = false;
> +     size_t offs = 0;
> +     int flags = 0;
> +     struct extra_context *extra = NULL;
> +     struct _aarch64_ctx *head =
> +             (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
> +
> +     if (!err)
> +             return false;
> +     /* Walk till the end terminator verifying __reserved contents */
> +     while (head && !terminated && offs < resv_sz) {
> +             if ((uint64_t)head & 0x0fUL) {
> +                     *err = "Misaligned HEAD";
> +                     return false;
> +             }
> +
> +             switch (head->magic) {
> +                     case 0:
> +                             if (head->size)
> +                                     *err = "Bad size for MAGIC0";
> +                             else
> +                                     terminated = true;
> +                             break;
> +                     case FPSIMD_MAGIC:
> +                             if (flags & FPSIMD_CTX)
> +                                     *err = "Multiple FPSIMD_MAGIC";
> +                             else if (head->size !=
> +                                      sizeof(struct fpsimd_context))
> +                                     *err = "Bad size for fpsimd_context";
> +                             flags |= FPSIMD_CTX;
> +                             break;
> +                     case ESR_MAGIC:
> +                             if (head->size != sizeof(struct esr_context))
> +                                     fprintf(stderr,
> +                                             "Bad size for esr_context is not an error...just ignore.\n");
> +                             break;
> +                     case SVE_MAGIC:
> +                             if (flags & SVE_CTX)
> +                                     *err = "Multiple SVE_MAGIC";
> +                             else if (head->size !=
> +                                      sizeof(struct sve_context))
> +                                     *err = "Bad size for sve_context";
> +                             flags |= SVE_CTX;
> +                             break;
> +                     case EXTRA_MAGIC:
> +                             if (flags & EXTRA_CTX)
> +                                     *err = "Multiple EXTRA_MAGIC";
> +                             else if (head->size !=
> +                                      sizeof(struct extra_context))
> +                                     *err = "Bad size for extra_context";
> +                             flags |= EXTRA_CTX;
> +                             extra = (struct extra_context *)head;
> +                             break;
> +                     case KSFT_BAD_MAGIC:
> +                             /*
> +                              * This is a BAD magic header defined
> +                              * artificially by a testcase and surely
> +                              * unknown to the Kernel parse_user_sigframe().
> +                              * It MUST cause a Kernel induced SEGV
> +                              */
> +                             *err = "BAD MAGIC !";
> +                             break;
> +                     default:
> +                             /*
> +                              * A still unknown Magic: potentially freshly added
> +                              * to the Kernel code and still unknown to the
> +                              * tests.
> +                              */
> +                             fprintf(stdout,
> +                                     "SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
> +                                     head->magic);
> +                             break;
> +             }
> +
> +             if (*err)
> +                     return false;
> +
> +             offs += head->size;
> +             if (resv_sz - offs < sizeof(*head)) {
> +                     *err = "HEAD Overrun";
> +                     return false;
> +             }
> +
> +             if (flags & EXTRA_CTX)
> +                     if (!validate_extra_context(extra, err))
> +                             return false;
> +
> +             head = GET_RESV_NEXT_HEAD(head);
> +     }
> +
> +     if (terminated && !(flags & FPSIMD_CTX)) {
> +             *err = "Missing FPSIMD";
> +             return false;
> +     }
> +
> +     return true;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> new file mode 100644
> index 000000000000..624717c71b1d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> @@ -0,0 +1,83 @@
> +#ifndef __TESTCASES_H__
> +#define __TESTCASES_H__
> +
> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <ucontext.h>
> +#include <assert.h>
> +
> +/* Architecture specific sigframe definitions */
> +#include <asm/sigcontext.h>
> +
> +#define FPSIMD_CTX   (1 << 0)
> +#define SVE_CTX              (1 << 1)
> +#define EXTRA_CTX    (1 << 2)
> +
> +#define KSFT_BAD_MAGIC       0xdeadbeef
> +
> +#define HDR_SZ \
> +     sizeof(struct _aarch64_ctx)
> +
> +#define GET_SF_RESV_HEAD(sf) \
> +     (struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
> +
> +#define GET_SF_RESV_SIZE(sf) \
> +     sizeof((sf).uc.uc_mcontext.__reserved)
> +
> +#define GET_UCP_RESV_SIZE(ucp) \
> +     sizeof((ucp)->uc_mcontext.__reserved)
> +
> +#define ASSERT_BAD_CONTEXT(uc) do {                                  \
> +     char *err = NULL;                                               \
> +     assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
> +     if (err)                                                        \
> +             fprintf(stderr,                                         \
> +                     "Using badly built context - ERR: %s\n", err);  \
> +} while(0)
> +
> +#define ASSERT_GOOD_CONTEXT(uc) do {                                  \
> +     char *err = NULL;                                                \
> +     if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) {   \
> +             if (err)                                                 \
> +                     fprintf(stderr,                                  \
> +                             "Detected BAD context - ERR: %s\n", err);\
> +             assert(0);                                               \
> +     } else {                                                         \
> +             fprintf(stderr, "uc context validated.\n");              \
> +     }                                                                \
> +} while(0)
> +
> +/* head->size accounts both for payload and header _aarch64_ctx size ! */
> +#define GET_RESV_NEXT_HEAD(h) \
> +     (struct _aarch64_ctx *)((char *)(h) + (h)->size)
> +
> +struct fake_sigframe {
> +     siginfo_t       info;
> +     ucontext_t      uc;
> +};
> +
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
> +
> +bool validate_extra_context(struct extra_context *extra, char **err);
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +                             size_t resv_sz, size_t *offset);
> +
> +static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
> +                                               size_t resv_sz,
> +                                               size_t *offset)
> +{
> +     return get_header(head, 0, resv_sz, offset);
> +}
> +
> +static inline void write_terminator_record(struct _aarch64_ctx *tail)
> +{
> +     if (tail) {
> +             tail->magic = 0;
> +             tail->size = 0;
> +     }
> +}
> +#endif
>
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-12 12:43   ` Amit Kachhap
@ 2019-08-13 13:22     ` Cristian Marussi
  2019-08-14 10:22       ` Amit Kachhap
  0 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-13 13:22 UTC (permalink / raw)
  To: Amit Kachhap, linux-kselftest, linux-arm-kernel, shuah
  Cc: andreyknvl, Dave P Martin

Hi Amit

thanks for the review.

On 12/08/2019 13:43, Amit Kachhap wrote:
> Hi Cristian,
> 
> On 8/2/19 10:32 PM, Cristian Marussi wrote:
>> Added some arm64/signal specific boilerplate and utility code to help
>> further testcase development.
>>
>> A simple testcase and related helpers are also introduced in this commit:
>> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
>> messes with the ucontext_t from within the sig_handler, trying to toggle
>> PSTATE state bits to switch the system between 32bit/64bit execution state.
>> Expects SIGSEGV on test PASS.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>> A few fixes:
>> - test_arm64_signals.sh runner script generation has been reviewed in order to
>>    be safe against the .gitignore
>> - using kselftest.h officially provided defines for tests' return values
>> - removed SAFE_WRITE()/dump_uc()
>> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>>    the sigfault had been directly triggered by Kernel
>> ---
>>   tools/testing/selftests/arm64/Makefile        |   2 +-
>>   .../testing/selftests/arm64/signal/.gitignore |   6 +
>>   tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>>   tools/testing/selftests/arm64/signal/README   |  59 ++++
>>   .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>>   .../selftests/arm64/signal/test_signals.c     |  26 ++
>>   .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>>   .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>>   .../arm64/signal/test_signals_utils.h         |  13 +
>>   .../arm64/signal/testcases/.gitignore         |   1 +
>>   .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>>   .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>>   .../arm64/signal/testcases/testcases.h        |  83 ++++++
>>   13 files changed, 905 insertions(+), 1 deletion(-)
>>   create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>>   create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>>   create mode 100644 tools/testing/selftests/arm64/signal/README
>>   create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>>   create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>>   create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
>>
>> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
>> index 03a0d4f71218..af59dc74e0dc 100644
>> --- a/tools/testing/selftests/arm64/Makefile
>> +++ b/tools/testing/selftests/arm64/Makefile
>> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>>   ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>>   
>>   ifeq ("x$(ARCH)", "xarm64")
>> -SUBDIRS :=
>> +SUBDIRS := signal
>>   else
>>   SUBDIRS :=
>>   endif
>> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
>> new file mode 100644
>> index 000000000000..434f65c15f03
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/.gitignore
>> @@ -0,0 +1,6 @@
>> +# Helper script's internal testcases list (TPROGS) is regenerated
>> +# each time by Makefile on standalone (non KSFT driven) runs.
>> +# Committing such list creates a dependency between testcases
>> +# patches such that they are no more easily revertable. Just ignore.
>> +test_arm64_signals.src_shell
>> +test_arm64_signals.sh
>> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
>> new file mode 100644
>> index 000000000000..8c8d08be4b0d
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/Makefile
>> @@ -0,0 +1,88 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2019 ARM Limited
>> +
>> +# Supports also standalone invokation out of KSFT-tree
>> +# Compile standalone and run on your device with:
>> +#
>> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
>> +#
>> +# Run standalone on device with:
>> +#
>> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
>> +#
>> +# If INSTALL_PATH= is NOT provided it will default to ./install
>> +
>> +# A proper top_srcdir is needed both by KSFT(lib.mk)
>> +# and standalone builds
>> +top_srcdir = ../../../../..
>> +
>> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
>> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
>> +PROGS := $(patsubst %.c,%,$(SRCS))
>> +
>> +# Guessing as best as we can where the Kernel headers
>> +# could have been installed depending on ENV config and
>> +# type of invocation.
>> +ifeq ($(KBUILD_OUTPUT),)
>> +khdr_dir = $(top_srcdir)/usr/include
>> +else
>> +ifeq (0,$(MAKELEVEL))
>> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
>> +else
>> +# the KSFT preferred location when KBUILD_OUTPUT is set
>> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
>> +endif
>> +endif
>> +
>> +CFLAGS += -I$(khdr_dir)
>> +
>> +# Standalone run
>> +ifeq (0,$(MAKELEVEL))
>> +CC := $(CROSS_COMPILE)gcc
>> +RUNNER_SRC = test_arm64_signals.src_shell
>> +RUNNER = test_arm64_signals.sh
>> +INSTALL_PATH ?= install/
>> +
>> +all: $(RUNNER)
>> +
>> +$(RUNNER): $(PROGS)
>> +	cp $(RUNNER_SRC) $(RUNNER)
>> +	sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
>> +
>> +install: all
>> +	mkdir -p $(INSTALL_PATH)/testcases
>> +	cp $(PROGS) $(INSTALL_PATH)/testcases
>> +	cp $(RUNNER) $(INSTALL_PATH)/
>> +
>> +.PHONY clean:
>> +	rm -f $(PROGS)
>> +# KSFT run
>> +else
>> +# 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
>> +
>> +# This include mk 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)
>> +endif
>> +
>> +# 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
>
> I suppose *.h can be removed from the targets here.

*.h are in the pre-reqs, $(PROGS) represent the targets and it's comprised by the *.c file contained in testcases/ (excluding testcases.c)

If I remove the *.h from this rule, targets won't be rebuilt when headers are changed (like after having added an hypotethical inline)...

or am I missing something else ?


> 
> 
>> +	@if [ ! -d $(khdr_dir) ]; then \
>> +		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
>> +		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
>> +	fi
>> +	$(CC) $(CFLAGS) $^ -o $@
>> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
>> new file mode 100644
>> index 000000000000..53f005f7910a
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/README
>> @@ -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 messes-up with the sigframe ucontext_t from
>> +    inside the sighandler 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
>> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>> new file mode 100755
>> index 000000000000..163e941e2997
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>> @@ -0,0 +1,55 @@
>> +#!/bin/sh
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2019 ARM Limited
>> +
>> +ret=0
>> +keep_on_fail=0
>> +err_out="2> /dev/null"
>> +
>> +usage() {
>> +	echo "Usage: `basename $0` [-v] [-k]"
>> +	exit 1
>> +}
>> +
>> +# avoiding getopt to avoid compatibility issues on targets
>> +# with limited resources
>> +while [ $# -gt 0 ]
>> +do
>> +	case $1 in
>> +		"-k")
>> +			keep_on_fail=1
>> +			;;
>> +		"-v")
>> +			err_out=
>> +			;;
>> +		*)
>> +			usage
>> +			;;
>> +	esac
>> +	shift
>> +done
>> +
>> +TPROGS=
>> +
>> +tot=$(echo $TPROGS | wc -w)
>> +
>> +# Tests are expected in testcases/ subdir inside the installation path
>> +workdir="`dirname $0 2>/dev/null`"
>> +[ -n $workdir ] && cd $workdir
>> +
>> +passed=0
>> +run=0
>> +for test in $TPROGS
>> +do
>> +	run=$((run + 1))
>> +	eval ./$test $err_out
>> +	if [ $? != 0 ]; then
>> +		[ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
>> +	else
>> +		passed=$((passed + 1))
>> +	fi
>> +done
>> +
>> +echo "==>> PASSED: $passed/$run on $tot available tests."
>> +
>> +exit $ret
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
>> new file mode 100644
>> index 000000000000..3447d7011aec
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
>> @@ -0,0 +1,26 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#include <kselftest.h>
>> +
>> +#include "test_signals.h"
>> +#include "test_signals_utils.h"
>> +
>> +struct tdescr *current;
>> +extern struct tdescr tde;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +	current = &tde;
>> +
>> +	ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
>> +		       current->name, current->descr, current->sig_trig,
>> +		       current->sig_ok, current);
>> +	if (test_setup(current)) {
>> +		if (test_run(current))
>> +			test_result(current);
>> +		test_cleanup(current);
>> +	}
>> +
>> +	return current->pass ? KSFT_PASS : KSFT_FAIL;
>> +}
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
>> new file mode 100644
>> index 000000000000..85db3ac44b32
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
>> @@ -0,0 +1,137 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#ifndef __TEST_SIGNALS_H__
>> +#define __TEST_SIGNALS_H__
>> +
>> +#include <assert.h>
>> +#include <stdbool.h>
>> +#include <signal.h>
>> +#include <ucontext.h>
>> +#include <stdint.h>
> Headers can be added in alphabetically order.
> 
Ok I'll do.

Cheers

Cristian

> Thanks,
> Amit D
>> +
>> +/*
>> + * 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>
>> +
>> +/* pasted from include/linux/stringify.h */
>> +#define __stringify_1(x...)	#x
>> +#define __stringify(x...)	__stringify_1(x)
>> +
>> +/*
>> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
>> + * avoid inject any dependency on the used toolchain regarding possibly
>> + * still unsupported ARMv8 extensions.
>> + *
>> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
>> + * would introduce a compile-time dependency on possibly unsupported ARMv8
>> + * Extensions: you could end-up failing to build the test depending on the
>> + * available toolchain.
>> + * This is undesirable since some tests, even if specifically targeted at some
>> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
>> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
>> + * it transparently not caring at all about the effective set of supported
>> + * features).
>> + * On the other side we will expect to observe different behaviours if the
>> + * feature is supported or not: usually getting a SIGILL when trying to use
>> + * unsupported features. For this reason we have anyway in place some
>> + * preliminary run-time checks about the cpu effectively supported features.
>> + *
>> + * This helper macro is meant to be used for regs readable at EL0, BUT some
>> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
>> + * if the required reg is included in the supported encoding space:
>> + *
>> + *  Documentation/arm64/cpu-feature-regsiters.txt
>> + *
>> + *  "The infrastructure emulates only the following system register space:
>> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
>> + */
>> +#define get_regval(regname, out) \
>> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
>> +
>> +/* Regs encoding and masks naming copied in from sysreg.h */
>> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
>> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
>> +#define ID_AA64MMFR1_PAN_SHIFT	20
>> +#define ID_AA64MMFR2_UAO_SHIFT	4
>> +
>> +/* Local Helpers */
>> +#define IS_PAN_SUPPORTED(val) \
>> +	(!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
>> +#define IS_UAO_SUPPORTED(val) \
>> +	(!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
>> +
>> +#define S3_MRS_SSBS_SYSREG		S3_3_C4_C2_6	/* EL0 supported */
>> +
>> +/*
>> + * Feature flags used in tdescr.feats_required to specify
>> + * any feature by the test
>> + */
>> +enum {
>> +	FSSBS_BIT,
>> +	FPAN_BIT,
>> +	FUAO_BIT,
>> +	FMAX_END
>> +};
>> +
>> +#define FEAT_SSBS		(1UL << FSSBS_BIT)
>> +#define FEAT_PAN		(1UL << FPAN_BIT)
>> +#define FEAT_UAO		(1UL << FUAO_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		feats_ok;
>> +	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;
>> +
>> +	/* a setup function to be called before test starts */
>> +	int (*setup)(struct tdescr *td);
>> +	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);
>> +
>> +	void *priv;
>> +};
>> +#endif
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> new file mode 100644
>> index 000000000000..ac0055f6340b
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> @@ -0,0 +1,261 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <signal.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +#include <assert.h>
>> +#include <sys/auxv.h>
>> +#include <linux/auxvec.h>
>> +#include <ucontext.h>
>> +
>> +#include "test_signals.h"
>> +#include "test_signals_utils.h"
>> +#include "testcases/testcases.h"
>> +
>> +extern struct tdescr *current;
>> +
>> +static char *feats_store[FMAX_END] = {
>> +	"SSBS",
>> +	"PAN",
>> +	"UAO"
>> +};
>> +
>> +#define MAX_FEATS_SZ	128
>> +static inline char *feats_to_string(unsigned long feats)
>> +{
>> +	static char feats_string[MAX_FEATS_SZ];
>> +
>> +	for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
>> +		if (feats & 1UL << i)
>> +			snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
>> +				 feats_string, feats_store[i]);
>> +	}
>> +
>> +	return feats_string;
>> +}
>> +
>> +static void unblock_signal(int signum)
>> +{
>> +	sigset_t sset;
>> +
>> +	sigemptyset(&sset);
>> +	sigaddset(&sset, signum);
>> +	sigprocmask(SIG_UNBLOCK, &sset, NULL);
>> +}
>> +
>> +static void default_result(struct tdescr *td, bool force_exit)
>> +{
>> +	if (td->pass)
>> +		fprintf(stderr, "==>> completed. PASS(1)\n");
>> +	else
>> +		fprintf(stdout, "==>> completed. FAIL(0)\n");
>> +	if (force_exit)
>> +		exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
>> +}
>> +
>> +static inline bool are_feats_ok(struct tdescr *td)
>> +{
>> +	return td ? td->feats_required == td->feats_supported : 0;
>> +}
>> +
>> +static void default_handler(int signum, siginfo_t *si, void *uc)
>> +{
>> +	if (current->sig_trig && signum == current->sig_trig) {
>> +		fprintf(stderr, "Handling SIG_TRIG\n");
>> +		current->triggered = 1;
>> +		/* ->run was asserted NON-NULL in test_setup() already */
>> +		current->run(current, si, uc);
>> +	} else if (signum == SIGILL && !current->initialized) {
>> +		/*
>> +		 * A SIGILL here while still not initialized means we failed
>> +		 * even to asses the existence of features during init
>> +		 */
>> +		fprintf(stdout,
>> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
>> +		current->feats_supported = 0;
>> +	} else if (current->sig_ok && signum == current->sig_ok) {
>> +		/* it's a bug in the test code when this assert fail */
>> +		assert(!current->sig_trig || current->triggered);
>> +		fprintf(stderr,
>> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
>> +			((ucontext_t *)uc)->uc_mcontext.sp,
>> +			si->si_addr, si->si_code, current->token,
>> +			current->token - si->si_addr);
>> +		/*
>> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
>> +		 * the very last time, the token field to the SP address used
>> +		 * to place the fake sigframe: so token==0 means we never made
>> +		 * it to the end, segfaulting well-before, and the test is
>> +		 * possibly broken.
>> +		 */
>> +		if (!current->sanity_disabled && !current->token) {
>> +			fprintf(stdout,
>> +				"current->token ZEROED...test is probably broken!\n");
>> +			assert(0);
>> +		}
>> +		/*
>> +		 * Trying to narrow down the SEGV to the ones generated by
>> +		 * Kernel itself via arm64_notify_segfault()
>> +		 */
>> +		if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
>> +			fprintf(stdout,
>> +				"si_code != SEGV_ACCERR...test is probably broken!\n");
>> +			assert(0);
>> +		}
>> +		fprintf(stderr, "Handling SIG_OK\n");
>> +		current->pass = 1;
>> +		/*
>> +		 * Some tests can lead to SEGV loops: in such a case we want
>> +		 * to terminate immediately exiting straight away
>> +		 */
>> +		default_result(current, 1);
>> +	} else {
>> +		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
>> +			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
>> +			current->pass = 1;
>> +		} else if (signum == SIGALRM && current->timeout) {
>> +			fprintf(stderr, "-- Timeout !\n");
>> +		} else {
>> +			fprintf(stderr,
>> +				"-- RX UNEXPECTED SIGNAL: %d\n", signum);
>> +		}
>> +		default_result(current, 1);
>> +	}
>> +}
>> +
>> +static int default_setup(struct tdescr *td)
>> +{
>> +	struct sigaction sa;
>> +
>> +	sa.sa_sigaction = default_handler;
>> +	sa.sa_flags = SA_SIGINFO;
>> +	if (td->sa_flags)
>> +		sa.sa_flags |= td->sa_flags;
>> +	sigemptyset(&sa.sa_mask);
>> +	/* uncatchable signals naturally skipped ... */
>> +	for (int sig = 1; sig < 32; sig++)
>> +		sigaction(sig, &sa, NULL);
>> +	/*
>> +	 * RT Signals default disposition is Term but they cannot be
>> +	 * generated by the Kernel in response to our tests; so just catch
>> +	 * them all and report them as UNEXPECTED signals.
>> +	 */
>> +	for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
>> +		sigaction(sig, &sa, NULL);
>> +
>> +	/* just in case...unblock explicitly all we need */
>> +	if (td->sig_trig)
>> +		unblock_signal(td->sig_trig);
>> +	if (td->sig_ok)
>> +		unblock_signal(td->sig_ok);
>> +	if (td->sig_unsupp)
>> +		unblock_signal(td->sig_unsupp);
>> +
>> +	if (td->timeout) {
>> +		unblock_signal(SIGALRM);
>> +		alarm(td->timeout);
>> +	}
>> +	fprintf(stderr, "Registered handlers for all signals.\n");
>> +
>> +	return 1;
>> +}
>> +
>> +static inline int default_trigger(struct tdescr *td)
>> +{
>> +	return !raise(td->sig_trig);
>> +}
>> +
>> +static int test_init(struct tdescr *td)
>> +{
>> +	td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
>> +	if (!td->minsigstksz)
>> +		td->minsigstksz = MINSIGSTKSZ;
>> +	fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
>> +
>> +	if (td->feats_required) {
>> +		bool feats_ok = false;
>> +		td->feats_supported = 0;
>> +		/*
>> +		 * Checking for CPU required features using both the
>> +		 * auxval and the arm64 MRS Emulation to read sysregs.
>> +		 */
>> +		if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
>> +			uint64_t val = 0;
>> +
>> +			if (td->feats_required & FEAT_SSBS) {
>> +				/* Uses HWCAP to check capability */
>> +				if (getauxval(AT_HWCAP) & HWCAP_SSBS)
>> +					td->feats_supported |= FEAT_SSBS;
>> +			}
>> +			if (td->feats_required & FEAT_PAN) {
>> +				/* Uses MRS emulation to check capability */
>> +				get_regval(SYS_ID_AA64MMFR1_EL1, val);
>> +				if (IS_PAN_SUPPORTED(val))
>> +					td->feats_supported |= FEAT_PAN;
>> +			}
>> +			if (td->feats_required & FEAT_UAO) {
>> +				/* Uses MRS emulation to check capability */
>> +				get_regval(SYS_ID_AA64MMFR2_EL1 , val);
>> +				if (IS_UAO_SUPPORTED(val))
>> +					td->feats_supported |= FEAT_UAO;
>> +			}
>> +		} else {
>> +			fprintf(stderr,
>> +				"HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
>> +		}
>> +		feats_ok = are_feats_ok(td);
>> +		fprintf(stderr,
>> +			"Required Features: [%s] %ssupported\n",
>> +			feats_ok ? feats_to_string(td->feats_supported) :
>> +		        feats_to_string(td->feats_required ^ td->feats_supported),
>> +			!feats_ok ? "NOT " : "");
>> +	}
>> +
>> +	td->initialized = 1;
>> +	return 1;
>> +}
>> +
>> +int test_setup(struct tdescr *td)
>> +{
>> +	/* assert core invariants symptom of a rotten testcase */
>> +	assert(current);
>> +	assert(td);
>> +	assert(td->name);
>> +	assert(td->run);
>> +
>> +	if (!test_init(td))
>> +		return 0;
>> +
>> +	if (td->setup)
>> +		return td->setup(td);
>> +	else
>> +		return default_setup(td);
>> +}
>> +
>> +int test_run(struct tdescr *td)
>> +{
>> +	if (td->sig_trig) {
>> +		if (td->trigger)
>> +			return td->trigger(td);
>> +		else
>> +			return default_trigger(td);
>> +	} else {
>> +		return td->run(td, NULL, NULL);
>> +	}
>> +}
>> +
>> +void test_result(struct tdescr *td)
>> +{
>> +	if (td->check_result)
>> +		td->check_result(td);
>> +	default_result(td, 0);
>> +}
>> +
>> +void test_cleanup(struct tdescr *td)
>> +{
>> +	if (td->cleanup)
>> +		td->cleanup(td);
>> +}
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> new file mode 100644
>> index 000000000000..8658d1a7d4b9
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> @@ -0,0 +1,13 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#ifndef __TEST_SIGNALS_UTILS_H__
>> +#define __TEST_SIGNALS_UTILS_H__
>> +
>> +#include "test_signals.h"
>> +
>> +int test_setup(struct tdescr *td);
>> +void test_cleanup(struct tdescr *td);
>> +int test_run(struct tdescr *td);
>> +void test_result(struct tdescr *td);
>> +#endif
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> new file mode 100644
>> index 000000000000..8651272e3cfc
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -0,0 +1 @@
>> +mangle_pstate_invalid_compat_toggle
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>> new file mode 100644
>> index 000000000000..971193e7501b
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>> @@ -0,0 +1,25 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
>> +				     ucontext_t *uc)
>> +{
>> +	ASSERT_GOOD_CONTEXT(uc);
>> +
>> +	/* This config should trigger a SIGSEGV by Kernel */
>> +	uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
>> +
>> +	return 1;
>> +}
>> +
>> +struct tdescr tde = {
>> +		.sanity_disabled = true,
>> +		.name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
>> +		.descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
>> +		.sig_trig = SIGUSR1,
>> +		.sig_ok = SIGSEGV,
>> +		.run = mangle_invalid_pstate_run,
>> +};
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
>> new file mode 100644
>> index 000000000000..a59785092e1f
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
>> @@ -0,0 +1,150 @@
>> +#include "testcases.h"
>> +
>> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
>> +				size_t resv_sz, size_t *offset)
>> +{
>> +	size_t offs = 0;
>> +	struct _aarch64_ctx *found = NULL;
>> +
>> +	if (!head || resv_sz < HDR_SZ)
>> +		return found;
>> +
>> +	do {
>> +		if (head->magic == magic) {
>> +			found = head;
>> +			break;
>> +		}
>> +		offs += head->size;
>> +		head = GET_RESV_NEXT_HEAD(head);
>> +	} while (offs < resv_sz - HDR_SZ);
>> +
>> +	if (offset)
>> +		*offset = offs;
>> +
>> +	return found;
>> +}
>> +
>> +bool validate_extra_context(struct extra_context *extra, char **err)
>> +{
>> +	struct _aarch64_ctx *term;
>> +
>> +	if (!extra || !err)
>> +		return false;
>> +
>> +	fprintf(stderr, "Validating EXTRA...\n");
>> +	term = GET_RESV_NEXT_HEAD(extra);
>> +	if (!term || term->magic || term->size) {
>> +		*err = "UN-Terminated EXTRA context";
>> +		return false;
>> +	}
>> +	if (extra->datap & 0x0fUL)
>> +		*err = "Extra DATAP misaligned";
>> +	else if (extra->size & 0x0fUL)
>> +		*err = "Extra SIZE misaligned";
>> +	else if (extra->datap != (uint64_t)term + sizeof(*term))
>> +		*err = "Extra DATAP misplaced (not contiguos)";
>> +	if (*err)
>> +		return false;
>> +
>> +	return true;
>> +}
>> +
>> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
>> +{
>> +	bool terminated = false;
>> +	size_t offs = 0;
>> +	int flags = 0;
>> +	struct extra_context *extra = NULL;
>> +	struct _aarch64_ctx *head =
>> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
>> +
>> +	if (!err)
>> +		return false;
>> +	/* Walk till the end terminator verifying __reserved contents */
>> +	while (head && !terminated && offs < resv_sz) {
>> +		if ((uint64_t)head & 0x0fUL) {
>> +			*err = "Misaligned HEAD";
>> +			return false;
>> +		}
>> +
>> +		switch (head->magic) {
>> +			case 0:
>> +				if (head->size)
>> +					*err = "Bad size for MAGIC0";
>> +				else
>> +					terminated = true;
>> +				break;
>> +			case FPSIMD_MAGIC:
>> +				if (flags & FPSIMD_CTX)
>> +					*err = "Multiple FPSIMD_MAGIC";
>> +				else if (head->size !=
>> +					 sizeof(struct fpsimd_context))
>> +					*err = "Bad size for fpsimd_context";
>> +				flags |= FPSIMD_CTX;
>> +				break;
>> +			case ESR_MAGIC:
>> +				if (head->size != sizeof(struct esr_context))
>> +					fprintf(stderr,
>> +						"Bad size for esr_context is not an error...just ignore.\n");
>> +				break;
>> +			case SVE_MAGIC:
>> +				if (flags & SVE_CTX)
>> +					*err = "Multiple SVE_MAGIC";
>> +				else if (head->size !=
>> +					 sizeof(struct sve_context))
>> +					*err = "Bad size for sve_context";
>> +				flags |= SVE_CTX;
>> +				break;
>> +			case EXTRA_MAGIC:
>> +				if (flags & EXTRA_CTX)
>> +					*err = "Multiple EXTRA_MAGIC";
>> +				else if (head->size !=
>> +					 sizeof(struct extra_context))
>> +					*err = "Bad size for extra_context";
>> +				flags |= EXTRA_CTX;
>> +				extra = (struct extra_context *)head;
>> +				break;
>> +			case KSFT_BAD_MAGIC:
>> +				/*
>> +				 * This is a BAD magic header defined
>> +				 * artificially by a testcase and surely
>> +				 * unknown to the Kernel parse_user_sigframe().
>> +				 * It MUST cause a Kernel induced SEGV
>> +				 */
>> +				*err = "BAD MAGIC !";
>> +				break;
>> +			default:
>> +				/*
>> +				 * A still unknown Magic: potentially freshly added
>> +				 * to the Kernel code and still unknown to the
>> +				 * tests.
>> +				 */
>> +				fprintf(stdout,
>> +					"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
>> +					head->magic);
>> +				break;
>> +		}
>> +
>> +		if (*err)
>> +			return false;
>> +
>> +		offs += head->size;
>> +		if (resv_sz - offs < sizeof(*head)) {
>> +			*err = "HEAD Overrun";
>> +			return false;
>> +		}
>> +
>> +		if (flags & EXTRA_CTX)
>> +			if (!validate_extra_context(extra, err))
>> +				return false;
>> +
>> +		head = GET_RESV_NEXT_HEAD(head);
>> +	}
>> +
>> +	if (terminated && !(flags & FPSIMD_CTX)) {
>> +		*err = "Missing FPSIMD";
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
>> new file mode 100644
>> index 000000000000..624717c71b1d
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
>> @@ -0,0 +1,83 @@
>> +#ifndef __TESTCASES_H__
>> +#define __TESTCASES_H__
>> +
>> +#include <stdio.h>
>> +#include <stdbool.h>
>> +#include <stdint.h>
>> +#include <unistd.h>
>> +#include <ucontext.h>
>> +#include <assert.h>
>> +
>> +/* Architecture specific sigframe definitions */
>> +#include <asm/sigcontext.h>
>> +
>> +#define FPSIMD_CTX	(1 << 0)
>> +#define SVE_CTX		(1 << 1)
>> +#define EXTRA_CTX	(1 << 2)
>> +
>> +#define KSFT_BAD_MAGIC	0xdeadbeef
>> +
>> +#define HDR_SZ \
>> +	sizeof(struct _aarch64_ctx)
>> +
>> +#define GET_SF_RESV_HEAD(sf) \
>> +	(struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
>> +
>> +#define GET_SF_RESV_SIZE(sf) \
>> +	sizeof((sf).uc.uc_mcontext.__reserved)
>> +
>> +#define GET_UCP_RESV_SIZE(ucp) \
>> +	sizeof((ucp)->uc_mcontext.__reserved)
>> +
>> +#define ASSERT_BAD_CONTEXT(uc) do {					\
>> +	char *err = NULL;						\
>> +	assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
>> +	if (err)							\
>> +		fprintf(stderr,						\
>> +			"Using badly built context - ERR: %s\n", err);	\
>> +} while(0)
>> +
>> +#define ASSERT_GOOD_CONTEXT(uc) do {					 \
>> +	char *err = NULL;						 \
>> +	if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) {	 \
>> +		if (err)						 \
>> +			fprintf(stderr,					 \
>> +				"Detected BAD context - ERR: %s\n", err);\
>> +		assert(0);						 \
>> +	} else {							 \
>> +		fprintf(stderr, "uc context validated.\n");		 \
>> +	}								 \
>> +} while(0)
>> +
>> +/* head->size accounts both for payload and header _aarch64_ctx size ! */
>> +#define GET_RESV_NEXT_HEAD(h) \
>> +	(struct _aarch64_ctx *)((char *)(h) + (h)->size)
>> +
>> +struct fake_sigframe {
>> +	siginfo_t	info;
>> +	ucontext_t	uc;
>> +};
>> +
>> +
>> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
>> +
>> +bool validate_extra_context(struct extra_context *extra, char **err);
>> +
>> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
>> +				size_t resv_sz, size_t *offset);
>> +
>> +static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
>> +						  size_t resv_sz,
>> +						  size_t *offset)
>> +{
>> +	return get_header(head, 0, resv_sz, offset);
>> +}
>> +
>> +static inline void write_terminator_record(struct _aarch64_ctx *tail)
>> +{
>> +	if (tail) {
>> +		tail->magic = 0;
>> +		tail->size = 0;
>> +	}
>> +}
>> +#endif
>>


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 00/11] Add arm64/signal initial kselftest support
  2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
                   ` (10 preceding siblings ...)
  2019-08-02 17:03 ` [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp Cristian Marussi
@ 2019-08-13 16:22 ` Dave Martin
  2019-08-30 16:40   ` Cristian Marussi
  11 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:22 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:49PM +0100, Cristian Marussi wrote:
> Hi
> 
> this patchset aims to add the initial arch-specific arm64 support to
> kselftest starting with signals-related test-cases.
> A common internal test-case layout is proposed which then it is anyway
> wired-up to the toplevel kselftest Makefile, so that it should be possible
> at the end to run it on an arm64 target in the usual way with KSFT.

The tests look like a reasonable base overall and something that we can
extend later as needed.

There are various minor things that need attention -- see my comments on
the individual patches.  Apart for some things that can be factored out,
I don't think any of it involves redesign.


A few general comments:

 * Please wrap all commit messages to <= 75 chars, and follow the other
   guidelines about commit messages in
   Documentation/process/submitting-patches.rst).

 * Remember to run scripts/checkpatch.pl on your patches.  Currently
   various issues are reported: they should mostly be trivial to fix.
   checkpatch does report some false positives, but most of the warnings
   I see look relevant.

 * If you like, you can add an Author: line alongside the copyright
   notice in new files that you create.  (You'll see this elsewhere in
   the kernel if you grep.)

One general stylistic issue (IMHO):

 * Try to avoid inventing names for things that have no established
   name (for example "magic0" to mean "magic number 0").

   The risk is that the reader wastes time grepping for the definition,
   when really the text should be read at face value.  It's best to use
   all caps just for #define names, abbreviations, and other things
   that are customarily capitalised (like "CPU" etc.).  Other words
   containing underscores may resemble variable / function names, and
   may cause confusion of there is no actual variable or function with
   that name.

   I don't think it's worth heavily reworking the patches for this, but
   it's something to bear in mind.

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code
  2019-08-02 17:02 ` [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code Cristian Marussi
@ 2019-08-13 16:23   ` Dave Martin
  2019-08-27 12:14     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:23 UTC (permalink / raw)
  To: Cristian Marussi
  Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl, dave.martin

^ Regarding the subject line, "boilerplate code" sounds a bit vague.
Could we say something like "Add skeleton Makefile"?

On Fri, Aug 02, 2019 at 06:02:50PM +0100, Cristian Marussi wrote:
> Added a new arm64-specific empty subsystem amongst TARGETS of KSFT build
> framework; once populated with testcases, it will be possible to build
> and invoke the new KSFT TARGETS=arm64 related tests from the toplevel
> Makefile in the usual ways.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> Reviewed the build instructions reported in the README, to be more
> agnostic regarding user/device etc..
> ---
>  tools/testing/selftests/Makefile       |  1 +
>  tools/testing/selftests/arm64/Makefile | 51 ++++++++++++++++++++++++++
>  tools/testing/selftests/arm64/README   | 43 ++++++++++++++++++++++
>  3 files changed, 95 insertions(+)
>  create mode 100644 tools/testing/selftests/arm64/Makefile
>  create mode 100644 tools/testing/selftests/arm64/README
> 
> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
> index 25b43a8c2b15..1722dae9381a 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -1,5 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  TARGETS = android
> +TARGETS += arm64
>  TARGETS += bpf
>  TARGETS += breakpoints
>  TARGETS += capabilities
> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
> new file mode 100644
> index 000000000000..03a0d4f71218
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/Makefile
> @@ -0,0 +1,51 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +# When ARCH not overridden for crosscompiling, lookup machine
> +ARCH ?= $(shell uname -m)
> +ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
> +
> +ifeq ("x$(ARCH)", "xarm64")
> +SUBDIRS :=
> +else
> +SUBDIRS :=
> +endif
> +
> +CFLAGS := -Wall -O2 -g
> +
> +export CC
> +export CFLAGS
> +
> +all:
> +	@for DIR in $(SUBDIRS); do				\
> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
> +		mkdir -p $$BUILD_TARGET;			\
> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
> +	done
> +
> +install: all
> +	@for DIR in $(SUBDIRS); do				\
> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
> +	done
> +
> +run_tests: all
> +	@for DIR in $(SUBDIRS); do				\
> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
> +	done
> +
> +# Avoid any output on non arm64 on emit_tests
> +emit_tests: all
> +	@for DIR in $(SUBDIRS); do				\
> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
> +	done
> +
> +clean:
> +	@for DIR in $(SUBDIRS); do				\
> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
> +	done
> +
> +.PHONY: all clean install run_tests emit_tests
> diff --git a/tools/testing/selftests/arm64/README b/tools/testing/selftests/arm64/README
> new file mode 100644
> index 000000000000..dee3306071cc
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/README
> @@ -0,0 +1,43 @@
> +KSelfTest ARM64
> +===============
> +
> +- These tests are arm64 specific and so not built or run but just skipped
> +  completely when env-variable ARCH is found to be different than 'arm64'
> +  and `uname -m` reports other than 'aarch64'.
> +
> +- Holding true the above, ARM64 KSFT tests can be run:
> +
> +   + as standalone (example for signal tests)
> +
> +      $ make -C tools/testing/selftest/arm64/signal \
> +		INSTALL_PATH=<your-installation-path> install
> +
> +      and then launching on the target device inside the installed path:
> +
> +      $ <your-installed-path>/test_arm64_signals.sh [-k | -v]
> +
> +   + within the KSelfTest framework using standard Linux top-level-makefile
> +     targets:
> +
> +      $ make TARGETS=arm64 kselftest-clean
> +      $ make TARGETS=arm64 kselftest
> +
> +   Further details on building and running KFST can be found in:
> +     Documentation/dev-tools/kselftest.rst

The next two paragraphs aren't relevant yet.  Can we split them out of
this patch and add them alongside the relevant code / Makefile changes?

> +
> +- Tests can depend on some arch-specific definitions which can be found in a
> +  standard Kernel Headers installation in $(top_srcdir)/usr/include.
> +  Such Kernel Headers are automatically installed (via make headers_install)
> +  by KSFT framework itself in a dedicated directory when tests are launched
> +  via KSFT itself; when running standalone, instead, a Warning is issued
> +  if such headers cannot be found somewhere (we try to guess a few standard
> +  locations anyway)
> +
> +- Some of these tests may be related to possibly not implemented ARMv8
> +  features: depending on their implementation status on the effective HW
> +  we'll expect different results. The tests' harness will take care to check
> +  at run-time if the required features are supported and will act accordingly.
> +  Moreover, in order to avoid any kind of compile-time dependency on the
> +  toolchain (possibly due to the above mentioned not-implemented features),
> +  we make strictly use of direct 'S3_ sysreg' raw-encoding while checking for
> +  those features and/or lookin up sysregs.

This last paragraph is only relevant for people adding new tests.  It
probably makes sense to start "When adding new tests, try to avoid
unnecessary toolchain dependencies where possible. [...]"

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-02 17:02 ` [PATCH v3 02/11] kselftest: arm64: adds first test and common utils Cristian Marussi
                     ` (3 preceding siblings ...)
  2019-08-12 12:43   ` Amit Kachhap
@ 2019-08-13 16:24   ` Dave Martin
  2019-08-28 17:34     ` Cristian Marussi
  4 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:24 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

For the subject line, maybe name the test being added (same as for the
other patches).

On Fri, Aug 02, 2019 at 06:02:51PM +0100, Cristian Marussi wrote:
> Added some arm64/signal specific boilerplate and utility code to help
> further testcase development.
> 
> A simple testcase and related helpers are also introduced in this commit:
> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
> messes with the ucontext_t from within the sig_handler, trying to toggle

"signal handler"?

> PSTATE state bits to switch the system between 32bit/64bit execution state.
> Expects SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> A few fixes:
> - test_arm64_signals.sh runner script generation has been reviewed in order to
>   be safe against the .gitignore
> - using kselftest.h officially provided defines for tests' return values
> - removed SAFE_WRITE()/dump_uc()
> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>   the sigfault had been directly triggered by Kernel
> ---
>  tools/testing/selftests/arm64/Makefile        |   2 +-
>  .../testing/selftests/arm64/signal/.gitignore |   6 +
>  tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>  tools/testing/selftests/arm64/signal/README   |  59 ++++
>  .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>  .../selftests/arm64/signal/test_signals.c     |  26 ++
>  .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>  .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>  .../arm64/signal/test_signals_utils.h         |  13 +
>  .../arm64/signal/testcases/.gitignore         |   1 +
>  .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>  .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>  .../arm64/signal/testcases/testcases.h        |  83 ++++++
>  13 files changed, 905 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>  create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>  create mode 100644 tools/testing/selftests/arm64/signal/README
>  create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
> 
> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
> index 03a0d4f71218..af59dc74e0dc 100644
> --- a/tools/testing/selftests/arm64/Makefile
> +++ b/tools/testing/selftests/arm64/Makefile
> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>  ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>  
>  ifeq ("x$(ARCH)", "xarm64")
> -SUBDIRS :=
> +SUBDIRS := signal
>  else
>  SUBDIRS :=
>  endif
> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
> new file mode 100644
> index 000000000000..434f65c15f03
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/.gitignore
> @@ -0,0 +1,6 @@
> +# Helper script's internal testcases list (TPROGS) is regenerated
> +# each time by Makefile on standalone (non KSFT driven) runs.
> +# Committing such list creates a dependency between testcases
> +# patches such that they are no more easily revertable. Just ignore.
> +test_arm64_signals.src_shell
> +test_arm64_signals.sh
> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
> new file mode 100644
> index 000000000000..8c8d08be4b0d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/Makefile
> @@ -0,0 +1,88 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +# Supports also standalone invokation out of KSFT-tree
> +# Compile standalone and run on your device with:
> +#
> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install

I'm wondering whether supporting stand-alone invocation is actually
worth it.  Maybe this just adds complexity for little benefit.

Although it's useful for debugging and development, it doesn't look like
other tests in kselftest support standalone invocation -- did I miss
some?

> +#
> +# Run standalone on device with:
> +#
> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
> +#
> +# If INSTALL_PATH= is NOT provided it will default to ./install
> +
> +# A proper top_srcdir is needed both by KSFT(lib.mk)
> +# and standalone builds
> +top_srcdir = ../../../../..
> +
> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
> +PROGS := $(patsubst %.c,%,$(SRCS))
> +
> +# Guessing as best as we can where the Kernel headers
> +# could have been installed depending on ENV config and
> +# type of invocation.
> +ifeq ($(KBUILD_OUTPUT),)
> +khdr_dir = $(top_srcdir)/usr/include
> +else
> +ifeq (0,$(MAKELEVEL))
> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
> +else
> +# the KSFT preferred location when KBUILD_OUTPUT is set
> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
> +endif
> +endif

When is KBUILD_OUTPUT set / not set?

> +
> +CFLAGS += -I$(khdr_dir)

Do we rely on any non-UAPI headers?  If not, the default should probably
be to rely on the system headers (or toolchain default headers) -- i.e.,
add no -I option at all.

I'm wondering why none of the other kselftests need this header search
logic.

> +
> +# Standalone run
> +ifeq (0,$(MAKELEVEL))
> +CC := $(CROSS_COMPILE)gcc
> +RUNNER_SRC = test_arm64_signals.src_shell
> +RUNNER = test_arm64_signals.sh
> +INSTALL_PATH ?= install/
> +
> +all: $(RUNNER)
> +
> +$(RUNNER): $(PROGS)

$(RUNNER_SRC) should also be in the dependencies here.

> +	cp $(RUNNER_SRC) $(RUNNER)
> +	sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@

Or just a single command: sed -e '...' <$< >$@

> +
> +install: all
> +	mkdir -p $(INSTALL_PATH)/testcases
> +	cp $(PROGS) $(INSTALL_PATH)/testcases
> +	cp $(RUNNER) $(INSTALL_PATH)/
> +
> +.PHONY clean:
> +	rm -f $(PROGS)
> +# KSFT run
> +else
> +# 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
> +
> +# This include mk 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)
> +endif
> +
> +# 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
> +	@if [ ! -d $(khdr_dir) ]; then \
> +		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
> +		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
> +	fi
> +	$(CC) $(CFLAGS) $^ -o $@
> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
> new file mode 100644
> index 000000000000..53f005f7910a
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/README
> @@ -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 messes-up with the sigframe ucontext_t from
> +    inside the sighandler itself.

"messes-up" makes it sound a bit like the test case code itself goes
wrong.

Maybe just say something like "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
> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> new file mode 100755
> index 000000000000..163e941e2997
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell

Unusual filename?

In the non-standalone case, is this run directly with TPROGS set in the
environment instead of modifying the script?  (I haven't understood all
the logic yet.)

If so, it is a shell script, and should just be called
test_arm64_signals.sh

Otherwise, it's a non-executable template for a shell script, so should
have 0644 permissions and could be called test_arm64_signals.sh.in or
test_arm64_signals.sh.template, say.

> @@ -0,0 +1,55 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2019 ARM Limited
> +
> +ret=0
> +keep_on_fail=0
> +err_out="2> /dev/null"
> +
> +usage() {
> +	echo "Usage: `basename $0` [-v] [-k]"
> +	exit 1
> +}
> +
> +# avoiding getopt to avoid compatibility issues on targets
> +# with limited resources
> +while [ $# -gt 0 ]
> +do
> +	case $1 in
> +		"-k")
> +			keep_on_fail=1
> +			;;
> +		"-v")
> +			err_out=
> +			;;
> +		*)
> +			usage
> +			;;
> +	esac
> +	shift
> +done
> +
> +TPROGS=
> +
> +tot=$(echo $TPROGS | wc -w)
> +
> +# Tests are expected in testcases/ subdir inside the installation path
> +workdir="`dirname $0 2>/dev/null`"
> +[ -n $workdir ] && cd $workdir
> +
> +passed=0
> +run=0
> +for test in $TPROGS
> +do
> +	run=$((run + 1))
> +	eval ./$test $err_out
> +	if [ $? != 0 ]; then
> +		[ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
> +	else
> +		passed=$((passed + 1))
> +	fi
> +done
> +
> +echo "==>> PASSED: $passed/$run on $tot available tests."
> +
> +exit $ret
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
> new file mode 100644
> index 000000000000..3447d7011aec
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */

We should probably have a brief comment to say what this is.
For example:

/*
 * Generic test wrapper for arm64 signal tests
 * Each test provides its own tde to link with this wrapper.
 */

> +
> +#include <kselftest.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +
> +struct tdescr *current;
> +extern struct tdescr tde;
> +
> +int main(int argc, char *argv[])
> +{
> +	current = &tde;
> +
> +	ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
> +		       current->name, current->descr, current->sig_trig,
> +		       current->sig_ok, current);

Does the user need all this?

It's sufficient to print the test name, a one-line description and
results.  If something goes wrong, we can print a bit more detail.

Maybe just do something like

#ifdef DEBUG
#define debug_printf(format, ...) ksft_print_msg(format, ## __VA_ARGS__)
#else
#define debug_printf(format, ...) ((void)0)
#endif

(Unless kselftest already has something like this, in which case you
could just use that.)

> +	if (test_setup(current)) {
> +		if (test_run(current))
> +			test_result(current);
> +		test_cleanup(current);
> +	}
> +
> +	return current->pass ? KSFT_PASS : KSFT_FAIL;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> new file mode 100644
> index 000000000000..85db3ac44b32
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
> @@ -0,0 +1,137 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_H__
> +#define __TEST_SIGNALS_H__
> +
> +#include <assert.h>
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <ucontext.h>
> +#include <stdint.h>

Does anything in this header use <assert.h> or <stdint.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>
> +
> +/* pasted from include/linux/stringify.h */
> +#define __stringify_1(x...)	#x
> +#define __stringify(x...)	__stringify_1(x)
> +
> +/*

I think we can delete this entire comment.

The macro name is fairly self-explanatory anyway.  Although the
rationale is interesting, our approach to reading system registers
here is just the same as elsewhere in the kernel.

> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
> + * avoid inject any dependency on the used toolchain regarding possibly
> + * still unsupported ARMv8 extensions.
> + *
> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
> + * would introduce a compile-time dependency on possibly unsupported ARMv8
> + * Extensions: you could end-up failing to build the test depending on the
> + * available toolchain.
> + * This is undesirable since some tests, even if specifically targeted at some
> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
> + * it transparently not caring at all about the effective set of supported
> + * features).
> + * On the other side we will expect to observe different behaviours if the
> + * feature is supported or not: usually getting a SIGILL when trying to use
> + * unsupported features. For this reason we have anyway in place some
> + * preliminary run-time checks about the cpu effectively supported features.
> + *
> + * This helper macro is meant to be used for regs readable at EL0, BUT some
> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
> + * if the required reg is included in the supported encoding space:
> + *
> + *  Documentation/arm64/cpu-feature-regsiters.txt
> + *
> + *  "The infrastructure emulates only the following system register space:
> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
> + */
> +#define get_regval(regname, out) \
> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
> +
> +/* Regs encoding and masks naming copied in from sysreg.h */
> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */

These ID regs are part of armv8.0-a, so we don't need to use the magic
syntax.

> +#define ID_AA64MMFR1_PAN_SHIFT	20
> +#define ID_AA64MMFR2_UAO_SHIFT	4
> +
> +/* Local Helpers */

Can these names indicate the sysreg they should be used with, e.g.

#define ID_AA64MMFR1_EL1_PAN_SUPPORTED(val) ...
#define ID_AA64MMFR2_EL1_UAO_SUPPORTED(val) ...

> +#define IS_PAN_SUPPORTED(val) \
> +	(!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
> +#define IS_UAO_SUPPORTED(val) \
> +	(!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
> +
> +#define S3_MRS_SSBS_SYSREG		S3_3_C4_C2_6	/* EL0 supported */

Maybe just SSBS_SYSREG.

Sysreg encodings are always for use with MRS/MSR anyway, and "S3" is
really part of the definition rather than part of the name.

> +
> +/*
> + * Feature flags used in tdescr.feats_required to specify
> + * any feature by the test
> + */
> +enum {
> +	FSSBS_BIT,
> +	FPAN_BIT,
> +	FUAO_BIT,
> +	FMAX_END
> +};
> +
> +#define FEAT_SSBS		(1UL << FSSBS_BIT)
> +#define FEAT_PAN		(1UL << FPAN_BIT)
> +#define FEAT_UAO		(1UL << FUAO_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		feats_ok;

Is feats_ok used?

> +	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;
> +
> +	/* a setup function to be called before test starts */
> +	int (*setup)(struct tdescr *td);
> +	void (*cleanup)(struct tdescr *td);

Add a comment to say what cleanup() is?

> +
> +	/* 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);
> +
> +	void *priv;
> +};
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> new file mode 100644
> index 000000000000..ac0055f6340b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -0,0 +1,261 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <assert.h>
> +#include <sys/auxv.h>
> +#include <linux/auxvec.h>
> +#include <ucontext.h>
> +
> +#include "test_signals.h"
> +#include "test_signals_utils.h"
> +#include "testcases/testcases.h"
> +
> +extern struct tdescr *current;
> +
> +static char *feats_store[FMAX_END] = {
> +	"SSBS",
> +	"PAN",
> +	"UAO"
> +};
> +
> +#define MAX_FEATS_SZ	128
> +static inline char *feats_to_string(unsigned long feats)
> +{
> +	static char feats_string[MAX_FEATS_SZ];
> +
> +	for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
> +		if (feats & 1UL << i)
> +			snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
> +				 feats_string, feats_store[i]);
> +	}
> +
> +	return feats_string;
> +}
> +
> +static void unblock_signal(int signum)
> +{
> +	sigset_t sset;
> +
> +	sigemptyset(&sset);
> +	sigaddset(&sset, signum);
> +	sigprocmask(SIG_UNBLOCK, &sset, NULL);
> +}
> +
> +static void default_result(struct tdescr *td, bool force_exit)
> +{
> +	if (td->pass)
> +		fprintf(stderr, "==>> completed. PASS(1)\n");
> +	else
> +		fprintf(stdout, "==>> completed. FAIL(0)\n");
> +	if (force_exit)
> +		exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
> +}
> +
> +static inline bool are_feats_ok(struct tdescr *td)
> +{
> +	return td ? td->feats_required == td->feats_supported : 0;

Should this be something like
(td->feats_required & td->feats_supported) == td->feats_required ?

Otherwise additional supported features that our test doesn't care about
will cause this check to fail.


Do we really need to check td?

assert(foo); followed by dereferincing foo is usually a bit pointless
because you'd get a SIGSEGV anyway.

However, since the tests generate deliberate SIGSEGVs too this could
be confusing -- in which case, having an explicit assert() here does
no harm.

> +}
> +
> +static void default_handler(int signum, siginfo_t *si, void *uc)
> +{
> +	if (current->sig_trig && signum == current->sig_trig) {
> +		fprintf(stderr, "Handling SIG_TRIG\n");
> +		current->triggered = 1;
> +		/* ->run was asserted NON-NULL in test_setup() already */
> +		current->run(current, si, uc);
> +	} else if (signum == SIGILL && !current->initialized) {
> +		/*
> +		 * A SIGILL here while still not initialized means we failed
> +		 * even to asses the existence of features during init
> +		 */
> +		fprintf(stdout,
> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
> +		current->feats_supported = 0;
> +	} else if (current->sig_ok && signum == current->sig_ok) {
> +		/* it's a bug in the test code when this assert fail */

Why?  Is this because sig_ok is considered acceptable only as an effect
of the test -- i.e., we shouldn't see it if the test hasn't been
triggered yet?

> +		assert(!current->sig_trig || current->triggered);
> +		fprintf(stderr,
> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> +			((ucontext_t *)uc)->uc_mcontext.sp,
> +			si->si_addr, si->si_code, current->token,
> +			current->token - si->si_addr);
> +		/*
> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
> +		 * the very last time, the token field to the SP address used
> +		 * to place the fake sigframe: so token==0 means we never made
> +		 * it to the end, segfaulting well-before, and the test is
> +		 * possibly broken.
> +		 */
> +		if (!current->sanity_disabled && !current->token) {
> +			fprintf(stdout,
> +				"current->token ZEROED...test is probably broken!\n");
> +			assert(0);

In case someone builds with -DNDEBUG, should we add abort()?

> +		}
> +		/*
> +		 * Trying to narrow down the SEGV to the ones generated by
> +		 * Kernel itself via arm64_notify_segfault()
> +		 */
> +		if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
> +			fprintf(stdout,
> +				"si_code != SEGV_ACCERR...test is probably broken!\n");
> +			assert(0);
> +		}

I'm not sure whether si_code is really ABI here, though I'm not sure
what else we can do to diagnose the signal more accurately.

Maybe add a comment to say that this might need to change if this
aspect of the kernel ABI evolves.

> +		fprintf(stderr, "Handling SIG_OK\n");
> +		current->pass = 1;
> +		/*
> +		 * Some tests can lead to SEGV loops: in such a case we want
> +		 * to terminate immediately exiting straight away
> +		 */
> +		default_result(current, 1);
> +	} else {
> +		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
> +			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
> +			current->pass = 1;
> +		} else if (signum == SIGALRM && current->timeout) {
> +			fprintf(stderr, "-- Timeout !\n");
> +		} else {
> +			fprintf(stderr,
> +				"-- RX UNEXPECTED SIGNAL: %d\n", signum);
> +		}
> +		default_result(current, 1);
> +	}
> +}
> +
> +static int default_setup(struct tdescr *td)
> +{
> +	struct sigaction sa;
> +
> +	sa.sa_sigaction = default_handler;
> +	sa.sa_flags = SA_SIGINFO;

Add SA_RESTART?

I'm not sure whether this affects these tests, but the libc stdio
functions don't like being interrupted by signals.  SA_RESTART should
hide most issues of this sort.

> +	if (td->sa_flags)
> +		sa.sa_flags |= td->sa_flags;

Do we need the if() here?  If td->sa_flags == 0, the assignment is
harmless anyway.

> +	sigemptyset(&sa.sa_mask);
> +	/* uncatchable signals naturally skipped ... */
> +	for (int sig = 1; sig < 32; sig++)
> +		sigaction(sig, &sa, NULL);
> +	/*
> +	 * RT Signals default disposition is Term but they cannot be
> +	 * generated by the Kernel in response to our tests; so just catch
> +	 * them all and report them as UNEXPECTED signals.
> +	 */
> +	for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
> +		sigaction(sig, &sa, NULL);
> +
> +	/* just in case...unblock explicitly all we need */
> +	if (td->sig_trig)
> +		unblock_signal(td->sig_trig);
> +	if (td->sig_ok)
> +		unblock_signal(td->sig_ok);
> +	if (td->sig_unsupp)
> +		unblock_signal(td->sig_unsupp);
> +
> +	if (td->timeout) {
> +		unblock_signal(SIGALRM);
> +		alarm(td->timeout);
> +	}
> +	fprintf(stderr, "Registered handlers for all signals.\n");
> +
> +	return 1;
> +}
> +
> +static inline int default_trigger(struct tdescr *td)
> +{
> +	return !raise(td->sig_trig);
> +}
> +
> +static int test_init(struct tdescr *td)
> +{
> +	td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
> +	if (!td->minsigstksz)
> +		td->minsigstksz = MINSIGSTKSZ;
> +	fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
> +
> +	if (td->feats_required) {
> +		bool feats_ok = false;
> +		td->feats_supported = 0;
> +		/*
> +		 * Checking for CPU required features using both the
> +		 * auxval and the arm64 MRS Emulation to read sysregs.
> +		 */
> +		if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
> +			uint64_t val = 0;
> +

Would it be simpler just to query all these features unconditionally?

We just need to check that all the features the test needs are present.
If other features are present, we can happily ignore them, but
discovering them is harmless.

> +			if (td->feats_required & FEAT_SSBS) {
> +				/* Uses HWCAP to check capability */
> +				if (getauxval(AT_HWCAP) & HWCAP_SSBS)
> +					td->feats_supported |= FEAT_SSBS;
> +			}
> +			if (td->feats_required & FEAT_PAN) {
> +				/* Uses MRS emulation to check capability */
> +				get_regval(SYS_ID_AA64MMFR1_EL1, val);
> +				if (IS_PAN_SUPPORTED(val))
> +					td->feats_supported |= FEAT_PAN;
> +			}
> +			if (td->feats_required & FEAT_UAO) {
> +				/* Uses MRS emulation to check capability */
> +				get_regval(SYS_ID_AA64MMFR2_EL1 , val);
> +				if (IS_UAO_SUPPORTED(val))
> +					td->feats_supported |= FEAT_UAO;
> +			}
> +		} else {
> +			fprintf(stderr,
> +				"HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
> +		}
> +		feats_ok = are_feats_ok(td);
> +		fprintf(stderr,
> +			"Required Features: [%s] %ssupported\n",
> +			feats_ok ? feats_to_string(td->feats_supported) :
> +		        feats_to_string(td->feats_required ^ td->feats_supported),
> +			!feats_ok ? "NOT " : "");
> +	}
> +
> +	td->initialized = 1;
> +	return 1;
> +}
> +
> +int test_setup(struct tdescr *td)
> +{
> +	/* assert core invariants symptom of a rotten testcase */
> +	assert(current);
> +	assert(td);
> +	assert(td->name);
> +	assert(td->run);
> +
> +	if (!test_init(td))
> +		return 0;
> +
> +	if (td->setup)
> +		return td->setup(td);
> +	else
> +		return default_setup(td);
> +}
> +
> +int test_run(struct tdescr *td)
> +{
> +	if (td->sig_trig) {
> +		if (td->trigger)
> +			return td->trigger(td);
> +		else
> +			return default_trigger(td);
> +	} else {
> +		return td->run(td, NULL, NULL);
> +	}
> +}
> +
> +void test_result(struct tdescr *td)
> +{
> +	if (td->check_result)
> +		td->check_result(td);
> +	default_result(td, 0);
> +}
> +
> +void test_cleanup(struct tdescr *td)
> +{
> +	if (td->cleanup)
> +		td->cleanup(td);
> +}
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> new file mode 100644
> index 000000000000..8658d1a7d4b9
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#ifndef __TEST_SIGNALS_UTILS_H__
> +#define __TEST_SIGNALS_UTILS_H__
> +
> +#include "test_signals.h"
> +
> +int test_setup(struct tdescr *td);
> +void test_cleanup(struct tdescr *td);
> +int test_run(struct tdescr *td);
> +void test_result(struct tdescr *td);
> +#endif
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> new file mode 100644
> index 000000000000..8651272e3cfc
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -0,0 +1 @@
> +mangle_pstate_invalid_compat_toggle
> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> new file mode 100644
> index 000000000000..971193e7501b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +

Each testcase should have a comment explaining what it is trying to
test, and how.

> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
> +				     ucontext_t *uc)
> +{
> +	ASSERT_GOOD_CONTEXT(uc);
> +
> +	/* This config should trigger a SIGSEGV by Kernel */
> +	uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
> +
> +	return 1;
> +}
> +
> +struct tdescr tde = {
> +		.sanity_disabled = true,
> +		.name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
> +		.descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
> +		.sig_trig = SIGUSR1,
> +		.sig_ok = SIGSEGV,
> +		.run = mangle_invalid_pstate_run,
> +};
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> new file mode 100644
> index 000000000000..a59785092e1f
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> @@ -0,0 +1,150 @@
> +#include "testcases.h"
> +
> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
> +				size_t resv_sz, size_t *offset)
> +{
> +	size_t offs = 0;
> +	struct _aarch64_ctx *found = NULL;
> +
> +	if (!head || resv_sz < HDR_SZ)
> +		return found;
> +
> +	do {
> +		if (head->magic == magic) {
> +			found = head;
> +			break;
> +		}
> +		offs += head->size;
> +		head = GET_RESV_NEXT_HEAD(head);

Are offs and head tracking the same thing here?

Maybe it would be cleaner to have GET_RESV_NEXT_HEAD() do the bounds
checking itself.

> +	} while (offs < resv_sz - HDR_SZ);
> +
> +	if (offset)
> +		*offset = offs;
> +
> +	return found;
> +}
> +
> +bool validate_extra_context(struct extra_context *extra, char **err)
> +{
> +	struct _aarch64_ctx *term;
> +
> +	if (!extra || !err)
> +		return false;
> +
> +	fprintf(stderr, "Validating EXTRA...\n");
> +	term = GET_RESV_NEXT_HEAD(extra);
> +	if (!term || term->magic || term->size) {
> +		*err = "UN-Terminated EXTRA context";

This sounds like the extra context doesn't contain a terminator, which
isn't what we're checking here.  Maybe say "terminator missing after
extra context", or similar.

> +		return false;
> +	}
> +	if (extra->datap & 0x0fUL)
> +		*err = "Extra DATAP misaligned";
> +	else if (extra->size & 0x0fUL)
> +		*err = "Extra SIZE misaligned";
> +	else if (extra->datap != (uint64_t)term + sizeof(*term))
> +		*err = "Extra DATAP misplaced (not contiguos)";
> +	if (*err)
> +		return false;
> +
> +	return true;
> +}
> +
> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
> +{
> +	bool terminated = false;
> +	size_t offs = 0;
> +	int flags = 0;
> +	struct extra_context *extra = NULL;
> +	struct _aarch64_ctx *head =
> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
> +
> +	if (!err)
> +		return false;
> +	/* Walk till the end terminator verifying __reserved contents */
> +	while (head && !terminated && offs < resv_sz) {
> +		if ((uint64_t)head & 0x0fUL) {
> +			*err = "Misaligned HEAD";
> +			return false;
> +		}
> +
> +		switch (head->magic) {
> +			case 0:
> +				if (head->size)
> +					*err = "Bad size for MAGIC0";

Or "terminator".  We don't have an actual symbolic name for magic number
0.  (Arguably it would have been nice to have a name, but we managed
without.)

> +				else
> +					terminated = true;
> +				break;
> +			case FPSIMD_MAGIC:
> +				if (flags & FPSIMD_CTX)
> +					*err = "Multiple FPSIMD_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct fpsimd_context))
> +					*err = "Bad size for fpsimd_context";
> +				flags |= FPSIMD_CTX;
> +				break;
> +			case ESR_MAGIC:
> +				if (head->size != sizeof(struct esr_context))
> +					fprintf(stderr,
> +						"Bad size for esr_context is not an error...just ignore.\n");

Why isn't this an error?  Should the kernel ever write an esr_context
with a different size?

> +				break;
> +			case SVE_MAGIC:
> +				if (flags & SVE_CTX)
> +					*err = "Multiple SVE_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct sve_context))
> +					*err = "Bad size for sve_context";
> +				flags |= SVE_CTX;
> +				break;
> +			case EXTRA_MAGIC:
> +				if (flags & EXTRA_CTX)
> +					*err = "Multiple EXTRA_MAGIC";
> +				else if (head->size !=
> +					 sizeof(struct extra_context))
> +					*err = "Bad size for extra_context";
> +				flags |= EXTRA_CTX;
> +				extra = (struct extra_context *)head;
> +				break;
> +			case KSFT_BAD_MAGIC:
> +				/*
> +				 * This is a BAD magic header defined
> +				 * artificially by a testcase and surely
> +				 * unknown to the Kernel parse_user_sigframe().
> +				 * It MUST cause a Kernel induced SEGV
> +				 */
> +				*err = "BAD MAGIC !";
> +				break;
> +			default:
> +				/*
> +				 * A still unknown Magic: potentially freshly added
> +				 * to the Kernel code and still unknown to the
> +				 * tests.
> +				 */
> +				fprintf(stdout,
> +					"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
> +					head->magic);
> +				break;
> +		}
> +
> +		if (*err)
> +			return false;
> +
> +		offs += head->size;

Can this addition cause offs to become > resv_sz?  If so, the next
comparison will go wrong.

> +		if (resv_sz - offs < sizeof(*head)) {
> +			*err = "HEAD Overrun";
> +			return false;
> +		}
> +
> +		if (flags & EXTRA_CTX)
> +			if (!validate_extra_context(extra, err))
> +				return false;

Can we validate the contents of the extra context too?

Ideally we can use the same code to check __reserved[] and the extra
context.

> +
> +		head = GET_RESV_NEXT_HEAD(head);
> +	}
> +
> +	if (terminated && !(flags & FPSIMD_CTX)) {
> +		*err = "Missing FPSIMD";
> +		return false;
> +	}
> +
> +	return true;
> +}
> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> new file mode 100644
> index 000000000000..624717c71b1d
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
> @@ -0,0 +1,83 @@
> +#ifndef __TESTCASES_H__
> +#define __TESTCASES_H__
> +

Pedantically, we should have <stddef.h> for NULL.

> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <unistd.h>

Is <unistd.h> used now that SAFE_WRITE() is gone?

> +#include <ucontext.h>
> +#include <assert.h>
> +
> +/* Architecture specific sigframe definitions */
> +#include <asm/sigcontext.h>

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 03/11] kselftest: arm64: mangle_pstate_invalid_daif_bits
  2019-08-02 17:02 ` [PATCH v3 03/11] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
@ 2019-08-13 16:24   ` Dave Martin
  2019-08-29 10:19     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:24 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:52PM +0100, Cristian Marussi wrote:
> Added a simple mangle testcase which messes with the ucontext_t

Strange past tense?  How about "Add"?

> from within the sig_handler, trying to set PSTATE DAIF bits to an

"signal handler"?

> invalid value (masking everything). Expects SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
>  .../arm64/signal/testcases/.gitignore         |  1 +
>  .../mangle_pstate_invalid_daif_bits.c         | 28 +++++++++++++++++++
>  2 files changed, 29 insertions(+)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> index 8651272e3cfc..8a0a29f0cc2a 100644
> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -1 +1,2 @@
>  mangle_pstate_invalid_compat_toggle
> +mangle_pstate_invalid_daif_bits
> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
> new file mode 100644
> index 000000000000..af899d4bb655
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
> +				     ucontext_t *uc)
> +{
> +	ASSERT_GOOD_CONTEXT(uc);
> +
> +	/*
> +	 * This config should trigger a SIGSEGV by Kernel when it checks
> +	 * the sigframe consistency in valid_user_regs() routine.
> +	 */
> +	uc->uc_mcontext.pstate |= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT;
> +
> +	return 1;
> +}

Hmmm, there was a lot of common framework code, but it seems like a good
investment if adding a new test is as simple as this :)

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 04/11] kselftest: arm64: mangle_pstate_invalid_mode_el
  2019-08-02 17:02 ` [PATCH v3 04/11] kselftest: arm64: mangle_pstate_invalid_mode_el Cristian Marussi
@ 2019-08-13 16:24   ` Dave Martin
  2019-08-29 11:50     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:24 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:53PM +0100, Cristian Marussi wrote:
> Added 3 simple mangle testcases that mess with the ucontext_t

Add

> from within the sig_handler, trying to toggle PSTATE mode bits to

signal handler

> trick the system into switching to EL1/EL2/EL3. Expects SIGSEGV
> on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
>  .../arm64/signal/testcases/.gitignore         |  3 ++
>  .../mangle_pstate_invalid_mode_el1.c          | 29 +++++++++++++++++++
>  .../mangle_pstate_invalid_mode_el2.c          | 29 +++++++++++++++++++
>  .../mangle_pstate_invalid_mode_el3.c          | 29 +++++++++++++++++++
>  4 files changed, 90 insertions(+)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> index 8a0a29f0cc2a..226bb179b673 100644
> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -1,2 +1,5 @@
>  mangle_pstate_invalid_compat_toggle
>  mangle_pstate_invalid_daif_bits
> +mangle_pstate_invalid_mode_el1
> +mangle_pstate_invalid_mode_el2
> +mangle_pstate_invalid_mode_el3

What about having

	!*.[ch]
	mangle_*

rather than having to update .gitignore to list every test executable?

> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
> new file mode 100644
> index 000000000000..07aed7624383
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
> +				     ucontext_t *uc)
> +{
> +	ASSERT_GOOD_CONTEXT(uc);
> +
> +	/*
> +	 * This config should trigger a SIGSEGV by Kernel
> +	 * when checking valid_user_regs()
> +	 */
> +	uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
> +	uc->uc_mcontext.pstate |= PSR_MODE_EL1t;
> +
> +	return 1;
> +}
> +
> +struct tdescr tde = {
> +		.sanity_disabled = true,
> +		.name = "MANGLE_PSTATE_INVALID_MODE_EL1t",
> +		.descr = "Mangling uc_mcontext with INVALID MODE EL1t",
> +		.sig_trig = SIGUSR1,
> +		.sig_ok = SIGSEGV,
> +		.run = mangle_invalid_pstate_run,
> +};

These tests seem identical except for the EL number.
Can we macro-ise them?

mangle_pstate_invalid_mode_el1.c could become

--8<--

#include "mangle_pstate_invalid_mode.h"

DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(1)

-->8--

(for example).

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 05/11] kselftest: arm64: mangle_pstate_ssbs_regs
  2019-08-02 17:02 ` [PATCH v3 05/11] kselftest: arm64: mangle_pstate_ssbs_regs Cristian Marussi
@ 2019-08-13 16:25   ` Dave Martin
  2019-08-29 15:35     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:25 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:54PM +0100, Cristian Marussi wrote:
> Added a simple mangle testcase which messes with the ucontext_t

Add

> from within the sig_handler, trying to toggle PSTATE SSBS bit.

signal handler

> Expect SIGILL if SSBS feature unsupported or that the value set in
> PSTATE.SSBS is preserved on test PASS.

The test doesn't set PSTATE.SSBS directly.

Maybe something like: "Expect SIGILL if the SSBS feature is unsupported.
Otherwise, expect sigreturn to set PSTATE.SSBS from the corresponding
bit in pstate in the signal frame."

> This commit also introduces a new common utility function:
> get_current_context() which can be used to grab a ucontext without
> the help of libc, and detect if such ucontext has been actively used
> to jump back into it.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
>  .../selftests/arm64/signal/test_signals.h     |  4 +
>  .../arm64/signal/test_signals_utils.c         | 93 +++++++++++++++++++
>  .../arm64/signal/test_signals_utils.h         |  2 +
>  .../arm64/signal/testcases/.gitignore         |  1 +
>  .../testcases/mangle_pstate_ssbs_regs.c       | 56 +++++++++++
>  5 files changed, 156 insertions(+)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> index 85db3ac44b32..37bed0590226 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals.h
> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
> @@ -116,6 +116,10 @@ struct tdescr {
>  	/* optional sa_flags for the installed handler */
>  	int		sa_flags;
>  	ucontext_t	saved_uc;
> +	/* used by get_current_ctx() */
> +	size_t		live_sz;
> +	ucontext_t	*live_uc;
> +	volatile bool	live_uc_valid;
>  
>  	/* a setup function to be called before test starts */
>  	int (*setup)(struct tdescr *td);
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> index ac0055f6340b..faf55ba99d58 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> @@ -11,12 +11,16 @@
>  #include <linux/auxvec.h>
>  #include <ucontext.h>
>  
> +#include <asm/unistd.h>
> +
>  #include "test_signals.h"
>  #include "test_signals_utils.h"
>  #include "testcases/testcases.h"
>  
>  extern struct tdescr *current;
>  
> +static int sig_copyctx = SIGUSR2;
> +
>  static char *feats_store[FMAX_END] = {
>  	"SSBS",
>  	"PAN",
> @@ -37,6 +41,85 @@ static inline char *feats_to_string(unsigned long feats)
>  	return feats_string;
>  }
>  
> +/*
> + * Obtaining a valid and full-blown ucontext_t from userspace is tricky:
> + * libc getcontext does() not save all the regs and messes with some of
> + * them (pstate value in particular is not reliable).
> + * Here we use a service signal to grab the ucontext_t from inside a
> + * dedicated signal handler, since there, it is populated by Kernel
> + * itself in setup_sigframe(). The grabbed context is then stored and
> + * made available in td->live_uc.
> + *
> + * Anyway this function really serves a dual purpose:
> + *
> + * 1. grab a valid sigcontext into td->live_uc for result analysis: in
> + * such case it returns 1.
> + *
> + * 2. detect if somehow a previously grabbed live_uc context has been
> + * used actively with a sigreturn: in such a case the execution would have
> + * magically resumed in the middle of the function itself (seen_already==1):
> + * in such a case return 0, since in fact we have not just simply grabbed
> + * the context.
> + *
> + * This latter case is useful to detect when a fake_sigreturn test-case has
> + * unexpectedly survived without hittig a SEGV.
> + */
> +bool get_current_context(struct tdescr *td, ucontext_t *dest_uc)
> +{
> +	static volatile sig_atomic_t seen_already;
> +
> +	if (!td || !dest_uc) {
> +		fprintf(stdout, "Signal-based Context dumping NOT available\n");

Should this ever happen inless there is a test bug?

Maybe this should just be an assert.

> +		return 0;
> +	}
> +
> +	/* it's a genuine invokation..reinit */
> +	seen_already = 0;
> +	td->live_uc_valid = 0;
> +	td->live_sz = sizeof(*dest_uc);
> +	memset(dest_uc, 0x00, td->live_sz);

Eventually we will need to examine the signal frame to determine its
size, but for now this is fine.

It will start to matter for SVE.

> +	td->live_uc = dest_uc;
> +	/*
> +	 * Grab ucontext_t triggering a signal...
> +	 * ASM equivalent of raise(sig_copyctx);
> +	 *
> +	 * Note that:
> +	 * - live_uc_valid is declared volatile in struct tdescr
> +	 *   since it will be changed inside the sig_copyctx handler.
> +	 * - the kill() syscall invocation returns only after any possible
> +	 *   registered sig_handler for the invoked signal has returned,

sig_handler looks like the name of some function of variable, but I
can't find it.  Did I miss something?

> +	 *   so that live_uc_valid flag is surely up to date when this
> +	 *   function return it.
> +	 * - the additional 'memory' clobber is there to avoid possible
> +	 *   compiler's assumption on the content pointed by dest_uc, which
> +	 *   is changed inside the handler, but not referenced here anyway.
> +	 */
> +	asm volatile ("mov x8, %0\n\t"
> +		      "svc #0\n\t"
> +		      "mov x1, %1\n\t"
> +		      "mov x8, %2\n\t"
> +		      "svc #0"
> +		      :
> +		      : "i" (__NR_getpid),
> +		        "r" (sig_copyctx),
> +			"i" (__NR_kill)
> +		      : "x1","x8","x0","memory");
> +	/*
> +	 * If we get here with seen_already==1 it implies the td->live_uc
> +	 * context has been used to get back here....this probably means
> +	 * a test has failed to cause a SEGV...anyway the live_uc has not
> +	 * just been acquired...so return 0
> +	 */
> +	if (seen_already) {
> +		fprintf(stdout,
> +			"Successful sigreturn detected: live_uc is stale !\n");
> +		return 0;
> +	}
> +	seen_already = 1;
> +
> +	return td->live_uc_valid;
> +}
> +
>  static void unblock_signal(int signum)
>  {
>  	sigset_t sset;
> @@ -112,6 +195,12 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
>  		 * to terminate immediately exiting straight away
>  		 */
>  		default_result(current, 1);
> +	} else if (signum == sig_copyctx && current->live_uc) {
> +		memcpy(current->live_uc, uc, current->live_sz);
> +		ASSERT_GOOD_CONTEXT(current->live_uc);
> +		current->live_uc_valid = 1;
> +		fprintf(stderr,
> +			"GOOD CONTEXT grabbed from sig_copyctx handler\n");
>  	} else {
>  		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
>  			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
> @@ -214,6 +303,10 @@ static int test_init(struct tdescr *td)
>  			!feats_ok ? "NOT " : "");
>  	}
>  
> +	if (td->sig_trig == sig_copyctx)
> +		sig_copyctx = SIGUSR1;

What's this for?  What if we have the same signal for sig_trig and
sig_copyctx?

> +	unblock_signal(sig_copyctx);
> +
>  	td->initialized = 1;
>  	return 1;
>  }
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> index 8658d1a7d4b9..ce35be8ebc8e 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -10,4 +10,6 @@ int test_setup(struct tdescr *td);
>  void test_cleanup(struct tdescr *td);
>  int test_run(struct tdescr *td);
>  void test_result(struct tdescr *td);
> +
> +bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
>  #endif
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> index 226bb179b673..a48a118b1a1a 100644
> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -3,3 +3,4 @@ mangle_pstate_invalid_daif_bits
>  mangle_pstate_invalid_mode_el1
>  mangle_pstate_invalid_mode_el2
>  mangle_pstate_invalid_mode_el3
> +mangle_pstate_ssbs_regs
> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
> new file mode 100644
> index 000000000000..a399d9aa40d5
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +
> +#include <stdio.h>
> +#include <ucontext.h>
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +static int mangle_invalid_pstate_ssbs_run(struct tdescr *td,
> +					  siginfo_t *si, ucontext_t *uc)
> +{
> +	ASSERT_GOOD_CONTEXT(uc);
> +
> +	/* set bit value */

Should we clear SSBS in the test setup (using MSR), to make sure that
sigreturn really succeeds in _changing_ the bit to 1?

> +	uc->uc_mcontext.pstate |= PSR_SSBS_BIT;
> +	fprintf(stderr, "SSBS set to 1 -- PSTATE: 0x%016lX\n",
> +		uc->uc_mcontext.pstate);
> +	/* Save after mangling...it should be preserved */
> +	td->saved_uc = *uc;
> +
> +	return 1;
> +}

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic
  2019-08-02 17:02 ` [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
@ 2019-08-13 16:25   ` Dave Martin
  2019-08-30 14:29     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:25 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:55PM +0100, Cristian Marussi wrote:
> Added a simple fake_sigreturn testcase which builds a ucontext_t

Add

> with a bad magic header and place it onto the stack.
> Expects a SIGSEGV on test PASS.
> This commit also introduces a common utility assembly function to
> invoke a sigreturn using a fake provided sigframe.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
>  tools/testing/selftests/arm64/signal/Makefile |  2 +-
>  .../testing/selftests/arm64/signal/signals.S  | 64 +++++++++++++++++++
>  .../arm64/signal/test_signals_utils.h         |  1 +
>  .../arm64/signal/testcases/.gitignore         |  1 +
>  .../testcases/fake_sigreturn_bad_magic.c      | 63 ++++++++++++++++++
>  5 files changed, 130 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/arm64/signal/signals.S
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
> index 8c8d08be4b0d..b3dcf315b5a4 100644
> --- a/tools/testing/selftests/arm64/signal/Makefile
> +++ b/tools/testing/selftests/arm64/signal/Makefile
> @@ -80,7 +80,7 @@ endif
>  # 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
> +$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c signals.S $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
>  	@if [ ! -d $(khdr_dir) ]; then \
>  		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
>  		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
> diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
> new file mode 100644
> index 000000000000..6262b877400b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/signals.S
> @@ -0,0 +1,64 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0
> + * Copyright (C) 2019 ARM Limited
> + */
> +
> +#include <asm/unistd.h>
> +
> +.section        ".rodata", "a"

The section name is not usually quoted in .section (though I guess it
works).

> +call_fmt:
> +	.asciz "Calling sigreturn with fake sigframe sized:%zd at calculated SP @%08lX\n"
> +
> +.text
> +
> +.globl fake_sigreturn
> +
> +/*	fake_sigreturn	x0:&sigframe,  x1:sigframe_size,  x2:alignment_SP */
> +fake_sigreturn:
> +	mov x20, x0
> +	mov x21, x1
> +	mov x22, x2
> +	mov x23, sp
> +
> +	/* create space on the stack for fake sigframe..."x22"-aligned */
> +	mov x0, #0

Why to we move 0 into x0?  We clobber x0 again in the next instruction:

> +	add x0, x21, x22
> +	sub x22, x22, #1
> +	bic x0, x0, x22
> +	sub x23, x23, x0

Can you explain the logic here?  I'm not sure I understand what this is
trying to do exactly.

I notice you further modify this in patch 11 -- see my comments there,
where I also suggest an alternative way of specifying a misaligned frame
that might be simpler.

> +
> +	ldr x0, =call_fmt
> +	mov x1, x21
> +	mov x2, x23
> +	bl printf
> +
> +	mov sp, x23
> +
> +	/* now fill it with the provided content... */
> +	mov x0, sp
> +	mov x1, x20
> +	mov x2, x21
> +	bl memcpy
> +
> +	/*
> +	 * Here saving a last minute SP to current->token acts as a marker:
> +	 * if we got here, we are successfully faking a sigreturn; in other
> +	 * words we are sure no bad fatal signal has been raised till now
> +	 * for unrelated reasons, so we should consider the possibl observed

typo: possible (or possibly?)

> +	 * fatal signal like SEGV coming from Kernel restore_sigframe() and
> +	 * triggered as expected from our test-case.
> +	 * For simplicity this assumes that current field 'token' is laid out
> +	 * as first in struct tdescr
> +	 */
> +	ldr x0, current
> +	str x23, [x0]
> +	/* SP is already pointing back to the just built fake sigframe here */
> +	mov x8, #__NR_rt_sigreturn
> +	svc #0
> +
> +	/*
> +	 * Above sigreturn should not return...looping here leads to a timeout
> +	 * and ensure proper and clean test failure, instead of jumping around
> +	 * on a potentially corrupted stack.
> +	 */
> +	b .
> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> index ce35be8ebc8e..2a71da7e6695 100644
> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
> @@ -12,4 +12,5 @@ int test_run(struct tdescr *td);
>  void test_result(struct tdescr *td);
>  
>  bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
> +int fake_sigreturn(void *sigframe, size_t sz, int alignment);
>  #endif
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> index a48a118b1a1a..0ea6fdc3765c 100644
> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -4,3 +4,4 @@ mangle_pstate_invalid_mode_el1
>  mangle_pstate_invalid_mode_el2
>  mangle_pstate_invalid_mode_el3
>  mangle_pstate_ssbs_regs
> +fake_sigreturn_bad_magic
> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
> new file mode 100644
> index 000000000000..b4c063e02a7a
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
> @@ -0,0 +1,63 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +

We should probably also include <signal.h> here, since we're using
siginfo_t etc.

> +#include <stdio.h>
> +#include <ucontext.h>
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +struct fake_sigframe sf;
> +
> +static int fake_sigreturn_bad_magic_run(struct tdescr *td,
> +					siginfo_t *si, ucontext_t *uc)
> +{
> +	size_t resv_sz, offset;
> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
> +
> +	/* just to fill the ucontext_t with something real */
> +	if (!get_current_context(td, &sf.uc))
> +		return 1;
> +
> +	resv_sz = GET_SF_RESV_SIZE(sf);
> +	/*
> +	 * find the terminator, preserving existing headers
> +	 * and verify amount of spare room in __reserved area.
> +	 */
> +	head = get_terminator(shead, resv_sz, &offset);
> +	/*
> +	 * try stripping extra_context header when low on space:
> +	 * we need at least 2*HDR_SZ space ... one for the KSFT_BAD_MAGIC
> +	 * and the other for the usual terminator.
> +	 */
> +	if (head && resv_sz - offset < HDR_SZ * 2) {

Can we factor out this logic for finding space in the signal frame?

We do pretty much the same thing in all the fake_sigreturn tests...

> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
> +			resv_sz - offset);
> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
> +	}
> +	/* just give up and timeout if still not enough space */

Do we actually time out?  I don't see where we actually wait, so doesn't
test_run() just fail immediately?

The same applies to all the other fake_sigreturn tests too.

> +	if (head && resv_sz - offset >= HDR_SZ) {

Should this be HDR_SZ * 2 again?  We need space for the face header and
space to write a terminator after it.

> +		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
> +			resv_sz - offset);
> +		/*
> +		 * use a well known NON existent bad magic...something
> +		 * we should pretty sure won't be ever defined in Kernel
> +		 */
> +		head->magic = KSFT_BAD_MAGIC;
> +		head->size = HDR_SZ;
> +		write_terminator_record(GET_RESV_NEXT_HEAD(head));
> +
> +		ASSERT_BAD_CONTEXT(&sf.uc);
> +		fake_sigreturn(&sf, sizeof(sf), 16);
> +	}
> +
> +	return 1;
> +}

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 07/11] kselftest: arm64: fake_sigreturn_bad_size_for_magic0
  2019-08-02 17:02 ` [PATCH v3 07/11] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
@ 2019-08-13 16:25   ` Dave Martin
  2019-08-30 14:49     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:25 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:56PM +0100, Cristian Marussi wrote:
> Added a simple fake_sigreturn testcase which builds a ucontext_t

Add

> with a badly sized magic0 header and place it onto the stack.

I usually call a record with magic number 0 a "terminator record".

> Expects a SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
>  .../arm64/signal/testcases/.gitignore         |  1 +
>  .../fake_sigreturn_bad_size_for_magic0.c      | 57 +++++++++++++++++++
>  2 files changed, 58 insertions(+)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> index 0ea6fdc3765c..cf2a73599818 100644
> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -5,3 +5,4 @@ mangle_pstate_invalid_mode_el2
>  mangle_pstate_invalid_mode_el3
>  mangle_pstate_ssbs_regs
>  fake_sigreturn_bad_magic
> +fake_sigreturn_bad_size_for_magic0
> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
> new file mode 100644
> index 000000000000..2f53c4740c85
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
> @@ -0,0 +1,57 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +

#include <signal.h> ?

> +#include <stdio.h>
> +#include <ucontext.h>
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +struct fake_sigframe sf;
> +
> +#define MIN_SZ_ALIGN	16
> +
> +static int fake_sigreturn_bad_size_for_magic0_run(struct tdescr *td,
> +						  siginfo_t *si, ucontext_t *uc)
> +{
> +	size_t resv_sz, offset;
> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
> +
> +	/* just to fill the ucontext_t with something real */
> +	if (!get_current_context(td, &sf.uc))
> +		return 1;
> +
> +	resv_sz = GET_SF_RESV_SIZE(sf);
> +	/*
> +	 * find the terminator, preserving existing headers
> +	 * and verify amount of spare room in __reserved area.
> +	 */
> +	head = get_terminator(shead, resv_sz, &offset);
> +	/*
> +	 * try stripping extra_context header when low on space:
> +	 * we need at least HDR_SZ + 16 space for the bad sized terminator.
> +	 */
> +	if (head && resv_sz - offset < HDR_SZ + MIN_SZ_ALIGN) {
> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
> +			resv_sz - offset);
> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
> +	}
> +	/* just give up and timeout if still not enough space */
> +	if (head && resv_sz - offset >= HDR_SZ + MIN_SZ_ALIGN) {
> +		head->magic = 0;
> +		head->size = MIN_SZ_ALIGN;

This is different from the amount of space we tested for
(HDR_SZ + MIN_SZ_ALIGN) earlier.

I'm not sure it matters which we use, but we should be consistent.

I suggest sticking with HDR_SZ, unless there's something I've missed.

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 08/11] kselftest: arm64: fake_sigreturn_missing_fpsimd
  2019-08-02 17:02 ` [PATCH v3 08/11] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
@ 2019-08-13 16:26   ` Dave Martin
  2019-08-30 14:55     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:26 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:57PM +0100, Cristian Marussi wrote:
> Added a simple fake_sigreturn testcase which builds a ucontext_t

Add

> without the required fpsimd_context and place it onto the stack.
> Expects a SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
>  .../arm64/signal/testcases/.gitignore         |  1 +
>  .../testcases/fake_sigreturn_missing_fpsimd.c | 44 +++++++++++++++++++
>  2 files changed, 45 insertions(+)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> index cf2a73599818..17d1c5e73319 100644
> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -6,3 +6,4 @@ mangle_pstate_invalid_mode_el3
>  mangle_pstate_ssbs_regs
>  fake_sigreturn_bad_magic
>  fake_sigreturn_bad_size_for_magic0
> +fake_sigreturn_missing_fpsimd
> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
> new file mode 100644
> index 000000000000..b8dd57ce6844
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +

signal.h?

> +#include <stdio.h>
> +#include <ucontext.h>
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +struct fake_sigframe sf;
> +
> +static int fake_sigreturn_missing_fpsimd_run(struct tdescr *td,
> +					     siginfo_t *si, ucontext_t *uc)
> +{
> +	size_t resv_sz, offset;
> +	struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
> +
> +	/* just to fill the ucontext_t with something real */
> +	if (!get_current_context(td, &sf.uc))
> +		return 1;
> +
> +	resv_sz = GET_SF_RESV_SIZE(sf);
> +	head = get_header(head, FPSIMD_MAGIC, resv_sz, &offset);
> +	/* just give up and timeout if still not enough space */
> +	if (head && resv_sz - offset >= HDR_SZ) {
> +		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
> +			resv_sz - offset);
> +		/* Just overwrite fpsmid_context */
> +		write_terminator_record(head);
> +
> +		ASSERT_BAD_CONTEXT(&sf.uc);
> +		fake_sigreturn(&sf, sizeof(sf), 16);
> +	}
> +
> +	return 1;
> +}

[...]

Seems reasonable otherwise.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 09/11] kselftest: arm64: fake_sigreturn_duplicated_fpsimd
  2019-08-02 17:02 ` [PATCH v3 09/11] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
@ 2019-08-13 16:26   ` Dave Martin
  2019-08-30 15:11     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:26 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:58PM +0100, Cristian Marussi wrote:
> Added a simple fake_sigreturn testcase which builds a ucontext_t

Add

> with an anomalous additional fpsimd_context and place it onto the stack.
> Expects a SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
>  .../arm64/signal/testcases/.gitignore         |  1 +
>  .../fake_sigreturn_duplicated_fpsimd.c        | 62 +++++++++++++++++++
>  2 files changed, 63 insertions(+)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> index 17d1c5e73319..94f9baaf638c 100644
> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -7,3 +7,4 @@ mangle_pstate_ssbs_regs
>  fake_sigreturn_bad_magic
>  fake_sigreturn_bad_size_for_magic0
>  fake_sigreturn_missing_fpsimd
> +fake_sigreturn_duplicated_fpsimd
> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
> new file mode 100644
> index 000000000000..09af7a0f8776
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
> @@ -0,0 +1,62 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +

signal.h?

> +#include <stdio.h>
> +#include <ucontext.h>
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +struct fake_sigframe sf;
> +
> +static int fake_sigreturn_duplicated_fpsimd_run(struct tdescr *td,
> +						siginfo_t *si, ucontext_t *uc)
> +{
> +	size_t resv_sz, offset;
> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
> +
> +	/* just to fill the ucontext_t with something real */
> +	if (!get_current_context(td, &sf.uc))
> +		return 1;
> +
> +	resv_sz = GET_SF_RESV_SIZE(sf);
> +	/*
> +	 * find the terminator, preserving existing headers
> +	 * and verify amount of spare room in __reserved area.
> +	 */
> +	head = get_terminator(shead, resv_sz, &offset);
> +	/*
> +	 * try stripping extra_context header when low on space:
> +	 * we need at least space for one additional fpsimd_context
> +	 */
> +	if (head && resv_sz - offset < sizeof(struct fpsimd_context)) {
> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
> +			resv_sz - offset);
> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
> +	}
> +
> +	/* just give up and timeout if still not enough space */
> +	if (head &&
> +	    resv_sz - offset >= sizeof(struct fpsimd_context) + HDR_SZ) {
> +		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
> +			resv_sz - offset);
> +		/* Add a spurios fpsimd_context */
> +		head->magic = FPSIMD_MAGIC;
> +		head->size = sizeof(struct fpsimd_context);
> +		/* and terminate */
> +		write_terminator_record(GET_RESV_NEXT_HEAD(head));
> +
> +		ASSERT_BAD_CONTEXT(&sf.uc);
> +		fake_sigreturn(&sf, sizeof(sf), 16);
> +	}
> +
> +	return 1;
> +}

[...]

Otherwise looks ok.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 10/11] kselftest: arm64: fake_sigreturn_bad_size
  2019-08-02 17:02 ` [PATCH v3 10/11] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
@ 2019-08-13 16:26   ` Dave Martin
  2019-08-30 15:21     ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:26 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:02:59PM +0100, Cristian Marussi wrote:
> Added a simple fake_sigreturn testcase which builds a ucontext_t

Add

> with a badly sized header that causes a overrun in the __reserved
> area and place it onto the stack. Expects a SIGSEGV on test PASS.
> 
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
>  .../arm64/signal/testcases/.gitignore         |  1 +
>  .../testcases/fake_sigreturn_bad_size.c       | 85 +++++++++++++++++++
>  2 files changed, 86 insertions(+)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> index 94f9baaf638c..3408e0f5ba98 100644
> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
> @@ -8,3 +8,4 @@ fake_sigreturn_bad_magic
>  fake_sigreturn_bad_size_for_magic0
>  fake_sigreturn_missing_fpsimd
>  fake_sigreturn_duplicated_fpsimd
> +fake_sigreturn_bad_size
> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
> new file mode 100644
> index 000000000000..1467fb534d8b
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
> @@ -0,0 +1,85 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +

signal.h?

> +#include <stdio.h>
> +#include <ucontext.h>
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +struct fake_sigframe sf;
> +
> +#define MIN_SZ_ALIGN	16
> +
> +static int fake_sigreturn_bad_size_run(struct tdescr *td,
> +				       siginfo_t *si, ucontext_t *uc)
> +{
> +	size_t resv_sz, need_sz, offset;
> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
> +
> +	/* just to fill the ucontext_t with something real */
> +	if (!get_current_context(td, &sf.uc))
> +		return 1;
> +
> +	resv_sz = GET_SF_RESV_SIZE(sf);
> +	/*
> +	 * find the terminator, preserving existing headers
> +	 * and verify amount of spare room in __reserved area.
> +	 */
> +	head = get_terminator(shead, resv_sz, &offset);
> +	/*
> +	 * try stripping extra_context header when low on space:
> +	 * we need at least  for the bad sized esr_context.

double space

> +	 */
> +	need_sz = HDR_SZ + sizeof(struct esr_context);
> +	if (head && resv_sz - offset < need_sz) {
> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
> +			resv_sz - offset);
> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
> +	}
> +	/* just give up and timeout if still not enough space */
> +	if (head && resv_sz - offset >= need_sz) {
> +		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
> +			resv_sz - offset);
> +		/*
> +		 * Use an esr_context to build a fake header with a
> +		 * size greater then the free __reserved area minus HDR_SZ;
> +		 * using ESR_MAGIC here since it is not checked for size nor
> +		 * is limited to one instance.
> +		 *
> +		 * At first inject an additional normal esr_context
> +		 */
> +		head->magic = ESR_MAGIC;
> +		head->size = sizeof(struct esr_context);
> +		/* and terminate properly */
> +		write_terminator_record(GET_RESV_NEXT_HEAD(head));
> +		ASSERT_GOOD_CONTEXT(&sf.uc);
> +
> +		/*
> +		 * now mess with fake esr_context size: leaving less space than
> +		 * neededwhile keeping size value 16-aligned
> +		 *
> +		 * It must trigger a SEGV from Kernel on:
> +		 *
> +		 *	resv_sz - offset < sizeof(*head)
> +		 */
> +		/* at first set the maximum good 16-aligned size */
> +		head->size = (resv_sz - offset - need_sz + MIN_SZ_ALIGN) & ~0xfUL;
> +		/* plus a bit more of 16-aligned sized stuff */
> +		head->size += MIN_SZ_ALIGN;
> +		/* and terminate properly */
> +		write_terminator_record(GET_RESV_NEXT_HEAD(head));
> +		ASSERT_BAD_CONTEXT(&sf.uc);
> +		fake_sigreturn(&sf, sizeof(sf), 16);
> +	}
> +
> +	return 1;
> +}

[...]

Otherwise looks reasonable.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp
  2019-08-02 17:03 ` [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp Cristian Marussi
  2019-08-07 16:04   ` Cristian Marussi
@ 2019-08-13 16:27   ` Dave Martin
  2019-08-30 16:33     ` Cristian Marussi
  1 sibling, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:27 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On Fri, Aug 02, 2019 at 06:03:00PM +0100, Cristian Marussi wrote:
> Added a simple fake_sigreturn testcase which places a valid

Add

> sigframe on a non-16 bytes aligned SP.
> fake_sigretrun() helper function has been patched accordingly
> to support placing a sigframe on a non-16 bytes aligned address.
> Expects a SIGSEGV on test PASS.
> 
> Adds also a test TODO lists holding some further test ideas.

Adds -> Also add
lists -> list

> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> Re-added this text after fixing the forced misaglinment procedure in
> fake_sigreturn() itself: require a ZERO alignment and you'll get
> your sigframe placed on a misaligned SP (2-bytes off the 16-align)
> ---
>  .../testing/selftests/arm64/signal/signals.S  | 21 +++++++++----
>  .../arm64/signal/testcases/TODO.readme        |  8 +++++
>  .../testcases/fake_sigreturn_misaligned_sp.c  | 30 +++++++++++++++++++
>  3 files changed, 53 insertions(+), 6 deletions(-)
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
> 
> diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
> index 6262b877400b..2099871176ed 100644
> --- a/tools/testing/selftests/arm64/signal/signals.S
> +++ b/tools/testing/selftests/arm64/signal/signals.S
> @@ -13,19 +13,28 @@ call_fmt:
>  
>  .globl fake_sigreturn
>  
> -/*	fake_sigreturn	x0:&sigframe,  x1:sigframe_size,  x2:alignment_SP */
> +/*	fake_sigreturn	x0:&sigframe, x1:sigframe_sz, x2:align */
>  fake_sigreturn:
> -	mov x20, x0
> -	mov x21, x1
> -	mov x22, x2
> -	mov x23, sp
>  
> -	/* create space on the stack for fake sigframe..."x22"-aligned */
> +	/* Save args and decide which aligment to enforce */
> +	mov 	x23, sp
> +	mov	x20, x0
> +	mov 	x21, x1
> +	/* x22 and x24 used for forcing alignment or misalignment */
> +	mov	x22, x2
> +	mov	x24, #0
> +	cbnz	x22, 1f
> +	mov	x22, #16
> +	mov	x24, #2
> +
> +1:	/* create space on the stack for fake sigframe..."x22"-aligned */
>  	mov x0, #0
>  	add x0, x21, x22
>  	sub x22, x22, #1
>  	bic x0, x0, x22
>  	sub x23, x23, x0
> +	/* force misaligned by x24 bytes if required alignment was zero */
> +	add x23, x23, x24
>  
>  	ldr x0, =call_fmt
>  	mov x1, x21

Would it be simpler for the third argument to specify a number of bytes
to subtract from SP after allocating 16-byte aligned storage to
accommodate sigframe_sz?

Then 0 gives an aligned frame, 1 gives a frame misaligned by 1 byte,
etc.


Also if all this is a fix to the original fake_sigreturn, can we merge
it into the original patch instead?

> diff --git a/tools/testing/selftests/arm64/signal/testcases/TODO.readme b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
> new file mode 100644
> index 000000000000..5c949492e7ab
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
> @@ -0,0 +1,8 @@
> +Some more possible ideas for signals tests:
> +
> +- fake_sigreturn_unmapped_sp
> +- fake_sigreturn_kernelspace_sp
> +- fake_sigreturn_sve_bad_extra_context
> +- mangle_sve_invalid_extra_context
> +- mangle_pstate_invalid_el for H modes (+ macroization ?)
> +- fake_sigreturn_overflow_reserved

This seems a reasonable list, but it occurs to me that it will tend to
go out of sync as tests get added.  So maybe just put this list in the
cover letter instead of including it in the patch.

We should probably have a one-line description of each proposed test,
since the names are a bit cryptic.

> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
> new file mode 100644
> index 000000000000..3ee8c500c7d1
> --- /dev/null
> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 ARM Limited */
> +

signal.h?

> +#include <ucontext.h>
> +
> +#include "test_signals_utils.h"
> +#include "testcases.h"
> +
> +struct fake_sigframe sf;
> +
> +static int fake_sigreturn_misaligned_run(struct tdescr *td,
> +				         siginfo_t *si, ucontext_t *uc)
> +{
> +	/* just to fill the ucontext_t with something real */
> +	if (!get_current_context(td, &sf.uc))
> +		return 1;
> +
> +	/* Forcing sigframe on misaligned (=!16) SP */
> +	fake_sigreturn(&sf, sizeof(sf), 0);
> +
> +	return 1;
> +}

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp
  2019-08-07 16:04   ` Cristian Marussi
@ 2019-08-13 16:28     ` Dave Martin
  2019-08-30 15:22       ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-08-13 16:28 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: linux-kselftest, linux-arm-kernel

On Wed, Aug 07, 2019 at 05:04:13PM +0100, Cristian Marussi wrote:
> On 02/08/2019 18:03, Cristian Marussi wrote:
> > Added a simple fake_sigreturn testcase which places a valid
> > sigframe on a non-16 bytes aligned SP.
> > fake_sigretrun() helper function has been patched accordingly
> > to support placing a sigframe on a non-16 bytes aligned address.
> > Expects a SIGSEGV on test PASS.
> > 
> > Adds also a test TODO lists holding some further test ideas.
> > 
> > Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> > ---
> > Re-added this text after fixing the forced misaglinment procedure in
> > fake_sigreturn() itself: require a ZERO alignment and you'll get
> > your sigframe placed on a misaligned SP (2-bytes off the 16-align)
> > ---
> >  .../testing/selftests/arm64/signal/signals.S  | 21 +++++++++----
> >  .../arm64/signal/testcases/TODO.readme        |  8 +++++
> >  .../testcases/fake_sigreturn_misaligned_sp.c  | 30 +++++++++++++++++++
> >  3 files changed, 53 insertions(+), 6 deletions(-)
> >  create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
> >  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
> > 
> 
> When this test was re-added in V3, the related .gitignore was missed.
> It will go in V4

Ack, or otherwise try switching to using wildcards in .gitignore as
suggested in my reply to patch 4.

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-13 13:22     ` Cristian Marussi
@ 2019-08-14 10:22       ` Amit Kachhap
  2019-08-27 14:24         ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Amit Kachhap @ 2019-08-14 10:22 UTC (permalink / raw)
  To: Cristian Marussi, linux-kselftest, linux-arm-kernel, shuah
  Cc: andreyknvl, Dave P Martin

Hi Cristian,

I have few more comments,

On 8/13/19 6:52 PM, Cristian Marussi wrote:
> Hi Amit
>
> thanks for the review.
>
> On 12/08/2019 13:43, Amit Kachhap wrote:
>> Hi Cristian,
>>
>> On 8/2/19 10:32 PM, Cristian Marussi wrote:
>>> Added some arm64/signal specific boilerplate and utility code to help
>>> further testcase development.
>>>
>>> A simple testcase and related helpers are also introduced in this commit:
>>> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
>>> messes with the ucontext_t from within the sig_handler, trying to toggle
>>> PSTATE state bits to switch the system between 32bit/64bit execution state.
>>> Expects SIGSEGV on test PASS.
>>>
>>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>>> ---
>>> A few fixes:
>>> - test_arm64_signals.sh runner script generation has been reviewed in order to
>>>     be safe against the .gitignore
>>> - using kselftest.h officially provided defines for tests' return values
>>> - removed SAFE_WRITE()/dump_uc()
>>> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>>>     the sigfault had been directly triggered by Kernel
>>> ---
>>>    tools/testing/selftests/arm64/Makefile        |   2 +-
>>>    .../testing/selftests/arm64/signal/.gitignore |   6 +
>>>    tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>>>    tools/testing/selftests/arm64/signal/README   |  59 ++++
>>>    .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>>>    .../selftests/arm64/signal/test_signals.c     |  26 ++
>>>    .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>>>    .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>>>    .../arm64/signal/test_signals_utils.h         |  13 +
>>>    .../arm64/signal/testcases/.gitignore         |   1 +
>>>    .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>>>    .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>>>    .../arm64/signal/testcases/testcases.h        |  83 ++++++
>>>    13 files changed, 905 insertions(+), 1 deletion(-)
>>>    create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>>>    create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>>>    create mode 100644 tools/testing/selftests/arm64/signal/README
>>>    create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>>    create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>>>    create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>>>    create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>>>    create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>>>    create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>>>    create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>>    create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>>>    create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
>>>
>>> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
>>> index 03a0d4f71218..af59dc74e0dc 100644
>>> --- a/tools/testing/selftests/arm64/Makefile
>>> +++ b/tools/testing/selftests/arm64/Makefile
>>> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>>>    ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>>>
>>>    ifeq ("x$(ARCH)", "xarm64")
>>> -SUBDIRS :=
>>> +SUBDIRS := signal
>>>    else
>>>    SUBDIRS :=
>>>    endif
>>> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
>>> new file mode 100644
>>> index 000000000000..434f65c15f03
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/.gitignore
>>> @@ -0,0 +1,6 @@
>>> +# Helper script's internal testcases list (TPROGS) is regenerated
>>> +# each time by Makefile on standalone (non KSFT driven) runs.
>>> +# Committing such list creates a dependency between testcases
>>> +# patches such that they are no more easily revertable. Just ignore.
>>> +test_arm64_signals.src_shell
>>> +test_arm64_signals.sh
>>> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
>>> new file mode 100644
>>> index 000000000000..8c8d08be4b0d
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/Makefile
>>> @@ -0,0 +1,88 @@
>>> +# SPDX-License-Identifier: GPL-2.0
>>> +# Copyright (C) 2019 ARM Limited
>>> +
>>> +# Supports also standalone invokation out of KSFT-tree
>>> +# Compile standalone and run on your device with:
>>> +#
>>> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
>>> +#
>>> +# Run standalone on device with:
>>> +#
>>> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
>>> +#
>>> +# If INSTALL_PATH= is NOT provided it will default to ./install
>>> +
>>> +# A proper top_srcdir is needed both by KSFT(lib.mk)
>>> +# and standalone builds
>>> +top_srcdir = ../../../../..
>>> +
>>> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
>>> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
>>> +PROGS := $(patsubst %.c,%,$(SRCS))
>>> +
>>> +# Guessing as best as we can where the Kernel headers
>>> +# could have been installed depending on ENV config and
>>> +# type of invocation.
>>> +ifeq ($(KBUILD_OUTPUT),)
>>> +khdr_dir = $(top_srcdir)/usr/include
>>> +else
>>> +ifeq (0,$(MAKELEVEL))
>>> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
>>> +else
>>> +# the KSFT preferred location when KBUILD_OUTPUT is set
>>> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
>>> +endif
>>> +endif
>>> +
>>> +CFLAGS += -I$(khdr_dir)
>>> +
>>> +# Standalone run
>>> +ifeq (0,$(MAKELEVEL))
>>> +CC := $(CROSS_COMPILE)gcc
>>> +RUNNER_SRC = test_arm64_signals.src_shell
>>> +RUNNER = test_arm64_signals.sh
Is this extra level of copying test_arm64_signals.src_shell to
test_arm64_signals.sh required? I cannot see them in other selftests.
Also if done then clean may be required. May be EXTRA_CLEAN parameter
can be used as done for other selftests.
>>> +INSTALL_PATH ?= install/
Here default INSTALL_PATH should be just "install" as it may insert "/"
twice for below install case.
>>> +
>>> +all: $(RUNNER)
>>> +
>>> +$(RUNNER): $(PROGS)
>>> +   cp $(RUNNER_SRC) $(RUNNER)
>>> +   sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
>>> +
>>> +install: all
>>> +   mkdir -p $(INSTALL_PATH)/testcases
>>> +   cp $(PROGS) $(INSTALL_PATH)/testcases
>>> +   cp $(RUNNER) $(INSTALL_PATH)/
>>> +
>>> +.PHONY clean:
>>> +   rm -f $(PROGS)
>>> +# KSFT run
>>> +else
>>> +# 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
>>> +
>>> +# This include mk 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)/
I guess this copy requires cleaning too.
>>> +
>>> +clean:
>>> +   $(CLEAN)
>>> +   rm -f $(PROGS)
Is clean requires to clean installed programs also?
>>> +endif
>>> +
>>> +# 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
>>
>> I suppose *.h can be removed from the targets here.
>
> *.h are in the pre-reqs, $(PROGS) represent the targets and it's comprised by the *.c file contained in testcases/ (excluding testcases.c)
>
> If I remove the *.h from this rule, targets won't be rebuilt when headers are changed (like after having added an hypotethical inline)...
>
> or am I missing something else ?
Yes You are right.

Thanks,
Amit Daniel
>
>
>>
>>
>>> +   @if [ ! -d $(khdr_dir) ]; then \
>>> +           echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
>>> +           echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
>>> +   fi
>>> +   $(CC) $(CFLAGS) $^ -o $@
>>> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
>>> new file mode 100644
>>> index 000000000000..53f005f7910a
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/README
>>> @@ -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 messes-up with the sigframe ucontext_t from
>>> +    inside the sighandler 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
>>> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>> new file mode 100755
>>> index 000000000000..163e941e2997
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>> @@ -0,0 +1,55 @@
>>> +#!/bin/sh
>>> +# SPDX-License-Identifier: GPL-2.0
>>> +# Copyright (C) 2019 ARM Limited
>>> +
>>> +ret=0
>>> +keep_on_fail=0
>>> +err_out="2> /dev/null"
>>> +
>>> +usage() {
>>> +   echo "Usage: `basename $0` [-v] [-k]"
>>> +   exit 1
>>> +}
>>> +
>>> +# avoiding getopt to avoid compatibility issues on targets
>>> +# with limited resources
>>> +while [ $# -gt 0 ]
>>> +do
>>> +   case $1 in
>>> +           "-k")
>>> +                   keep_on_fail=1
>>> +                   ;;
>>> +           "-v")
>>> +                   err_out=
>>> +                   ;;
>>> +           *)
>>> +                   usage
>>> +                   ;;
>>> +   esac
>>> +   shift
>>> +done
>>> +
>>> +TPROGS=
>>> +
>>> +tot=$(echo $TPROGS | wc -w)
>>> +
>>> +# Tests are expected in testcases/ subdir inside the installation path
>>> +workdir="`dirname $0 2>/dev/null`"
>>> +[ -n $workdir ] && cd $workdir
>>> +
>>> +passed=0
>>> +run=0
>>> +for test in $TPROGS
>>> +do
>>> +   run=$((run + 1))
>>> +   eval ./$test $err_out
>>> +   if [ $? != 0 ]; then
>>> +           [ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
>>> +   else
>>> +           passed=$((passed + 1))
>>> +   fi
>>> +done
>>> +
>>> +echo "==>> PASSED: $passed/$run on $tot available tests."
>>> +
>>> +exit $ret
>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
>>> new file mode 100644
>>> index 000000000000..3447d7011aec
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
>>> @@ -0,0 +1,26 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/* Copyright (C) 2019 ARM Limited */
>>> +
>>> +#include <kselftest.h>
>>> +
>>> +#include "test_signals.h"
>>> +#include "test_signals_utils.h"
>>> +
>>> +struct tdescr *current;
>>> +extern struct tdescr tde;
>>> +
>>> +int main(int argc, char *argv[])
>>> +{
>>> +   current = &tde;
>>> +
>>> +   ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
>>> +                  current->name, current->descr, current->sig_trig,
>>> +                  current->sig_ok, current);
>>> +   if (test_setup(current)) {
>>> +           if (test_run(current))
>>> +                   test_result(current);
>>> +           test_cleanup(current);
>>> +   }
>>> +
>>> +   return current->pass ? KSFT_PASS : KSFT_FAIL;
>>> +}
>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
>>> new file mode 100644
>>> index 000000000000..85db3ac44b32
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
>>> @@ -0,0 +1,137 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/* Copyright (C) 2019 ARM Limited */
>>> +
>>> +#ifndef __TEST_SIGNALS_H__
>>> +#define __TEST_SIGNALS_H__
>>> +
>>> +#include <assert.h>
>>> +#include <stdbool.h>
>>> +#include <signal.h>
>>> +#include <ucontext.h>
>>> +#include <stdint.h>
>> Headers can be added in alphabetically order.
>>
> Ok I'll do.
>
> Cheers
>
> Cristian
>
>> Thanks,
>> Amit D
>>> +
>>> +/*
>>> + * 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>
>>> +
>>> +/* pasted from include/linux/stringify.h */
>>> +#define __stringify_1(x...)        #x
>>> +#define __stringify(x...)  __stringify_1(x)
>>> +
>>> +/*
>>> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
>>> + * avoid inject any dependency on the used toolchain regarding possibly
>>> + * still unsupported ARMv8 extensions.
>>> + *
>>> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
>>> + * would introduce a compile-time dependency on possibly unsupported ARMv8
>>> + * Extensions: you could end-up failing to build the test depending on the
>>> + * available toolchain.
>>> + * This is undesirable since some tests, even if specifically targeted at some
>>> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
>>> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
>>> + * it transparently not caring at all about the effective set of supported
>>> + * features).
>>> + * On the other side we will expect to observe different behaviours if the
>>> + * feature is supported or not: usually getting a SIGILL when trying to use
>>> + * unsupported features. For this reason we have anyway in place some
>>> + * preliminary run-time checks about the cpu effectively supported features.
>>> + *
>>> + * This helper macro is meant to be used for regs readable at EL0, BUT some
>>> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
>>> + * if the required reg is included in the supported encoding space:
>>> + *
>>> + *  Documentation/arm64/cpu-feature-regsiters.txt
>>> + *
>>> + *  "The infrastructure emulates only the following system register space:
>>> + *         Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
>>> + */
>>> +#define get_regval(regname, out) \
>>> +   asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
>>> +
>>> +/* Regs encoding and masks naming copied in from sysreg.h */
>>> +#define SYS_ID_AA64MMFR1_EL1       S3_0_C0_C7_1    /* MRS Emulated */
>>> +#define SYS_ID_AA64MMFR2_EL1       S3_0_C0_C7_2    /* MRS Emulated */
>>> +#define ID_AA64MMFR1_PAN_SHIFT     20
>>> +#define ID_AA64MMFR2_UAO_SHIFT     4
>>> +
>>> +/* Local Helpers */
>>> +#define IS_PAN_SUPPORTED(val) \
>>> +   (!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
>>> +#define IS_UAO_SUPPORTED(val) \
>>> +   (!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
>>> +
>>> +#define S3_MRS_SSBS_SYSREG         S3_3_C4_C2_6    /* EL0 supported */
>>> +
>>> +/*
>>> + * Feature flags used in tdescr.feats_required to specify
>>> + * any feature by the test
>>> + */
>>> +enum {
>>> +   FSSBS_BIT,
>>> +   FPAN_BIT,
>>> +   FUAO_BIT,
>>> +   FMAX_END
>>> +};
>>> +
>>> +#define FEAT_SSBS          (1UL << FSSBS_BIT)
>>> +#define FEAT_PAN           (1UL << FPAN_BIT)
>>> +#define FEAT_UAO           (1UL << FUAO_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            feats_ok;
>>> +   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;
>>> +
>>> +   /* a setup function to be called before test starts */
>>> +   int (*setup)(struct tdescr *td);
>>> +   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);
>>> +
>>> +   void *priv;
>>> +};
>>> +#endif
>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>>> new file mode 100644
>>> index 000000000000..ac0055f6340b
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>>> @@ -0,0 +1,261 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/* Copyright (C) 2019 ARM Limited */
>>> +
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +#include <signal.h>
>>> +#include <string.h>
>>> +#include <unistd.h>
>>> +#include <assert.h>
>>> +#include <sys/auxv.h>
>>> +#include <linux/auxvec.h>
>>> +#include <ucontext.h>
>>> +
>>> +#include "test_signals.h"
>>> +#include "test_signals_utils.h"
>>> +#include "testcases/testcases.h"
>>> +
>>> +extern struct tdescr *current;
>>> +
>>> +static char *feats_store[FMAX_END] = {
>>> +   "SSBS",
>>> +   "PAN",
>>> +   "UAO"
>>> +};
>>> +
>>> +#define MAX_FEATS_SZ       128
>>> +static inline char *feats_to_string(unsigned long feats)
>>> +{
>>> +   static char feats_string[MAX_FEATS_SZ];
>>> +
>>> +   for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
>>> +           if (feats & 1UL << i)
>>> +                   snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
>>> +                            feats_string, feats_store[i]);
>>> +   }
>>> +
>>> +   return feats_string;
>>> +}
>>> +
>>> +static void unblock_signal(int signum)
>>> +{
>>> +   sigset_t sset;
>>> +
>>> +   sigemptyset(&sset);
>>> +   sigaddset(&sset, signum);
>>> +   sigprocmask(SIG_UNBLOCK, &sset, NULL);
>>> +}
>>> +
>>> +static void default_result(struct tdescr *td, bool force_exit)
>>> +{
>>> +   if (td->pass)
>>> +           fprintf(stderr, "==>> completed. PASS(1)\n");
>>> +   else
>>> +           fprintf(stdout, "==>> completed. FAIL(0)\n");
>>> +   if (force_exit)
>>> +           exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
>>> +}
>>> +
>>> +static inline bool are_feats_ok(struct tdescr *td)
>>> +{
>>> +   return td ? td->feats_required == td->feats_supported : 0;
>>> +}
>>> +
>>> +static void default_handler(int signum, siginfo_t *si, void *uc)
>>> +{
>>> +   if (current->sig_trig && signum == current->sig_trig) {
>>> +           fprintf(stderr, "Handling SIG_TRIG\n");
>>> +           current->triggered = 1;
>>> +           /* ->run was asserted NON-NULL in test_setup() already */
>>> +           current->run(current, si, uc);
>>> +   } else if (signum == SIGILL && !current->initialized) {
>>> +           /*
>>> +            * A SIGILL here while still not initialized means we failed
>>> +            * even to asses the existence of features during init
>>> +            */
>>> +           fprintf(stdout,
>>> +                   "Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
>>> +           current->feats_supported = 0;
>>> +   } else if (current->sig_ok && signum == current->sig_ok) {
>>> +           /* it's a bug in the test code when this assert fail */
>>> +           assert(!current->sig_trig || current->triggered);
>>> +           fprintf(stderr,
>>> +                   "SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
>>> +                   ((ucontext_t *)uc)->uc_mcontext.sp,
>>> +                   si->si_addr, si->si_code, current->token,
>>> +                   current->token - si->si_addr);
>>> +           /*
>>> +            * fake_sigreturn tests, which have sanity_enabled=1, set, at
>>> +            * the very last time, the token field to the SP address used
>>> +            * to place the fake sigframe: so token==0 means we never made
>>> +            * it to the end, segfaulting well-before, and the test is
>>> +            * possibly broken.
>>> +            */
>>> +           if (!current->sanity_disabled && !current->token) {
>>> +                   fprintf(stdout,
>>> +                           "current->token ZEROED...test is probably broken!\n");
>>> +                   assert(0);
>>> +           }
>>> +           /*
>>> +            * Trying to narrow down the SEGV to the ones generated by
>>> +            * Kernel itself via arm64_notify_segfault()
>>> +            */
>>> +           if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
>>> +                   fprintf(stdout,
>>> +                           "si_code != SEGV_ACCERR...test is probably broken!\n");
>>> +                   assert(0);
>>> +           }
>>> +           fprintf(stderr, "Handling SIG_OK\n");
>>> +           current->pass = 1;
>>> +           /*
>>> +            * Some tests can lead to SEGV loops: in such a case we want
>>> +            * to terminate immediately exiting straight away
>>> +            */
>>> +           default_result(current, 1);
>>> +   } else {
>>> +           if (signum == current->sig_unsupp && !are_feats_ok(current)) {
>>> +                   fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
>>> +                   current->pass = 1;
>>> +           } else if (signum == SIGALRM && current->timeout) {
>>> +                   fprintf(stderr, "-- Timeout !\n");
>>> +           } else {
>>> +                   fprintf(stderr,
>>> +                           "-- RX UNEXPECTED SIGNAL: %d\n", signum);
>>> +           }
>>> +           default_result(current, 1);
>>> +   }
>>> +}
>>> +
>>> +static int default_setup(struct tdescr *td)
>>> +{
>>> +   struct sigaction sa;
>>> +
>>> +   sa.sa_sigaction = default_handler;
>>> +   sa.sa_flags = SA_SIGINFO;
>>> +   if (td->sa_flags)
>>> +           sa.sa_flags |= td->sa_flags;
>>> +   sigemptyset(&sa.sa_mask);
>>> +   /* uncatchable signals naturally skipped ... */
>>> +   for (int sig = 1; sig < 32; sig++)
>>> +           sigaction(sig, &sa, NULL);
>>> +   /*
>>> +    * RT Signals default disposition is Term but they cannot be
>>> +    * generated by the Kernel in response to our tests; so just catch
>>> +    * them all and report them as UNEXPECTED signals.
>>> +    */
>>> +   for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
>>> +           sigaction(sig, &sa, NULL);
>>> +
>>> +   /* just in case...unblock explicitly all we need */
>>> +   if (td->sig_trig)
>>> +           unblock_signal(td->sig_trig);
>>> +   if (td->sig_ok)
>>> +           unblock_signal(td->sig_ok);
>>> +   if (td->sig_unsupp)
>>> +           unblock_signal(td->sig_unsupp);
>>> +
>>> +   if (td->timeout) {
>>> +           unblock_signal(SIGALRM);
>>> +           alarm(td->timeout);
>>> +   }
>>> +   fprintf(stderr, "Registered handlers for all signals.\n");
>>> +
>>> +   return 1;
>>> +}
>>> +
>>> +static inline int default_trigger(struct tdescr *td)
>>> +{
>>> +   return !raise(td->sig_trig);
>>> +}
>>> +
>>> +static int test_init(struct tdescr *td)
>>> +{
>>> +   td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
>>> +   if (!td->minsigstksz)
>>> +           td->minsigstksz = MINSIGSTKSZ;
>>> +   fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
>>> +
>>> +   if (td->feats_required) {
>>> +           bool feats_ok = false;
>>> +           td->feats_supported = 0;
>>> +           /*
>>> +            * Checking for CPU required features using both the
>>> +            * auxval and the arm64 MRS Emulation to read sysregs.
>>> +            */
>>> +           if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
>>> +                   uint64_t val = 0;
>>> +
>>> +                   if (td->feats_required & FEAT_SSBS) {
>>> +                           /* Uses HWCAP to check capability */
>>> +                           if (getauxval(AT_HWCAP) & HWCAP_SSBS)
>>> +                                   td->feats_supported |= FEAT_SSBS;
>>> +                   }
>>> +                   if (td->feats_required & FEAT_PAN) {
>>> +                           /* Uses MRS emulation to check capability */
>>> +                           get_regval(SYS_ID_AA64MMFR1_EL1, val);
>>> +                           if (IS_PAN_SUPPORTED(val))
>>> +                                   td->feats_supported |= FEAT_PAN;
>>> +                   }
>>> +                   if (td->feats_required & FEAT_UAO) {
>>> +                           /* Uses MRS emulation to check capability */
>>> +                           get_regval(SYS_ID_AA64MMFR2_EL1 , val);
>>> +                           if (IS_UAO_SUPPORTED(val))
>>> +                                   td->feats_supported |= FEAT_UAO;
>>> +                   }
>>> +           } else {
>>> +                   fprintf(stderr,
>>> +                           "HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
>>> +           }
>>> +           feats_ok = are_feats_ok(td);
>>> +           fprintf(stderr,
>>> +                   "Required Features: [%s] %ssupported\n",
>>> +                   feats_ok ? feats_to_string(td->feats_supported) :
>>> +                   feats_to_string(td->feats_required ^ td->feats_supported),
>>> +                   !feats_ok ? "NOT " : "");
>>> +   }
>>> +
>>> +   td->initialized = 1;
>>> +   return 1;
>>> +}
>>> +
>>> +int test_setup(struct tdescr *td)
>>> +{
>>> +   /* assert core invariants symptom of a rotten testcase */
>>> +   assert(current);
>>> +   assert(td);
>>> +   assert(td->name);
>>> +   assert(td->run);
>>> +
>>> +   if (!test_init(td))
>>> +           return 0;
>>> +
>>> +   if (td->setup)
>>> +           return td->setup(td);
>>> +   else
>>> +           return default_setup(td);
>>> +}
>>> +
>>> +int test_run(struct tdescr *td)
>>> +{
>>> +   if (td->sig_trig) {
>>> +           if (td->trigger)
>>> +                   return td->trigger(td);
>>> +           else
>>> +                   return default_trigger(td);
>>> +   } else {
>>> +           return td->run(td, NULL, NULL);
>>> +   }
>>> +}
>>> +
>>> +void test_result(struct tdescr *td)
>>> +{
>>> +   if (td->check_result)
>>> +           td->check_result(td);
>>> +   default_result(td, 0);
>>> +}
>>> +
>>> +void test_cleanup(struct tdescr *td)
>>> +{
>>> +   if (td->cleanup)
>>> +           td->cleanup(td);
>>> +}
>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>>> new file mode 100644
>>> index 000000000000..8658d1a7d4b9
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>>> @@ -0,0 +1,13 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/* Copyright (C) 2019 ARM Limited */
>>> +
>>> +#ifndef __TEST_SIGNALS_UTILS_H__
>>> +#define __TEST_SIGNALS_UTILS_H__
>>> +
>>> +#include "test_signals.h"
>>> +
>>> +int test_setup(struct tdescr *td);
>>> +void test_cleanup(struct tdescr *td);
>>> +int test_run(struct tdescr *td);
>>> +void test_result(struct tdescr *td);
>>> +#endif
>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>>> new file mode 100644
>>> index 000000000000..8651272e3cfc
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>>> @@ -0,0 +1 @@
>>> +mangle_pstate_invalid_compat_toggle
>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>> new file mode 100644
>>> index 000000000000..971193e7501b
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>> @@ -0,0 +1,25 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/* Copyright (C) 2019 ARM Limited */
>>> +
>>> +#include "test_signals_utils.h"
>>> +#include "testcases.h"
>>> +
>>> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
>>> +                                ucontext_t *uc)
>>> +{
>>> +   ASSERT_GOOD_CONTEXT(uc);
>>> +
>>> +   /* This config should trigger a SIGSEGV by Kernel */
>>> +   uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
>>> +
>>> +   return 1;
>>> +}
>>> +
>>> +struct tdescr tde = {
>>> +           .sanity_disabled = true,
>>> +           .name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
>>> +           .descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
>>> +           .sig_trig = SIGUSR1,
>>> +           .sig_ok = SIGSEGV,
>>> +           .run = mangle_invalid_pstate_run,
>>> +};
>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
>>> new file mode 100644
>>> index 000000000000..a59785092e1f
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
>>> @@ -0,0 +1,150 @@
>>> +#include "testcases.h"
>>> +
>>> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
>>> +                           size_t resv_sz, size_t *offset)
>>> +{
>>> +   size_t offs = 0;
>>> +   struct _aarch64_ctx *found = NULL;
>>> +
>>> +   if (!head || resv_sz < HDR_SZ)
>>> +           return found;
>>> +
>>> +   do {
>>> +           if (head->magic == magic) {
>>> +                   found = head;
>>> +                   break;
>>> +           }
>>> +           offs += head->size;
>>> +           head = GET_RESV_NEXT_HEAD(head);
>>> +   } while (offs < resv_sz - HDR_SZ);
>>> +
>>> +   if (offset)
>>> +           *offset = offs;
>>> +
>>> +   return found;
>>> +}
>>> +
>>> +bool validate_extra_context(struct extra_context *extra, char **err)
>>> +{
>>> +   struct _aarch64_ctx *term;
>>> +
>>> +   if (!extra || !err)
>>> +           return false;
>>> +
>>> +   fprintf(stderr, "Validating EXTRA...\n");
>>> +   term = GET_RESV_NEXT_HEAD(extra);
>>> +   if (!term || term->magic || term->size) {
>>> +           *err = "UN-Terminated EXTRA context";
>>> +           return false;
>>> +   }
>>> +   if (extra->datap & 0x0fUL)
>>> +           *err = "Extra DATAP misaligned";
>>> +   else if (extra->size & 0x0fUL)
>>> +           *err = "Extra SIZE misaligned";
>>> +   else if (extra->datap != (uint64_t)term + sizeof(*term))
>>> +           *err = "Extra DATAP misplaced (not contiguos)";
>>> +   if (*err)
>>> +           return false;
>>> +
>>> +   return true;
>>> +}
>>> +
>>> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
>>> +{
>>> +   bool terminated = false;
>>> +   size_t offs = 0;
>>> +   int flags = 0;
>>> +   struct extra_context *extra = NULL;
>>> +   struct _aarch64_ctx *head =
>>> +           (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
>>> +
>>> +   if (!err)
>>> +           return false;
>>> +   /* Walk till the end terminator verifying __reserved contents */
>>> +   while (head && !terminated && offs < resv_sz) {
>>> +           if ((uint64_t)head & 0x0fUL) {
>>> +                   *err = "Misaligned HEAD";
>>> +                   return false;
>>> +           }
>>> +
>>> +           switch (head->magic) {
>>> +                   case 0:
>>> +                           if (head->size)
>>> +                                   *err = "Bad size for MAGIC0";
>>> +                           else
>>> +                                   terminated = true;
>>> +                           break;
>>> +                   case FPSIMD_MAGIC:
>>> +                           if (flags & FPSIMD_CTX)
>>> +                                   *err = "Multiple FPSIMD_MAGIC";
>>> +                           else if (head->size !=
>>> +                                    sizeof(struct fpsimd_context))
>>> +                                   *err = "Bad size for fpsimd_context";
>>> +                           flags |= FPSIMD_CTX;
>>> +                           break;
>>> +                   case ESR_MAGIC:
>>> +                           if (head->size != sizeof(struct esr_context))
>>> +                                   fprintf(stderr,
>>> +                                           "Bad size for esr_context is not an error...just ignore.\n");
>>> +                           break;
>>> +                   case SVE_MAGIC:
>>> +                           if (flags & SVE_CTX)
>>> +                                   *err = "Multiple SVE_MAGIC";
>>> +                           else if (head->size !=
>>> +                                    sizeof(struct sve_context))
>>> +                                   *err = "Bad size for sve_context";
>>> +                           flags |= SVE_CTX;
>>> +                           break;
>>> +                   case EXTRA_MAGIC:
>>> +                           if (flags & EXTRA_CTX)
>>> +                                   *err = "Multiple EXTRA_MAGIC";
>>> +                           else if (head->size !=
>>> +                                    sizeof(struct extra_context))
>>> +                                   *err = "Bad size for extra_context";
>>> +                           flags |= EXTRA_CTX;
>>> +                           extra = (struct extra_context *)head;
>>> +                           break;
>>> +                   case KSFT_BAD_MAGIC:
>>> +                           /*
>>> +                            * This is a BAD magic header defined
>>> +                            * artificially by a testcase and surely
>>> +                            * unknown to the Kernel parse_user_sigframe().
>>> +                            * It MUST cause a Kernel induced SEGV
>>> +                            */
>>> +                           *err = "BAD MAGIC !";
>>> +                           break;
>>> +                   default:
>>> +                           /*
>>> +                            * A still unknown Magic: potentially freshly added
>>> +                            * to the Kernel code and still unknown to the
>>> +                            * tests.
>>> +                            */
>>> +                           fprintf(stdout,
>>> +                                   "SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
>>> +                                   head->magic);
>>> +                           break;
>>> +           }
>>> +
>>> +           if (*err)
>>> +                   return false;
>>> +
>>> +           offs += head->size;
>>> +           if (resv_sz - offs < sizeof(*head)) {
>>> +                   *err = "HEAD Overrun";
>>> +                   return false;
>>> +           }
>>> +
>>> +           if (flags & EXTRA_CTX)
>>> +                   if (!validate_extra_context(extra, err))
>>> +                           return false;
>>> +
>>> +           head = GET_RESV_NEXT_HEAD(head);
>>> +   }
>>> +
>>> +   if (terminated && !(flags & FPSIMD_CTX)) {
>>> +           *err = "Missing FPSIMD";
>>> +           return false;
>>> +   }
>>> +
>>> +   return true;
>>> +}
>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
>>> new file mode 100644
>>> index 000000000000..624717c71b1d
>>> --- /dev/null
>>> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
>>> @@ -0,0 +1,83 @@
>>> +#ifndef __TESTCASES_H__
>>> +#define __TESTCASES_H__
>>> +
>>> +#include <stdio.h>
>>> +#include <stdbool.h>
>>> +#include <stdint.h>
>>> +#include <unistd.h>
>>> +#include <ucontext.h>
>>> +#include <assert.h>
>>> +
>>> +/* Architecture specific sigframe definitions */
>>> +#include <asm/sigcontext.h>
>>> +
>>> +#define FPSIMD_CTX (1 << 0)
>>> +#define SVE_CTX            (1 << 1)
>>> +#define EXTRA_CTX  (1 << 2)
>>> +
>>> +#define KSFT_BAD_MAGIC     0xdeadbeef
>>> +
>>> +#define HDR_SZ \
>>> +   sizeof(struct _aarch64_ctx)
>>> +
>>> +#define GET_SF_RESV_HEAD(sf) \
>>> +   (struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
>>> +
>>> +#define GET_SF_RESV_SIZE(sf) \
>>> +   sizeof((sf).uc.uc_mcontext.__reserved)
>>> +
>>> +#define GET_UCP_RESV_SIZE(ucp) \
>>> +   sizeof((ucp)->uc_mcontext.__reserved)
>>> +
>>> +#define ASSERT_BAD_CONTEXT(uc) do {                                        \
>>> +   char *err = NULL;                                               \
>>> +   assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
>>> +   if (err)                                                        \
>>> +           fprintf(stderr,                                         \
>>> +                   "Using badly built context - ERR: %s\n", err);  \
>>> +} while(0)
>>> +
>>> +#define ASSERT_GOOD_CONTEXT(uc) do {                                        \
>>> +   char *err = NULL;                                                \
>>> +   if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) {   \
>>> +           if (err)                                                 \
>>> +                   fprintf(stderr,                                  \
>>> +                           "Detected BAD context - ERR: %s\n", err);\
>>> +           assert(0);                                               \
>>> +   } else {                                                         \
>>> +           fprintf(stderr, "uc context validated.\n");              \
>>> +   }                                                                \
>>> +} while(0)
>>> +
>>> +/* head->size accounts both for payload and header _aarch64_ctx size ! */
>>> +#define GET_RESV_NEXT_HEAD(h) \
>>> +   (struct _aarch64_ctx *)((char *)(h) + (h)->size)
>>> +
>>> +struct fake_sigframe {
>>> +   siginfo_t       info;
>>> +   ucontext_t      uc;
>>> +};
>>> +
>>> +
>>> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
>>> +
>>> +bool validate_extra_context(struct extra_context *extra, char **err);
>>> +
>>> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
>>> +                           size_t resv_sz, size_t *offset);
>>> +
>>> +static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
>>> +                                             size_t resv_sz,
>>> +                                             size_t *offset)
>>> +{
>>> +   return get_header(head, 0, resv_sz, offset);
>>> +}
>>> +
>>> +static inline void write_terminator_record(struct _aarch64_ctx *tail)
>>> +{
>>> +   if (tail) {
>>> +           tail->magic = 0;
>>> +           tail->size = 0;
>>> +   }
>>> +}
>>> +#endif
>>>
>
>
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code
  2019-08-13 16:23   ` Dave Martin
@ 2019-08-27 12:14     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-27 12:14 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

Hi

On 13/08/2019 17:23, Dave Martin wrote:
> ^ Regarding the subject line, "boilerplate code" sounds a bit vague.
> Could we say something like "Add skeleton Makefile"?
> 

Yes of course.

> On Fri, Aug 02, 2019 at 06:02:50PM +0100, Cristian Marussi wrote:
>> Added a new arm64-specific empty subsystem amongst TARGETS of KSFT build
>> framework; once populated with testcases, it will be possible to build
>> and invoke the new KSFT TARGETS=arm64 related tests from the toplevel
>> Makefile in the usual ways.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>> Reviewed the build instructions reported in the README, to be more
>> agnostic regarding user/device etc..
>> ---
>>  tools/testing/selftests/Makefile       |  1 +
>>  tools/testing/selftests/arm64/Makefile | 51 ++++++++++++++++++++++++++
>>  tools/testing/selftests/arm64/README   | 43 ++++++++++++++++++++++
>>  3 files changed, 95 insertions(+)
>>  create mode 100644 tools/testing/selftests/arm64/Makefile
>>  create mode 100644 tools/testing/selftests/arm64/README
>>
>> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
>> index 25b43a8c2b15..1722dae9381a 100644
>> --- a/tools/testing/selftests/Makefile
>> +++ b/tools/testing/selftests/Makefile
>> @@ -1,5 +1,6 @@
>>  # SPDX-License-Identifier: GPL-2.0
>>  TARGETS = android
>> +TARGETS += arm64
>>  TARGETS += bpf
>>  TARGETS += breakpoints
>>  TARGETS += capabilities
>> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
>> new file mode 100644
>> index 000000000000..03a0d4f71218
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/Makefile
>> @@ -0,0 +1,51 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2019 ARM Limited
>> +
>> +# When ARCH not overridden for crosscompiling, lookup machine
>> +ARCH ?= $(shell uname -m)
>> +ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>> +
>> +ifeq ("x$(ARCH)", "xarm64")
>> +SUBDIRS :=
>> +else
>> +SUBDIRS :=
>> +endif
>> +
>> +CFLAGS := -Wall -O2 -g
>> +
>> +export CC
>> +export CFLAGS
>> +
>> +all:
>> +	@for DIR in $(SUBDIRS); do				\
>> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
>> +		mkdir -p $$BUILD_TARGET;			\
>> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
>> +	done
>> +
>> +install: all
>> +	@for DIR in $(SUBDIRS); do				\
>> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
>> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
>> +	done
>> +
>> +run_tests: all
>> +	@for DIR in $(SUBDIRS); do				\
>> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
>> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
>> +	done
>> +
>> +# Avoid any output on non arm64 on emit_tests
>> +emit_tests: all
>> +	@for DIR in $(SUBDIRS); do				\
>> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
>> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
>> +	done
>> +
>> +clean:
>> +	@for DIR in $(SUBDIRS); do				\
>> +		BUILD_TARGET=$(OUTPUT)/$$DIR;			\
>> +		make OUTPUT=$$BUILD_TARGET -C $$DIR $@;		\
>> +	done
>> +
>> +.PHONY: all clean install run_tests emit_tests
>> diff --git a/tools/testing/selftests/arm64/README b/tools/testing/selftests/arm64/README
>> new file mode 100644
>> index 000000000000..dee3306071cc
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/README
>> @@ -0,0 +1,43 @@
>> +KSelfTest ARM64
>> +===============
>> +
>> +- These tests are arm64 specific and so not built or run but just skipped
>> +  completely when env-variable ARCH is found to be different than 'arm64'
>> +  and `uname -m` reports other than 'aarch64'.
>> +
>> +- Holding true the above, ARM64 KSFT tests can be run:
>> +
>> +   + as standalone (example for signal tests)
>> +
>> +      $ make -C tools/testing/selftest/arm64/signal \
>> +		INSTALL_PATH=<your-installation-path> install
>> +
>> +      and then launching on the target device inside the installed path:
>> +
>> +      $ <your-installed-path>/test_arm64_signals.sh [-k | -v]
>> +
>> +   + within the KSelfTest framework using standard Linux top-level-makefile
>> +     targets:
>> +
>> +      $ make TARGETS=arm64 kselftest-clean
>> +      $ make TARGETS=arm64 kselftest
>> +
>> +   Further details on building and running KFST can be found in:
>> +     Documentation/dev-tools/kselftest.rst
> 
> The next two paragraphs aren't relevant yet.  Can we split them out of
> this patch and add them alongside the relevant code / Makefile changes?
> 

Sure. I'm going to remove also standalone mode in V4 as elsewhere advised,
so I'll drop part of this README too.

>> +
>> +- Tests can depend on some arch-specific definitions which can be found in a
>> +  standard Kernel Headers installation in $(top_srcdir)/usr/include.
>> +  Such Kernel Headers are automatically installed (via make headers_install)
>> +  by KSFT framework itself in a dedicated directory when tests are launched
>> +  via KSFT itself; when running standalone, instead, a Warning is issued
>> +  if such headers cannot be found somewhere (we try to guess a few standard
>> +  locations anyway)
>> +
>> +- Some of these tests may be related to possibly not implemented ARMv8
>> +  features: depending on their implementation status on the effective HW
>> +  we'll expect different results. The tests' harness will take care to check
>> +  at run-time if the required features are supported and will act accordingly.
>> +  Moreover, in order to avoid any kind of compile-time dependency on the
>> +  toolchain (possibly due to the above mentioned not-implemented features),
>> +  we make strictly use of direct 'S3_ sysreg' raw-encoding while checking for
>> +  those features and/or lookin up sysregs.
> 
> This last paragraph is only relevant for people adding new tests.  It
> probably makes sense to start "When adding new tests, try to avoid
> unnecessary toolchain dependencies where possible. [...]"
> 
> Cheers
> ---Dave
> 

Cheers

Cristian


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-14 10:22       ` Amit Kachhap
@ 2019-08-27 14:24         ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-27 14:24 UTC (permalink / raw)
  To: Amit Kachhap, linux-kselftest, linux-arm-kernel, shuah
  Cc: andreyknvl, Dave P Martin

Hi

On 14/08/2019 11:22, Amit Kachhap wrote:
> Hi Cristian,
> 
> I have few more comments,
> 
> On 8/13/19 6:52 PM, Cristian Marussi wrote:
>> Hi Amit
>>
>> thanks for the review.
>>
>> On 12/08/2019 13:43, Amit Kachhap wrote:
>>> Hi Cristian,
>>>
>>> On 8/2/19 10:32 PM, Cristian Marussi wrote:
>>>> Added some arm64/signal specific boilerplate and utility code to help
>>>> further testcase development.
>>>>
>>>> A simple testcase and related helpers are also introduced in this commit:
>>>> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
>>>> messes with the ucontext_t from within the sig_handler, trying to toggle
>>>> PSTATE state bits to switch the system between 32bit/64bit execution state.
>>>> Expects SIGSEGV on test PASS.
>>>>
>>>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>>>> ---
>>>> A few fixes:
>>>> - test_arm64_signals.sh runner script generation has been reviewed in order to
>>>>     be safe against the .gitignore
>>>> - using kselftest.h officially provided defines for tests' return values
>>>> - removed SAFE_WRITE()/dump_uc()
>>>> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>>>>     the sigfault had been directly triggered by Kernel
>>>> ---
>>>>    tools/testing/selftests/arm64/Makefile        |   2 +-
>>>>    .../testing/selftests/arm64/signal/.gitignore |   6 +
>>>>    tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>>>>    tools/testing/selftests/arm64/signal/README   |  59 ++++
>>>>    .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>>>>    .../selftests/arm64/signal/test_signals.c     |  26 ++
>>>>    .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>>>>    .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>>>>    .../arm64/signal/test_signals_utils.h         |  13 +
>>>>    .../arm64/signal/testcases/.gitignore         |   1 +
>>>>    .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>>>>    .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>>>>    .../arm64/signal/testcases/testcases.h        |  83 ++++++
>>>>    13 files changed, 905 insertions(+), 1 deletion(-)
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/README
>>>>    create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>>>>    create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
>>>>
>>>> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
>>>> index 03a0d4f71218..af59dc74e0dc 100644
>>>> --- a/tools/testing/selftests/arm64/Makefile
>>>> +++ b/tools/testing/selftests/arm64/Makefile
>>>> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>>>>    ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>>>>    
>>>>    ifeq ("x$(ARCH)", "xarm64")
>>>> -SUBDIRS :=
>>>> +SUBDIRS := signal
>>>>    else
>>>>    SUBDIRS :=
>>>>    endif
>>>> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
>>>> new file mode 100644
>>>> index 000000000000..434f65c15f03
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/.gitignore
>>>> @@ -0,0 +1,6 @@
>>>> +# Helper script's internal testcases list (TPROGS) is regenerated
>>>> +# each time by Makefile on standalone (non KSFT driven) runs.
>>>> +# Committing such list creates a dependency between testcases
>>>> +# patches such that they are no more easily revertable. Just ignore.
>>>> +test_arm64_signals.src_shell
>>>> +test_arm64_signals.sh
>>>> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
>>>> new file mode 100644
>>>> index 000000000000..8c8d08be4b0d
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/Makefile
>>>> @@ -0,0 +1,88 @@
>>>> +# SPDX-License-Identifier: GPL-2.0
>>>> +# Copyright (C) 2019 ARM Limited
>>>> +
>>>> +# Supports also standalone invokation out of KSFT-tree
>>>> +# Compile standalone and run on your device with:
>>>> +#
>>>> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
>>>> +#
>>>> +# Run standalone on device with:
>>>> +#
>>>> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
>>>> +#
>>>> +# If INSTALL_PATH= is NOT provided it will default to ./install
>>>> +
>>>> +# A proper top_srcdir is needed both by KSFT(lib.mk)
>>>> +# and standalone builds
>>>> +top_srcdir = ../../../../..
>>>> +
>>>> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
>>>> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
>>>> +PROGS := $(patsubst %.c,%,$(SRCS))
>>>> +
>>>> +# Guessing as best as we can where the Kernel headers
>>>> +# could have been installed depending on ENV config and
>>>> +# type of invocation.
>>>> +ifeq ($(KBUILD_OUTPUT),)
>>>> +khdr_dir = $(top_srcdir)/usr/include
>>>> +else
>>>> +ifeq (0,$(MAKELEVEL))
>>>> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
>>>> +else
>>>> +# the KSFT preferred location when KBUILD_OUTPUT is set
>>>> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
>>>> +endif
>>>> +endif
>>>> +
>>>> +CFLAGS += -I$(khdr_dir)
>>>> +
>>>> +# Standalone run
>>>> +ifeq (0,$(MAKELEVEL))
>>>> +CC := $(CROSS_COMPILE)gcc
>>>> +RUNNER_SRC = test_arm64_signals.src_shell
>>>> +RUNNER = test_arm64_signals.sh
> Is this extra level of copying test_arm64_signals.src_shell to 
> test_arm64_signals.sh required? I cannot see them in other selftests.
> Also if done then clean may be required. May be EXTRA_CLEAN parameter
> can be used as done for other selftests.
This was the runner script for standalone mode (build/run): it was generated on
the fly sedding the PROGS list inside the .src_shell template script: I had to be
done this way in order to properly have it .gitignored
Anyway I'm throwing away standalone mode in V4

>>>> +INSTALL_PATH ?= install/
> Here default INSTALL_PATH should be just "install" as it may insert "/" 
> twice for below install case.

Ok
>>>> +
>>>> +all: $(RUNNER)
>>>> +
>>>> +$(RUNNER): $(PROGS)
>>>> +	cp $(RUNNER_SRC) $(RUNNER)
>>>> +	sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
>>>> +
>>>> +install: all
>>>> +	mkdir -p $(INSTALL_PATH)/testcases
>>>> +	cp $(PROGS) $(INSTALL_PATH)/testcases
>>>> +	cp $(RUNNER) $(INSTALL_PATH)/
>>>> +
>>>> +.PHONY clean:
>>>> +	rm -f $(PROGS)
>>>> +# KSFT run
>>>> +else
>>>> +# 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
>>>> +
>>>> +# This include mk 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)/
> I guess this copy requires cleaning too.
I'll double check but I think OUTPUT is already cleaned by lib.mk default $(CLEAN) target
called below....here I'm copying the just built PROGS in their final destination OUTPUT
since they were built in the subdir arm64/signal and it could not be found by KSFT otherwise,
which expects they in OUTPUT.

>>>> +
>>>> +clean:
>>>> +	$(CLEAN)
>>>> +	rm -f $(PROGS)
> Is clean requires to clean installed programs also?

I avoided cleaning explicitly installed programs. I think by convention Make target
clean is not expected to remove installed files.
ftp://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_14.html

uninstall seems a possible target for that operation, but KSFT does not define it.

Anyway given that these tests could be installed on NFS share mounted on remote testing unit
I don't think it is useful here to be able to unistall

Thanks

Cristian

>>>> +endif
>>>> +
>>>> +# 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
>>>
>>> I suppose *.h can be removed from the targets here.
>>
>> *.h are in the pre-reqs, $(PROGS) represent the targets and it's comprised by the *.c file contained in testcases/ (excluding testcases.c)
>>
>> If I remove the *.h from this rule, targets won't be rebuilt when headers are changed (like after having added an hypotethical inline)...
>>
>> or am I missing something else ?
> Yes You are right.
> 
> Thanks,
> Amit Daniel
>>
>>
>>>
>>>
>>>> +	@if [ ! -d $(khdr_dir) ]; then \
>>>> +		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
>>>> +		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
>>>> +	fi
>>>> +	$(CC) $(CFLAGS) $^ -o $@
>>>> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
>>>> new file mode 100644
>>>> index 000000000000..53f005f7910a
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/README
>>>> @@ -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 messes-up with the sigframe ucontext_t from
>>>> +    inside the sighandler 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
>>>> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>>> new file mode 100755
>>>> index 000000000000..163e941e2997
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>>> @@ -0,0 +1,55 @@
>>>> +#!/bin/sh
>>>> +# SPDX-License-Identifier: GPL-2.0
>>>> +# Copyright (C) 2019 ARM Limited
>>>> +
>>>> +ret=0
>>>> +keep_on_fail=0
>>>> +err_out="2> /dev/null"
>>>> +
>>>> +usage() {
>>>> +	echo "Usage: `basename $0` [-v] [-k]"
>>>> +	exit 1
>>>> +}
>>>> +
>>>> +# avoiding getopt to avoid compatibility issues on targets
>>>> +# with limited resources
>>>> +while [ $# -gt 0 ]
>>>> +do
>>>> +	case $1 in
>>>> +		"-k")
>>>> +			keep_on_fail=1
>>>> +			;;
>>>> +		"-v")
>>>> +			err_out=
>>>> +			;;
>>>> +		*)
>>>> +			usage
>>>> +			;;
>>>> +	esac
>>>> +	shift
>>>> +done
>>>> +
>>>> +TPROGS=
>>>> +
>>>> +tot=$(echo $TPROGS | wc -w)
>>>> +
>>>> +# Tests are expected in testcases/ subdir inside the installation path
>>>> +workdir="`dirname $0 2>/dev/null`"
>>>> +[ -n $workdir ] && cd $workdir
>>>> +
>>>> +passed=0
>>>> +run=0
>>>> +for test in $TPROGS
>>>> +do
>>>> +	run=$((run + 1))
>>>> +	eval ./$test $err_out
>>>> +	if [ $? != 0 ]; then
>>>> +		[ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
>>>> +	else
>>>> +		passed=$((passed + 1))
>>>> +	fi
>>>> +done
>>>> +
>>>> +echo "==>> PASSED: $passed/$run on $tot available tests."
>>>> +
>>>> +exit $ret
>>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
>>>> new file mode 100644
>>>> index 000000000000..3447d7011aec
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
>>>> @@ -0,0 +1,26 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/* Copyright (C) 2019 ARM Limited */
>>>> +
>>>> +#include <kselftest.h>
>>>> +
>>>> +#include "test_signals.h"
>>>> +#include "test_signals_utils.h"
>>>> +
>>>> +struct tdescr *current;
>>>> +extern struct tdescr tde;
>>>> +
>>>> +int main(int argc, char *argv[])
>>>> +{
>>>> +	current = &tde;
>>>> +
>>>> +	ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
>>>> +		       current->name, current->descr, current->sig_trig,
>>>> +		       current->sig_ok, current);
>>>> +	if (test_setup(current)) {
>>>> +		if (test_run(current))
>>>> +			test_result(current);
>>>> +		test_cleanup(current);
>>>> +	}
>>>> +
>>>> +	return current->pass ? KSFT_PASS : KSFT_FAIL;
>>>> +}
>>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
>>>> new file mode 100644
>>>> index 000000000000..85db3ac44b32
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
>>>> @@ -0,0 +1,137 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/* Copyright (C) 2019 ARM Limited */
>>>> +
>>>> +#ifndef __TEST_SIGNALS_H__
>>>> +#define __TEST_SIGNALS_H__
>>>> +
>>>> +#include <assert.h>
>>>> +#include <stdbool.h>
>>>> +#include <signal.h>
>>>> +#include <ucontext.h>
>>>> +#include <stdint.h>
>>> Headers can be added in alphabetically order.
>>>
>> Ok I'll do.
>>
>> Cheers
>>
>> Cristian
>>
>>> Thanks,
>>> Amit D
>>>> +
>>>> +/*
>>>> + * 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>
>>>> +
>>>> +/* pasted from include/linux/stringify.h */
>>>> +#define __stringify_1(x...)	#x
>>>> +#define __stringify(x...)	__stringify_1(x)
>>>> +
>>>> +/*
>>>> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
>>>> + * avoid inject any dependency on the used toolchain regarding possibly
>>>> + * still unsupported ARMv8 extensions.
>>>> + *
>>>> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
>>>> + * would introduce a compile-time dependency on possibly unsupported ARMv8
>>>> + * Extensions: you could end-up failing to build the test depending on the
>>>> + * available toolchain.
>>>> + * This is undesirable since some tests, even if specifically targeted at some
>>>> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
>>>> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
>>>> + * it transparently not caring at all about the effective set of supported
>>>> + * features).
>>>> + * On the other side we will expect to observe different behaviours if the
>>>> + * feature is supported or not: usually getting a SIGILL when trying to use
>>>> + * unsupported features. For this reason we have anyway in place some
>>>> + * preliminary run-time checks about the cpu effectively supported features.
>>>> + *
>>>> + * This helper macro is meant to be used for regs readable at EL0, BUT some
>>>> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
>>>> + * if the required reg is included in the supported encoding space:
>>>> + *
>>>> + *  Documentation/arm64/cpu-feature-regsiters.txt
>>>> + *
>>>> + *  "The infrastructure emulates only the following system register space:
>>>> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
>>>> + */
>>>> +#define get_regval(regname, out) \
>>>> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
>>>> +
>>>> +/* Regs encoding and masks naming copied in from sysreg.h */
>>>> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
>>>> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
>>>> +#define ID_AA64MMFR1_PAN_SHIFT	20
>>>> +#define ID_AA64MMFR2_UAO_SHIFT	4
>>>> +
>>>> +/* Local Helpers */
>>>> +#define IS_PAN_SUPPORTED(val) \
>>>> +	(!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
>>>> +#define IS_UAO_SUPPORTED(val) \
>>>> +	(!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
>>>> +
>>>> +#define S3_MRS_SSBS_SYSREG		S3_3_C4_C2_6	/* EL0 supported */
>>>> +
>>>> +/*
>>>> + * Feature flags used in tdescr.feats_required to specify
>>>> + * any feature by the test
>>>> + */
>>>> +enum {
>>>> +	FSSBS_BIT,
>>>> +	FPAN_BIT,
>>>> +	FUAO_BIT,
>>>> +	FMAX_END
>>>> +};
>>>> +
>>>> +#define FEAT_SSBS		(1UL << FSSBS_BIT)
>>>> +#define FEAT_PAN		(1UL << FPAN_BIT)
>>>> +#define FEAT_UAO		(1UL << FUAO_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		feats_ok;
>>>> +	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;
>>>> +
>>>> +	/* a setup function to be called before test starts */
>>>> +	int (*setup)(struct tdescr *td);
>>>> +	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);
>>>> +
>>>> +	void *priv;
>>>> +};
>>>> +#endif
>>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>>>> new file mode 100644
>>>> index 000000000000..ac0055f6340b
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>>>> @@ -0,0 +1,261 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/* Copyright (C) 2019 ARM Limited */
>>>> +
>>>> +#include <stdio.h>
>>>> +#include <stdlib.h>
>>>> +#include <signal.h>
>>>> +#include <string.h>
>>>> +#include <unistd.h>
>>>> +#include <assert.h>
>>>> +#include <sys/auxv.h>
>>>> +#include <linux/auxvec.h>
>>>> +#include <ucontext.h>
>>>> +
>>>> +#include "test_signals.h"
>>>> +#include "test_signals_utils.h"
>>>> +#include "testcases/testcases.h"
>>>> +
>>>> +extern struct tdescr *current;
>>>> +
>>>> +static char *feats_store[FMAX_END] = {
>>>> +	"SSBS",
>>>> +	"PAN",
>>>> +	"UAO"
>>>> +};
>>>> +
>>>> +#define MAX_FEATS_SZ	128
>>>> +static inline char *feats_to_string(unsigned long feats)
>>>> +{
>>>> +	static char feats_string[MAX_FEATS_SZ];
>>>> +
>>>> +	for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
>>>> +		if (feats & 1UL << i)
>>>> +			snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
>>>> +				 feats_string, feats_store[i]);
>>>> +	}
>>>> +
>>>> +	return feats_string;
>>>> +}
>>>> +
>>>> +static void unblock_signal(int signum)
>>>> +{
>>>> +	sigset_t sset;
>>>> +
>>>> +	sigemptyset(&sset);
>>>> +	sigaddset(&sset, signum);
>>>> +	sigprocmask(SIG_UNBLOCK, &sset, NULL);
>>>> +}
>>>> +
>>>> +static void default_result(struct tdescr *td, bool force_exit)
>>>> +{
>>>> +	if (td->pass)
>>>> +		fprintf(stderr, "==>> completed. PASS(1)\n");
>>>> +	else
>>>> +		fprintf(stdout, "==>> completed. FAIL(0)\n");
>>>> +	if (force_exit)
>>>> +		exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
>>>> +}
>>>> +
>>>> +static inline bool are_feats_ok(struct tdescr *td)
>>>> +{
>>>> +	return td ? td->feats_required == td->feats_supported : 0;
>>>> +}
>>>> +
>>>> +static void default_handler(int signum, siginfo_t *si, void *uc)
>>>> +{
>>>> +	if (current->sig_trig && signum == current->sig_trig) {
>>>> +		fprintf(stderr, "Handling SIG_TRIG\n");
>>>> +		current->triggered = 1;
>>>> +		/* ->run was asserted NON-NULL in test_setup() already */
>>>> +		current->run(current, si, uc);
>>>> +	} else if (signum == SIGILL && !current->initialized) {
>>>> +		/*
>>>> +		 * A SIGILL here while still not initialized means we failed
>>>> +		 * even to asses the existence of features during init
>>>> +		 */
>>>> +		fprintf(stdout,
>>>> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
>>>> +		current->feats_supported = 0;
>>>> +	} else if (current->sig_ok && signum == current->sig_ok) {
>>>> +		/* it's a bug in the test code when this assert fail */
>>>> +		assert(!current->sig_trig || current->triggered);
>>>> +		fprintf(stderr,
>>>> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
>>>> +			((ucontext_t *)uc)->uc_mcontext.sp,
>>>> +			si->si_addr, si->si_code, current->token,
>>>> +			current->token - si->si_addr);
>>>> +		/*
>>>> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
>>>> +		 * the very last time, the token field to the SP address used
>>>> +		 * to place the fake sigframe: so token==0 means we never made
>>>> +		 * it to the end, segfaulting well-before, and the test is
>>>> +		 * possibly broken.
>>>> +		 */
>>>> +		if (!current->sanity_disabled && !current->token) {
>>>> +			fprintf(stdout,
>>>> +				"current->token ZEROED...test is probably broken!\n");
>>>> +			assert(0);
>>>> +		}
>>>> +		/*
>>>> +		 * Trying to narrow down the SEGV to the ones generated by
>>>> +		 * Kernel itself via arm64_notify_segfault()
>>>> +		 */
>>>> +		if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
>>>> +			fprintf(stdout,
>>>> +				"si_code != SEGV_ACCERR...test is probably broken!\n");
>>>> +			assert(0);
>>>> +		}
>>>> +		fprintf(stderr, "Handling SIG_OK\n");
>>>> +		current->pass = 1;
>>>> +		/*
>>>> +		 * Some tests can lead to SEGV loops: in such a case we want
>>>> +		 * to terminate immediately exiting straight away
>>>> +		 */
>>>> +		default_result(current, 1);
>>>> +	} else {
>>>> +		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
>>>> +			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
>>>> +			current->pass = 1;
>>>> +		} else if (signum == SIGALRM && current->timeout) {
>>>> +			fprintf(stderr, "-- Timeout !\n");
>>>> +		} else {
>>>> +			fprintf(stderr,
>>>> +				"-- RX UNEXPECTED SIGNAL: %d\n", signum);
>>>> +		}
>>>> +		default_result(current, 1);
>>>> +	}
>>>> +}
>>>> +
>>>> +static int default_setup(struct tdescr *td)
>>>> +{
>>>> +	struct sigaction sa;
>>>> +
>>>> +	sa.sa_sigaction = default_handler;
>>>> +	sa.sa_flags = SA_SIGINFO;
>>>> +	if (td->sa_flags)
>>>> +		sa.sa_flags |= td->sa_flags;
>>>> +	sigemptyset(&sa.sa_mask);
>>>> +	/* uncatchable signals naturally skipped ... */
>>>> +	for (int sig = 1; sig < 32; sig++)
>>>> +		sigaction(sig, &sa, NULL);
>>>> +	/*
>>>> +	 * RT Signals default disposition is Term but they cannot be
>>>> +	 * generated by the Kernel in response to our tests; so just catch
>>>> +	 * them all and report them as UNEXPECTED signals.
>>>> +	 */
>>>> +	for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
>>>> +		sigaction(sig, &sa, NULL);
>>>> +
>>>> +	/* just in case...unblock explicitly all we need */
>>>> +	if (td->sig_trig)
>>>> +		unblock_signal(td->sig_trig);
>>>> +	if (td->sig_ok)
>>>> +		unblock_signal(td->sig_ok);
>>>> +	if (td->sig_unsupp)
>>>> +		unblock_signal(td->sig_unsupp);
>>>> +
>>>> +	if (td->timeout) {
>>>> +		unblock_signal(SIGALRM);
>>>> +		alarm(td->timeout);
>>>> +	}
>>>> +	fprintf(stderr, "Registered handlers for all signals.\n");
>>>> +
>>>> +	return 1;
>>>> +}
>>>> +
>>>> +static inline int default_trigger(struct tdescr *td)
>>>> +{
>>>> +	return !raise(td->sig_trig);
>>>> +}
>>>> +
>>>> +static int test_init(struct tdescr *td)
>>>> +{
>>>> +	td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
>>>> +	if (!td->minsigstksz)
>>>> +		td->minsigstksz = MINSIGSTKSZ;
>>>> +	fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
>>>> +
>>>> +	if (td->feats_required) {
>>>> +		bool feats_ok = false;
>>>> +		td->feats_supported = 0;
>>>> +		/*
>>>> +		 * Checking for CPU required features using both the
>>>> +		 * auxval and the arm64 MRS Emulation to read sysregs.
>>>> +		 */
>>>> +		if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
>>>> +			uint64_t val = 0;
>>>> +
>>>> +			if (td->feats_required & FEAT_SSBS) {
>>>> +				/* Uses HWCAP to check capability */
>>>> +				if (getauxval(AT_HWCAP) & HWCAP_SSBS)
>>>> +					td->feats_supported |= FEAT_SSBS;
>>>> +			}
>>>> +			if (td->feats_required & FEAT_PAN) {
>>>> +				/* Uses MRS emulation to check capability */
>>>> +				get_regval(SYS_ID_AA64MMFR1_EL1, val);
>>>> +				if (IS_PAN_SUPPORTED(val))
>>>> +					td->feats_supported |= FEAT_PAN;
>>>> +			}
>>>> +			if (td->feats_required & FEAT_UAO) {
>>>> +				/* Uses MRS emulation to check capability */
>>>> +				get_regval(SYS_ID_AA64MMFR2_EL1 , val);
>>>> +				if (IS_UAO_SUPPORTED(val))
>>>> +					td->feats_supported |= FEAT_UAO;
>>>> +			}
>>>> +		} else {
>>>> +			fprintf(stderr,
>>>> +				"HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
>>>> +		}
>>>> +		feats_ok = are_feats_ok(td);
>>>> +		fprintf(stderr,
>>>> +			"Required Features: [%s] %ssupported\n",
>>>> +			feats_ok ? feats_to_string(td->feats_supported) :
>>>> +		        feats_to_string(td->feats_required ^ td->feats_supported),
>>>> +			!feats_ok ? "NOT " : "");
>>>> +	}
>>>> +
>>>> +	td->initialized = 1;
>>>> +	return 1;
>>>> +}
>>>> +
>>>> +int test_setup(struct tdescr *td)
>>>> +{
>>>> +	/* assert core invariants symptom of a rotten testcase */
>>>> +	assert(current);
>>>> +	assert(td);
>>>> +	assert(td->name);
>>>> +	assert(td->run);
>>>> +
>>>> +	if (!test_init(td))
>>>> +		return 0;
>>>> +
>>>> +	if (td->setup)
>>>> +		return td->setup(td);
>>>> +	else
>>>> +		return default_setup(td);
>>>> +}
>>>> +
>>>> +int test_run(struct tdescr *td)
>>>> +{
>>>> +	if (td->sig_trig) {
>>>> +		if (td->trigger)
>>>> +			return td->trigger(td);
>>>> +		else
>>>> +			return default_trigger(td);
>>>> +	} else {
>>>> +		return td->run(td, NULL, NULL);
>>>> +	}
>>>> +}
>>>> +
>>>> +void test_result(struct tdescr *td)
>>>> +{
>>>> +	if (td->check_result)
>>>> +		td->check_result(td);
>>>> +	default_result(td, 0);
>>>> +}
>>>> +
>>>> +void test_cleanup(struct tdescr *td)
>>>> +{
>>>> +	if (td->cleanup)
>>>> +		td->cleanup(td);
>>>> +}
>>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>>>> new file mode 100644
>>>> index 000000000000..8658d1a7d4b9
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>>>> @@ -0,0 +1,13 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/* Copyright (C) 2019 ARM Limited */
>>>> +
>>>> +#ifndef __TEST_SIGNALS_UTILS_H__
>>>> +#define __TEST_SIGNALS_UTILS_H__
>>>> +
>>>> +#include "test_signals.h"
>>>> +
>>>> +int test_setup(struct tdescr *td);
>>>> +void test_cleanup(struct tdescr *td);
>>>> +int test_run(struct tdescr *td);
>>>> +void test_result(struct tdescr *td);
>>>> +#endif
>>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>>>> new file mode 100644
>>>> index 000000000000..8651272e3cfc
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>>>> @@ -0,0 +1 @@
>>>> +mangle_pstate_invalid_compat_toggle
>>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>>> new file mode 100644
>>>> index 000000000000..971193e7501b
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>>> @@ -0,0 +1,25 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/* Copyright (C) 2019 ARM Limited */
>>>> +
>>>> +#include "test_signals_utils.h"
>>>> +#include "testcases.h"
>>>> +
>>>> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
>>>> +				     ucontext_t *uc)
>>>> +{
>>>> +	ASSERT_GOOD_CONTEXT(uc);
>>>> +
>>>> +	/* This config should trigger a SIGSEGV by Kernel */
>>>> +	uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
>>>> +
>>>> +	return 1;
>>>> +}
>>>> +
>>>> +struct tdescr tde = {
>>>> +		.sanity_disabled = true,
>>>> +		.name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
>>>> +		.descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
>>>> +		.sig_trig = SIGUSR1,
>>>> +		.sig_ok = SIGSEGV,
>>>> +		.run = mangle_invalid_pstate_run,
>>>> +};
>>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
>>>> new file mode 100644
>>>> index 000000000000..a59785092e1f
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
>>>> @@ -0,0 +1,150 @@
>>>> +#include "testcases.h"
>>>> +
>>>> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
>>>> +				size_t resv_sz, size_t *offset)
>>>> +{
>>>> +	size_t offs = 0;
>>>> +	struct _aarch64_ctx *found = NULL;
>>>> +
>>>> +	if (!head || resv_sz < HDR_SZ)
>>>> +		return found;
>>>> +
>>>> +	do {
>>>> +		if (head->magic == magic) {
>>>> +			found = head;
>>>> +			break;
>>>> +		}
>>>> +		offs += head->size;
>>>> +		head = GET_RESV_NEXT_HEAD(head);
>>>> +	} while (offs < resv_sz - HDR_SZ);
>>>> +
>>>> +	if (offset)
>>>> +		*offset = offs;
>>>> +
>>>> +	return found;
>>>> +}
>>>> +
>>>> +bool validate_extra_context(struct extra_context *extra, char **err)
>>>> +{
>>>> +	struct _aarch64_ctx *term;
>>>> +
>>>> +	if (!extra || !err)
>>>> +		return false;
>>>> +
>>>> +	fprintf(stderr, "Validating EXTRA...\n");
>>>> +	term = GET_RESV_NEXT_HEAD(extra);
>>>> +	if (!term || term->magic || term->size) {
>>>> +		*err = "UN-Terminated EXTRA context";
>>>> +		return false;
>>>> +	}
>>>> +	if (extra->datap & 0x0fUL)
>>>> +		*err = "Extra DATAP misaligned";
>>>> +	else if (extra->size & 0x0fUL)
>>>> +		*err = "Extra SIZE misaligned";
>>>> +	else if (extra->datap != (uint64_t)term + sizeof(*term))
>>>> +		*err = "Extra DATAP misplaced (not contiguos)";
>>>> +	if (*err)
>>>> +		return false;
>>>> +
>>>> +	return true;
>>>> +}
>>>> +
>>>> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
>>>> +{
>>>> +	bool terminated = false;
>>>> +	size_t offs = 0;
>>>> +	int flags = 0;
>>>> +	struct extra_context *extra = NULL;
>>>> +	struct _aarch64_ctx *head =
>>>> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
>>>> +
>>>> +	if (!err)
>>>> +		return false;
>>>> +	/* Walk till the end terminator verifying __reserved contents */
>>>> +	while (head && !terminated && offs < resv_sz) {
>>>> +		if ((uint64_t)head & 0x0fUL) {
>>>> +			*err = "Misaligned HEAD";
>>>> +			return false;
>>>> +		}
>>>> +
>>>> +		switch (head->magic) {
>>>> +			case 0:
>>>> +				if (head->size)
>>>> +					*err = "Bad size for MAGIC0";
>>>> +				else
>>>> +					terminated = true;
>>>> +				break;
>>>> +			case FPSIMD_MAGIC:
>>>> +				if (flags & FPSIMD_CTX)
>>>> +					*err = "Multiple FPSIMD_MAGIC";
>>>> +				else if (head->size !=
>>>> +					 sizeof(struct fpsimd_context))
>>>> +					*err = "Bad size for fpsimd_context";
>>>> +				flags |= FPSIMD_CTX;
>>>> +				break;
>>>> +			case ESR_MAGIC:
>>>> +				if (head->size != sizeof(struct esr_context))
>>>> +					fprintf(stderr,
>>>> +						"Bad size for esr_context is not an error...just ignore.\n");
>>>> +				break;
>>>> +			case SVE_MAGIC:
>>>> +				if (flags & SVE_CTX)
>>>> +					*err = "Multiple SVE_MAGIC";
>>>> +				else if (head->size !=
>>>> +					 sizeof(struct sve_context))
>>>> +					*err = "Bad size for sve_context";
>>>> +				flags |= SVE_CTX;
>>>> +				break;
>>>> +			case EXTRA_MAGIC:
>>>> +				if (flags & EXTRA_CTX)
>>>> +					*err = "Multiple EXTRA_MAGIC";
>>>> +				else if (head->size !=
>>>> +					 sizeof(struct extra_context))
>>>> +					*err = "Bad size for extra_context";
>>>> +				flags |= EXTRA_CTX;
>>>> +				extra = (struct extra_context *)head;
>>>> +				break;
>>>> +			case KSFT_BAD_MAGIC:
>>>> +				/*
>>>> +				 * This is a BAD magic header defined
>>>> +				 * artificially by a testcase and surely
>>>> +				 * unknown to the Kernel parse_user_sigframe().
>>>> +				 * It MUST cause a Kernel induced SEGV
>>>> +				 */
>>>> +				*err = "BAD MAGIC !";
>>>> +				break;
>>>> +			default:
>>>> +				/*
>>>> +				 * A still unknown Magic: potentially freshly added
>>>> +				 * to the Kernel code and still unknown to the
>>>> +				 * tests.
>>>> +				 */
>>>> +				fprintf(stdout,
>>>> +					"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
>>>> +					head->magic);
>>>> +				break;
>>>> +		}
>>>> +
>>>> +		if (*err)
>>>> +			return false;
>>>> +
>>>> +		offs += head->size;
>>>> +		if (resv_sz - offs < sizeof(*head)) {
>>>> +			*err = "HEAD Overrun";
>>>> +			return false;
>>>> +		}
>>>> +
>>>> +		if (flags & EXTRA_CTX)
>>>> +			if (!validate_extra_context(extra, err))
>>>> +				return false;
>>>> +
>>>> +		head = GET_RESV_NEXT_HEAD(head);
>>>> +	}
>>>> +
>>>> +	if (terminated && !(flags & FPSIMD_CTX)) {
>>>> +		*err = "Missing FPSIMD";
>>>> +		return false;
>>>> +	}
>>>> +
>>>> +	return true;
>>>> +}
>>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
>>>> new file mode 100644
>>>> index 000000000000..624717c71b1d
>>>> --- /dev/null
>>>> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
>>>> @@ -0,0 +1,83 @@
>>>> +#ifndef __TESTCASES_H__
>>>> +#define __TESTCASES_H__
>>>> +
>>>> +#include <stdio.h>
>>>> +#include <stdbool.h>
>>>> +#include <stdint.h>
>>>> +#include <unistd.h>
>>>> +#include <ucontext.h>
>>>> +#include <assert.h>
>>>> +
>>>> +/* Architecture specific sigframe definitions */
>>>> +#include <asm/sigcontext.h>
>>>> +
>>>> +#define FPSIMD_CTX	(1 << 0)
>>>> +#define SVE_CTX		(1 << 1)
>>>> +#define EXTRA_CTX	(1 << 2)
>>>> +
>>>> +#define KSFT_BAD_MAGIC	0xdeadbeef
>>>> +
>>>> +#define HDR_SZ \
>>>> +	sizeof(struct _aarch64_ctx)
>>>> +
>>>> +#define GET_SF_RESV_HEAD(sf) \
>>>> +	(struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
>>>> +
>>>> +#define GET_SF_RESV_SIZE(sf) \
>>>> +	sizeof((sf).uc.uc_mcontext.__reserved)
>>>> +
>>>> +#define GET_UCP_RESV_SIZE(ucp) \
>>>> +	sizeof((ucp)->uc_mcontext.__reserved)
>>>> +
>>>> +#define ASSERT_BAD_CONTEXT(uc) do {					\
>>>> +	char *err = NULL;						\
>>>> +	assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
>>>> +	if (err)							\
>>>> +		fprintf(stderr,						\
>>>> +			"Using badly built context - ERR: %s\n", err);	\
>>>> +} while(0)
>>>> +
>>>> +#define ASSERT_GOOD_CONTEXT(uc) do {					 \
>>>> +	char *err = NULL;						 \
>>>> +	if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) {	 \
>>>> +		if (err)						 \
>>>> +			fprintf(stderr,					 \
>>>> +				"Detected BAD context - ERR: %s\n", err);\
>>>> +		assert(0);						 \
>>>> +	} else {							 \
>>>> +		fprintf(stderr, "uc context validated.\n");		 \
>>>> +	}								 \
>>>> +} while(0)
>>>> +
>>>> +/* head->size accounts both for payload and header _aarch64_ctx size ! */
>>>> +#define GET_RESV_NEXT_HEAD(h) \
>>>> +	(struct _aarch64_ctx *)((char *)(h) + (h)->size)
>>>> +
>>>> +struct fake_sigframe {
>>>> +	siginfo_t	info;
>>>> +	ucontext_t	uc;
>>>> +};
>>>> +
>>>> +
>>>> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
>>>> +
>>>> +bool validate_extra_context(struct extra_context *extra, char **err);
>>>> +
>>>> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
>>>> +				size_t resv_sz, size_t *offset);
>>>> +
>>>> +static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
>>>> +						  size_t resv_sz,
>>>> +						  size_t *offset)
>>>> +{
>>>> +	return get_header(head, 0, resv_sz, offset);
>>>> +}
>>>> +
>>>> +static inline void write_terminator_record(struct _aarch64_ctx *tail)
>>>> +{
>>>> +	if (tail) {
>>>> +		tail->magic = 0;
>>>> +		tail->size = 0;
>>>> +	}
>>>> +}
>>>> +#endif
>>>>
>>
>>


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-13 16:24   ` Dave Martin
@ 2019-08-28 17:34     ` Cristian Marussi
  2019-09-03 15:34       ` Dave Martin
  0 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-28 17:34 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

Hi

On 13/08/2019 17:24, Dave Martin wrote:
> For the subject line, maybe name the test being added (same as for the
> other patches).

I doubt to be able to fit within 50 chars Subject line constraint, if I add
the test case name.

> 
> On Fri, Aug 02, 2019 at 06:02:51PM +0100, Cristian Marussi wrote:
>> Added some arm64/signal specific boilerplate and utility code to help
>> further testcase development.
>>
>> A simple testcase and related helpers are also introduced in this commit:
>> mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
>> messes with the ucontext_t from within the sig_handler, trying to toggle
> 
> "signal handler"?
> 

ok

>> PSTATE state bits to switch the system between 32bit/64bit execution state.
>> Expects SIGSEGV on test PASS.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>> A few fixes:
>> - test_arm64_signals.sh runner script generation has been reviewed in order to
>>   be safe against the .gitignore
>> - using kselftest.h officially provided defines for tests' return values
>> - removed SAFE_WRITE()/dump_uc()
>> - looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
>>   the sigfault had been directly triggered by Kernel
>> ---
>>  tools/testing/selftests/arm64/Makefile        |   2 +-
>>  .../testing/selftests/arm64/signal/.gitignore |   6 +
>>  tools/testing/selftests/arm64/signal/Makefile |  88 ++++++
>>  tools/testing/selftests/arm64/signal/README   |  59 ++++
>>  .../arm64/signal/test_arm64_signals.src_shell |  55 ++++
>>  .../selftests/arm64/signal/test_signals.c     |  26 ++
>>  .../selftests/arm64/signal/test_signals.h     | 137 +++++++++
>>  .../arm64/signal/test_signals_utils.c         | 261 ++++++++++++++++++
>>  .../arm64/signal/test_signals_utils.h         |  13 +
>>  .../arm64/signal/testcases/.gitignore         |   1 +
>>  .../mangle_pstate_invalid_compat_toggle.c     |  25 ++
>>  .../arm64/signal/testcases/testcases.c        | 150 ++++++++++
>>  .../arm64/signal/testcases/testcases.h        |  83 ++++++
>>  13 files changed, 905 insertions(+), 1 deletion(-)
>>  create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
>>  create mode 100644 tools/testing/selftests/arm64/signal/Makefile
>>  create mode 100644 tools/testing/selftests/arm64/signal/README
>>  create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
>>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
>>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
>>  create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
>>
>> diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
>> index 03a0d4f71218..af59dc74e0dc 100644
>> --- a/tools/testing/selftests/arm64/Makefile
>> +++ b/tools/testing/selftests/arm64/Makefile
>> @@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
>>  ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
>>  
>>  ifeq ("x$(ARCH)", "xarm64")
>> -SUBDIRS :=
>> +SUBDIRS := signal
>>  else
>>  SUBDIRS :=
>>  endif
>> diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
>> new file mode 100644
>> index 000000000000..434f65c15f03
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/.gitignore
>> @@ -0,0 +1,6 @@
>> +# Helper script's internal testcases list (TPROGS) is regenerated
>> +# each time by Makefile on standalone (non KSFT driven) runs.
>> +# Committing such list creates a dependency between testcases
>> +# patches such that they are no more easily revertable. Just ignore.
>> +test_arm64_signals.src_shell
>> +test_arm64_signals.sh
>> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
>> new file mode 100644
>> index 000000000000..8c8d08be4b0d
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/Makefile
>> @@ -0,0 +1,88 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2019 ARM Limited
>> +
>> +# Supports also standalone invokation out of KSFT-tree
>> +# Compile standalone and run on your device with:
>> +#
>> +#  $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
> 
> I'm wondering whether supporting stand-alone invocation is actually
> worth it.  Maybe this just adds complexity for little benefit.
> 
> Although it's useful for debugging and development, it doesn't look like
> other tests in kselftest support standalone invocation -- did I miss
> some?

I introduced standalone to be able to 'detach' from KSFT during tests' devel phase,
but it does not seem worth all this work to maintain it. So I'm removing it in V4.

> 
>> +#
>> +# Run standalone on device with:
>> +#
>> +#  $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
>> +#
>> +# If INSTALL_PATH= is NOT provided it will default to ./install
>> +
>> +# A proper top_srcdir is needed both by KSFT(lib.mk)
>> +# and standalone builds
>> +top_srcdir = ../../../../..
>> +
>> +CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
>> +SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
>> +PROGS := $(patsubst %.c,%,$(SRCS))
>> +
>> +# Guessing as best as we can where the Kernel headers
>> +# could have been installed depending on ENV config and
>> +# type of invocation.
>> +ifeq ($(KBUILD_OUTPUT),)
>> +khdr_dir = $(top_srcdir)/usr/include
>> +else
>> +ifeq (0,$(MAKELEVEL))
>> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
>> +else
>> +# the KSFT preferred location when KBUILD_OUTPUT is set
>> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
>> +endif
>> +endif
> 
> When is KBUILD_OUTPUT set / not set?
> 

Depending how the user/CI is configured KSFT installs the kernel
headers in different places....here I'm trying to guess where they
have been installed by KSFT.

>> +
>> +CFLAGS += -I$(khdr_dir)
> 
> Do we rely on any non-UAPI headers?  If not, the default should probably
> be to rely on the system headers (or toolchain default headers) -- i.e.,
> add no -I option at all.

I only need updated UAPI headers, but I cannot build without this specific -I..
that points to the installed kernel headers directory.

As an example it fails with: undefined  HWCAP_SSBS if I remove the -I

> 
> I'm wondering why none of the other kselftests need this header search
> logic.
> 

Well... a lot of KSFT tests has something related to headers search in their Makefiles:

../kcmp/Makefile:CFLAGS += -I../../../../usr/include/
../networking/timestamping/Makefile:CFLAGS += -I../../../../../usr/include
../ipc/Makefile:CFLAGS += -I../../../../usr/include/
../memfd/Makefile:CFLAGS += -I../../../../include/uapi/
../memfd/Makefile:CFLAGS += -I../../../../include/
../memfd/Makefile:CFLAGS += -I../../../../usr/include/

which seems aimed at doing the same thing, but it is a broken approach
as far as I can see since if KBUILD_OUTPUT is set, KSFT will install the
headers accordingly, so that the above static includes won't work anymore.

Not sure if I'm missing something here, but my understanding was that

- some KSFT requires arch specific bits, usually included within the dedicated kernel
headers provided with the source itself and installed with make headers_install.

and that

- such headers can be found naturally, being included from top level libc headers
only if:

1. a fully updated toolchain containing updated headers too is available at CROSS_COMPILE=

or

2. proper -I options are specified to the compiler to specify where KSFT installed the 
  kernel headers related to this kernel and its related KSFT testcases

or

3. updated kernel headers were installed on top of the available CROSS_COMPILE toolchain

or

4. we are building and running natively, so you can install the kernel headers on
   system default path and those will be searched


My 'feeling' would have been that in the KSFT scenario we should try to stick with option  2.,
in order to be able to run KSFT and run the related testcases, relying just on the shipped
Kernel/KSFT and possibly underlying hw features, but not having any dependencies
on the toolchain/libc.

My question is: what happens on a CI-somewhere if suddenly there's the need to update
the toolchain somehow (fully or partially only the headers) to be able to simply
build/run the new KSFT included with this Kernel ?; even if we accept this need to update
the toochain, where this CI should get/scrap-from these minimum toolchain requirements ?
(in an automated manner)

If instead we can agree to stick with 2.,  I wonder if this locate-headers mechanism which I introduced
here should be in charge of the KSFT framework or if there is something broken in my tests: but 
in these regards similar issues seems to affect KSFT arm64 tags tests queued on arm64/for-next

https://lkml.org/lkml/2019/8/23/721


>> +
>> +# Standalone run
>> +ifeq (0,$(MAKELEVEL))
>> +CC := $(CROSS_COMPILE)gcc
>> +RUNNER_SRC = test_arm64_signals.src_shell
>> +RUNNER = test_arm64_signals.sh
>> +INSTALL_PATH ?= install/
>> +
>> +all: $(RUNNER)
>> +
>> +$(RUNNER): $(PROGS)
> 
> $(RUNNER_SRC) should also be in the dependencies here.
> 
>> +	cp $(RUNNER_SRC) $(RUNNER)
>> +	sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
> 
> Or just a single command: sed -e '...' <$< >$@

I'll drop all of this together with standalone mode.
> 
>> +
>> +install: all
>> +	mkdir -p $(INSTALL_PATH)/testcases
>> +	cp $(PROGS) $(INSTALL_PATH)/testcases
>> +	cp $(RUNNER) $(INSTALL_PATH)/
>> +
>> +.PHONY clean:
>> +	rm -f $(PROGS)
>> +# KSFT run
>> +else
>> +# 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
>> +
>> +# This include mk 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)
>> +endif
>> +
>> +# 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
>> +	@if [ ! -d $(khdr_dir) ]; then \
>> +		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
>> +		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
>> +	fi
>> +	$(CC) $(CFLAGS) $^ -o $@
>> diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
>> new file mode 100644
>> index 000000000000..53f005f7910a
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/README
>> @@ -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 messes-up with the sigframe ucontext_t from
>> +    inside the sighandler itself.
> 
> "messes-up" makes it sound a bit like the test case code itself goes
> wrong.
> 
> Maybe just say something like "the test case code modifies the signal
> frame from inside the signal handler itself."

ok
> 
>> +
>> +  - '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
>> diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
>> new file mode 100755
>> index 000000000000..163e941e2997
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
> 
> Unusual filename?
> 
> In the non-standalone case, is this run directly with TPROGS set in the
> environment instead of modifying the script?  (I haven't understood all
> the logic yet.)
> 
> If so, it is a shell script, and should just be called
> test_arm64_signals.sh
> 
> Otherwise, it's a non-executable template for a shell script, so should
> have 0644 permissions and could be called test_arm64_signals.sh.in or
> test_arm64_signals.sh.template, say.
> 

It's a non-executable template for a shell script and all of this is needed
only in standalone mode. I'm dropping it.
(this re-generation on the fly from a template was needed to properly .gitignoring this)

>> @@ -0,0 +1,55 @@
>> +#!/bin/sh
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2019 ARM Limited
>> +
>> +ret=0
>> +keep_on_fail=0
>> +err_out="2> /dev/null"
>> +
>> +usage() {
>> +	echo "Usage: `basename $0` [-v] [-k]"
>> +	exit 1
>> +}
>> +
>> +# avoiding getopt to avoid compatibility issues on targets
>> +# with limited resources
>> +while [ $# -gt 0 ]
>> +do
>> +	case $1 in
>> +		"-k")
>> +			keep_on_fail=1
>> +			;;
>> +		"-v")
>> +			err_out=
>> +			;;
>> +		*)
>> +			usage
>> +			;;
>> +	esac
>> +	shift
>> +done
>> +
>> +TPROGS=
>> +
>> +tot=$(echo $TPROGS | wc -w)
>> +
>> +# Tests are expected in testcases/ subdir inside the installation path
>> +workdir="`dirname $0 2>/dev/null`"
>> +[ -n $workdir ] && cd $workdir
>> +
>> +passed=0
>> +run=0
>> +for test in $TPROGS
>> +do
>> +	run=$((run + 1))
>> +	eval ./$test $err_out
>> +	if [ $? != 0 ]; then
>> +		[ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
>> +	else
>> +		passed=$((passed + 1))
>> +	fi
>> +done
>> +
>> +echo "==>> PASSED: $passed/$run on $tot available tests."
>> +
>> +exit $ret
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
>> new file mode 100644
>> index 000000000000..3447d7011aec
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_signals.c
>> @@ -0,0 +1,26 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
> 
> We should probably have a brief comment to say what this is.
> For example:
> 
> /*
>  * Generic test wrapper for arm64 signal tests
>  * Each test provides its own tde to link with this wrapper.
>  */
> 
Ok I'll do.

>> +
>> +#include <kselftest.h>
>> +
>> +#include "test_signals.h"
>> +#include "test_signals_utils.h"
>> +
>> +struct tdescr *current;
>> +extern struct tdescr tde;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +	current = &tde;
>> +
>> +	ksft_print_msg("%s :: %s - SIG_TRIG:%d  SIG_OK:%d -- current:%p\n",
>> +		       current->name, current->descr, current->sig_trig,
>> +		       current->sig_ok, current);
> 
> Does the user need all this?
> 
> It's sufficient to print the test name, a one-line description and
> results.  If something goes wrong, we can print a bit more detail.
> 
> Maybe just do something like
> 
> #ifdef DEBUG
> #define debug_printf(format, ...) ksft_print_msg(format, ## __VA_ARGS__)
> #else
> #define debug_printf(format, ...) ((void)0)
> #endif
> 
> (Unless kselftest already has something like this, in which case you
> could just use that.)

I don't think KSFT has this capability by itself.
I was thinking about reducing verbosity.

> 
>> +	if (test_setup(current)) {
>> +		if (test_run(current))
>> +			test_result(current);
>> +		test_cleanup(current);
>> +	}
>> +
>> +	return current->pass ? KSFT_PASS : KSFT_FAIL;
>> +}
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
>> new file mode 100644
>> index 000000000000..85db3ac44b32
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
>> @@ -0,0 +1,137 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#ifndef __TEST_SIGNALS_H__
>> +#define __TEST_SIGNALS_H__
>> +
>> +#include <assert.h>
>> +#include <stdbool.h>
>> +#include <signal.h>
>> +#include <ucontext.h>
>> +#include <stdint.h>
> 
> Does anything in this header use <assert.h> or <stdint.h>?
> 

Probably no more...I'll check.

>> +
>> +/*
>> + * 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>
>> +
>> +/* pasted from include/linux/stringify.h */
>> +#define __stringify_1(x...)	#x
>> +#define __stringify(x...)	__stringify_1(x)
>> +
>> +/*
> 
> I think we can delete this entire comment.
> 
> The macro name is fairly self-explanatory anyway.  Although the
> rationale is interesting, our approach to reading system registers
> here is just the same as elsewhere in the kernel.

OK
> 
>> + * Reads a sysreg using the, possibly provided, S3_ encoding in order to
>> + * avoid inject any dependency on the used toolchain regarding possibly
>> + * still unsupported ARMv8 extensions.
>> + *
>> + * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
>> + * would introduce a compile-time dependency on possibly unsupported ARMv8
>> + * Extensions: you could end-up failing to build the test depending on the
>> + * available toolchain.
>> + * This is undesirable since some tests, even if specifically targeted at some
>> + * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
>> + * optional ARM features. (SSBS bit preservation is an example: Kernel handles
>> + * it transparently not caring at all about the effective set of supported
>> + * features).
>> + * On the other side we will expect to observe different behaviours if the
>> + * feature is supported or not: usually getting a SIGILL when trying to use
>> + * unsupported features. For this reason we have anyway in place some
>> + * preliminary run-time checks about the cpu effectively supported features.
>> + *
>> + * This helper macro is meant to be used for regs readable at EL0, BUT some
>> + * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
>> + * if the required reg is included in the supported encoding space:
>> + *
>> + *  Documentation/arm64/cpu-feature-regsiters.txt
>> + *
>> + *  "The infrastructure emulates only the following system register space:
>> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
>> + */
>> +#define get_regval(regname, out) \
>> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
>> +
>> +/* Regs encoding and masks naming copied in from sysreg.h */
>> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
>> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
> 
> These ID regs are part of armv8.0-a, so we don't need to use the magic
> syntax.
> mmm... why I found them in non UAPI headers defined as follows ?

arch/arm64/include/asm/sysreg.h:#define SYS_ID_AA64MMFR1_EL1            sys_reg(3, 0, 0, 7, 1)

anyway I tried to use nonS3 regular sysreg naming (with a reasonably new compiler:

/opt/toolchains/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/aarch64-linux-gnu-

and it fails (only on id_aa64mmfr2_el1) as follows:
/tmp/ccqAyE8P.s: Assembler messages:                      
/tmp/ccoGrnGc.s:1085: Error: selected processor does not support system register name 'id_aa64mmfr2_el1'

In fact this seems to remind me (not totally sure) that this was the reason to use such S3 syntax on this
sysregs too.

>> +#define ID_AA64MMFR1_PAN_SHIFT	20
>> +#define ID_AA64MMFR2_UAO_SHIFT	4
>> +
>> +/* Local Helpers */
> 
> Can these names indicate the sysreg they should be used with, e.g.
> 
> #define ID_AA64MMFR1_EL1_PAN_SUPPORTED(val) ...
> #define ID_AA64MMFR2_EL1_UAO_SUPPORTED(val) ...
> 
ok

>> +#define IS_PAN_SUPPORTED(val) \
>> +	(!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
>> +#define IS_UAO_SUPPORTED(val) \
>> +	(!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
>> +
>> +#define S3_MRS_SSBS_SYSREG		S3_3_C4_C2_6	/* EL0 supported */
> 
> Maybe just SSBS_SYSREG.
> 
> Sysreg encodings are always for use with MRS/MSR anyway, and "S3" is
> really part of the definition rather than part of the name.
> 
ok

>> +
>> +/*
>> + * Feature flags used in tdescr.feats_required to specify
>> + * any feature by the test
>> + */
>> +enum {
>> +	FSSBS_BIT,
>> +	FPAN_BIT,
>> +	FUAO_BIT,
>> +	FMAX_END
>> +};
>> +
>> +#define FEAT_SSBS		(1UL << FSSBS_BIT)
>> +#define FEAT_PAN		(1UL << FPAN_BIT)
>> +#define FEAT_UAO		(1UL << FUAO_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		feats_ok;
> 
> Is feats_ok used?

Removed.

> 
>> +	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;
>> +
>> +	/* a setup function to be called before test starts */
>> +	int (*setup)(struct tdescr *td);
>> +	void (*cleanup)(struct tdescr *td);
> 
> Add a comment to say what cleanup() is?
> 
ok
>> +
>> +	/* 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);
>> +
>> +	void *priv;
>> +};
>> +#endif
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> new file mode 100644
>> index 000000000000..ac0055f6340b
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> @@ -0,0 +1,261 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <signal.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +#include <assert.h>
>> +#include <sys/auxv.h>
>> +#include <linux/auxvec.h>
>> +#include <ucontext.h>
>> +
>> +#include "test_signals.h"
>> +#include "test_signals_utils.h"
>> +#include "testcases/testcases.h"
>> +
>> +extern struct tdescr *current;
>> +
>> +static char *feats_store[FMAX_END] = {
>> +	"SSBS",
>> +	"PAN",
>> +	"UAO"
>> +};
>> +
>> +#define MAX_FEATS_SZ	128
>> +static inline char *feats_to_string(unsigned long feats)
>> +{
>> +	static char feats_string[MAX_FEATS_SZ];
>> +
>> +	for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
>> +		if (feats & 1UL << i)
>> +			snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
>> +				 feats_string, feats_store[i]);
>> +	}
>> +
>> +	return feats_string;
>> +}
>> +
>> +static void unblock_signal(int signum)
>> +{
>> +	sigset_t sset;
>> +
>> +	sigemptyset(&sset);
>> +	sigaddset(&sset, signum);
>> +	sigprocmask(SIG_UNBLOCK, &sset, NULL);
>> +}
>> +
>> +static void default_result(struct tdescr *td, bool force_exit)
>> +{
>> +	if (td->pass)
>> +		fprintf(stderr, "==>> completed. PASS(1)\n");
>> +	else
>> +		fprintf(stdout, "==>> completed. FAIL(0)\n");
>> +	if (force_exit)
>> +		exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
>> +}
>> +
>> +static inline bool are_feats_ok(struct tdescr *td)
>> +{
>> +	return td ? td->feats_required == td->feats_supported : 0;
> 
> Should this be something like
> (td->feats_required & td->feats_supported) == td->feats_required ?
> 
> Otherwise additional supported features that our test doesn't care about
> will cause this check to fail.
> 
Yes better.

> 
> Do we really need to check td?
> 

Overly defensive

> assert(foo); followed by dereferincing foo is usually a bit pointless
> because you'd get a SIGSEGV anyway.
>
> However, since the tests generate deliberate SIGSEGVs too this could
> be confusing -- in which case, having an explicit assert() here does
> no harm.
> 
not sure about which assert you refer here

>> +}
>> +
>> +static void default_handler(int signum, siginfo_t *si, void *uc)
>> +{
>> +	if (current->sig_trig && signum == current->sig_trig) {
>> +		fprintf(stderr, "Handling SIG_TRIG\n");
>> +		current->triggered = 1;
>> +		/* ->run was asserted NON-NULL in test_setup() already */
>> +		current->run(current, si, uc);
>> +	} else if (signum == SIGILL && !current->initialized) {
>> +		/*
>> +		 * A SIGILL here while still not initialized means we failed
>> +		 * even to asses the existence of features during init
>> +		 */
>> +		fprintf(stdout,
>> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
>> +		current->feats_supported = 0;
>> +	} else if (current->sig_ok && signum == current->sig_ok) {
>> +		/* it's a bug in the test code when this assert fail */
> 
> Why?  Is this because sig_ok is considered acceptable only as an effect
> of the test -- i.e., we shouldn't see it if the test hasn't been
> triggered yet?

This assert would like to ensure that when you receive a sig_ok signal,
if a sig_trig was defined != 0, the trigger have been in fact used and processed before
receiving this sig_ok here: so you didn't define a signal trigger at all, or, if defined
it has been fired to arrive here. I'll add some commenting about this.

> 
>> +		assert(!current->sig_trig || current->triggered);
>> +		fprintf(stderr,
>> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
>> +			((ucontext_t *)uc)->uc_mcontext.sp,
>> +			si->si_addr, si->si_code, current->token,
>> +			current->token - si->si_addr);
>> +		/*
>> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
>> +		 * the very last time, the token field to the SP address used
>> +		 * to place the fake sigframe: so token==0 means we never made
>> +		 * it to the end, segfaulting well-before, and the test is
>> +		 * possibly broken.
>> +		 */
>> +		if (!current->sanity_disabled && !current->token) {
>> +			fprintf(stdout,
>> +				"current->token ZEROED...test is probably broken!\n");
>> +			assert(0);
> 
> In case someone builds with -DNDEBUG, should we add abort()?
> 
Well, in such a case all the test suite is mostly compromised anyway.
But you are right, I'll add an abort() at least here when broken tests are detected.

>> +		}
>> +		/*
>> +		 * Trying to narrow down the SEGV to the ones generated by
>> +		 * Kernel itself via arm64_notify_segfault()
>> +		 */
>> +		if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
>> +			fprintf(stdout,
>> +				"si_code != SEGV_ACCERR...test is probably broken!\n");
>> +			assert(0);
>> +		}
> 
> I'm not sure whether si_code is really ABI here, though I'm not sure
> what else we can do to diagnose the signal more accurately.
> 
> Maybe add a comment to say that this might need to change if this
> aspect of the kernel ABI evolves.
Ok
> 
>> +		fprintf(stderr, "Handling SIG_OK\n");
>> +		current->pass = 1;
>> +		/*
>> +		 * Some tests can lead to SEGV loops: in such a case we want
>> +		 * to terminate immediately exiting straight away
>> +		 */
>> +		default_result(current, 1);
>> +	} else {
>> +		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
>> +			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
>> +			current->pass = 1;
>> +		} else if (signum == SIGALRM && current->timeout) {
>> +			fprintf(stderr, "-- Timeout !\n");
>> +		} else {
>> +			fprintf(stderr,
>> +				"-- RX UNEXPECTED SIGNAL: %d\n", signum);
>> +		}
>> +		default_result(current, 1);
>> +	}
>> +}
>> +
>> +static int default_setup(struct tdescr *td)
>> +{
>> +	struct sigaction sa;
>> +
>> +	sa.sa_sigaction = default_handler;
>> +	sa.sa_flags = SA_SIGINFO;
> 
> Add SA_RESTART?
> 
> I'm not sure whether this affects these tests, but the libc stdio
> functions don't like being interrupted by signals.  SA_RESTART should
> hide most issues of this sort.
> 

Ok...I was not aware of these possible issues.

>> +	if (td->sa_flags)
>> +		sa.sa_flags |= td->sa_flags;
> 
> Do we need the if() here?  If td->sa_flags == 0, the assignment is
> harmless anyway.
True.

> 
>> +	sigemptyset(&sa.sa_mask);
>> +	/* uncatchable signals naturally skipped ... */
>> +	for (int sig = 1; sig < 32; sig++)
>> +		sigaction(sig, &sa, NULL);
>> +	/*
>> +	 * RT Signals default disposition is Term but they cannot be
>> +	 * generated by the Kernel in response to our tests; so just catch
>> +	 * them all and report them as UNEXPECTED signals.
>> +	 */
>> +	for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
>> +		sigaction(sig, &sa, NULL);
>> +
>> +	/* just in case...unblock explicitly all we need */
>> +	if (td->sig_trig)
>> +		unblock_signal(td->sig_trig);
>> +	if (td->sig_ok)
>> +		unblock_signal(td->sig_ok);
>> +	if (td->sig_unsupp)
>> +		unblock_signal(td->sig_unsupp);
>> +
>> +	if (td->timeout) {
>> +		unblock_signal(SIGALRM);
>> +		alarm(td->timeout);
>> +	}
>> +	fprintf(stderr, "Registered handlers for all signals.\n");
>> +
>> +	return 1;
>> +}
>> +
>> +static inline int default_trigger(struct tdescr *td)
>> +{
>> +	return !raise(td->sig_trig);
>> +}
>> +
>> +static int test_init(struct tdescr *td)
>> +{
>> +	td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
>> +	if (!td->minsigstksz)
>> +		td->minsigstksz = MINSIGSTKSZ;
>> +	fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
>> +
>> +	if (td->feats_required) {
>> +		bool feats_ok = false;
>> +		td->feats_supported = 0;
>> +		/*
>> +		 * Checking for CPU required features using both the
>> +		 * auxval and the arm64 MRS Emulation to read sysregs.
>> +		 */
>> +		if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
>> +			uint64_t val = 0;
>> +
> 
> Would it be simpler just to query all these features unconditionally?
> 
> We just need to check that all the features the test needs are present.
> If other features are present, we can happily ignore them, but
> discovering them is harmless.
> 
Ok
>> +			if (td->feats_required & FEAT_SSBS) {
>> +				/* Uses HWCAP to check capability */
>> +				if (getauxval(AT_HWCAP) & HWCAP_SSBS)
>> +					td->feats_supported |= FEAT_SSBS;
>> +			}
>> +			if (td->feats_required & FEAT_PAN) {
>> +				/* Uses MRS emulation to check capability */
>> +				get_regval(SYS_ID_AA64MMFR1_EL1, val);
>> +				if (IS_PAN_SUPPORTED(val))
>> +					td->feats_supported |= FEAT_PAN;
>> +			}
>> +			if (td->feats_required & FEAT_UAO) {
>> +				/* Uses MRS emulation to check capability */
>> +				get_regval(SYS_ID_AA64MMFR2_EL1 , val);
>> +				if (IS_UAO_SUPPORTED(val))
>> +					td->feats_supported |= FEAT_UAO;
>> +			}
>> +		} else {
>> +			fprintf(stderr,
>> +				"HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
>> +		}
>> +		feats_ok = are_feats_ok(td);
>> +		fprintf(stderr,
>> +			"Required Features: [%s] %ssupported\n",
>> +			feats_ok ? feats_to_string(td->feats_supported) :
>> +		        feats_to_string(td->feats_required ^ td->feats_supported),
>> +			!feats_ok ? "NOT " : "");
>> +	}
>> +
>> +	td->initialized = 1;
>> +	return 1;
>> +}
>> +
>> +int test_setup(struct tdescr *td)
>> +{
>> +	/* assert core invariants symptom of a rotten testcase */
>> +	assert(current);
>> +	assert(td);
>> +	assert(td->name);
>> +	assert(td->run);
>> +
>> +	if (!test_init(td))
>> +		return 0;
>> +
>> +	if (td->setup)
>> +		return td->setup(td);
>> +	else
>> +		return default_setup(td);
>> +}
>> +
>> +int test_run(struct tdescr *td)
>> +{
>> +	if (td->sig_trig) {
>> +		if (td->trigger)
>> +			return td->trigger(td);
>> +		else
>> +			return default_trigger(td);
>> +	} else {
>> +		return td->run(td, NULL, NULL);
>> +	}
>> +}
>> +
>> +void test_result(struct tdescr *td)
>> +{
>> +	if (td->check_result)
>> +		td->check_result(td);
>> +	default_result(td, 0);
>> +}
>> +
>> +void test_cleanup(struct tdescr *td)
>> +{
>> +	if (td->cleanup)
>> +		td->cleanup(td);
>> +}
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> new file mode 100644
>> index 000000000000..8658d1a7d4b9
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> @@ -0,0 +1,13 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#ifndef __TEST_SIGNALS_UTILS_H__
>> +#define __TEST_SIGNALS_UTILS_H__
>> +
>> +#include "test_signals.h"
>> +
>> +int test_setup(struct tdescr *td);
>> +void test_cleanup(struct tdescr *td);
>> +int test_run(struct tdescr *td);
>> +void test_result(struct tdescr *td);
>> +#endif
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> new file mode 100644
>> index 000000000000..8651272e3cfc
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -0,0 +1 @@
>> +mangle_pstate_invalid_compat_toggle
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>> new file mode 100644
>> index 000000000000..971193e7501b
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
>> @@ -0,0 +1,25 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
> 
> Each testcase should have a comment explaining what it is trying to
> test, and how.
> 
Ok

>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
>> +				     ucontext_t *uc)
>> +{
>> +	ASSERT_GOOD_CONTEXT(uc);
>> +
>> +	/* This config should trigger a SIGSEGV by Kernel */
>> +	uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
>> +
>> +	return 1;
>> +}
>> +
>> +struct tdescr tde = {
>> +		.sanity_disabled = true,
>> +		.name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
>> +		.descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
>> +		.sig_trig = SIGUSR1,
>> +		.sig_ok = SIGSEGV,
>> +		.run = mangle_invalid_pstate_run,
>> +};
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
>> new file mode 100644
>> index 000000000000..a59785092e1f
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
>> @@ -0,0 +1,150 @@
>> +#include "testcases.h"
>> +
>> +struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
>> +				size_t resv_sz, size_t *offset)
>> +{
>> +	size_t offs = 0;
>> +	struct _aarch64_ctx *found = NULL;
>> +
>> +	if (!head || resv_sz < HDR_SZ)
>> +		return found;
>> +
>> +	do {
>> +		if (head->magic == magic) {
>> +			found = head;
>> +			break;
>> +		}
>> +		offs += head->size;
>> +		head = GET_RESV_NEXT_HEAD(head);
> 
> Are offs and head tracking the same thing here?
> 
> Maybe it would be cleaner to have GET_RESV_NEXT_HEAD() do the bounds
> checking itself.
> 
offs is used for bound checking but it is also optionally provided to the
caller as the offset in bytes at which the header was found, and yes it tracks the
underlying same thing at the end.
I'll try to cleanup and re-org this function a bit.

>> +	} while (offs < resv_sz - HDR_SZ);
>> +
>> +	if (offset)
>> +		*offset = offs;
>> +
>> +	return found;
>> +}
>> +
>> +bool validate_extra_context(struct extra_context *extra, char **err)
>> +{
>> +	struct _aarch64_ctx *term;
>> +
>> +	if (!extra || !err)
>> +		return false;
>> +
>> +	fprintf(stderr, "Validating EXTRA...\n");
>> +	term = GET_RESV_NEXT_HEAD(extra);
>> +	if (!term || term->magic || term->size) {
>> +		*err = "UN-Terminated EXTRA context";
> 
> This sounds like the extra context doesn't contain a terminator, which
> isn't what we're checking here.  Maybe say "terminator missing after
> extra context", or similar.

ok
> 
>> +		return false;
>> +	}
>> +	if (extra->datap & 0x0fUL)
>> +		*err = "Extra DATAP misaligned";
>> +	else if (extra->size & 0x0fUL)
>> +		*err = "Extra SIZE misaligned";
>> +	else if (extra->datap != (uint64_t)term + sizeof(*term))
>> +		*err = "Extra DATAP misplaced (not contiguos)";
>> +	if (*err)
>> +		return false;
>> +
>> +	return true;
>> +}
>> +
>> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
>> +{
>> +	bool terminated = false;
>> +	size_t offs = 0;
>> +	int flags = 0;
>> +	struct extra_context *extra = NULL;
>> +	struct _aarch64_ctx *head =
>> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
>> +
>> +	if (!err)
>> +		return false;
>> +	/* Walk till the end terminator verifying __reserved contents */
>> +	while (head && !terminated && offs < resv_sz) {
>> +		if ((uint64_t)head & 0x0fUL) {
>> +			*err = "Misaligned HEAD";
>> +			return false;
>> +		}
>> +
>> +		switch (head->magic) {
>> +			case 0:
>> +				if (head->size)
>> +					*err = "Bad size for MAGIC0";
> 
> Or "terminator".  We don't have an actual symbolic name for magic number
> 0.  (Arguably it would have been nice to have a name, but we managed
> without.)

ok
> 
>> +				else
>> +					terminated = true;
>> +				break;
>> +			case FPSIMD_MAGIC:
>> +				if (flags & FPSIMD_CTX)
>> +					*err = "Multiple FPSIMD_MAGIC";
>> +				else if (head->size !=
>> +					 sizeof(struct fpsimd_context))
>> +					*err = "Bad size for fpsimd_context";
>> +				flags |= FPSIMD_CTX;
>> +				break;
>> +			case ESR_MAGIC:
>> +				if (head->size != sizeof(struct esr_context))
>> +					fprintf(stderr,
>> +						"Bad size for esr_context is not an error...just ignore.\n");
> 
> Why isn't this an error?  Should the kernel ever write an esr_context
> with a different size?

There is no check on Kernel side:

    case ESR_MAGIC:
    	/* ignore */
        break;

so I sticked with that, since this function can be used to validate a Kernel originated sigframe
or a crafted one which will be passed down to the Kernel.

> 
>> +				break;
>> +			case SVE_MAGIC:
>> +				if (flags & SVE_CTX)
>> +					*err = "Multiple SVE_MAGIC";
>> +				else if (head->size !=
>> +					 sizeof(struct sve_context))
>> +					*err = "Bad size for sve_context";
>> +				flags |= SVE_CTX;
>> +				break;
>> +			case EXTRA_MAGIC:
>> +				if (flags & EXTRA_CTX)
>> +					*err = "Multiple EXTRA_MAGIC";
>> +				else if (head->size !=
>> +					 sizeof(struct extra_context))
>> +					*err = "Bad size for extra_context";
>> +				flags |= EXTRA_CTX;
>> +				extra = (struct extra_context *)head;
>> +				break;
>> +			case KSFT_BAD_MAGIC:
>> +				/*
>> +				 * This is a BAD magic header defined
>> +				 * artificially by a testcase and surely
>> +				 * unknown to the Kernel parse_user_sigframe().
>> +				 * It MUST cause a Kernel induced SEGV
>> +				 */
>> +				*err = "BAD MAGIC !";
>> +				break;
>> +			default:
>> +				/*
>> +				 * A still unknown Magic: potentially freshly added
>> +				 * to the Kernel code and still unknown to the
>> +				 * tests.
>> +				 */
>> +				fprintf(stdout,
>> +					"SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
>> +					head->magic);
>> +				break;
>> +		}
>> +
>> +		if (*err)
>> +			return false;
>> +
>> +		offs += head->size;
> 
> Can this addition cause offs to become > resv_sz?  If so, the next
> comparison will go wrong.

True. I'll refactor the comparison to avoid subtraction like in :

	if (resv_sz < offs + sizeof(*head)) {

> 
>> +		if (resv_sz - offs < sizeof(*head)) {
>> +			*err = "HEAD Overrun";
>> +			return false;
>> +		}
>> +
>> +		if (flags & EXTRA_CTX)
>> +			if (!validate_extra_context(extra, err))
>> +				return false;
> 
> Can we validate the contents of the extra context too?
> 
> Ideally we can use the same code to check __reserved[] and the extra
> context.
> 
Do you mean the content pointed by extra->datap ?
This extra_context validation routine is generally under review and fixes in a further
arm64/signal SVE extensions patch still to be published (and cleaned up):
[kselftest: arm64: adds SVE-related signal test], given that EXTRA_CONTEXT can effectively
appear only when SVE related instruction are used properly.

Should I introduce this and other extra-context related fixes here instead ?
(it is hard to test and debug without any triggering SVE instruction though...)

>> +
>> +		head = GET_RESV_NEXT_HEAD(head);
>> +	}
>> +
>> +	if (terminated && !(flags & FPSIMD_CTX)) {
>> +		*err = "Missing FPSIMD";
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
>> new file mode 100644
>> index 000000000000..624717c71b1d
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
>> @@ -0,0 +1,83 @@
>> +#ifndef __TESTCASES_H__
>> +#define __TESTCASES_H__
>> +
> 
> Pedantically, we should have <stddef.h> for NULL.
> 

ok

>> +#include <stdio.h>
>> +#include <stdbool.h>
>> +#include <stdint.h>
>> +#include <unistd.h>
> 
> Is <unistd.h> used now that SAFE_WRITE() is gone?
> 

Removed.

>> +#include <ucontext.h>
>> +#include <assert.h>
>> +
>> +/* Architecture specific sigframe definitions */
>> +#include <asm/sigcontext.h>
> 
> [...]
> 
> Cheers
> ---Dave
> 

Cheers

Cristian

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 03/11] kselftest: arm64: mangle_pstate_invalid_daif_bits
  2019-08-13 16:24   ` Dave Martin
@ 2019-08-29 10:19     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-29 10:19 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On 13/08/2019 17:24, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:52PM +0100, Cristian Marussi wrote:
>> Added a simple mangle testcase which messes with the ucontext_t
> 
> Strange past tense?  How about "Add"?
> 
>> from within the sig_handler, trying to set PSTATE DAIF bits to an
> 
> "signal handler"?
> 

Ok I'll fix the commit message and use imperative mood.

Cheers

Cristian
>> invalid value (masking everything). Expects SIGSEGV on test PASS.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>>  .../arm64/signal/testcases/.gitignore         |  1 +
>>  .../mangle_pstate_invalid_daif_bits.c         | 28 +++++++++++++++++++
>>  2 files changed, 29 insertions(+)
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> index 8651272e3cfc..8a0a29f0cc2a 100644
>> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -1 +1,2 @@
>>  mangle_pstate_invalid_compat_toggle
>> +mangle_pstate_invalid_daif_bits
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
>> new file mode 100644
>> index 000000000000..af899d4bb655
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
>> @@ -0,0 +1,28 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
>> +				     ucontext_t *uc)
>> +{
>> +	ASSERT_GOOD_CONTEXT(uc);
>> +
>> +	/*
>> +	 * This config should trigger a SIGSEGV by Kernel when it checks
>> +	 * the sigframe consistency in valid_user_regs() routine.
>> +	 */
>> +	uc->uc_mcontext.pstate |= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT;
>> +
>> +	return 1;
>> +}
> 
> Hmmm, there was a lot of common framework code, but it seems like a good
> investment if adding a new test is as simple as this :)
> 
> [...]
> 
> Cheers
> ---Dave
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 04/11] kselftest: arm64: mangle_pstate_invalid_mode_el
  2019-08-13 16:24   ` Dave Martin
@ 2019-08-29 11:50     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-29 11:50 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On 13/08/2019 17:24, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:53PM +0100, Cristian Marussi wrote:
>> Added 3 simple mangle testcases that mess with the ucontext_t
> 
> Add
> 
>> from within the sig_handler, trying to toggle PSTATE mode bits to
> 
> signal handler
> 
>> trick the system into switching to EL1/EL2/EL3. Expects SIGSEGV
>> on test PASS.

Ok
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>>  .../arm64/signal/testcases/.gitignore         |  3 ++
>>  .../mangle_pstate_invalid_mode_el1.c          | 29 +++++++++++++++++++
>>  .../mangle_pstate_invalid_mode_el2.c          | 29 +++++++++++++++++++
>>  .../mangle_pstate_invalid_mode_el3.c          | 29 +++++++++++++++++++
>>  4 files changed, 90 insertions(+)
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> index 8a0a29f0cc2a..226bb179b673 100644
>> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -1,2 +1,5 @@
>>  mangle_pstate_invalid_compat_toggle
>>  mangle_pstate_invalid_daif_bits
>> +mangle_pstate_invalid_mode_el1
>> +mangle_pstate_invalid_mode_el2
>> +mangle_pstate_invalid_mode_el3
> 
> What about having
> 
> 	!*.[ch]
> 	mangle_*
> 
> rather than having to update .gitignore to list every test executable?
> 
Yes it reduces inter-dependencies between testcases patches in fact,
and in fact I already know all the possible name patterns on this set of tests:
mangle_ fake_sigreturn_


>> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
>> new file mode 100644
>> index 000000000000..07aed7624383
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
>> @@ -0,0 +1,29 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
>> +				     ucontext_t *uc)
>> +{
>> +	ASSERT_GOOD_CONTEXT(uc);
>> +
>> +	/*
>> +	 * This config should trigger a SIGSEGV by Kernel
>> +	 * when checking valid_user_regs()
>> +	 */
>> +	uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
>> +	uc->uc_mcontext.pstate |= PSR_MODE_EL1t;
>> +
>> +	return 1;
>> +}
>> +
>> +struct tdescr tde = {
>> +		.sanity_disabled = true,
>> +		.name = "MANGLE_PSTATE_INVALID_MODE_EL1t",
>> +		.descr = "Mangling uc_mcontext with INVALID MODE EL1t",
>> +		.sig_trig = SIGUSR1,
>> +		.sig_ok = SIGSEGV,
>> +		.run = mangle_invalid_pstate_run,
>> +};
> 
> These tests seem identical except for the EL number.
> Can we macro-ise them?
> 
> mangle_pstate_invalid_mode_el1.c could become
> 
> --8<--
> 
> #include "mangle_pstate_invalid_mode.h"
> 
> DEFINE_TESTCASE_MANGLE_PSTATE_INVALID_MODE(1)
> 
> -->8--
Yes I'll do, and I'll split these 3 testcases in 6 macro-ized test cases to cover
all EL_x h/t variants (something you already told me in V2 I think)

Cheers

Cristian
> 
> (for example).
> 
> [...]
> 
> Cheers
> ---Dave
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 05/11] kselftest: arm64: mangle_pstate_ssbs_regs
  2019-08-13 16:25   ` Dave Martin
@ 2019-08-29 15:35     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-29 15:35 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

Hi

On 13/08/2019 17:25, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:54PM +0100, Cristian Marussi wrote:
>> Added a simple mangle testcase which messes with the ucontext_t
> 
> Add
> 
>> from within the sig_handler, trying to toggle PSTATE SSBS bit.
> 
> signal handler
> 

Ok.
>> Expect SIGILL if SSBS feature unsupported or that the value set in
>> PSTATE.SSBS is preserved on test PASS.
> 
> The test doesn't set PSTATE.SSBS directly.
> 
> Maybe something like: "Expect SIGILL if the SSBS feature is unsupported.
> Otherwise, expect sigreturn to set PSTATE.SSBS from the corresponding
> bit in pstate in the signal frame."
> 

Ok
>> This commit also introduces a new common utility function:
>> get_current_context() which can be used to grab a ucontext without
>> the help of libc, and detect if such ucontext has been actively used
>> to jump back into it.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>>  .../selftests/arm64/signal/test_signals.h     |  4 +
>>  .../arm64/signal/test_signals_utils.c         | 93 +++++++++++++++++++
>>  .../arm64/signal/test_signals_utils.h         |  2 +
>>  .../arm64/signal/testcases/.gitignore         |  1 +
>>  .../testcases/mangle_pstate_ssbs_regs.c       | 56 +++++++++++
>>  5 files changed, 156 insertions(+)
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
>> index 85db3ac44b32..37bed0590226 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals.h
>> +++ b/tools/testing/selftests/arm64/signal/test_signals.h
>> @@ -116,6 +116,10 @@ struct tdescr {
>>  	/* optional sa_flags for the installed handler */
>>  	int		sa_flags;
>>  	ucontext_t	saved_uc;
>> +	/* used by get_current_ctx() */
>> +	size_t		live_sz;
>> +	ucontext_t	*live_uc;
>> +	volatile bool	live_uc_valid;
>>  
>>  	/* a setup function to be called before test starts */
>>  	int (*setup)(struct tdescr *td);
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> index ac0055f6340b..faf55ba99d58 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
>> @@ -11,12 +11,16 @@
>>  #include <linux/auxvec.h>
>>  #include <ucontext.h>
>>  
>> +#include <asm/unistd.h>
>> +
>>  #include "test_signals.h"
>>  #include "test_signals_utils.h"
>>  #include "testcases/testcases.h"
>>  
>>  extern struct tdescr *current;
>>  
>> +static int sig_copyctx = SIGUSR2;
>> +
>>  static char *feats_store[FMAX_END] = {
>>  	"SSBS",
>>  	"PAN",
>> @@ -37,6 +41,85 @@ static inline char *feats_to_string(unsigned long feats)
>>  	return feats_string;
>>  }
>>  
>> +/*
>> + * Obtaining a valid and full-blown ucontext_t from userspace is tricky:
>> + * libc getcontext does() not save all the regs and messes with some of
>> + * them (pstate value in particular is not reliable).
>> + * Here we use a service signal to grab the ucontext_t from inside a
>> + * dedicated signal handler, since there, it is populated by Kernel
>> + * itself in setup_sigframe(). The grabbed context is then stored and
>> + * made available in td->live_uc.
>> + *
>> + * Anyway this function really serves a dual purpose:
>> + *
>> + * 1. grab a valid sigcontext into td->live_uc for result analysis: in
>> + * such case it returns 1.
>> + *
>> + * 2. detect if somehow a previously grabbed live_uc context has been
>> + * used actively with a sigreturn: in such a case the execution would have
>> + * magically resumed in the middle of the function itself (seen_already==1):
>> + * in such a case return 0, since in fact we have not just simply grabbed
>> + * the context.
>> + *
>> + * This latter case is useful to detect when a fake_sigreturn test-case has
>> + * unexpectedly survived without hittig a SEGV.
>> + */
>> +bool get_current_context(struct tdescr *td, ucontext_t *dest_uc)
>> +{
>> +	static volatile sig_atomic_t seen_already;
>> +
>> +	if (!td || !dest_uc) {
>> +		fprintf(stdout, "Signal-based Context dumping NOT available\n");
> 
> Should this ever happen inless there is a test bug?
> 
> Maybe this should just be an assert.

Yes definitely better.
> 
>> +		return 0;
>> +	}
>> +
>> +	/* it's a genuine invokation..reinit */
>> +	seen_already = 0;
>> +	td->live_uc_valid = 0;
>> +	td->live_sz = sizeof(*dest_uc);
>> +	memset(dest_uc, 0x00, td->live_sz);
> 
> Eventually we will need to examine the signal frame to determine its
> size, but for now this is fine.
> 
> It will start to matter for SVE.

Yes this function has been reworked in the SVE signal frame patches to
dynamically detect runtime signal frame and be able to optionally grab
a sigframe containing SVE material (avoiding the kill() syscall to trigger
a signal in favour of a brk instruction to cause a SIGTRAP without passing
via the syscall machinery which would zero the SVE sigframe stuff)

Such patch, which depends on this series, is still not published.
> 
>> +	td->live_uc = dest_uc;
>> +	/*
>> +	 * Grab ucontext_t triggering a signal...
>> +	 * ASM equivalent of raise(sig_copyctx);
>> +	 *
>> +	 * Note that:
>> +	 * - live_uc_valid is declared volatile in struct tdescr
>> +	 *   since it will be changed inside the sig_copyctx handler.
>> +	 * - the kill() syscall invocation returns only after any possible
>> +	 *   registered sig_handler for the invoked signal has returned,
> 
> sig_handler looks like the name of some function of variable, but I
> can't find it.  Did I miss something?

No I'll replace the comment with "signal handler" 
> 
>> +	 *   so that live_uc_valid flag is surely up to date when this
>> +	 *   function return it.
>> +	 * - the additional 'memory' clobber is there to avoid possible
>> +	 *   compiler's assumption on the content pointed by dest_uc, which
>> +	 *   is changed inside the handler, but not referenced here anyway.
>> +	 */
>> +	asm volatile ("mov x8, %0\n\t"
>> +		      "svc #0\n\t"
>> +		      "mov x1, %1\n\t"
>> +		      "mov x8, %2\n\t"
>> +		      "svc #0"
>> +		      :
>> +		      : "i" (__NR_getpid),
>> +		        "r" (sig_copyctx),
>> +			"i" (__NR_kill)
>> +		      : "x1","x8","x0","memory");
>> +	/*
>> +	 * If we get here with seen_already==1 it implies the td->live_uc
>> +	 * context has been used to get back here....this probably means
>> +	 * a test has failed to cause a SEGV...anyway the live_uc has not
>> +	 * just been acquired...so return 0
>> +	 */
>> +	if (seen_already) {
>> +		fprintf(stdout,
>> +			"Successful sigreturn detected: live_uc is stale !\n");
>> +		return 0;
>> +	}
>> +	seen_already = 1;
>> +
>> +	return td->live_uc_valid;
>> +}
>> +
>>  static void unblock_signal(int signum)
>>  {
>>  	sigset_t sset;
>> @@ -112,6 +195,12 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
>>  		 * to terminate immediately exiting straight away
>>  		 */
>>  		default_result(current, 1);
>> +	} else if (signum == sig_copyctx && current->live_uc) {
>> +		memcpy(current->live_uc, uc, current->live_sz);
>> +		ASSERT_GOOD_CONTEXT(current->live_uc);
>> +		current->live_uc_valid = 1;
>> +		fprintf(stderr,
>> +			"GOOD CONTEXT grabbed from sig_copyctx handler\n");
>>  	} else {
>>  		if (signum == current->sig_unsupp && !are_feats_ok(current)) {
>>  			fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
>> @@ -214,6 +303,10 @@ static int test_init(struct tdescr *td)
>>  			!feats_ok ? "NOT " : "");
>>  	}
>>  
>> +	if (td->sig_trig == sig_copyctx)
>> +		sig_copyctx = SIGUSR1;
> 
> What's this for?  What if we have the same signal for sig_trig and
> sig_copyctx?
> 

To avoid that a user defined sig_trig equal to sig_copyctx can fool this function.
In SVE signal frame patch (not in this series), I'll anyway switch to use a distinct
SIGTRAP sig_trig.

>> +	unblock_signal(sig_copyctx);
>> +
>>  	td->initialized = 1;
>>  	return 1;
>>  }
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> index 8658d1a7d4b9..ce35be8ebc8e 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> @@ -10,4 +10,6 @@ int test_setup(struct tdescr *td);
>>  void test_cleanup(struct tdescr *td);
>>  int test_run(struct tdescr *td);
>>  void test_result(struct tdescr *td);
>> +
>> +bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
>>  #endif
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> index 226bb179b673..a48a118b1a1a 100644
>> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -3,3 +3,4 @@ mangle_pstate_invalid_daif_bits
>>  mangle_pstate_invalid_mode_el1
>>  mangle_pstate_invalid_mode_el2
>>  mangle_pstate_invalid_mode_el3
>> +mangle_pstate_ssbs_regs
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
>> new file mode 100644
>> index 000000000000..a399d9aa40d5
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
>> @@ -0,0 +1,56 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
>> +#include <stdio.h>
>> +#include <ucontext.h>
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +static int mangle_invalid_pstate_ssbs_run(struct tdescr *td,
>> +					  siginfo_t *si, ucontext_t *uc)
>> +{
>> +	ASSERT_GOOD_CONTEXT(uc);
>> +
>> +	/* set bit value */
> 
> Should we clear SSBS in the test setup (using MSR), to make sure that
> sigreturn really succeeds in _changing_ the bit to 1?
> 
Yes. I introduced a set_regval() asm helper and added a new .init signal-test
framework entry in tdescr to be able to call per-test specific initialization.

I took the chance also to remove the remaining volatile qualifiers from signal
handling code to please checkpatch, and add a dsb barrier to ensure the writes
by the signal handler.

>> +	uc->uc_mcontext.pstate |= PSR_SSBS_BIT;
>> +	fprintf(stderr, "SSBS set to 1 -- PSTATE: 0x%016lX\n",
>> +		uc->uc_mcontext.pstate);
>> +	/* Save after mangling...it should be preserved */
>> +	td->saved_uc = *uc;
>> +
>> +	return 1;
>> +}
> 
> [...]
> 
> Cheers
> ---Dave
> 
Cheers

Cristian

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic
  2019-08-13 16:25   ` Dave Martin
@ 2019-08-30 14:29     ` Cristian Marussi
  2019-09-04 10:05       ` Dave Martin
  0 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-30 14:29 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

Hi

On 13/08/2019 17:25, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:55PM +0100, Cristian Marussi wrote:
>> Added a simple fake_sigreturn testcase which builds a ucontext_t
> 
> Add

Ok
> 
>> with a bad magic header and place it onto the stack.
>> Expects a SIGSEGV on test PASS.
>> This commit also introduces a common utility assembly function to
>> invoke a sigreturn using a fake provided sigframe.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>>  tools/testing/selftests/arm64/signal/Makefile |  2 +-
>>  .../testing/selftests/arm64/signal/signals.S  | 64 +++++++++++++++++++
>>  .../arm64/signal/test_signals_utils.h         |  1 +
>>  .../arm64/signal/testcases/.gitignore         |  1 +
>>  .../testcases/fake_sigreturn_bad_magic.c      | 63 ++++++++++++++++++
>>  5 files changed, 130 insertions(+), 1 deletion(-)
>>  create mode 100644 tools/testing/selftests/arm64/signal/signals.S
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
>> index 8c8d08be4b0d..b3dcf315b5a4 100644
>> --- a/tools/testing/selftests/arm64/signal/Makefile
>> +++ b/tools/testing/selftests/arm64/signal/Makefile
>> @@ -80,7 +80,7 @@ endif
>>  # 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
>> +$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c signals.S $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
>>  	@if [ ! -d $(khdr_dir) ]; then \
>>  		echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
>>  		echo "===>  Are you sure Kernel Headers have been installed properly ?\n"; \
>> diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
>> new file mode 100644
>> index 000000000000..6262b877400b
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/signals.S
>> @@ -0,0 +1,64 @@
>> +/*
>> + * SPDX-License-Identifier: GPL-2.0
>> + * Copyright (C) 2019 ARM Limited
>> + */
>> +
>> +#include <asm/unistd.h>
>> +
>> +.section        ".rodata", "a"
> 
> The section name is not usually quoted in .section (though I guess it
> works).
> 
Ok

>> +call_fmt:
>> +	.asciz "Calling sigreturn with fake sigframe sized:%zd at calculated SP @%08lX\n"
>> +
>> +.text
>> +
>> +.globl fake_sigreturn
>> +
>> +/*	fake_sigreturn	x0:&sigframe,  x1:sigframe_size,  x2:alignment_SP */
>> +fake_sigreturn:
>> +	mov x20, x0
>> +	mov x21, x1
>> +	mov x22, x2
>> +	mov x23, sp
>> +
>> +	/* create space on the stack for fake sigframe..."x22"-aligned */
>> +	mov x0, #0
> 
> Why to we move 0 into x0?  We clobber x0 again in the next instruction:
Yes unneeded.

>> +	add x0, x21, x22
>> +	sub x22, x22, #1
>> +	bic x0, x0, x22
>> +	sub x23, x23, x0
> 
> Can you explain the logic here?  I'm not sure I understand what this is
> trying to do exactly.

The attempt is to make space on the stack for a x22-bytes-aligned sigframe
of at least x21-bytes-size (assuming x22 is power-of-two):

- calculate the needed aligned space (sigframe_size + x22) & ~(x22 - 1)
- calculate new SP in x23: x3 = sp - needed_aligned_space
- later down... move SP to the calculated sp in x23
- copy the provided sigframe on such new SP

> I notice you further modify this in patch 11 -- see my comments there,
> where I also suggest an alternative way of specifying a misaligned frame
> that might be simpler.

I've seen your comments on patch 11. I think I'll simplify that as you suggested:
patch 11 was meant to add the capability to misalign the sigframe  on the SP
(which is needed in testcase contained in 11) but in fact is better if I move all
of the simplified logic here.

>> +
>> +	ldr x0, =call_fmt
>> +	mov x1, x21
>> +	mov x2, x23
>> +	bl printf
>> +
>> +	mov sp, x23
>> +
>> +	/* now fill it with the provided content... */
>> +	mov x0, sp
>> +	mov x1, x20
>> +	mov x2, x21
>> +	bl memcpy
>> +
>> +	/*
>> +	 * Here saving a last minute SP to current->token acts as a marker:
>> +	 * if we got here, we are successfully faking a sigreturn; in other
>> +	 * words we are sure no bad fatal signal has been raised till now
>> +	 * for unrelated reasons, so we should consider the possibl observed
> 
> typo: possible (or possibly?)
> 
possibly

>> +	 * fatal signal like SEGV coming from Kernel restore_sigframe() and
>> +	 * triggered as expected from our test-case.
>> +	 * For simplicity this assumes that current field 'token' is laid out
>> +	 * as first in struct tdescr
>> +	 */
>> +	ldr x0, current
>> +	str x23, [x0]
>> +	/* SP is already pointing back to the just built fake sigframe here */
>> +	mov x8, #__NR_rt_sigreturn
>> +	svc #0
>> +
>> +	/*
>> +	 * Above sigreturn should not return...looping here leads to a timeout
>> +	 * and ensure proper and clean test failure, instead of jumping around
>> +	 * on a potentially corrupted stack.
>> +	 */
>> +	b .
>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> index ce35be8ebc8e..2a71da7e6695 100644
>> --- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> +++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
>> @@ -12,4 +12,5 @@ int test_run(struct tdescr *td);
>>  void test_result(struct tdescr *td);
>>  
>>  bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
>> +int fake_sigreturn(void *sigframe, size_t sz, int alignment);
>>  #endif
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> index a48a118b1a1a..0ea6fdc3765c 100644
>> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -4,3 +4,4 @@ mangle_pstate_invalid_mode_el1
>>  mangle_pstate_invalid_mode_el2
>>  mangle_pstate_invalid_mode_el3
>>  mangle_pstate_ssbs_regs
>> +fake_sigreturn_bad_magic
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
>> new file mode 100644
>> index 000000000000..b4c063e02a7a
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
>> @@ -0,0 +1,63 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
> 
> We should probably also include <signal.h> here, since we're using
> siginfo_t etc.

Yes indeed. It was included via some other headers only.
> 
>> +#include <stdio.h>
>> +#include <ucontext.h>
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +struct fake_sigframe sf;
>> +
>> +static int fake_sigreturn_bad_magic_run(struct tdescr *td,
>> +					siginfo_t *si, ucontext_t *uc)
>> +{
>> +	size_t resv_sz, offset;
>> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
>> +
>> +	/* just to fill the ucontext_t with something real */
>> +	if (!get_current_context(td, &sf.uc))
>> +		return 1;
>> +
>> +	resv_sz = GET_SF_RESV_SIZE(sf);
>> +	/*
>> +	 * find the terminator, preserving existing headers
>> +	 * and verify amount of spare room in __reserved area.
>> +	 */
>> +	head = get_terminator(shead, resv_sz, &offset);
>> +	/*
>> +	 * try stripping extra_context header when low on space:
>> +	 * we need at least 2*HDR_SZ space ... one for the KSFT_BAD_MAGIC
>> +	 * and the other for the usual terminator.
>> +	 */
>> +	if (head && resv_sz - offset < HDR_SZ * 2) {
> 
> Can we factor out this logic for finding space in the signal frame?
> 
> We do pretty much the same thing in all the fake_sigreturn tests...

Ok
> 
>> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
>> +			resv_sz - offset);
>> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
>> +	}
>> +	/* just give up and timeout if still not enough space */
> 
> Do we actually time out?  I don't see where we actually wait, so doesn't
> test_run() just fail immediately?
> 
> The same applies to all the other fake_sigreturn tests too.
> 
Right. It is probably a leftover.

SIGALRM is used as an extreme measure to kill tests gone bad, but this
can happen only once the fake sigframe has been effectively placed on the stack
and sigreturned.


>> +	if (head && resv_sz - offset >= HDR_SZ) {
> 
> Should this be HDR_SZ * 2 again?  We need space for the face header and
> space to write a terminator after it.

I'll fix in the new factored out code.

> 
>> +		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
>> +			resv_sz - offset);
>> +		/*
>> +		 * use a well known NON existent bad magic...something
>> +		 * we should pretty sure won't be ever defined in Kernel
>> +		 */
>> +		head->magic = KSFT_BAD_MAGIC;
>> +		head->size = HDR_SZ;
>> +		write_terminator_record(GET_RESV_NEXT_HEAD(head));
>> +
>> +		ASSERT_BAD_CONTEXT(&sf.uc);
>> +		fake_sigreturn(&sf, sizeof(sf), 16);
>> +	}
>> +
>> +	return 1;
>> +}
> 
> [...]
> 
> Cheers
> ---Dave
> 

Cheers

Cristian


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 07/11] kselftest: arm64: fake_sigreturn_bad_size_for_magic0
  2019-08-13 16:25   ` Dave Martin
@ 2019-08-30 14:49     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-30 14:49 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On 13/08/2019 17:25, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:56PM +0100, Cristian Marussi wrote:
>> Added a simple fake_sigreturn testcase which builds a ucontext_t
> 
> Add

Ok
> 
>> with a badly sized magic0 header and place it onto the stack.
> 
> I usually call a record with magic number 0 a "terminator record".
> 

Ok
>> Expects a SIGSEGV on test PASS.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>>  .../arm64/signal/testcases/.gitignore         |  1 +
>>  .../fake_sigreturn_bad_size_for_magic0.c      | 57 +++++++++++++++++++
>>  2 files changed, 58 insertions(+)
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> index 0ea6fdc3765c..cf2a73599818 100644
>> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -5,3 +5,4 @@ mangle_pstate_invalid_mode_el2
>>  mangle_pstate_invalid_mode_el3
>>  mangle_pstate_ssbs_regs
>>  fake_sigreturn_bad_magic
>> +fake_sigreturn_bad_size_for_magic0
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
>> new file mode 100644
>> index 000000000000..2f53c4740c85
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
>> @@ -0,0 +1,57 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
> 
> #include <signal.h> ?
> 

Ok
>> +#include <stdio.h>
>> +#include <ucontext.h>
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +struct fake_sigframe sf;
>> +
>> +#define MIN_SZ_ALIGN	16
>> +
>> +static int fake_sigreturn_bad_size_for_magic0_run(struct tdescr *td,
>> +						  siginfo_t *si, ucontext_t *uc)
>> +{
>> +	size_t resv_sz, offset;
>> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
>> +
>> +	/* just to fill the ucontext_t with something real */
>> +	if (!get_current_context(td, &sf.uc))
>> +		return 1;
>> +
>> +	resv_sz = GET_SF_RESV_SIZE(sf);
>> +	/*
>> +	 * find the terminator, preserving existing headers
>> +	 * and verify amount of spare room in __reserved area.
>> +	 */
>> +	head = get_terminator(shead, resv_sz, &offset);
>> +	/*
>> +	 * try stripping extra_context header when low on space:
>> +	 * we need at least HDR_SZ + 16 space for the bad sized terminator.
>> +	 */
>> +	if (head && resv_sz - offset < HDR_SZ + MIN_SZ_ALIGN) {
>> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
>> +			resv_sz - offset);
>> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
>> +	}
>> +	/* just give up and timeout if still not enough space */
>> +	if (head && resv_sz - offset >= HDR_SZ + MIN_SZ_ALIGN) {
>> +		head->magic = 0;
>> +		head->size = MIN_SZ_ALIGN;
> 
> This is different from the amount of space we tested for
> (HDR_SZ + MIN_SZ_ALIGN) earlier.
> 
> I'm not sure it matters which we use, but we should be consistent.
> 
> I suggest sticking with HDR_SZ, unless there's something I've missed.
> 
I'll stick to HDR_SZ in this case and use the new helper from 06/11
(get_starting_head)

> [...]
> 
> Cheers
> ---Dave
> 

Cheers

Cristian

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 08/11] kselftest: arm64: fake_sigreturn_missing_fpsimd
  2019-08-13 16:26   ` Dave Martin
@ 2019-08-30 14:55     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-30 14:55 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

Hi

On 13/08/2019 17:26, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:57PM +0100, Cristian Marussi wrote:
>> Added a simple fake_sigreturn testcase which builds a ucontext_t
> 
> Add
Ok

> 
>> without the required fpsimd_context and place it onto the stack.
>> Expects a SIGSEGV on test PASS.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>>  .../arm64/signal/testcases/.gitignore         |  1 +
>>  .../testcases/fake_sigreturn_missing_fpsimd.c | 44 +++++++++++++++++++
>>  2 files changed, 45 insertions(+)
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> index cf2a73599818..17d1c5e73319 100644
>> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -6,3 +6,4 @@ mangle_pstate_invalid_mode_el3
>>  mangle_pstate_ssbs_regs
>>  fake_sigreturn_bad_magic
>>  fake_sigreturn_bad_size_for_magic0
>> +fake_sigreturn_missing_fpsimd
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
>> new file mode 100644
>> index 000000000000..b8dd57ce6844
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
>> @@ -0,0 +1,44 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
> 
> signal.h?
> 
Ok
>> +#include <stdio.h>
>> +#include <ucontext.h>
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +struct fake_sigframe sf;
>> +
>> +static int fake_sigreturn_missing_fpsimd_run(struct tdescr *td,
>> +					     siginfo_t *si, ucontext_t *uc)
>> +{
>> +	size_t resv_sz, offset;
>> +	struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
>> +
>> +	/* just to fill the ucontext_t with something real */
>> +	if (!get_current_context(td, &sf.uc))
>> +		return 1;
>> +
>> +	resv_sz = GET_SF_RESV_SIZE(sf);
>> +	head = get_header(head, FPSIMD_MAGIC, resv_sz, &offset);
>> +	/* just give up and timeout if still not enough space */
>> +	if (head && resv_sz - offset >= HDR_SZ) {
>> +		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
>> +			resv_sz - offset);
>> +		/* Just overwrite fpsmid_context */
>> +		write_terminator_record(head);
>> +
>> +		ASSERT_BAD_CONTEXT(&sf.uc);
>> +		fake_sigreturn(&sf, sizeof(sf), 16);
>> +	}
>> +
>> +	return 1;
>> +}
> 
> [...]
> 
> Seems reasonable otherwise.
> 
> Cheers
> ---Dave
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 09/11] kselftest: arm64: fake_sigreturn_duplicated_fpsimd
  2019-08-13 16:26   ` Dave Martin
@ 2019-08-30 15:11     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-30 15:11 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On 13/08/2019 17:26, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:58PM +0100, Cristian Marussi wrote:
>> Added a simple fake_sigreturn testcase which builds a ucontext_t
> 
> Add

Ok
> 
>> with an anomalous additional fpsimd_context and place it onto the stack.
>> Expects a SIGSEGV on test PASS.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>>  .../arm64/signal/testcases/.gitignore         |  1 +
>>  .../fake_sigreturn_duplicated_fpsimd.c        | 62 +++++++++++++++++++
>>  2 files changed, 63 insertions(+)
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> index 17d1c5e73319..94f9baaf638c 100644
>> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -7,3 +7,4 @@ mangle_pstate_ssbs_regs
>>  fake_sigreturn_bad_magic
>>  fake_sigreturn_bad_size_for_magic0
>>  fake_sigreturn_missing_fpsimd
>> +fake_sigreturn_duplicated_fpsimd
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
>> new file mode 100644
>> index 000000000000..09af7a0f8776
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
>> @@ -0,0 +1,62 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
> 
> signal.h?
Ok
> 
>> +#include <stdio.h>
>> +#include <ucontext.h>
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +struct fake_sigframe sf;
>> +
>> +static int fake_sigreturn_duplicated_fpsimd_run(struct tdescr *td,
>> +						siginfo_t *si, ucontext_t *uc)
>> +{
>> +	size_t resv_sz, offset;
>> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
>> +
>> +	/* just to fill the ucontext_t with something real */
>> +	if (!get_current_context(td, &sf.uc))
>> +		return 1;
>> +
>> +	resv_sz = GET_SF_RESV_SIZE(sf);
>> +	/*
>> +	 * find the terminator, preserving existing headers
>> +	 * and verify amount of spare room in __reserved area.
>> +	 */
>> +	head = get_terminator(shead, resv_sz, &offset);
>> +	/*
>> +	 * try stripping extra_context header when low on space:
>> +	 * we need at least space for one additional fpsimd_context
>> +	 */
>> +	if (head && resv_sz - offset < sizeof(struct fpsimd_context)) {
>> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
>> +			resv_sz - offset);
>> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
>> +	}
>> +
>> +	/* just give up and timeout if still not enough space */
>> +	if (head &&
>> +	    resv_sz - offset >= sizeof(struct fpsimd_context) + HDR_SZ) {
>> +		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
>> +			resv_sz - offset);
>> +		/* Add a spurios fpsimd_context */
>> +		head->magic = FPSIMD_MAGIC;
>> +		head->size = sizeof(struct fpsimd_context);
>> +		/* and terminate */
>> +		write_terminator_record(GET_RESV_NEXT_HEAD(head));
>> +
>> +		ASSERT_BAD_CONTEXT(&sf.uc);
>> +		fake_sigreturn(&sf, sizeof(sf), 16);
>> +	}
>> +
>> +	return 1;
>> +}
> 

I'll convert to use new helper get_starting_head() to make space in __reserved.

Cheers

Cristian

> [...]
> 
> Otherwise looks ok.
> 
> Cheers
> ---Dave
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 10/11] kselftest: arm64: fake_sigreturn_bad_size
  2019-08-13 16:26   ` Dave Martin
@ 2019-08-30 15:21     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-30 15:21 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On 13/08/2019 17:26, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:59PM +0100, Cristian Marussi wrote:
>> Added a simple fake_sigreturn testcase which builds a ucontext_t
> 
> Add

Ok

> 
>> with a badly sized header that causes a overrun in the __reserved
>> area and place it onto the stack. Expects a SIGSEGV on test PASS.
>>
>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>>  .../arm64/signal/testcases/.gitignore         |  1 +
>>  .../testcases/fake_sigreturn_bad_size.c       | 85 +++++++++++++++++++
>>  2 files changed, 86 insertions(+)
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> index 94f9baaf638c..3408e0f5ba98 100644
>> --- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> +++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
>> @@ -8,3 +8,4 @@ fake_sigreturn_bad_magic
>>  fake_sigreturn_bad_size_for_magic0
>>  fake_sigreturn_missing_fpsimd
>>  fake_sigreturn_duplicated_fpsimd
>> +fake_sigreturn_bad_size
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
>> new file mode 100644
>> index 000000000000..1467fb534d8b
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
>> @@ -0,0 +1,85 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
> 
> signal.h?
> 
Ok
>> +#include <stdio.h>
>> +#include <ucontext.h>
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +struct fake_sigframe sf;
>> +
>> +#define MIN_SZ_ALIGN	16
>> +
>> +static int fake_sigreturn_bad_size_run(struct tdescr *td,
>> +				       siginfo_t *si, ucontext_t *uc)
>> +{
>> +	size_t resv_sz, need_sz, offset;
>> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
>> +
>> +	/* just to fill the ucontext_t with something real */
>> +	if (!get_current_context(td, &sf.uc))
>> +		return 1;
>> +
>> +	resv_sz = GET_SF_RESV_SIZE(sf);
>> +	/*
>> +	 * find the terminator, preserving existing headers
>> +	 * and verify amount of spare room in __reserved area.
>> +	 */
>> +	head = get_terminator(shead, resv_sz, &offset);
>> +	/*
>> +	 * try stripping extra_context header when low on space:
>> +	 * we need at least  for the bad sized esr_context.
> 
> double space
> 
ok.
>> +	 */
>> +	need_sz = HDR_SZ + sizeof(struct esr_context);
>> +	if (head && resv_sz - offset < need_sz) {
>> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
>> +			resv_sz - offset);
>> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
>> +	}
>> +	/* just give up and timeout if still not enough space */
>> +	if (head && resv_sz - offset >= need_sz) {
>> +		fprintf(stderr, "Mangling template header. Spare space:%zd\n",
>> +			resv_sz - offset);
>> +		/*
>> +		 * Use an esr_context to build a fake header with a
>> +		 * size greater then the free __reserved area minus HDR_SZ;
>> +		 * using ESR_MAGIC here since it is not checked for size nor
>> +		 * is limited to one instance.
>> +		 *
>> +		 * At first inject an additional normal esr_context
>> +		 */
>> +		head->magic = ESR_MAGIC;
>> +		head->size = sizeof(struct esr_context);
>> +		/* and terminate properly */
>> +		write_terminator_record(GET_RESV_NEXT_HEAD(head));
>> +		ASSERT_GOOD_CONTEXT(&sf.uc);
>> +
>> +		/*
>> +		 * now mess with fake esr_context size: leaving less space than
>> +		 * neededwhile keeping size value 16-aligned
>> +		 *
>> +		 * It must trigger a SEGV from Kernel on:
>> +		 *
>> +		 *	resv_sz - offset < sizeof(*head)
>> +		 */
>> +		/* at first set the maximum good 16-aligned size */
>> +		head->size = (resv_sz - offset - need_sz + MIN_SZ_ALIGN) & ~0xfUL;
>> +		/* plus a bit more of 16-aligned sized stuff */
>> +		head->size += MIN_SZ_ALIGN;
>> +		/* and terminate properly */
>> +		write_terminator_record(GET_RESV_NEXT_HEAD(head));
>> +		ASSERT_BAD_CONTEXT(&sf.uc);
>> +		fake_sigreturn(&sf, sizeof(sf), 16);
>> +	}
>> +
>> +	return 1;
>> +}
> 

I'll convert to use new helper get_starting_head() to make space in __reserved.

> [...]
> 
> Otherwise looks reasonable.
> 
> Cheers
> ---Dave

Cheers

Cristian
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp
  2019-08-13 16:28     ` Dave Martin
@ 2019-08-30 15:22       ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-30 15:22 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel

On 13/08/2019 17:28, Dave Martin wrote:
> On Wed, Aug 07, 2019 at 05:04:13PM +0100, Cristian Marussi wrote:
>> On 02/08/2019 18:03, Cristian Marussi wrote:
>>> Added a simple fake_sigreturn testcase which places a valid
>>> sigframe on a non-16 bytes aligned SP.
>>> fake_sigretrun() helper function has been patched accordingly
>>> to support placing a sigframe on a non-16 bytes aligned address.
>>> Expects a SIGSEGV on test PASS.
>>>
>>> Adds also a test TODO lists holding some further test ideas.
>>>
>>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>>> ---
>>> Re-added this text after fixing the forced misaglinment procedure in
>>> fake_sigreturn() itself: require a ZERO alignment and you'll get
>>> your sigframe placed on a misaligned SP (2-bytes off the 16-align)
>>> ---
>>>  .../testing/selftests/arm64/signal/signals.S  | 21 +++++++++----
>>>  .../arm64/signal/testcases/TODO.readme        |  8 +++++
>>>  .../testcases/fake_sigreturn_misaligned_sp.c  | 30 +++++++++++++++++++
>>>  3 files changed, 53 insertions(+), 6 deletions(-)
>>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
>>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
>>>
>>
>> When this test was re-added in V3, the related .gitignore was missed.
>> It will go in V4
> 
> Ack, or otherwise try switching to using wildcards in .gitignore as
> suggested in my reply to patch 4.

Used wildcard in .gitignore as advised.
> 

> [...]
> 
> Cheers
> ---Dave
> 
Cheers

Cristian

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp
  2019-08-13 16:27   ` Dave Martin
@ 2019-08-30 16:33     ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-08-30 16:33 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

On 13/08/2019 17:27, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:03:00PM +0100, Cristian Marussi wrote:
>> Added a simple fake_sigreturn testcase which places a valid
> 
> Add
> 
Ok

>> sigframe on a non-16 bytes aligned SP.
>> fake_sigretrun() helper function has been patched accordingly
>> to support placing a sigframe on a non-16 bytes aligned address.
>> Expects a SIGSEGV on test PASS.
>>
>> Adds also a test TODO lists holding some further test ideas.
> 
> Adds -> Also add
> lists -> list
> 

Removed together with the TODO.

>> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>> ---
>> Re-added this text after fixing the forced misaglinment procedure in
>> fake_sigreturn() itself: require a ZERO alignment and you'll get
>> your sigframe placed on a misaligned SP (2-bytes off the 16-align)
>> ---
>>  .../testing/selftests/arm64/signal/signals.S  | 21 +++++++++----
>>  .../arm64/signal/testcases/TODO.readme        |  8 +++++
>>  .../testcases/fake_sigreturn_misaligned_sp.c  | 30 +++++++++++++++++++
>>  3 files changed, 53 insertions(+), 6 deletions(-)
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
>>  create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
>>
>> diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
>> index 6262b877400b..2099871176ed 100644
>> --- a/tools/testing/selftests/arm64/signal/signals.S
>> +++ b/tools/testing/selftests/arm64/signal/signals.S
>> @@ -13,19 +13,28 @@ call_fmt:
>>  
>>  .globl fake_sigreturn
>>  
>> -/*	fake_sigreturn	x0:&sigframe,  x1:sigframe_size,  x2:alignment_SP */
>> +/*	fake_sigreturn	x0:&sigframe, x1:sigframe_sz, x2:align */
>>  fake_sigreturn:
>> -	mov x20, x0
>> -	mov x21, x1
>> -	mov x22, x2
>> -	mov x23, sp
>>  
>> -	/* create space on the stack for fake sigframe..."x22"-aligned */
>> +	/* Save args and decide which aligment to enforce */
>> +	mov 	x23, sp
>> +	mov	x20, x0
>> +	mov 	x21, x1
>> +	/* x22 and x24 used for forcing alignment or misalignment */
>> +	mov	x22, x2
>> +	mov	x24, #0
>> +	cbnz	x22, 1f
>> +	mov	x22, #16
>> +	mov	x24, #2
>> +
>> +1:	/* create space on the stack for fake sigframe..."x22"-aligned */
>>  	mov x0, #0
>>  	add x0, x21, x22
>>  	sub x22, x22, #1
>>  	bic x0, x0, x22
>>  	sub x23, x23, x0
>> +	/* force misaligned by x24 bytes if required alignment was zero */
>> +	add x23, x23, x24
>>  
>>  	ldr x0, =call_fmt
>>  	mov x1, x21
> 
> Would it be simpler for the third argument to specify a number of bytes
> to subtract from SP after allocating 16-byte aligned storage to
> accommodate sigframe_sz?
> 
> Then 0 gives an aligned frame, 1 gives a frame misaligned by 1 byte,
> etc.
> 
> 
> Also if all this is a fix to the original fake_sigreturn, can we merge
> it into the original patch instead?
> 
Yes simplified and merged into 6/11

>> diff --git a/tools/testing/selftests/arm64/signal/testcases/TODO.readme b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
>> new file mode 100644
>> index 000000000000..5c949492e7ab
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
>> @@ -0,0 +1,8 @@
>> +Some more possible ideas for signals tests:
>> +
>> +- fake_sigreturn_unmapped_sp
>> +- fake_sigreturn_kernelspace_sp
>> +- fake_sigreturn_sve_bad_extra_context
>> +- mangle_sve_invalid_extra_context
>> +- mangle_pstate_invalid_el for H modes (+ macroization ?)
>> +- fake_sigreturn_overflow_reserved
> 
> This seems a reasonable list, but it occurs to me that it will tend to
> go out of sync as tests get added.  So maybe just put this list in the
> cover letter instead of including it in the patch.
> 
> We should probably have a one-line description of each proposed test,
> since the names are a bit cryptic.

Moving to cover letter with description.

> 
>> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
>> new file mode 100644
>> index 000000000000..3ee8c500c7d1
>> --- /dev/null
>> +++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
>> @@ -0,0 +1,30 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2019 ARM Limited */
>> +
> 
> signal.h?

ok
> 
>> +#include <ucontext.h>
>> +
>> +#include "test_signals_utils.h"
>> +#include "testcases.h"
>> +
>> +struct fake_sigframe sf;
>> +
>> +static int fake_sigreturn_misaligned_run(struct tdescr *td,
>> +				         siginfo_t *si, ucontext_t *uc)
>> +{
>> +	/* just to fill the ucontext_t with something real */
>> +	if (!get_current_context(td, &sf.uc))
>> +		return 1;
>> +
>> +	/* Forcing sigframe on misaligned (=!16) SP */
>> +	fake_sigreturn(&sf, sizeof(sf), 0);
>> +
>> +	return 1;
>> +}
> 
> [...]
> 
> Cheers
> ---Dave
> 

Cheers

Cristian

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 00/11] Add arm64/signal initial kselftest support
  2019-08-13 16:22 ` [PATCH v3 00/11] Add arm64/signal initial kselftest support Dave Martin
@ 2019-08-30 16:40   ` Cristian Marussi
  2019-09-02 10:53     ` Dave Martin
  0 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-08-30 16:40 UTC (permalink / raw)
  To: Dave Martin; +Cc: linux-kselftest, linux-arm-kernel, shuah, andreyknvl

Hi

On 13/08/2019 17:22, Dave Martin wrote:
> On Fri, Aug 02, 2019 at 06:02:49PM +0100, Cristian Marussi wrote:
>> Hi
>>
>> this patchset aims to add the initial arch-specific arm64 support to
>> kselftest starting with signals-related test-cases.
>> A common internal test-case layout is proposed which then it is anyway
>> wired-up to the toplevel kselftest Makefile, so that it should be possible
>> at the end to run it on an arm64 target in the usual way with KSFT.
> 
> The tests look like a reasonable base overall and something that we can
> extend later as needed.
> 
> There are various minor things that need attention -- see my comments on
> the individual patches.  Apart for some things that can be factored out,
> I don't think any of it involves redesign.
> 
> 
> A few general comments:
> 
>  * Please wrap all commit messages to <= 75 chars, and follow the other
>    guidelines about commit messages in
>    Documentation/process/submitting-patches.rst).
> 
>  * Remember to run scripts/checkpatch.pl on your patches.  Currently
>    various issues are reported: they should mostly be trivial to fix.
>    checkpatch does report some false positives, but most of the warnings
>    I see look relevant.
> 

Thanks for the review. I addressed latest issues in V4, published now.

I kept tests verbose (outputting to stderr) as of now.
Removed as a whole standalone build/run.

Thanks

Cristian

>  * If you like, you can add an Author: line alongside the copyright
>    notice in new files that you create.  (You'll see this elsewhere in
>    the kernel if you grep.)
> 
> One general stylistic issue (IMHO):
> 
>  * Try to avoid inventing names for things that have no established
>    name (for example "magic0" to mean "magic number 0").
> 
>    The risk is that the reader wastes time grepping for the definition,
>    when really the text should be read at face value.  It's best to use
>    all caps just for #define names, abbreviations, and other things
>    that are customarily capitalised (like "CPU" etc.).  Other words
>    containing underscores may resemble variable / function names, and
>    may cause confusion of there is no actual variable or function with
>    that name.
> 
>    I don't think it's worth heavily reworking the patches for this, but
>    it's something to bear in mind.
> 
> [...]
> 
> Cheers
> ---Dave
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 00/11] Add arm64/signal initial kselftest support
  2019-08-30 16:40   ` Cristian Marussi
@ 2019-09-02 10:53     ` Dave Martin
  2019-09-02 11:30       ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-09-02 10:53 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: andreyknvl, shuah, linux-arm-kernel, linux-kselftest

On Fri, Aug 30, 2019 at 05:40:42PM +0100, Cristian Marussi wrote:
> Hi
> 
> On 13/08/2019 17:22, Dave Martin wrote:
> > On Fri, Aug 02, 2019 at 06:02:49PM +0100, Cristian Marussi wrote:
> >> Hi
> >>
> >> this patchset aims to add the initial arch-specific arm64 support to
> >> kselftest starting with signals-related test-cases.
> >> A common internal test-case layout is proposed which then it is anyway
> >> wired-up to the toplevel kselftest Makefile, so that it should be possible
> >> at the end to run it on an arm64 target in the usual way with KSFT.
> > 
> > The tests look like a reasonable base overall and something that we can
> > extend later as needed.
> > 
> > There are various minor things that need attention -- see my comments on
> > the individual patches.  Apart for some things that can be factored out,
> > I don't think any of it involves redesign.
> > 
> > 
> > A few general comments:
> > 
> >  * Please wrap all commit messages to <= 75 chars, and follow the other
> >    guidelines about commit messages in
> >    Documentation/process/submitting-patches.rst).
> > 
> >  * Remember to run scripts/checkpatch.pl on your patches.  Currently
> >    various issues are reported: they should mostly be trivial to fix.
> >    checkpatch does report some false positives, but most of the warnings
> >    I see look relevant.
> > 
> 
> Thanks for the review. I addressed latest issues in V4, published now.
> 
> I kept tests verbose (outputting to stderr) as of now.
> Removed as a whole standalone build/run.

The responses look reasonable, thanks for repost.

I'll take a look.

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 00/11] Add arm64/signal initial kselftest support
  2019-09-02 10:53     ` Dave Martin
@ 2019-09-02 11:30       ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-09-02 11:30 UTC (permalink / raw)
  To: Dave Martin; +Cc: andreyknvl, shuah, linux-arm-kernel, linux-kselftest

Hi

On 02/09/2019 11:53, Dave Martin wrote:
> On Fri, Aug 30, 2019 at 05:40:42PM +0100, Cristian Marussi wrote:
>> Hi
>>
>> On 13/08/2019 17:22, Dave Martin wrote:
>>> On Fri, Aug 02, 2019 at 06:02:49PM +0100, Cristian Marussi wrote:
>>>> Hi
>>>>
>>>> this patchset aims to add the initial arch-specific arm64 support to
>>>> kselftest starting with signals-related test-cases.
>>>> A common internal test-case layout is proposed which then it is anyway
>>>> wired-up to the toplevel kselftest Makefile, so that it should be possible
>>>> at the end to run it on an arm64 target in the usual way with KSFT.
>>>
>>> The tests look like a reasonable base overall and something that we can
>>> extend later as needed.
>>>
>>> There are various minor things that need attention -- see my comments on
>>> the individual patches.  Apart for some things that can be factored out,
>>> I don't think any of it involves redesign.
>>>
>>>
>>> A few general comments:
>>>
>>>  * Please wrap all commit messages to <= 75 chars, and follow the other
>>>    guidelines about commit messages in
>>>    Documentation/process/submitting-patches.rst).
>>>
>>>  * Remember to run scripts/checkpatch.pl on your patches.  Currently
>>>    various issues are reported: they should mostly be trivial to fix.
>>>    checkpatch does report some false positives, but most of the warnings
>>>    I see look relevant.
>>>
>>
>> Thanks for the review. I addressed latest issues in V4, published now.
>>
>> I kept tests verbose (outputting to stderr) as of now.
>> Removed as a whole standalone build/run.
> 
> The responses look reasonable, thanks for repost.
> 
> I'll take a look.
> 
Ok Thanks...but...

I'm re-posting now a further V5 which is also rebased on arm64/for-next/core and so deals
with the conflicts against queued commit:

https://lore.kernel.org/linux-arm-kernel/c1e6aad230658bc175b42d92daeff2e30050302a.1563904656.git.andreyknvl@google.com/
Subject: [PATCH v19 15/15] selftests, arm64: add a selftest for passing tagged pointers to kernel

Differences from v4 are limited to 01/02 and reported in changelog.

Thanks

Cristian

> [...]
> 
> Cheers
> ---Dave
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-08-28 17:34     ` Cristian Marussi
@ 2019-09-03 15:34       ` Dave Martin
  2019-09-03 16:08         ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-09-03 15:34 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: andreyknvl, shuah, linux-arm-kernel, linux-kselftest

Hi, responding to some non-trivial comments here where re-work isn't
needed -- so we have the right context for the mail thread.

For any remaining nits, I'll comment on the v5 patch.

On Wed, Aug 28, 2019 at 06:34:09PM +0100, Cristian Marussi wrote:
> Hi
> 
> On 13/08/2019 17:24, Dave Martin wrote:

[...]

> >> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile

[...]

> >> +# Guessing as best as we can where the Kernel headers
> >> +# could have been installed depending on ENV config and
> >> +# type of invocation.
> >> +ifeq ($(KBUILD_OUTPUT),)
> >> +khdr_dir = $(top_srcdir)/usr/include
> >> +else
> >> +ifeq (0,$(MAKELEVEL))
> >> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
> >> +else
> >> +# the KSFT preferred location when KBUILD_OUTPUT is set
> >> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
> >> +endif
> >> +endif
> > 
> > When is KBUILD_OUTPUT set / not set?
> > 
> 
> Depending how the user/CI is configured KSFT installs the kernel
> headers in different places....here I'm trying to guess where they
> have been installed by KSFT.
> 
> >> +
> >> +CFLAGS += -I$(khdr_dir)
> > 
> > Do we rely on any non-UAPI headers?  If not, the default should probably
> > be to rely on the system headers (or toolchain default headers) -- i.e.,
> > add no -I option at all.
> 
> I only need updated UAPI headers, but I cannot build without this specific -I..
> that points to the installed kernel headers directory.
> 
> As an example it fails with: undefined  HWCAP_SSBS if I remove the -I
> 
> > 
> > I'm wondering why none of the other kselftests need this header search
> > logic.
> > 
> 
> Well... a lot of KSFT tests has something related to headers search in their Makefiles:
> 
> ../kcmp/Makefile:CFLAGS += -I../../../../usr/include/
> ../networking/timestamping/Makefile:CFLAGS += -I../../../../../usr/include
> ../ipc/Makefile:CFLAGS += -I../../../../usr/include/
> ../memfd/Makefile:CFLAGS += -I../../../../include/uapi/
> ../memfd/Makefile:CFLAGS += -I../../../../include/
> ../memfd/Makefile:CFLAGS += -I../../../../usr/include/
> 
> which seems aimed at doing the same thing, but it is a broken approach
> as far as I can see since if KBUILD_OUTPUT is set, KSFT will install the
> headers accordingly, so that the above static includes won't work anymore.
> 
> Not sure if I'm missing something here, but my understanding was that
> 
> - some KSFT requires arch specific bits, usually included within the dedicated kernel
> headers provided with the source itself and installed with make headers_install.
> 
> and that
> 
> - such headers can be found naturally, being included from top level libc headers
> only if:
> 
> 1. a fully updated toolchain containing updated headers too is available at CROSS_COMPILE=
> 
> or
> 
> 2. proper -I options are specified to the compiler to specify where KSFT installed the 
>   kernel headers related to this kernel and its related KSFT testcases
> 
> or
> 
> 3. updated kernel headers were installed on top of the available CROSS_COMPILE toolchain
> 
> or
> 
> 4. we are building and running natively, so you can install the kernel headers on
>    system default path and those will be searched
> 
> 
> My 'feeling' would have been that in the KSFT scenario we should try to stick with option  2.,
> in order to be able to run KSFT and run the related testcases, relying just on the shipped
> Kernel/KSFT and possibly underlying hw features, but not having any dependencies
> on the toolchain/libc.
> 
> My question is: what happens on a CI-somewhere if suddenly there's the need to update
> the toolchain somehow (fully or partially only the headers) to be able to simply
> build/run the new KSFT included with this Kernel ?; even if we accept this need to update
> the toochain, where this CI should get/scrap-from these minimum toolchain requirements ?
> (in an automated manner)
> 
> If instead we can agree to stick with 2.,  I wonder if this locate-headers mechanism which I introduced
> here should be in charge of the KSFT framework or if there is something broken in my tests: but 
> in these regards similar issues seems to affect KSFT arm64 tags tests queued on arm64/for-next
> 
> https://lkml.org/lkml/2019/8/23/721

Ack, I think we should stick with option 2 for now, but I agree to keep
it local to your tests for now to avoid breaking stuff elsewhere.

In general I think that kselftest should always search the installed
UAPI headers from the containing kernel tree first, since that's the
best way to ensure the headers are 100% up to date.

This may need wider discussion in order to be deployed more widely
across kselftest though.

[...]

> >> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h

[...]

> >> + *  "The infrastructure emulates only the following system register space:
> >> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
> >> + */
> >> +#define get_regval(regname, out) \
> >> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
> >> +
> >> +/* Regs encoding and masks naming copied in from sysreg.h */
> >> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
> >> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
> > 
> > These ID regs are part of armv8.0-a, so we don't need to use the magic
> > syntax.
> > mmm... why I found them in non UAPI headers defined as follows ?
> 
> arch/arm64/include/asm/sysreg.h:#define SYS_ID_AA64MMFR1_EL1            sys_reg(3, 0, 0, 7, 1)
> 
> anyway I tried to use nonS3 regular sysreg naming (with a reasonably new compiler:
> 
> /opt/toolchains/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/aarch64-linux-gnu-
> 
> and it fails (only on id_aa64mmfr2_el1) as follows:
> /tmp/ccqAyE8P.s: Assembler messages:                      
> /tmp/ccoGrnGc.s:1085: Error: selected processor does not support system register name 'id_aa64mmfr2_el1'
> 
> In fact this seems to remind me (not totally sure) that this was the reason to use such S3 syntax on this
> sysregs too.

Ah, it looks like ID_AA64MMFR2_EL1 was added from ARMv8.2-A only.  My
bad.

To keep things consistent, I'm fine with keeping the S3_ syntax for
everything here.

> >> +#define ID_AA64MMFR1_PAN_SHIFT	20
> >> +#define ID_AA64MMFR2_UAO_SHIFT	4

[...]

> >> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c

[...]

> >> +static inline bool are_feats_ok(struct tdescr *td)
> >> +{
> >> +	return td ? td->feats_required == td->feats_supported : 0;
> > 
> > Should this be something like
> > (td->feats_required & td->feats_supported) == td->feats_required ?
> > 
> > Otherwise additional supported features that our test doesn't care about
> > will cause this check to fail.
> > 
> Yes better.
> 
> > 
> > Do we really need to check td?
> > 
> 
> Overly defensive
> 
> > assert(foo); followed by dereferincing foo is usually a bit pointless
> > because you'd get a SIGSEGV anyway.
> >
> > However, since the tests generate deliberate SIGSEGVs too this could
> > be confusing -- in which case, having an explicit assert() here does
> > no harm.
> > 
> not sure about which assert you refer here

I was persuading myself that my own comment was unnecessary, so don't
worry about it.  The code is fine as-is.

> >> +}
> >> +
> >> +static void default_handler(int signum, siginfo_t *si, void *uc)
> >> +{
> >> +	if (current->sig_trig && signum == current->sig_trig) {
> >> +		fprintf(stderr, "Handling SIG_TRIG\n");
> >> +		current->triggered = 1;
> >> +		/* ->run was asserted NON-NULL in test_setup() already */
> >> +		current->run(current, si, uc);
> >> +	} else if (signum == SIGILL && !current->initialized) {
> >> +		/*
> >> +		 * A SIGILL here while still not initialized means we failed
> >> +		 * even to asses the existence of features during init
> >> +		 */
> >> +		fprintf(stdout,
> >> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
> >> +		current->feats_supported = 0;
> >> +	} else if (current->sig_ok && signum == current->sig_ok) {
> >> +		/* it's a bug in the test code when this assert fail */
> > 
> > Why?  Is this because sig_ok is considered acceptable only as an effect
> > of the test -- i.e., we shouldn't see it if the test hasn't been
> > triggered yet?
> 
> This assert would like to ensure that when you receive a sig_ok signal,
> if a sig_trig was defined != 0, the trigger have been in fact used and processed before
> receiving this sig_ok here: so you didn't define a signal trigger at all, or, if defined
> it has been fired to arrive here. I'll add some commenting about this.

OK

> >> +		assert(!current->sig_trig || current->triggered);
> >> +		fprintf(stderr,
> >> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
> >> +			((ucontext_t *)uc)->uc_mcontext.sp,
> >> +			si->si_addr, si->si_code, current->token,
> >> +			current->token - si->si_addr);
> >> +		/*
> >> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
> >> +		 * the very last time, the token field to the SP address used
> >> +		 * to place the fake sigframe: so token==0 means we never made
> >> +		 * it to the end, segfaulting well-before, and the test is
> >> +		 * possibly broken.
> >> +		 */
> >> +		if (!current->sanity_disabled && !current->token) {
> >> +			fprintf(stdout,
> >> +				"current->token ZEROED...test is probably broken!\n");
> >> +			assert(0);
> > 
> > In case someone builds with -DNDEBUG, should we add abort()?
> > 
> Well, in such a case all the test suite is mostly compromised anyway.
> But you are right, I'll add an abort() at least here when broken tests
> are detected.

I guess you're right.  The abort() does no harm, anyway.

[...]

> >> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c

[...]

> >> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
> >> +{
> >> +	bool terminated = false;
> >> +	size_t offs = 0;
> >> +	int flags = 0;
> >> +	struct extra_context *extra = NULL;
> >> +	struct _aarch64_ctx *head =
> >> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
> >> +
> >> +	if (!err)
> >> +		return false;
> >> +	/* Walk till the end terminator verifying __reserved contents */
> >> +	while (head && !terminated && offs < resv_sz) {
> >> +		if ((uint64_t)head & 0x0fUL) {
> >> +			*err = "Misaligned HEAD";
> >> +			return false;
> >> +		}
> >> +
> >> +		switch (head->magic) {
> >> +			case 0:
> >> +				if (head->size)
> >> +					*err = "Bad size for MAGIC0";
> > 
> > Or "terminator".  We don't have an actual symbolic name for magic number
> > 0.  (Arguably it would have been nice to have a name, but we managed
> > without.)
> 
> ok
> > 
> >> +				else
> >> +					terminated = true;
> >> +				break;
> >> +			case FPSIMD_MAGIC:
> >> +				if (flags & FPSIMD_CTX)
> >> +					*err = "Multiple FPSIMD_MAGIC";
> >> +				else if (head->size !=
> >> +					 sizeof(struct fpsimd_context))
> >> +					*err = "Bad size for fpsimd_context";
> >> +				flags |= FPSIMD_CTX;
> >> +				break;
> >> +			case ESR_MAGIC:
> >> +				if (head->size != sizeof(struct esr_context))
> >> +					fprintf(stderr,
> >> +						"Bad size for esr_context is not an error...just ignore.\n");
> > 
> > Why isn't this an error?  Should the kernel ever write an esr_context
> > with a different size?
> 
> There is no check on Kernel side:
> 
>     case ESR_MAGIC:
>     	/* ignore */
>         break;
> 
> so I sticked with that, since this function can be used to validate a
> Kernel originated sigframe or a crafted one which will be passed down
> to the Kernel.

I see where you're coming from: I'll comment on the v5 patch instead of
here, to make it easier to track any rework.

[...]

> >> +		if (flags & EXTRA_CTX)
> >> +			if (!validate_extra_context(extra, err))
> >> +				return false;
> > 
> > Can we validate the contents of the extra context too?
> > 
> > Ideally we can use the same code to check __reserved[] and the extra
> > context.
> > 
> Do you mean the content pointed by extra->datap ?
> This extra_context validation routine is generally under review and fixes in a further
> arm64/signal SVE extensions patch still to be published (and cleaned up):
> [kselftest: arm64: adds SVE-related signal test], given that EXTRA_CONTEXT can effectively
> appear only when SVE related instruction are used properly.
> 
> Should I introduce this and other extra-context related fixes here instead ?
> (it is hard to test and debug without any triggering SVE instruction though...)

No, it's fine to exclude it for now.

If there's a plan to add it later, that's good enough for me.

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
  2019-09-03 15:34       ` Dave Martin
@ 2019-09-03 16:08         ` Cristian Marussi
  0 siblings, 0 replies; 56+ messages in thread
From: Cristian Marussi @ 2019-09-03 16:08 UTC (permalink / raw)
  To: Dave Martin; +Cc: andreyknvl, shuah, linux-arm-kernel, linux-kselftest

Hi

On 03/09/2019 16:34, Dave Martin wrote:
> Hi, responding to some non-trivial comments here where re-work isn't
> needed -- so we have the right context for the mail thread.
> 
> For any remaining nits, I'll comment on the v5 patch.
> 
ok

> On Wed, Aug 28, 2019 at 06:34:09PM +0100, Cristian Marussi wrote:
>> Hi
>>
>> On 13/08/2019 17:24, Dave Martin wrote:
> 
> [...]
> 
>>>> diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
> 
> [...]
> 
>>>> +# Guessing as best as we can where the Kernel headers
>>>> +# could have been installed depending on ENV config and
>>>> +# type of invocation.
>>>> +ifeq ($(KBUILD_OUTPUT),)
>>>> +khdr_dir = $(top_srcdir)/usr/include
>>>> +else
>>>> +ifeq (0,$(MAKELEVEL))
>>>> +khdr_dir = $(KBUILD_OUTPUT)/usr/include
>>>> +else
>>>> +# the KSFT preferred location when KBUILD_OUTPUT is set
>>>> +khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
>>>> +endif
>>>> +endif
>>>
>>> When is KBUILD_OUTPUT set / not set?
>>>
>>
>> Depending how the user/CI is configured KSFT installs the kernel
>> headers in different places....here I'm trying to guess where they
>> have been installed by KSFT.
>>
>>>> +
>>>> +CFLAGS += -I$(khdr_dir)
>>>
>>> Do we rely on any non-UAPI headers?  If not, the default should probably
>>> be to rely on the system headers (or toolchain default headers) -- i.e.,
>>> add no -I option at all.
>>
>> I only need updated UAPI headers, but I cannot build without this specific -I..
>> that points to the installed kernel headers directory.
>>
>> As an example it fails with: undefined  HWCAP_SSBS if I remove the -I
>>
>>>
>>> I'm wondering why none of the other kselftests need this header search
>>> logic.
>>>
>>
>> Well... a lot of KSFT tests has something related to headers search in their Makefiles:
>>
>> ../kcmp/Makefile:CFLAGS += -I../../../../usr/include/
>> ../networking/timestamping/Makefile:CFLAGS += -I../../../../../usr/include
>> ../ipc/Makefile:CFLAGS += -I../../../../usr/include/
>> ../memfd/Makefile:CFLAGS += -I../../../../include/uapi/
>> ../memfd/Makefile:CFLAGS += -I../../../../include/
>> ../memfd/Makefile:CFLAGS += -I../../../../usr/include/
>>
>> which seems aimed at doing the same thing, but it is a broken approach
>> as far as I can see since if KBUILD_OUTPUT is set, KSFT will install the
>> headers accordingly, so that the above static includes won't work anymore.
>>
>> Not sure if I'm missing something here, but my understanding was that
>>
>> - some KSFT requires arch specific bits, usually included within the dedicated kernel
>> headers provided with the source itself and installed with make headers_install.
>>
>> and that
>>
>> - such headers can be found naturally, being included from top level libc headers
>> only if:
>>
>> 1. a fully updated toolchain containing updated headers too is available at CROSS_COMPILE=
>>
>> or
>>
>> 2. proper -I options are specified to the compiler to specify where KSFT installed the 
>>   kernel headers related to this kernel and its related KSFT testcases
>>
>> or
>>
>> 3. updated kernel headers were installed on top of the available CROSS_COMPILE toolchain
>>
>> or
>>
>> 4. we are building and running natively, so you can install the kernel headers on
>>    system default path and those will be searched
>>
>>
>> My 'feeling' would have been that in the KSFT scenario we should try to stick with option  2.,
>> in order to be able to run KSFT and run the related testcases, relying just on the shipped
>> Kernel/KSFT and possibly underlying hw features, but not having any dependencies
>> on the toolchain/libc.
>>
>> My question is: what happens on a CI-somewhere if suddenly there's the need to update
>> the toolchain somehow (fully or partially only the headers) to be able to simply
>> build/run the new KSFT included with this Kernel ?; even if we accept this need to update
>> the toochain, where this CI should get/scrap-from these minimum toolchain requirements ?
>> (in an automated manner)
>>
>> If instead we can agree to stick with 2.,  I wonder if this locate-headers mechanism which I introduced
>> here should be in charge of the KSFT framework or if there is something broken in my tests: but 
>> in these regards similar issues seems to affect KSFT arm64 tags tests queued on arm64/for-next
>>
>> https://lkml.org/lkml/2019/8/23/721
> 
> Ack, I think we should stick with option 2 for now, but I agree to keep
> it local to your tests for now to avoid breaking stuff elsewhere.
> 
> In general I think that kselftest should always search the installed
> UAPI headers from the containing kernel tree first, since that's the
> best way to ensure the headers are 100% up to date.
> 
> This may need wider discussion in order to be deployed more widely
> across kselftest though.
> 

Yes I agree, in the meantime in V5 I moved such mechanism (2. add -I$(khdr_src)) into the toplevel
KSFT arm64 Makefile at least so that it transparently works for all arm64 KSFT test families...in fact
in this way now also KSFT tags tests from Andrey compile fine (without a custom -I ../../../)
...not sure if it is the proper fix anyway.

> [...]
> 
>>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
> 
> [...]
> 
>>>> + *  "The infrastructure emulates only the following system register space:
>>>> + *   	Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
>>>> + */
>>>> +#define get_regval(regname, out) \
>>>> +	asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
>>>> +
>>>> +/* Regs encoding and masks naming copied in from sysreg.h */
>>>> +#define SYS_ID_AA64MMFR1_EL1	S3_0_C0_C7_1	/* MRS Emulated */
>>>> +#define SYS_ID_AA64MMFR2_EL1	S3_0_C0_C7_2	/* MRS Emulated */
>>>
>>> These ID regs are part of armv8.0-a, so we don't need to use the magic
>>> syntax.
>>> mmm... why I found them in non UAPI headers defined as follows ?
>>
>> arch/arm64/include/asm/sysreg.h:#define SYS_ID_AA64MMFR1_EL1            sys_reg(3, 0, 0, 7, 1)
>>
>> anyway I tried to use nonS3 regular sysreg naming (with a reasonably new compiler:
>>
>> /opt/toolchains/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin/aarch64-linux-gnu-
>>
>> and it fails (only on id_aa64mmfr2_el1) as follows:
>> /tmp/ccqAyE8P.s: Assembler messages:                      
>> /tmp/ccoGrnGc.s:1085: Error: selected processor does not support system register name 'id_aa64mmfr2_el1'
>>
>> In fact this seems to remind me (not totally sure) that this was the reason to use such S3 syntax on this
>> sysregs too.
> 
> Ah, it looks like ID_AA64MMFR2_EL1 was added from ARMv8.2-A only.  My
> bad.
> 
> To keep things consistent, I'm fine with keeping the S3_ syntax for
> everything here.
> 
>>>> +#define ID_AA64MMFR1_PAN_SHIFT	20
>>>> +#define ID_AA64MMFR2_UAO_SHIFT	4
> 
> [...]
> 
Not sure if in v5 I fixed only the fixable or left everything as it was...I have to double check.

>>>> diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
> 
> [...]
> 
>>>> +static inline bool are_feats_ok(struct tdescr *td)
>>>> +{
>>>> +	return td ? td->feats_required == td->feats_supported : 0;
>>>
>>> Should this be something like
>>> (td->feats_required & td->feats_supported) == td->feats_required ?
>>>
>>> Otherwise additional supported features that our test doesn't care about
>>> will cause this check to fail.
>>>
>> Yes better.
>>
>>>
>>> Do we really need to check td?
>>>
>>
>> Overly defensive
>>
>>> assert(foo); followed by dereferincing foo is usually a bit pointless
>>> because you'd get a SIGSEGV anyway.
>>>
>>> However, since the tests generate deliberate SIGSEGVs too this could
>>> be confusing -- in which case, having an explicit assert() here does
>>> no harm.
>>>
>> not sure about which assert you refer here
> 
> I was persuading myself that my own comment was unnecessary, so don't
> worry about it.  The code is fine as-is.

ok
> 
>>>> +}
>>>> +
>>>> +static void default_handler(int signum, siginfo_t *si, void *uc)
>>>> +{
>>>> +	if (current->sig_trig && signum == current->sig_trig) {
>>>> +		fprintf(stderr, "Handling SIG_TRIG\n");
>>>> +		current->triggered = 1;
>>>> +		/* ->run was asserted NON-NULL in test_setup() already */
>>>> +		current->run(current, si, uc);
>>>> +	} else if (signum == SIGILL && !current->initialized) {
>>>> +		/*
>>>> +		 * A SIGILL here while still not initialized means we failed
>>>> +		 * even to asses the existence of features during init
>>>> +		 */
>>>> +		fprintf(stdout,
>>>> +			"Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
>>>> +		current->feats_supported = 0;
>>>> +	} else if (current->sig_ok && signum == current->sig_ok) {
>>>> +		/* it's a bug in the test code when this assert fail */
>>>
>>> Why?  Is this because sig_ok is considered acceptable only as an effect
>>> of the test -- i.e., we shouldn't see it if the test hasn't been
>>> triggered yet?
>>
>> This assert would like to ensure that when you receive a sig_ok signal,
>> if a sig_trig was defined != 0, the trigger have been in fact used and processed before
>> receiving this sig_ok here: so you didn't define a signal trigger at all, or, if defined
>> it has been fired to arrive here. I'll add some commenting about this.
> 
> OK
> 
>>>> +		assert(!current->sig_trig || current->triggered);
>>>> +		fprintf(stderr,
>>>> +			"SIG_OK -- SP:%p  si_addr@:0x%p  si_code:%d  token@:0x%p  offset:%ld\n",
>>>> +			((ucontext_t *)uc)->uc_mcontext.sp,
>>>> +			si->si_addr, si->si_code, current->token,
>>>> +			current->token - si->si_addr);
>>>> +		/*
>>>> +		 * fake_sigreturn tests, which have sanity_enabled=1, set, at
>>>> +		 * the very last time, the token field to the SP address used
>>>> +		 * to place the fake sigframe: so token==0 means we never made
>>>> +		 * it to the end, segfaulting well-before, and the test is
>>>> +		 * possibly broken.
>>>> +		 */
>>>> +		if (!current->sanity_disabled && !current->token) {
>>>> +			fprintf(stdout,
>>>> +				"current->token ZEROED...test is probably broken!\n");
>>>> +			assert(0);
>>>
>>> In case someone builds with -DNDEBUG, should we add abort()?
>>>
>> Well, in such a case all the test suite is mostly compromised anyway.
>> But you are right, I'll add an abort() at least here when broken tests
>> are detected.
> 
> I guess you're right.  The abort() does no harm, anyway.
> Gone with abort() in v5

> [...]
> 
>>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
> 
> [...]
> 
>>>> +bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
>>>> +{
>>>> +	bool terminated = false;
>>>> +	size_t offs = 0;
>>>> +	int flags = 0;
>>>> +	struct extra_context *extra = NULL;
>>>> +	struct _aarch64_ctx *head =
>>>> +		(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
>>>> +
>>>> +	if (!err)
>>>> +		return false;
>>>> +	/* Walk till the end terminator verifying __reserved contents */
>>>> +	while (head && !terminated && offs < resv_sz) {
>>>> +		if ((uint64_t)head & 0x0fUL) {
>>>> +			*err = "Misaligned HEAD";
>>>> +			return false;
>>>> +		}
>>>> +
>>>> +		switch (head->magic) {
>>>> +			case 0:
>>>> +				if (head->size)
>>>> +					*err = "Bad size for MAGIC0";
>>>
>>> Or "terminator".  We don't have an actual symbolic name for magic number
>>> 0.  (Arguably it would have been nice to have a name, but we managed
>>> without.)
>>
>> ok
>>>
>>>> +				else
>>>> +					terminated = true;
>>>> +				break;
>>>> +			case FPSIMD_MAGIC:
>>>> +				if (flags & FPSIMD_CTX)
>>>> +					*err = "Multiple FPSIMD_MAGIC";
>>>> +				else if (head->size !=
>>>> +					 sizeof(struct fpsimd_context))
>>>> +					*err = "Bad size for fpsimd_context";
>>>> +				flags |= FPSIMD_CTX;
>>>> +				break;
>>>> +			case ESR_MAGIC:
>>>> +				if (head->size != sizeof(struct esr_context))
>>>> +					fprintf(stderr,
>>>> +						"Bad size for esr_context is not an error...just ignore.\n");
>>>
>>> Why isn't this an error?  Should the kernel ever write an esr_context
>>> with a different size?
>>
>> There is no check on Kernel side:
>>
>>     case ESR_MAGIC:
>>     	/* ignore */
>>         break;
>>
>> so I sticked with that, since this function can be used to validate a
>> Kernel originated sigframe or a crafted one which will be passed down
>> to the Kernel.
> 
> I see where you're coming from: I'll comment on the v5 patch instead of
> here, to make it easier to track any rework.
> 
ok
> [...]
> 
>>>> +		if (flags & EXTRA_CTX)
>>>> +			if (!validate_extra_context(extra, err))
>>>> +				return false;
>>>
>>> Can we validate the contents of the extra context too?
>>>
>>> Ideally we can use the same code to check __reserved[] and the extra
>>> context.
>>>
>> Do you mean the content pointed by extra->datap ?
>> This extra_context validation routine is generally under review and fixes in a further
>> arm64/signal SVE extensions patch still to be published (and cleaned up):
>> [kselftest: arm64: adds SVE-related signal test], given that EXTRA_CONTEXT can effectively
>> appear only when SVE related instruction are used properly.
>>
>> Should I introduce this and other extra-context related fixes here instead ?
>> (it is hard to test and debug without any triggering SVE instruction though...)
> 
> No, it's fine to exclude it for now.
> 
> If there's a plan to add it later, that's good enough for me.

ok
> 
> [...]
> 
> Cheers
> ---Dave
> 

Thanks

Cheers 

Cristian

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic
  2019-08-30 14:29     ` Cristian Marussi
@ 2019-09-04 10:05       ` Dave Martin
  2019-09-04 10:37         ` Cristian Marussi
  0 siblings, 1 reply; 56+ messages in thread
From: Dave Martin @ 2019-09-04 10:05 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: andreyknvl, shuah, linux-arm-kernel, linux-kselftest

On Fri, Aug 30, 2019 at 03:29:29PM +0100, Cristian Marussi wrote:
> Hi
> 
> On 13/08/2019 17:25, Dave Martin wrote:
> > On Fri, Aug 02, 2019 at 06:02:55PM +0100, Cristian Marussi wrote:

[...]

> >> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c

[...]

> >> +static int fake_sigreturn_bad_magic_run(struct tdescr *td,
> >> +					siginfo_t *si, ucontext_t *uc)
> >> +{
> >> +	size_t resv_sz, offset;
> >> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
> >> +
> >> +	/* just to fill the ucontext_t with something real */
> >> +	if (!get_current_context(td, &sf.uc))
> >> +		return 1;
> >> +
> >> +	resv_sz = GET_SF_RESV_SIZE(sf);
> >> +	/*
> >> +	 * find the terminator, preserving existing headers
> >> +	 * and verify amount of spare room in __reserved area.
> >> +	 */
> >> +	head = get_terminator(shead, resv_sz, &offset);
> >> +	/*
> >> +	 * try stripping extra_context header when low on space:
> >> +	 * we need at least 2*HDR_SZ space ... one for the KSFT_BAD_MAGIC
> >> +	 * and the other for the usual terminator.
> >> +	 */
> >> +	if (head && resv_sz - offset < HDR_SZ * 2) {
> > 
> > Can we factor out this logic for finding space in the signal frame?
> > 
> > We do pretty much the same thing in all the fake_sigreturn tests...
> 
> Ok
> > 
> >> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
> >> +			resv_sz - offset);
> >> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
> >> +	}
> >> +	/* just give up and timeout if still not enough space */
> > 
> > Do we actually time out?  I don't see where we actually wait, so doesn't
> > test_run() just fail immediately?
> > 
> > The same applies to all the other fake_sigreturn tests too.
> > 
> Right. It is probably a leftover.
> 
> SIGALRM is used as an extreme measure to kill tests gone bad, but this
> can happen only once the fake sigframe has been effectively placed on the stack
> and sigreturned.

OK, so this gets reported as a test failure because with no SIGSEGV,
nothing ever sets td->pass?

This is probably OK for now, though I wonder whether this should be
reported as a skipped test instead.

In case of doubt, reporting a failure is preferable anyway, since that
will encourage people actually to investigate what went wrong.

[...]

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic
  2019-09-04 10:05       ` Dave Martin
@ 2019-09-04 10:37         ` Cristian Marussi
  2019-09-04 10:47           ` Dave Martin
  0 siblings, 1 reply; 56+ messages in thread
From: Cristian Marussi @ 2019-09-04 10:37 UTC (permalink / raw)
  To: Dave Martin; +Cc: andreyknvl, shuah, linux-arm-kernel, linux-kselftest

On 04/09/2019 11:05, Dave Martin wrote:
> On Fri, Aug 30, 2019 at 03:29:29PM +0100, Cristian Marussi wrote:
>> Hi
>>
>> On 13/08/2019 17:25, Dave Martin wrote:
>>> On Fri, Aug 02, 2019 at 06:02:55PM +0100, Cristian Marussi wrote:
> 
> [...]
> 
>>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
> 
> [...]
> 
>>>> +static int fake_sigreturn_bad_magic_run(struct tdescr *td,
>>>> +					siginfo_t *si, ucontext_t *uc)
>>>> +{
>>>> +	size_t resv_sz, offset;
>>>> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
>>>> +
>>>> +	/* just to fill the ucontext_t with something real */
>>>> +	if (!get_current_context(td, &sf.uc))
>>>> +		return 1;
>>>> +
>>>> +	resv_sz = GET_SF_RESV_SIZE(sf);
>>>> +	/*
>>>> +	 * find the terminator, preserving existing headers
>>>> +	 * and verify amount of spare room in __reserved area.
>>>> +	 */
>>>> +	head = get_terminator(shead, resv_sz, &offset);
>>>> +	/*
>>>> +	 * try stripping extra_context header when low on space:
>>>> +	 * we need at least 2*HDR_SZ space ... one for the KSFT_BAD_MAGIC
>>>> +	 * and the other for the usual terminator.
>>>> +	 */
>>>> +	if (head && resv_sz - offset < HDR_SZ * 2) {
>>>
>>> Can we factor out this logic for finding space in the signal frame?
>>>
>>> We do pretty much the same thing in all the fake_sigreturn tests...
>>
>> Ok
>>>
>>>> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
>>>> +			resv_sz - offset);
>>>> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
>>>> +	}
>>>> +	/* just give up and timeout if still not enough space */
>>>
>>> Do we actually time out?  I don't see where we actually wait, so doesn't
>>> test_run() just fail immediately?
>>>
>>> The same applies to all the other fake_sigreturn tests too.
>>>
>> Right. It is probably a leftover.
>>
>> SIGALRM is used as an extreme measure to kill tests gone bad, but this
>> can happen only once the fake sigframe has been effectively placed on the stack
>> and sigreturned.
> 
> OK, so this gets reported as a test failure because with no SIGSEGV,
> nothing ever sets td->pass?

Yes exactly. End result is based on value on td->pass, in case of abrupt
termination or timeout nobody sets td->pass ever.
> 
> This is probably OK for now, though I wonder whether this should be
> reported as a skipped test instead.
> 
> In case of doubt, reporting a failure is preferable anyway, since that
> will encourage people actually to investigate what went wrong.
> 

As of now I never skip a test in fact...also tests for unsupported features
are built and run expecting a SIGILL, and reported as PASS in that case.

Cristian
> [...]
> 
> Cheers
> ---Dave
> 


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic
  2019-09-04 10:37         ` Cristian Marussi
@ 2019-09-04 10:47           ` Dave Martin
  0 siblings, 0 replies; 56+ messages in thread
From: Dave Martin @ 2019-09-04 10:47 UTC (permalink / raw)
  To: Cristian Marussi; +Cc: andreyknvl, shuah, linux-kselftest, linux-arm-kernel

On Wed, Sep 04, 2019 at 11:37:36AM +0100, Cristian Marussi wrote:
> On 04/09/2019 11:05, Dave Martin wrote:
> > On Fri, Aug 30, 2019 at 03:29:29PM +0100, Cristian Marussi wrote:
> >> Hi
> >>
> >> On 13/08/2019 17:25, Dave Martin wrote:
> >>> On Fri, Aug 02, 2019 at 06:02:55PM +0100, Cristian Marussi wrote:
> > 
> > [...]
> > 
> >>>> diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
> > 
> > [...]
> > 
> >>>> +static int fake_sigreturn_bad_magic_run(struct tdescr *td,
> >>>> +					siginfo_t *si, ucontext_t *uc)
> >>>> +{
> >>>> +	size_t resv_sz, offset;
> >>>> +	struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
> >>>> +
> >>>> +	/* just to fill the ucontext_t with something real */
> >>>> +	if (!get_current_context(td, &sf.uc))
> >>>> +		return 1;
> >>>> +
> >>>> +	resv_sz = GET_SF_RESV_SIZE(sf);
> >>>> +	/*
> >>>> +	 * find the terminator, preserving existing headers
> >>>> +	 * and verify amount of spare room in __reserved area.
> >>>> +	 */
> >>>> +	head = get_terminator(shead, resv_sz, &offset);
> >>>> +	/*
> >>>> +	 * try stripping extra_context header when low on space:
> >>>> +	 * we need at least 2*HDR_SZ space ... one for the KSFT_BAD_MAGIC
> >>>> +	 * and the other for the usual terminator.
> >>>> +	 */
> >>>> +	if (head && resv_sz - offset < HDR_SZ * 2) {
> >>>
> >>> Can we factor out this logic for finding space in the signal frame?
> >>>
> >>> We do pretty much the same thing in all the fake_sigreturn tests...
> >>
> >> Ok
> >>>
> >>>> +		fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
> >>>> +			resv_sz - offset);
> >>>> +		head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
> >>>> +	}
> >>>> +	/* just give up and timeout if still not enough space */
> >>>
> >>> Do we actually time out?  I don't see where we actually wait, so doesn't
> >>> test_run() just fail immediately?
> >>>
> >>> The same applies to all the other fake_sigreturn tests too.
> >>>
> >> Right. It is probably a leftover.
> >>
> >> SIGALRM is used as an extreme measure to kill tests gone bad, but this
> >> can happen only once the fake sigframe has been effectively placed on the stack
> >> and sigreturned.
> > 
> > OK, so this gets reported as a test failure because with no SIGSEGV,
> > nothing ever sets td->pass?
> 
> Yes exactly. End result is based on value on td->pass, in case of abrupt
> termination or timeout nobody sets td->pass ever.
> > 
> > This is probably OK for now, though I wonder whether this should be
> > reported as a skipped test instead.
> > 
> > In case of doubt, reporting a failure is preferable anyway, since that
> > will encourage people actually to investigate what went wrong.
> > 
> 
> As of now I never skip a test in fact...also tests for unsupported features
> are built and run expecting a SIGILL, and reported as PASS in that case.

OK, just wanted to check I'd understood correcly.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2019-09-04 10:47 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-02 17:02 [PATCH v3 00/11] Add arm64/signal initial kselftest support Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code Cristian Marussi
2019-08-13 16:23   ` Dave Martin
2019-08-27 12:14     ` Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 02/11] kselftest: arm64: adds first test and common utils Cristian Marussi
2019-08-06 15:50   ` Cristian Marussi
2019-08-07 15:42   ` Cristian Marussi
2019-08-09 10:54   ` Cristian Marussi
2019-08-09 11:16     ` Dave Martin
2019-08-09 12:20       ` Cristian Marussi
2019-08-09 12:32         ` Dave Martin
2019-08-12 12:43   ` Amit Kachhap
2019-08-13 13:22     ` Cristian Marussi
2019-08-14 10:22       ` Amit Kachhap
2019-08-27 14:24         ` Cristian Marussi
2019-08-13 16:24   ` Dave Martin
2019-08-28 17:34     ` Cristian Marussi
2019-09-03 15:34       ` Dave Martin
2019-09-03 16:08         ` Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 03/11] kselftest: arm64: mangle_pstate_invalid_daif_bits Cristian Marussi
2019-08-13 16:24   ` Dave Martin
2019-08-29 10:19     ` Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 04/11] kselftest: arm64: mangle_pstate_invalid_mode_el Cristian Marussi
2019-08-13 16:24   ` Dave Martin
2019-08-29 11:50     ` Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 05/11] kselftest: arm64: mangle_pstate_ssbs_regs Cristian Marussi
2019-08-13 16:25   ` Dave Martin
2019-08-29 15:35     ` Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic Cristian Marussi
2019-08-13 16:25   ` Dave Martin
2019-08-30 14:29     ` Cristian Marussi
2019-09-04 10:05       ` Dave Martin
2019-09-04 10:37         ` Cristian Marussi
2019-09-04 10:47           ` Dave Martin
2019-08-02 17:02 ` [PATCH v3 07/11] kselftest: arm64: fake_sigreturn_bad_size_for_magic0 Cristian Marussi
2019-08-13 16:25   ` Dave Martin
2019-08-30 14:49     ` Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 08/11] kselftest: arm64: fake_sigreturn_missing_fpsimd Cristian Marussi
2019-08-13 16:26   ` Dave Martin
2019-08-30 14:55     ` Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 09/11] kselftest: arm64: fake_sigreturn_duplicated_fpsimd Cristian Marussi
2019-08-13 16:26   ` Dave Martin
2019-08-30 15:11     ` Cristian Marussi
2019-08-02 17:02 ` [PATCH v3 10/11] kselftest: arm64: fake_sigreturn_bad_size Cristian Marussi
2019-08-13 16:26   ` Dave Martin
2019-08-30 15:21     ` Cristian Marussi
2019-08-02 17:03 ` [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp Cristian Marussi
2019-08-07 16:04   ` Cristian Marussi
2019-08-13 16:28     ` Dave Martin
2019-08-30 15:22       ` Cristian Marussi
2019-08-13 16:27   ` Dave Martin
2019-08-30 16:33     ` Cristian Marussi
2019-08-13 16:22 ` [PATCH v3 00/11] Add arm64/signal initial kselftest support Dave Martin
2019-08-30 16:40   ` Cristian Marussi
2019-09-02 10:53     ` Dave Martin
2019-09-02 11:30       ` Cristian Marussi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).