diff options
-rw-r--r-- | tools/testing/selftests/powerpc/tm/.gitignore | 1 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/tm/Makefile | 2 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c | 74 |
3 files changed, 76 insertions, 1 deletions
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 2699635d2cd9..61c318fdace4 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore | |||
@@ -1,2 +1,3 @@ | |||
1 | tm-resched-dscr | 1 | tm-resched-dscr |
2 | tm-syscall | 2 | tm-syscall |
3 | tm-signal-msr-resv | ||
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 63b55d01da35..c6b4ca8b2812 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | TEST_PROGS := tm-resched-dscr tm-syscall | 1 | TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv |
2 | 2 | ||
3 | all: $(TEST_PROGS) | 3 | all: $(TEST_PROGS) |
4 | 4 | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c new file mode 100644 index 000000000000..d86653f282b1 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Michael Neuling, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * | ||
5 | * Test the kernel's signal return code to ensure that it doesn't | ||
6 | * crash when both the transactional and suspend MSR bits are set in | ||
7 | * the signal context. | ||
8 | * | ||
9 | * For this test, we send ourselves a SIGUSR1. In the SIGUSR1 handler | ||
10 | * we modify the signal context to set both MSR TM S and T bits (which | ||
11 | * is "reserved" by the PowerISA). When we return from the signal | ||
12 | * handler (implicit sigreturn), the kernel should detect reserved MSR | ||
13 | * value and send us with a SIGSEGV. | ||
14 | */ | ||
15 | |||
16 | #include <stdlib.h> | ||
17 | #include <stdio.h> | ||
18 | #include <signal.h> | ||
19 | #include <unistd.h> | ||
20 | |||
21 | #include "utils.h" | ||
22 | #include "tm.h" | ||
23 | |||
24 | int segv_expected = 0; | ||
25 | |||
26 | void signal_segv(int signum) | ||
27 | { | ||
28 | if (segv_expected && (signum == SIGSEGV)) | ||
29 | _exit(0); | ||
30 | _exit(1); | ||
31 | } | ||
32 | |||
33 | void signal_usr1(int signum, siginfo_t *info, void *uc) | ||
34 | { | ||
35 | ucontext_t *ucp = uc; | ||
36 | |||
37 | /* Link tm checkpointed context to normal context */ | ||
38 | ucp->uc_link = ucp; | ||
39 | /* Set all TM bits so that the context is now invalid */ | ||
40 | #ifdef __powerpc64__ | ||
41 | ucp->uc_mcontext.gp_regs[PT_MSR] |= (7ULL << 32); | ||
42 | #else | ||
43 | ucp->uc_mcontext.regs->gpr[PT_MSR] |= (7ULL); | ||
44 | #endif | ||
45 | /* Should segv on return becuase of invalid context */ | ||
46 | segv_expected = 1; | ||
47 | } | ||
48 | |||
49 | int tm_signal_msr_resv() | ||
50 | { | ||
51 | struct sigaction act; | ||
52 | |||
53 | SKIP_IF(!have_htm()); | ||
54 | |||
55 | act.sa_sigaction = signal_usr1; | ||
56 | sigemptyset(&act.sa_mask); | ||
57 | act.sa_flags = SA_SIGINFO; | ||
58 | if (sigaction(SIGUSR1, &act, NULL) < 0) { | ||
59 | perror("sigaction sigusr1"); | ||
60 | exit(1); | ||
61 | } | ||
62 | if (signal(SIGSEGV, signal_segv) == SIG_ERR) | ||
63 | exit(1); | ||
64 | |||
65 | raise(SIGUSR1); | ||
66 | |||
67 | /* We shouldn't get here as we exit in the segv handler */ | ||
68 | return 1; | ||
69 | } | ||
70 | |||
71 | int main(void) | ||
72 | { | ||
73 | return test_harness(tm_signal_msr_resv, "tm_signal_msr_resv"); | ||
74 | } | ||