aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/powerpc/Makefile3
-rw-r--r--tools/testing/selftests/powerpc/include/reg.h1
-rw-r--r--tools/testing/selftests/powerpc/include/utils.h18
-rw-r--r--tools/testing/selftests/powerpc/mm/.gitignore3
-rw-r--r--tools/testing/selftests/powerpc/mm/Makefile4
-rw-r--r--tools/testing/selftests/powerpc/mm/wild_bctr.c155
-rw-r--r--tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c8
-rw-r--r--tools/testing/selftests/powerpc/ptrace/Makefile2
-rw-r--r--tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c228
-rw-r--r--tools/testing/selftests/powerpc/security/Makefile9
-rw-r--r--tools/testing/selftests/powerpc/security/rfi_flush.c132
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-tmspr.c27
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-unavailable.c9
-rw-r--r--tools/testing/selftests/powerpc/tm/tm.h9
-rw-r--r--tools/testing/selftests/powerpc/utils.c152
15 files changed, 735 insertions, 25 deletions
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 201b598558b9..b3ad909aefbc 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -28,7 +28,8 @@ SUB_DIRS = alignment \
28 tm \ 28 tm \
29 vphn \ 29 vphn \
30 math \ 30 math \
31 ptrace 31 ptrace \
32 security
32 33
33endif 34endif
34 35
diff --git a/tools/testing/selftests/powerpc/include/reg.h b/tools/testing/selftests/powerpc/include/reg.h
index 7f348c059bc2..52b4710469d2 100644
--- a/tools/testing/selftests/powerpc/include/reg.h
+++ b/tools/testing/selftests/powerpc/include/reg.h
@@ -17,6 +17,7 @@
17 : "memory") 17 : "memory")
18 18
19#define mb() asm volatile("sync" : : : "memory"); 19#define mb() asm volatile("sync" : : : "memory");
20#define barrier() asm volatile("" : : : "memory");
20 21
21#define SPRN_MMCR2 769 22#define SPRN_MMCR2 769
22#define SPRN_MMCRA 770 23#define SPRN_MMCRA 770
diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h
index c58c370828b4..49621822d7c3 100644
--- a/tools/testing/selftests/powerpc/include/utils.h
+++ b/tools/testing/selftests/powerpc/include/utils.h
@@ -11,6 +11,7 @@
11#include <stdint.h> 11#include <stdint.h>
12#include <stdbool.h> 12#include <stdbool.h>
13#include <linux/auxvec.h> 13#include <linux/auxvec.h>
14#include <linux/perf_event.h>
14#include "reg.h" 15#include "reg.h"
15 16
16/* Avoid headaches with PRI?64 - just use %ll? always */ 17/* Avoid headaches with PRI?64 - just use %ll? always */
@@ -31,6 +32,15 @@ void *get_auxv_entry(int type);
31 32
32int pick_online_cpu(void); 33int pick_online_cpu(void);
33 34
35int read_debugfs_file(char *debugfs_file, int *result);
36int write_debugfs_file(char *debugfs_file, int result);
37void set_dscr(unsigned long val);
38int perf_event_open_counter(unsigned int type,
39 unsigned long config, int group_fd);
40int perf_event_enable(int fd);
41int perf_event_disable(int fd);
42int perf_event_reset(int fd);
43
34static inline bool have_hwcap(unsigned long ftr) 44static inline bool have_hwcap(unsigned long ftr)
35{ 45{
36 return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr; 46 return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr;
@@ -80,4 +90,12 @@ do { \
80#define PPC_FEATURE2_ARCH_3_00 0x00800000 90#define PPC_FEATURE2_ARCH_3_00 0x00800000
81#endif 91#endif
82 92
93#if defined(__powerpc64__)
94#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP]
95#elif defined(__powerpc__)
96#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP]
97#else
98#error implement UCONTEXT_NIA
99#endif
100
83#endif /* _SELFTESTS_POWERPC_UTILS_H */ 101#endif /* _SELFTESTS_POWERPC_UTILS_H */
diff --git a/tools/testing/selftests/powerpc/mm/.gitignore b/tools/testing/selftests/powerpc/mm/.gitignore
index 7d7c42ed6de9..ba919308fe30 100644
--- a/tools/testing/selftests/powerpc/mm/.gitignore
+++ b/tools/testing/selftests/powerpc/mm/.gitignore
@@ -2,4 +2,5 @@ hugetlb_vs_thp_test
2subpage_prot 2subpage_prot
3tempfile 3tempfile
4prot_sao 4prot_sao
5segv_errors \ No newline at end of file 5segv_errors
6wild_bctr \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/mm/Makefile b/tools/testing/selftests/powerpc/mm/Makefile
index 33ced6e0ad25..43d68420e363 100644
--- a/tools/testing/selftests/powerpc/mm/Makefile
+++ b/tools/testing/selftests/powerpc/mm/Makefile
@@ -2,7 +2,7 @@
2noarg: 2noarg:
3 $(MAKE) -C ../ 3 $(MAKE) -C ../
4 4
5TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors 5TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors wild_bctr
6TEST_GEN_FILES := tempfile 6TEST_GEN_FILES := tempfile
7 7
8top_srcdir = ../../../../.. 8top_srcdir = ../../../../..
@@ -12,6 +12,8 @@ $(TEST_GEN_PROGS): ../harness.c
12 12
13$(OUTPUT)/prot_sao: ../utils.c 13$(OUTPUT)/prot_sao: ../utils.c
14 14
15$(OUTPUT)/wild_bctr: CFLAGS += -m64
16
15$(OUTPUT)/tempfile: 17$(OUTPUT)/tempfile:
16 dd if=/dev/zero of=$@ bs=64k count=1 18 dd if=/dev/zero of=$@ bs=64k count=1
17 19
diff --git a/tools/testing/selftests/powerpc/mm/wild_bctr.c b/tools/testing/selftests/powerpc/mm/wild_bctr.c
new file mode 100644
index 000000000000..1b0e9e9a2ddc
--- /dev/null
+++ b/tools/testing/selftests/powerpc/mm/wild_bctr.c
@@ -0,0 +1,155 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018, Michael Ellerman, IBM Corp.
4 *
5 * Test that an out-of-bounds branch to counter behaves as expected.
6 */
7
8#include <setjmp.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/mman.h>
13#include <sys/types.h>
14#include <sys/wait.h>
15#include <ucontext.h>
16#include <unistd.h>
17
18#include "utils.h"
19
20
21#define BAD_NIP 0x788c545a18000000ull
22
23static struct pt_regs signal_regs;
24static jmp_buf setjmp_env;
25
26static void save_regs(ucontext_t *ctxt)
27{
28 struct pt_regs *regs = ctxt->uc_mcontext.regs;
29
30 memcpy(&signal_regs, regs, sizeof(signal_regs));
31}
32
33static void segv_handler(int signum, siginfo_t *info, void *ctxt_v)
34{
35 save_regs(ctxt_v);
36 longjmp(setjmp_env, 1);
37}
38
39static void usr2_handler(int signum, siginfo_t *info, void *ctxt_v)
40{
41 save_regs(ctxt_v);
42}
43
44static int ok(void)
45{
46 printf("Everything is OK in here.\n");
47 return 0;
48}
49
50#define REG_POISON 0x5a5aUL
51#define POISONED_REG(n) ((REG_POISON << 48) | ((n) << 32) | (REG_POISON << 16) | (n))
52
53static inline void poison_regs(void)
54{
55 #define POISON_REG(n) \
56 "lis " __stringify(n) "," __stringify(REG_POISON) ";" \
57 "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";" \
58 "sldi " __stringify(n) "," __stringify(n) ", 32 ;" \
59 "oris " __stringify(n) "," __stringify(n) "," __stringify(REG_POISON) ";" \
60 "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";"
61
62 asm (POISON_REG(15)
63 POISON_REG(16)
64 POISON_REG(17)
65 POISON_REG(18)
66 POISON_REG(19)
67 POISON_REG(20)
68 POISON_REG(21)
69 POISON_REG(22)
70 POISON_REG(23)
71 POISON_REG(24)
72 POISON_REG(25)
73 POISON_REG(26)
74 POISON_REG(27)
75 POISON_REG(28)
76 POISON_REG(29)
77 : // inputs
78 : // outputs
79 : "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
80 "26", "27", "28", "29"
81 );
82 #undef POISON_REG
83}
84
85static int check_regs(void)
86{
87 unsigned long i;
88
89 for (i = 15; i <= 29; i++)
90 FAIL_IF(signal_regs.gpr[i] != POISONED_REG(i));
91
92 printf("Regs OK\n");
93 return 0;
94}
95
96static void dump_regs(void)
97{
98 for (int i = 0; i < 32; i += 4) {
99 printf("r%02d 0x%016lx r%02d 0x%016lx " \
100 "r%02d 0x%016lx r%02d 0x%016lx\n",
101 i, signal_regs.gpr[i],
102 i+1, signal_regs.gpr[i+1],
103 i+2, signal_regs.gpr[i+2],
104 i+3, signal_regs.gpr[i+3]);
105 }
106}
107
108int test_wild_bctr(void)
109{
110 int (*func_ptr)(void);
111 struct sigaction segv = {
112 .sa_sigaction = segv_handler,
113 .sa_flags = SA_SIGINFO
114 };
115 struct sigaction usr2 = {
116 .sa_sigaction = usr2_handler,
117 .sa_flags = SA_SIGINFO
118 };
119
120 FAIL_IF(sigaction(SIGSEGV, &segv, NULL));
121 FAIL_IF(sigaction(SIGUSR2, &usr2, NULL));
122
123 bzero(&signal_regs, sizeof(signal_regs));
124
125 if (setjmp(setjmp_env) == 0) {
126 func_ptr = ok;
127 func_ptr();
128
129 kill(getpid(), SIGUSR2);
130 printf("Regs before:\n");
131 dump_regs();
132 bzero(&signal_regs, sizeof(signal_regs));
133
134 poison_regs();
135
136 func_ptr = (int (*)(void))BAD_NIP;
137 func_ptr();
138
139 FAIL_IF(1); /* we didn't segv? */
140 }
141
142 FAIL_IF(signal_regs.nip != BAD_NIP);
143
144 printf("All good - took SEGV as expected branching to 0x%llx\n", BAD_NIP);
145
146 dump_regs();
147 FAIL_IF(check_regs());
148
149 return 0;
150}
151
152int main(void)
153{
154 return test_harness(test_wild_bctr, "wild_bctr");
155}
diff --git a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
index ed3239bbfae2..ee1e9ca22f0d 100644
--- a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
+++ b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
@@ -65,14 +65,6 @@ static int unprotect_region(void)
65extern char __start___ex_table[]; 65extern char __start___ex_table[];
66extern char __stop___ex_table[]; 66extern char __stop___ex_table[];
67 67
68#if defined(__powerpc64__)
69#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP]
70#elif defined(__powerpc__)
71#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP]
72#else
73#error implement UCONTEXT_NIA
74#endif
75
76struct extbl_entry { 68struct extbl_entry {
77 int insn; 69 int insn;
78 int fixup; 70 int fixup;
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile
index 923d531265f8..9b35ca8e8f13 100644
--- a/tools/testing/selftests/powerpc/ptrace/Makefile
+++ b/tools/testing/selftests/powerpc/ptrace/Makefile
@@ -2,7 +2,7 @@
2TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \ 2TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \
3 ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \ 3 ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \
4 ptrace-tm-spd-vsx ptrace-tm-spr ptrace-hwbreak ptrace-pkey core-pkey \ 4 ptrace-tm-spd-vsx ptrace-tm-spr ptrace-hwbreak ptrace-pkey core-pkey \
5 perf-hwbreak 5 perf-hwbreak ptrace-syscall
6 6
7top_srcdir = ../../../../.. 7top_srcdir = ../../../../..
8include ../../lib.mk 8include ../../lib.mk
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c b/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c
new file mode 100644
index 000000000000..3353210dcdbd
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace-syscall.c
@@ -0,0 +1,228 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * A ptrace test for testing PTRACE_SYSEMU, PTRACE_SETREGS and
4 * PTRACE_GETREG. This test basically create a child process that executes
5 * syscalls and the parent process check if it is being traced appropriated.
6 *
7 * This test is heavily based on tools/testing/selftests/x86/ptrace_syscall.c
8 * test, and it was adapted to run on Powerpc by
9 * Breno Leitao <leitao@debian.org>
10 */
11#define _GNU_SOURCE
12
13#include <sys/ptrace.h>
14#include <sys/types.h>
15#include <sys/wait.h>
16#include <sys/syscall.h>
17#include <sys/user.h>
18#include <unistd.h>
19#include <errno.h>
20#include <stddef.h>
21#include <stdio.h>
22#include <err.h>
23#include <string.h>
24#include <sys/auxv.h>
25#include "utils.h"
26
27/* Bitness-agnostic defines for user_regs_struct fields. */
28#define user_syscall_nr gpr[0]
29#define user_arg0 gpr[3]
30#define user_arg1 gpr[4]
31#define user_arg2 gpr[5]
32#define user_arg3 gpr[6]
33#define user_arg4 gpr[7]
34#define user_arg5 gpr[8]
35#define user_ip nip
36
37#define PTRACE_SYSEMU 0x1d
38
39static int nerrs;
40
41static void wait_trap(pid_t chld)
42{
43 siginfo_t si;
44
45 if (waitid(P_PID, chld, &si, WEXITED|WSTOPPED) != 0)
46 err(1, "waitid");
47 if (si.si_pid != chld)
48 errx(1, "got unexpected pid in event\n");
49 if (si.si_code != CLD_TRAPPED)
50 errx(1, "got unexpected event type %d\n", si.si_code);
51}
52
53static void test_ptrace_syscall_restart(void)
54{
55 int status;
56 struct pt_regs regs;
57 pid_t chld;
58
59 printf("[RUN]\tptrace-induced syscall restart\n");
60
61 chld = fork();
62 if (chld < 0)
63 err(1, "fork");
64
65 /*
66 * Child process is running 4 syscalls after ptrace.
67 *
68 * 1) getpid()
69 * 2) gettid()
70 * 3) tgkill() -> Send SIGSTOP
71 * 4) gettid() -> Where the tests will happen essentially
72 */
73 if (chld == 0) {
74 if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0)
75 err(1, "PTRACE_TRACEME");
76
77 pid_t pid = getpid(), tid = syscall(SYS_gettid);
78
79 printf("\tChild will make one syscall\n");
80 syscall(SYS_tgkill, pid, tid, SIGSTOP);
81
82 syscall(SYS_gettid, 10, 11, 12, 13, 14, 15);
83 _exit(0);
84 }
85 /* Parent process below */
86
87 /* Wait for SIGSTOP sent by tgkill above. */
88 if (waitpid(chld, &status, 0) != chld || !WIFSTOPPED(status))
89 err(1, "waitpid");
90
91 printf("[RUN]\tSYSEMU\n");
92 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
93 err(1, "PTRACE_SYSEMU");
94 wait_trap(chld);
95
96 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
97 err(1, "PTRACE_GETREGS");
98
99 /*
100 * Ptrace trapped prior to executing the syscall, thus r3 still has
101 * the syscall number instead of the sys_gettid() result
102 */
103 if (regs.user_syscall_nr != SYS_gettid ||
104 regs.user_arg0 != 10 || regs.user_arg1 != 11 ||
105 regs.user_arg2 != 12 || regs.user_arg3 != 13 ||
106 regs.user_arg4 != 14 || regs.user_arg5 != 15) {
107 printf("[FAIL]\tInitial args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n",
108 (unsigned long)regs.user_syscall_nr,
109 (unsigned long)regs.user_arg0,
110 (unsigned long)regs.user_arg1,
111 (unsigned long)regs.user_arg2,
112 (unsigned long)regs.user_arg3,
113 (unsigned long)regs.user_arg4,
114 (unsigned long)regs.user_arg5);
115 nerrs++;
116 } else {
117 printf("[OK]\tInitial nr and args are correct\n"); }
118
119 printf("[RUN]\tRestart the syscall (ip = 0x%lx)\n",
120 (unsigned long)regs.user_ip);
121
122 /*
123 * Rewind to retry the same syscall again. This will basically test
124 * the rewind process together with PTRACE_SETREGS and PTRACE_GETREGS.
125 */
126 regs.user_ip -= 4;
127 if (ptrace(PTRACE_SETREGS, chld, 0, &regs) != 0)
128 err(1, "PTRACE_SETREGS");
129
130 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
131 err(1, "PTRACE_SYSEMU");
132 wait_trap(chld);
133
134 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
135 err(1, "PTRACE_GETREGS");
136
137 if (regs.user_syscall_nr != SYS_gettid ||
138 regs.user_arg0 != 10 || regs.user_arg1 != 11 ||
139 regs.user_arg2 != 12 || regs.user_arg3 != 13 ||
140 regs.user_arg4 != 14 || regs.user_arg5 != 15) {
141 printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n",
142 (unsigned long)regs.user_syscall_nr,
143 (unsigned long)regs.user_arg0,
144 (unsigned long)regs.user_arg1,
145 (unsigned long)regs.user_arg2,
146 (unsigned long)regs.user_arg3,
147 (unsigned long)regs.user_arg4,
148 (unsigned long)regs.user_arg5);
149 nerrs++;
150 } else {
151 printf("[OK]\tRestarted nr and args are correct\n");
152 }
153
154 printf("[RUN]\tChange nr and args and restart the syscall (ip = 0x%lx)\n",
155 (unsigned long)regs.user_ip);
156
157 /*
158 * Inject a new syscall (getpid) in the same place the previous
159 * syscall (gettid), rewind and re-execute.
160 */
161 regs.user_syscall_nr = SYS_getpid;
162 regs.user_arg0 = 20;
163 regs.user_arg1 = 21;
164 regs.user_arg2 = 22;
165 regs.user_arg3 = 23;
166 regs.user_arg4 = 24;
167 regs.user_arg5 = 25;
168 regs.user_ip -= 4;
169
170 if (ptrace(PTRACE_SETREGS, chld, 0, &regs) != 0)
171 err(1, "PTRACE_SETREGS");
172
173 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
174 err(1, "PTRACE_SYSEMU");
175 wait_trap(chld);
176
177 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
178 err(1, "PTRACE_GETREGS");
179
180 /* Check that ptrace stopped at the new syscall that was
181 * injected, and guarantee that it haven't executed, i.e, user_args
182 * contain the arguments and not the syscall return value, for
183 * instance.
184 */
185 if (regs.user_syscall_nr != SYS_getpid
186 || regs.user_arg0 != 20 || regs.user_arg1 != 21
187 || regs.user_arg2 != 22 || regs.user_arg3 != 23
188 || regs.user_arg4 != 24 || regs.user_arg5 != 25) {
189
190 printf("[FAIL]\tRestart nr or args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n",
191 (unsigned long)regs.user_syscall_nr,
192 (unsigned long)regs.user_arg0,
193 (unsigned long)regs.user_arg1,
194 (unsigned long)regs.user_arg2,
195 (unsigned long)regs.user_arg3,
196 (unsigned long)regs.user_arg4,
197 (unsigned long)regs.user_arg5);
198 nerrs++;
199 } else {
200 printf("[OK]\tReplacement nr and args are correct\n");
201 }
202
203 if (ptrace(PTRACE_CONT, chld, 0, 0) != 0)
204 err(1, "PTRACE_CONT");
205
206 if (waitpid(chld, &status, 0) != chld)
207 err(1, "waitpid");
208
209 /* Guarantee that the process executed properly, returning 0 */
210 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
211 printf("[FAIL]\tChild failed\n");
212 nerrs++;
213 } else {
214 printf("[OK]\tChild exited cleanly\n");
215 }
216}
217
218int ptrace_syscall(void)
219{
220 test_ptrace_syscall_restart();
221
222 return nerrs;
223}
224
225int main(void)
226{
227 return test_harness(ptrace_syscall, "ptrace_syscall");
228}
diff --git a/tools/testing/selftests/powerpc/security/Makefile b/tools/testing/selftests/powerpc/security/Makefile
new file mode 100644
index 000000000000..44690f1bb26a
--- /dev/null
+++ b/tools/testing/selftests/powerpc/security/Makefile
@@ -0,0 +1,9 @@
1# SPDX-License-Identifier: GPL-2.0+
2
3TEST_GEN_PROGS := rfi_flush
4
5CFLAGS += -I../../../../../usr/include
6
7include ../../lib.mk
8
9$(TEST_GEN_PROGS): ../harness.c ../utils.c
diff --git a/tools/testing/selftests/powerpc/security/rfi_flush.c b/tools/testing/selftests/powerpc/security/rfi_flush.c
new file mode 100644
index 000000000000..564ed45bbf73
--- /dev/null
+++ b/tools/testing/selftests/powerpc/security/rfi_flush.c
@@ -0,0 +1,132 @@
1// SPDX-License-Identifier: GPL-2.0+
2
3/*
4 * Copyright 2018 IBM Corporation.
5 */
6
7#define __SANE_USERSPACE_TYPES__
8
9#include <sys/types.h>
10#include <stdint.h>
11#include <malloc.h>
12#include <unistd.h>
13#include <stdlib.h>
14#include <string.h>
15#include <stdio.h>
16#include "utils.h"
17
18#define CACHELINE_SIZE 128
19
20struct perf_event_read {
21 __u64 nr;
22 __u64 l1d_misses;
23};
24
25static inline __u64 load(void *addr)
26{
27 __u64 tmp;
28
29 asm volatile("ld %0,0(%1)" : "=r"(tmp) : "b"(addr));
30
31 return tmp;
32}
33
34static void syscall_loop(char *p, unsigned long iterations,
35 unsigned long zero_size)
36{
37 for (unsigned long i = 0; i < iterations; i++) {
38 for (unsigned long j = 0; j < zero_size; j += CACHELINE_SIZE)
39 load(p + j);
40 getppid();
41 }
42}
43
44int rfi_flush_test(void)
45{
46 char *p;
47 int repetitions = 10;
48 int fd, passes = 0, iter, rc = 0;
49 struct perf_event_read v;
50 __u64 l1d_misses_total = 0;
51 unsigned long iterations = 100000, zero_size = 24 * 1024;
52 int rfi_flush_org, rfi_flush;
53
54 SKIP_IF(geteuid() != 0);
55
56 if (read_debugfs_file("powerpc/rfi_flush", &rfi_flush_org)) {
57 perror("Unable to read powerpc/rfi_flush debugfs file");
58 SKIP_IF(1);
59 }
60
61 rfi_flush = rfi_flush_org;
62
63 fd = perf_event_open_counter(PERF_TYPE_RAW, /* L1d miss */ 0x400f0, -1);
64 FAIL_IF(fd < 0);
65
66 p = (char *)memalign(zero_size, CACHELINE_SIZE);
67
68 FAIL_IF(perf_event_enable(fd));
69
70 set_dscr(1);
71
72 iter = repetitions;
73
74again:
75 FAIL_IF(perf_event_reset(fd));
76
77 syscall_loop(p, iterations, zero_size);
78
79 FAIL_IF(read(fd, &v, sizeof(v)) != sizeof(v));
80
81 /* Expect at least zero_size/CACHELINE_SIZE misses per iteration */
82 if (v.l1d_misses >= (iterations * zero_size / CACHELINE_SIZE) && rfi_flush)
83 passes++;
84 else if (v.l1d_misses < iterations && !rfi_flush)
85 passes++;
86
87 l1d_misses_total += v.l1d_misses;
88
89 while (--iter)
90 goto again;
91
92 if (passes < repetitions) {
93 printf("FAIL (L1D misses with rfi_flush=%d: %llu %c %lu) [%d/%d failures]\n",
94 rfi_flush, l1d_misses_total, rfi_flush ? '<' : '>',
95 rfi_flush ? (repetitions * iterations * zero_size / CACHELINE_SIZE) : iterations,
96 repetitions - passes, repetitions);
97 rc = 1;
98 } else
99 printf("PASS (L1D misses with rfi_flush=%d: %llu %c %lu) [%d/%d pass]\n",
100 rfi_flush, l1d_misses_total, rfi_flush ? '>' : '<',
101 rfi_flush ? (repetitions * iterations * zero_size / CACHELINE_SIZE) : iterations,
102 passes, repetitions);
103
104 if (rfi_flush == rfi_flush_org) {
105 rfi_flush = !rfi_flush_org;
106 if (write_debugfs_file("powerpc/rfi_flush", rfi_flush) < 0) {
107 perror("error writing to powerpc/rfi_flush debugfs file");
108 return 1;
109 }
110 iter = repetitions;
111 l1d_misses_total = 0;
112 passes = 0;
113 goto again;
114 }
115
116 perf_event_disable(fd);
117 close(fd);
118
119 set_dscr(0);
120
121 if (write_debugfs_file("powerpc/rfi_flush", rfi_flush_org) < 0) {
122 perror("unable to restore original value of powerpc/rfi_flush debugfs file");
123 return 1;
124 }
125
126 return rc;
127}
128
129int main(int argc, char *argv[])
130{
131 return test_harness(rfi_flush_test, "rfi_flush_test");
132}
diff --git a/tools/testing/selftests/powerpc/tm/tm-tmspr.c b/tools/testing/selftests/powerpc/tm/tm-tmspr.c
index 2bda81c7bf23..df1d7d4b1c89 100644
--- a/tools/testing/selftests/powerpc/tm/tm-tmspr.c
+++ b/tools/testing/selftests/powerpc/tm/tm-tmspr.c
@@ -98,7 +98,7 @@ void texasr(void *in)
98 98
99int test_tmspr() 99int test_tmspr()
100{ 100{
101 pthread_t thread; 101 pthread_t *thread;
102 int thread_num; 102 int thread_num;
103 unsigned long i; 103 unsigned long i;
104 104
@@ -107,21 +107,28 @@ int test_tmspr()
107 /* To cause some context switching */ 107 /* To cause some context switching */
108 thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN); 108 thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN);
109 109
110 thread = malloc(thread_num * sizeof(pthread_t));
111 if (thread == NULL)
112 return EXIT_FAILURE;
113
110 /* Test TFIAR and TFHAR */ 114 /* Test TFIAR and TFHAR */
111 for (i = 0 ; i < thread_num ; i += 2){ 115 for (i = 0; i < thread_num; i += 2) {
112 if (pthread_create(&thread, NULL, (void*)tfiar_tfhar, (void *)i)) 116 if (pthread_create(&thread[i], NULL, (void *)tfiar_tfhar,
117 (void *)i))
113 return EXIT_FAILURE; 118 return EXIT_FAILURE;
114 } 119 }
115 if (pthread_join(thread, NULL) != 0)
116 return EXIT_FAILURE;
117
118 /* Test TEXASR */ 120 /* Test TEXASR */
119 for (i = 0 ; i < thread_num ; i++){ 121 for (i = 1; i < thread_num; i += 2) {
120 if (pthread_create(&thread, NULL, (void*)texasr, (void *)i)) 122 if (pthread_create(&thread[i], NULL, (void *)texasr, (void *)i))
121 return EXIT_FAILURE; 123 return EXIT_FAILURE;
122 } 124 }
123 if (pthread_join(thread, NULL) != 0) 125
124 return EXIT_FAILURE; 126 for (i = 0; i < thread_num; i++) {
127 if (pthread_join(thread[i], NULL) != 0)
128 return EXIT_FAILURE;
129 }
130
131 free(thread);
125 132
126 if (passed) 133 if (passed)
127 return 0; 134 return 0;
diff --git a/tools/testing/selftests/powerpc/tm/tm-unavailable.c b/tools/testing/selftests/powerpc/tm/tm-unavailable.c
index 156c8e750259..09894f4ff62e 100644
--- a/tools/testing/selftests/powerpc/tm/tm-unavailable.c
+++ b/tools/testing/selftests/powerpc/tm/tm-unavailable.c
@@ -236,7 +236,8 @@ void *tm_una_ping(void *input)
236 } 236 }
237 237
238 /* Check if we were not expecting a failure and a it occurred. */ 238 /* Check if we were not expecting a failure and a it occurred. */
239 if (!expecting_failure() && is_failure(cr_)) { 239 if (!expecting_failure() && is_failure(cr_) &&
240 !failure_is_reschedule()) {
240 printf("\n\tUnexpected transaction failure 0x%02lx\n\t", 241 printf("\n\tUnexpected transaction failure 0x%02lx\n\t",
241 failure_code()); 242 failure_code());
242 return (void *) -1; 243 return (void *) -1;
@@ -244,9 +245,11 @@ void *tm_una_ping(void *input)
244 245
245 /* 246 /*
246 * Check if TM failed due to the cause we were expecting. 0xda is a 247 * Check if TM failed due to the cause we were expecting. 0xda is a
247 * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause. 248 * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause, unless
249 * it was caused by a reschedule.
248 */ 250 */
249 if (is_failure(cr_) && !failure_is_unavailable()) { 251 if (is_failure(cr_) && !failure_is_unavailable() &&
252 !failure_is_reschedule()) {
250 printf("\n\tUnexpected failure cause 0x%02lx\n\t", 253 printf("\n\tUnexpected failure cause 0x%02lx\n\t",
251 failure_code()); 254 failure_code());
252 return (void *) -1; 255 return (void *) -1;
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h
index df4204247d45..5518b1d4ef8b 100644
--- a/tools/testing/selftests/powerpc/tm/tm.h
+++ b/tools/testing/selftests/powerpc/tm/tm.h
@@ -52,6 +52,15 @@ static inline bool failure_is_unavailable(void)
52 return (failure_code() & TM_CAUSE_FAC_UNAV) == TM_CAUSE_FAC_UNAV; 52 return (failure_code() & TM_CAUSE_FAC_UNAV) == TM_CAUSE_FAC_UNAV;
53} 53}
54 54
55static inline bool failure_is_reschedule(void)
56{
57 if ((failure_code() & TM_CAUSE_RESCHED) == TM_CAUSE_RESCHED ||
58 (failure_code() & TM_CAUSE_KVM_RESCHED) == TM_CAUSE_KVM_RESCHED)
59 return true;
60
61 return false;
62}
63
55static inline bool failure_is_nesting(void) 64static inline bool failure_is_nesting(void)
56{ 65{
57 return (__builtin_get_texasru() & 0x400000); 66 return (__builtin_get_texasru() & 0x400000);
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
index aa8fc1e6365b..43c342845be0 100644
--- a/tools/testing/selftests/powerpc/utils.c
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -10,16 +10,22 @@
10#include <fcntl.h> 10#include <fcntl.h>
11#include <link.h> 11#include <link.h>
12#include <sched.h> 12#include <sched.h>
13#include <signal.h>
13#include <stdio.h> 14#include <stdio.h>
15#include <stdlib.h>
14#include <string.h> 16#include <string.h>
17#include <sys/ioctl.h>
15#include <sys/stat.h> 18#include <sys/stat.h>
16#include <sys/types.h> 19#include <sys/types.h>
17#include <sys/utsname.h> 20#include <sys/utsname.h>
18#include <unistd.h> 21#include <unistd.h>
22#include <asm/unistd.h>
23#include <linux/limits.h>
19 24
20#include "utils.h" 25#include "utils.h"
21 26
22static char auxv[4096]; 27static char auxv[4096];
28extern unsigned int dscr_insn[];
23 29
24int read_auxv(char *buf, ssize_t buf_size) 30int read_auxv(char *buf, ssize_t buf_size)
25{ 31{
@@ -121,3 +127,149 @@ bool is_ppc64le(void)
121 127
122 return strcmp(uts.machine, "ppc64le") == 0; 128 return strcmp(uts.machine, "ppc64le") == 0;
123} 129}
130
131int read_debugfs_file(char *debugfs_file, int *result)
132{
133 int rc = -1, fd;
134 char path[PATH_MAX];
135 char value[16];
136
137 strcpy(path, "/sys/kernel/debug/");
138 strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
139
140 if ((fd = open(path, O_RDONLY)) < 0)
141 return rc;
142
143 if ((rc = read(fd, value, sizeof(value))) < 0)
144 return rc;
145
146 value[15] = 0;
147 *result = atoi(value);
148 close(fd);
149
150 return 0;
151}
152
153int write_debugfs_file(char *debugfs_file, int result)
154{
155 int rc = -1, fd;
156 char path[PATH_MAX];
157 char value[16];
158
159 strcpy(path, "/sys/kernel/debug/");
160 strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
161
162 if ((fd = open(path, O_WRONLY)) < 0)
163 return rc;
164
165 snprintf(value, 16, "%d", result);
166
167 if ((rc = write(fd, value, strlen(value))) < 0)
168 return rc;
169
170 close(fd);
171
172 return 0;
173}
174
175static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
176 int cpu, int group_fd, unsigned long flags)
177{
178 return syscall(__NR_perf_event_open, hw_event, pid, cpu,
179 group_fd, flags);
180}
181
182static void perf_event_attr_init(struct perf_event_attr *event_attr,
183 unsigned int type,
184 unsigned long config)
185{
186 memset(event_attr, 0, sizeof(*event_attr));
187
188 event_attr->type = type;
189 event_attr->size = sizeof(struct perf_event_attr);
190 event_attr->config = config;
191 event_attr->read_format = PERF_FORMAT_GROUP;
192 event_attr->disabled = 1;
193 event_attr->exclude_kernel = 1;
194 event_attr->exclude_hv = 1;
195 event_attr->exclude_guest = 1;
196}
197
198int perf_event_open_counter(unsigned int type,
199 unsigned long config, int group_fd)
200{
201 int fd;
202 struct perf_event_attr event_attr;
203
204 perf_event_attr_init(&event_attr, type, config);
205
206 fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
207
208 if (fd < 0)
209 perror("perf_event_open() failed");
210
211 return fd;
212}
213
214int perf_event_enable(int fd)
215{
216 if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
217 perror("error while enabling perf events");
218 return -1;
219 }
220
221 return 0;
222}
223
224int perf_event_disable(int fd)
225{
226 if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
227 perror("error disabling perf events");
228 return -1;
229 }
230
231 return 0;
232}
233
234int perf_event_reset(int fd)
235{
236 if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
237 perror("error resetting perf events");
238 return -1;
239 }
240
241 return 0;
242}
243
244static void sigill_handler(int signr, siginfo_t *info, void *unused)
245{
246 static int warned = 0;
247 ucontext_t *ctx = (ucontext_t *)unused;
248 unsigned long *pc = &UCONTEXT_NIA(ctx);
249
250 if (*pc == (unsigned long)&dscr_insn) {
251 if (!warned++)
252 printf("WARNING: Skipping over dscr setup. Consider running 'ppc64_cpu --dscr=1' manually.\n");
253 *pc += 4;
254 } else {
255 printf("SIGILL at %p\n", pc);
256 abort();
257 }
258}
259
260void set_dscr(unsigned long val)
261{
262 static int init = 0;
263 struct sigaction sa;
264
265 if (!init) {
266 memset(&sa, 0, sizeof(sa));
267 sa.sa_sigaction = sigill_handler;
268 sa.sa_flags = SA_SIGINFO;
269 if (sigaction(SIGILL, &sa, NULL))
270 perror("sigill_handler");
271 init = 1;
272 }
273
274 asm volatile("dscr_insn: mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR));
275}