diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-06-30 19:20:08 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-06-30 19:20:08 +0300 |
commit | d8b0bd57c2d68eb500f356f0f9228e6183da94ae (patch) | |
tree | 2da4c9148f96d7cbe86e98e39bff879c62525a3a /tools/testing | |
parent | b69f0aeb068980af983d399deafc7477cec8bc04 (diff) | |
parent | 54a11654de163994e32b24e3aa90ef81f4a3184d (diff) | |
download | linux-d8b0bd57c2d68eb500f356f0f9228e6183da94ae.tar.xz |
Merge tag 'powerpc-6.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc updates from Michael Ellerman:
- Extend KCSAN support to 32-bit and BookE. Add some KCSAN annotations
- Make ELFv2 ABI the default for 64-bit big-endian kernel builds, and
use the -mprofile-kernel option (kernel specific ftrace ABI) for big
endian ELFv2 kernels
- Add initial Dynamic Execution Control Register (DEXCR) support, and
allow the ROP protection instructions to be used on Power 10
- Various other small features and fixes
Thanks to Aditya Gupta, Aneesh Kumar K.V, Benjamin Gray, Brian King,
Christophe Leroy, Colin Ian King, Dmitry Torokhov, Gaurav Batra, Jean
Delvare, Joel Stanley, Marco Elver, Masahiro Yamada, Nageswara R Sastry,
Nathan Chancellor, Naveen N Rao, Nayna Jain, Nicholas Piggin, Paul
Gortmaker, Randy Dunlap, Rob Herring, Rohan McLure, Russell Currey,
Sachin Sant, Timothy Pearson, Tom Rix, and Uwe Kleine-König.
* tag 'powerpc-6.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (76 commits)
powerpc: remove checks for binutils older than 2.25
powerpc: Fail build if using recordmcount with binutils v2.37
powerpc/iommu: TCEs are incorrectly manipulated with DLPAR add/remove of memory
powerpc/iommu: Only build sPAPR access functions on pSeries
powerpc: powernv: Annotate data races in opal events
powerpc: Mark writes registering ipi to host cpu through kvm and polling
powerpc: Annotate accesses to ipi message flags
powerpc: powernv: Fix KCSAN datarace warnings on idle_state contention
powerpc: Mark [h]ssr_valid accesses in check_return_regs_valid
powerpc: qspinlock: Enforce qnode writes prior to publishing to queue
powerpc: qspinlock: Mark accesses to qnode lock checks
powerpc/powernv/pci: Remove last IODA1 defines
powerpc/powernv/pci: Remove MVE code
powerpc/powernv/pci: Remove ioda1 support
powerpc: 52xx: Make immr_id DT match tables static
powerpc: mpc512x: Remove open coded "ranges" parsing
powerpc: fsl_soc: Use of_range_to_resource() for "ranges" parsing
powerpc: fsl: Use of_property_read_reg() to parse "reg"
powerpc: fsl_rio: Use of_range_to_resource() for "ranges" parsing
macintosh: Use of_property_read_reg() to parse "reg"
...
Diffstat (limited to 'tools/testing')
-rw-r--r-- | tools/testing/selftests/powerpc/Makefile | 1 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/dexcr/.gitignore | 2 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/dexcr/Makefile | 9 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/dexcr/dexcr.c | 132 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/dexcr/dexcr.h | 49 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/dexcr/hashchk_test.c | 227 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/dexcr/lsdexcr.c | 141 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/include/reg.h | 4 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/include/utils.h | 31 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/pmu/sampling_tests/misc.h | 2 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/utils.c | 24 |
11 files changed, 619 insertions, 3 deletions
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index ae2bfc0d822f..49f2ad1793fd 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile @@ -17,6 +17,7 @@ SUB_DIRS = alignment \ benchmarks \ cache_shape \ copyloops \ + dexcr \ dscr \ mm \ nx-gzip \ diff --git a/tools/testing/selftests/powerpc/dexcr/.gitignore b/tools/testing/selftests/powerpc/dexcr/.gitignore new file mode 100644 index 000000000000..b82f45dd46b9 --- /dev/null +++ b/tools/testing/selftests/powerpc/dexcr/.gitignore @@ -0,0 +1,2 @@ +hashchk_test +lsdexcr diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile new file mode 100644 index 000000000000..76210f2bcec3 --- /dev/null +++ b/tools/testing/selftests/powerpc/dexcr/Makefile @@ -0,0 +1,9 @@ +TEST_GEN_PROGS := hashchk_test +TEST_GEN_FILES := lsdexcr + +include ../../lib.mk + +$(OUTPUT)/hashchk_test: CFLAGS += -fno-pie $(call cc-option,-mno-rop-protect) + +$(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c +$(TEST_GEN_FILES): ../utils.c ./dexcr.c diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr.c b/tools/testing/selftests/powerpc/dexcr/dexcr.c new file mode 100644 index 000000000000..65ec5347de98 --- /dev/null +++ b/tools/testing/selftests/powerpc/dexcr/dexcr.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <errno.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "dexcr.h" +#include "reg.h" +#include "utils.h" + +static jmp_buf generic_signal_jump_buf; + +static void generic_signal_handler(int signum, siginfo_t *info, void *context) +{ + longjmp(generic_signal_jump_buf, 0); +} + +bool dexcr_exists(void) +{ + struct sigaction old; + volatile bool exists; + + old = push_signal_handler(SIGILL, generic_signal_handler); + if (setjmp(generic_signal_jump_buf)) + goto out; + + /* + * If the SPR is not recognised by the hardware it triggers + * a hypervisor emulation interrupt. If the kernel does not + * recognise/try to emulate it, we receive a SIGILL signal. + * + * If we do not receive a signal, assume we have the SPR or the + * kernel is trying to emulate it correctly. + */ + exists = false; + mfspr(SPRN_DEXCR_RO); + exists = true; + +out: + pop_signal_handler(SIGILL, old); + return exists; +} + +/* + * Just test if a bad hashchk triggers a signal, without checking + * for support or if the NPHIE aspect is enabled. + */ +bool hashchk_triggers(void) +{ + struct sigaction old; + volatile bool triggers; + + old = push_signal_handler(SIGILL, generic_signal_handler); + if (setjmp(generic_signal_jump_buf)) + goto out; + + triggers = true; + do_bad_hashchk(); + triggers = false; + +out: + pop_signal_handler(SIGILL, old); + return triggers; +} + +unsigned int get_dexcr(enum dexcr_source source) +{ + switch (source) { + case DEXCR: + return mfspr(SPRN_DEXCR_RO); + case HDEXCR: + return mfspr(SPRN_HDEXCR_RO); + case EFFECTIVE: + return mfspr(SPRN_DEXCR_RO) | mfspr(SPRN_HDEXCR_RO); + default: + FAIL_IF_EXIT_MSG(true, "bad enum dexcr_source"); + } +} + +void await_child_success(pid_t pid) +{ + int wstatus; + + FAIL_IF_EXIT_MSG(pid == -1, "fork failed"); + FAIL_IF_EXIT_MSG(waitpid(pid, &wstatus, 0) == -1, "wait failed"); + FAIL_IF_EXIT_MSG(!WIFEXITED(wstatus), "child did not exit cleanly"); + FAIL_IF_EXIT_MSG(WEXITSTATUS(wstatus) != 0, "child exit error"); +} + +/* + * Perform a hashst instruction. The following components determine the result + * + * 1. The LR value (any register technically) + * 2. The SP value (also any register, but it must be a valid address) + * 3. A secret key managed by the kernel + * + * The result is stored to the address held in SP. + */ +void hashst(unsigned long lr, void *sp) +{ + asm volatile ("addi 31, %0, 0;" /* set r31 (pretend LR) to lr */ + "addi 30, %1, 8;" /* set r30 (pretend SP) to sp + 8 */ + PPC_RAW_HASHST(31, -8, 30) /* compute hash into stack location */ + : : "r" (lr), "r" (sp) : "r31", "r30", "memory"); +} + +/* + * Perform a hashchk instruction. A hash is computed as per hashst(), + * however the result is not stored to memory. Instead the existing + * value is read and compared against the computed hash. + * + * If they match, execution continues. + * If they differ, an interrupt triggers. + */ +void hashchk(unsigned long lr, void *sp) +{ + asm volatile ("addi 31, %0, 0;" /* set r31 (pretend LR) to lr */ + "addi 30, %1, 8;" /* set r30 (pretend SP) to sp + 8 */ + PPC_RAW_HASHCHK(31, -8, 30) /* check hash at stack location */ + : : "r" (lr), "r" (sp) : "r31", "r30", "memory"); +} + +void do_bad_hashchk(void) +{ + unsigned long hash = 0; + + hashst(0, &hash); + hash += 1; + hashchk(0, &hash); +} diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr.h b/tools/testing/selftests/powerpc/dexcr/dexcr.h new file mode 100644 index 000000000000..f55cbbc8643b --- /dev/null +++ b/tools/testing/selftests/powerpc/dexcr/dexcr.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * POWER Dynamic Execution Control Facility (DEXCR) + * + * This header file contains helper functions and macros + * required for all the DEXCR related test cases. + */ +#ifndef _SELFTESTS_POWERPC_DEXCR_DEXCR_H +#define _SELFTESTS_POWERPC_DEXCR_DEXCR_H + +#include <stdbool.h> +#include <sys/types.h> + +#include "reg.h" + +#define DEXCR_PR_BIT(aspect) __MASK(63 - (32 + (aspect))) +#define DEXCR_PR_SBHE DEXCR_PR_BIT(0) +#define DEXCR_PR_IBRTPD DEXCR_PR_BIT(3) +#define DEXCR_PR_SRAPD DEXCR_PR_BIT(4) +#define DEXCR_PR_NPHIE DEXCR_PR_BIT(5) + +#define PPC_RAW_HASH_ARGS(b, i, a) \ + ((((i) >> 3) & 0x1F) << 21 | (a) << 16 | (b) << 11 | (((i) >> 8) & 0x1)) +#define PPC_RAW_HASHST(b, i, a) \ + str(.long (0x7C0005A4 | PPC_RAW_HASH_ARGS(b, i, a));) +#define PPC_RAW_HASHCHK(b, i, a) \ + str(.long (0x7C0005E4 | PPC_RAW_HASH_ARGS(b, i, a));) + +bool dexcr_exists(void); + +bool hashchk_triggers(void); + +enum dexcr_source { + DEXCR, /* Userspace DEXCR value */ + HDEXCR, /* Hypervisor enforced DEXCR value */ + EFFECTIVE, /* Bitwise OR of UDEXCR and ENFORCED DEXCR bits */ +}; + +unsigned int get_dexcr(enum dexcr_source source); + +void await_child_success(pid_t pid); + +void hashst(unsigned long lr, void *sp); + +void hashchk(unsigned long lr, void *sp); + +void do_bad_hashchk(void); + +#endif /* _SELFTESTS_POWERPC_DEXCR_DEXCR_H */ diff --git a/tools/testing/selftests/powerpc/dexcr/hashchk_test.c b/tools/testing/selftests/powerpc/dexcr/hashchk_test.c new file mode 100644 index 000000000000..7d5658c9ebe4 --- /dev/null +++ b/tools/testing/selftests/powerpc/dexcr/hashchk_test.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#define _GNU_SOURCE + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <sched.h> +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/prctl.h> +#include <unistd.h> + +#include "dexcr.h" +#include "utils.h" + +static int require_nphie(void) +{ + SKIP_IF_MSG(!dexcr_exists(), "DEXCR not supported"); + SKIP_IF_MSG(!(get_dexcr(EFFECTIVE) & DEXCR_PR_NPHIE), + "DEXCR[NPHIE] not enabled"); + + return 0; +} + +static jmp_buf hashchk_detected_buf; +static const char *hashchk_failure_msg; + +static void hashchk_handler(int signum, siginfo_t *info, void *context) +{ + if (signum != SIGILL) + hashchk_failure_msg = "wrong signal received"; + else if (info->si_code != ILL_ILLOPN) + hashchk_failure_msg = "wrong signal code received"; + + longjmp(hashchk_detected_buf, 0); +} + +/* + * Check that hashchk triggers when DEXCR[NPHIE] is enabled + * and is detected as such by the kernel exception handler + */ +static int hashchk_detected_test(void) +{ + struct sigaction old; + int err; + + err = require_nphie(); + if (err) + return err; + + old = push_signal_handler(SIGILL, hashchk_handler); + if (setjmp(hashchk_detected_buf)) + goto out; + + hashchk_failure_msg = NULL; + do_bad_hashchk(); + hashchk_failure_msg = "hashchk failed to trigger"; + +out: + pop_signal_handler(SIGILL, old); + FAIL_IF_MSG(hashchk_failure_msg, hashchk_failure_msg); + return 0; +} + +#define HASH_COUNT 8 + +static unsigned long hash_values[HASH_COUNT + 1]; + +static void fill_hash_values(void) +{ + for (unsigned long i = 0; i < HASH_COUNT; i++) + hashst(i, &hash_values[i]); + + /* Used to ensure the checks uses the same addresses as the hashes */ + hash_values[HASH_COUNT] = (unsigned long)&hash_values; +} + +static unsigned int count_hash_values_matches(void) +{ + unsigned long matches = 0; + + for (unsigned long i = 0; i < HASH_COUNT; i++) { + unsigned long orig_hash = hash_values[i]; + hash_values[i] = 0; + + hashst(i, &hash_values[i]); + + if (hash_values[i] == orig_hash) + matches++; + } + + return matches; +} + +static int hashchk_exec_child(void) +{ + ssize_t count; + + fill_hash_values(); + + count = write(STDOUT_FILENO, hash_values, sizeof(hash_values)); + return count == sizeof(hash_values) ? 0 : EOVERFLOW; +} + +static char *hashchk_exec_child_args[] = { "hashchk_exec_child", NULL }; + +/* + * Check that new programs get different keys so a malicious process + * can't recreate a victim's hash values. + */ +static int hashchk_exec_random_key_test(void) +{ + pid_t pid; + int err; + int pipefd[2]; + + err = require_nphie(); + if (err) + return err; + + FAIL_IF_MSG(pipe(pipefd), "failed to create pipe"); + + pid = fork(); + if (pid == 0) { + if (dup2(pipefd[1], STDOUT_FILENO) == -1) + _exit(errno); + + execve("/proc/self/exe", hashchk_exec_child_args, NULL); + _exit(errno); + } + + await_child_success(pid); + FAIL_IF_MSG(read(pipefd[0], hash_values, sizeof(hash_values)) != sizeof(hash_values), + "missing expected child output"); + + /* Verify the child used the same hash_values address */ + FAIL_IF_EXIT_MSG(hash_values[HASH_COUNT] != (unsigned long)&hash_values, + "bad address check"); + + /* If all hashes are the same it means (most likely) same key */ + FAIL_IF_MSG(count_hash_values_matches() == HASH_COUNT, "shared key detected"); + + return 0; +} + +/* + * Check that forks share the same key so that existing hash values + * remain valid. + */ +static int hashchk_fork_share_key_test(void) +{ + pid_t pid; + int err; + + err = require_nphie(); + if (err) + return err; + + fill_hash_values(); + + pid = fork(); + if (pid == 0) { + if (count_hash_values_matches() != HASH_COUNT) + _exit(1); + _exit(0); + } + + await_child_success(pid); + return 0; +} + +#define STACK_SIZE (1024 * 1024) + +static int hashchk_clone_child_fn(void *args) +{ + fill_hash_values(); + return 0; +} + +/* + * Check that threads share the same key so that existing hash values + * remain valid. + */ +static int hashchk_clone_share_key_test(void) +{ + void *child_stack; + pid_t pid; + int err; + + err = require_nphie(); + if (err) + return err; + + child_stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + + FAIL_IF_MSG(child_stack == MAP_FAILED, "failed to map child stack"); + + pid = clone(hashchk_clone_child_fn, child_stack + STACK_SIZE, + CLONE_VM | SIGCHLD, NULL); + + await_child_success(pid); + FAIL_IF_MSG(count_hash_values_matches() != HASH_COUNT, + "different key detected"); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int err = 0; + + if (argc >= 1 && !strcmp(argv[0], hashchk_exec_child_args[0])) + return hashchk_exec_child(); + + err |= test_harness(hashchk_detected_test, "hashchk_detected"); + err |= test_harness(hashchk_exec_random_key_test, "hashchk_exec_random_key"); + err |= test_harness(hashchk_fork_share_key_test, "hashchk_fork_share_key"); + err |= test_harness(hashchk_clone_share_key_test, "hashchk_clone_share_key"); + + return err; +} diff --git a/tools/testing/selftests/powerpc/dexcr/lsdexcr.c b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c new file mode 100644 index 000000000000..94abbfcc389e --- /dev/null +++ b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +#include "dexcr.h" +#include "utils.h" + +static unsigned int dexcr; +static unsigned int hdexcr; +static unsigned int effective; + +struct dexcr_aspect { + const char *name; + const char *desc; + unsigned int index; +}; + +static const struct dexcr_aspect aspects[] = { + { + .name = "SBHE", + .desc = "Speculative branch hint enable", + .index = 0, + }, + { + .name = "IBRTPD", + .desc = "Indirect branch recurrent target prediction disable", + .index = 3, + }, + { + .name = "SRAPD", + .desc = "Subroutine return address prediction disable", + .index = 4, + }, + { + .name = "NPHIE", + .desc = "Non-privileged hash instruction enable", + .index = 5, + }, + { + .name = "PHIE", + .desc = "Privileged hash instruction enable", + .index = 6, + }, +}; + +static void print_list(const char *list[], size_t len) +{ + for (size_t i = 0; i < len; i++) { + printf("%s", list[i]); + if (i + 1 < len) + printf(", "); + } +} + +static void print_dexcr(char *name, unsigned int bits) +{ + const char *enabled_aspects[ARRAY_SIZE(aspects) + 1] = {NULL}; + size_t j = 0; + + printf("%s: %08x", name, bits); + + if (bits == 0) { + printf("\n"); + return; + } + + for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) { + unsigned int mask = DEXCR_PR_BIT(aspects[i].index); + + if (bits & mask) { + enabled_aspects[j++] = aspects[i].name; + bits &= ~mask; + } + } + + if (bits) + enabled_aspects[j++] = "unknown"; + + printf(" ("); + print_list(enabled_aspects, j); + printf(")\n"); +} + +static void print_aspect(const struct dexcr_aspect *aspect) +{ + const char *attributes[8] = {NULL}; + size_t j = 0; + unsigned long mask; + + mask = DEXCR_PR_BIT(aspect->index); + if (dexcr & mask) + attributes[j++] = "set"; + if (hdexcr & mask) + attributes[j++] = "set (hypervisor)"; + if (!(effective & mask)) + attributes[j++] = "clear"; + + printf("%12s %c (%d): ", aspect->name, effective & mask ? '*' : ' ', aspect->index); + print_list(attributes, j); + printf(" \t(%s)\n", aspect->desc); +} + +int main(int argc, char *argv[]) +{ + if (!dexcr_exists()) { + printf("DEXCR not detected on this hardware\n"); + return 1; + } + + dexcr = get_dexcr(DEXCR); + hdexcr = get_dexcr(HDEXCR); + effective = dexcr | hdexcr; + + print_dexcr(" DEXCR", dexcr); + print_dexcr(" HDEXCR", hdexcr); + print_dexcr("Effective", effective); + printf("\n"); + + for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) + print_aspect(&aspects[i]); + printf("\n"); + + if (effective & DEXCR_PR_NPHIE) { + printf("DEXCR[NPHIE] enabled: hashst/hashchk "); + if (hashchk_triggers()) + printf("working\n"); + else + printf("failed to trigger\n"); + } else { + printf("DEXCR[NPHIE] disabled: hashst/hashchk "); + if (hashchk_triggers()) + printf("unexpectedly triggered\n"); + else + printf("ignored\n"); + } + + return 0; +} diff --git a/tools/testing/selftests/powerpc/include/reg.h b/tools/testing/selftests/powerpc/include/reg.h index d5a547f72669..fad09c9d3387 100644 --- a/tools/testing/selftests/powerpc/include/reg.h +++ b/tools/testing/selftests/powerpc/include/reg.h @@ -19,6 +19,8 @@ #define mb() asm volatile("sync" : : : "memory"); #define barrier() asm volatile("" : : : "memory"); +#define SPRN_HDEXCR_RO 455 /* Userspace readonly view of SPRN_HDEXCR (471) */ + #define SPRN_MMCR2 769 #define SPRN_MMCRA 770 #define SPRN_MMCR0 779 @@ -47,6 +49,8 @@ #define SPRN_SDAR 781 #define SPRN_SIER 768 +#define SPRN_DEXCR_RO 812 /* Userspace readonly view of SPRN_DEXCR (828) */ + #define SPRN_TEXASR 0x82 /* Transaction Exception and Status Register */ #define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */ #define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */ diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h index 44bfd48b93d6..36c30c611457 100644 --- a/tools/testing/selftests/powerpc/include/utils.h +++ b/tools/testing/selftests/powerpc/include/utils.h @@ -9,11 +9,18 @@ #define __cacheline_aligned __attribute__((aligned(128))) #include <stdint.h> +#include <stdio.h> #include <stdbool.h> +#include <sys/signal.h> #include <linux/auxvec.h> #include <linux/perf_event.h> #include <asm/cputable.h> #include "reg.h" +#include <unistd.h> + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif /* Avoid headaches with PRI?64 - just use %ll? always */ typedef unsigned long long u64; @@ -67,7 +74,6 @@ struct perf_event_read { }; #if !defined(__GLIBC_PREREQ) || !__GLIBC_PREREQ(2, 30) -#include <unistd.h> #include <sys/syscall.h> static inline pid_t gettid(void) @@ -106,6 +112,9 @@ static inline char *auxv_platform(void) bool is_ppc64le(void); int using_hash_mmu(bool *using_hash); +struct sigaction push_signal_handler(int sig, void (*fn)(int, siginfo_t *, void *)); +struct sigaction pop_signal_handler(int sig, struct sigaction old_handler); + /* Yes, this is evil */ #define FAIL_IF(x) \ do { \ @@ -116,6 +125,16 @@ do { \ } \ } while (0) +#define FAIL_IF_MSG(x, msg) \ +do { \ + if ((x)) { \ + fprintf(stderr, \ + "[FAIL] Test FAILED on line %d: %s\n", \ + __LINE__, msg); \ + return 1; \ + } \ +} while (0) + #define FAIL_IF_EXIT(x) \ do { \ if ((x)) { \ @@ -125,6 +144,16 @@ do { \ } \ } while (0) +#define FAIL_IF_EXIT_MSG(x, msg) \ +do { \ + if ((x)) { \ + fprintf(stderr, \ + "[FAIL] Test FAILED on line %d: %s\n", \ + __LINE__, msg); \ + _exit(1); \ + } \ +} while (0) + /* The test harness uses this, yes it's gross */ #define MAGIC_SKIP_RETURN_VALUE 99 diff --git a/tools/testing/selftests/powerpc/pmu/sampling_tests/misc.h b/tools/testing/selftests/powerpc/pmu/sampling_tests/misc.h index 4181755cf5a0..64e25cce1435 100644 --- a/tools/testing/selftests/powerpc/pmu/sampling_tests/misc.h +++ b/tools/testing/selftests/powerpc/pmu/sampling_tests/misc.h @@ -18,8 +18,6 @@ #define MMCR1_RSQ 0x200000000000ULL /* radix scope qual field */ #define BHRB_DISABLE 0x2000000000ULL /* MMCRA BHRB DISABLE bit */ -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - extern int ev_mask_pmcxsel, ev_shift_pmcxsel; extern int ev_mask_marked, ev_shift_marked; extern int ev_mask_comb, ev_shift_comb; diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c index 252fb4a95e90..e5f2d8735c64 100644 --- a/tools/testing/selftests/powerpc/utils.c +++ b/tools/testing/selftests/powerpc/utils.c @@ -618,3 +618,27 @@ out: fclose(f); return rc; } + +struct sigaction push_signal_handler(int sig, void (*fn)(int, siginfo_t *, void *)) +{ + struct sigaction sa; + struct sigaction old_handler; + + sa.sa_sigaction = fn; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + FAIL_IF_EXIT_MSG(sigaction(sig, &sa, &old_handler), + "failed to push signal handler"); + + return old_handler; +} + +struct sigaction pop_signal_handler(int sig, struct sigaction old_handler) +{ + struct sigaction popped; + + FAIL_IF_EXIT_MSG(sigaction(sig, &old_handler, &popped), + "failed to pop signal handler"); + + return popped; +} |