aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-10-26 17:36:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-26 17:36:21 -0400
commit685f7e4f161425b137056abe35ba8ef7b669d83d (patch)
tree550dd1f5dc9e852cfeec26bf5e3ce9dd060c8a33 /tools
parentc7a2c49ea6c9eebbe44ff2c08b663b2905ee2c13 (diff)
parent58cfbac25b1fd2b76f94566aed28a3662b0ff8c6 (diff)
Merge tag 'powerpc-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc updates from Michael Ellerman: "Notable changes: - A large series to rewrite our SLB miss handling, replacing a lot of fairly complicated asm with much fewer lines of C. - Following on from that, we now maintain a cache of SLB entries for each process and preload them on context switch. Leading to a 27% speedup for our context switch benchmark on Power9. - Improvements to our handling of SLB multi-hit errors. We now print more debug information when they occur, and try to continue running by flushing the SLB and reloading, rather than treating them as fatal. - Enable THP migration on 64-bit Book3S machines (eg. Power7/8/9). - Add support for physical memory up to 2PB in the linear mapping on 64-bit Book3S. We only support up to 512TB as regular system memory, otherwise the percpu allocator runs out of vmalloc space. - Add stack protector support for 32 and 64-bit, with a per-task canary. - Add support for PTRACE_SYSEMU and PTRACE_SYSEMU_SINGLESTEP. - Support recognising "big cores" on Power9, where two SMT4 cores are presented to us as a single SMT8 core. - A large series to cleanup some of our ioremap handling and PTE flags. - Add a driver for the PAPR SCM (storage class memory) interface, allowing guests to operate on SCM devices (acked by Dan). - Changes to our ftrace code to handle very large kernels, where we need to use a trampoline to get to ftrace_caller(). And many other smaller enhancements and cleanups. Thanks to: Alan Modra, Alistair Popple, Aneesh Kumar K.V, Anton Blanchard, Aravinda Prasad, Bartlomiej Zolnierkiewicz, Benjamin Herrenschmidt, Breno Leitao, Cédric Le Goater, Christophe Leroy, Christophe Lombard, Dan Carpenter, Daniel Axtens, Finn Thain, Gautham R. Shenoy, Gustavo Romero, Haren Myneni, Hari Bathini, Jia Hongtao, Joel Stanley, John Allen, Laurent Dufour, Madhavan Srinivasan, Mahesh Salgaonkar, Mark Hairgrove, Masahiro Yamada, Michael Bringmann, Michael Neuling, Michal Suchanek, Murilo Opsfelder Araujo, Nathan Fontenot, Naveen N. Rao, Nicholas Piggin, Nick Desaulniers, Oliver O'Halloran, Paul Mackerras, Petr Vorel, Rashmica Gupta, Reza Arbab, Rob Herring, Sam Bobroff, Samuel Mendoza-Jonas, Scott Wood, Stan Johnson, Stephen Rothwell, Stewart Smith, Suraj Jitindar Singh, Tyrel Datwyler, Vaibhav Jain, Vasant Hegde, YueHaibing, zhong jiang" * tag 'powerpc-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (221 commits) Revert "selftests/powerpc: Fix out-of-tree build errors" powerpc/msi: Fix compile error on mpc83xx powerpc: Fix stack protector crashes on CPU hotplug powerpc/traps: restore recoverability of machine_check interrupts powerpc/64/module: REL32 relocation range check powerpc/64s/radix: Fix radix__flush_tlb_collapsed_pmd double flushing pmd selftests/powerpc: Add a test of wild bctr powerpc/mm: Fix page table dump to work on Radix powerpc/mm/radix: Display if mappings are exec or not powerpc/mm/radix: Simplify split mapping logic powerpc/mm/radix: Remove the retry in the split mapping logic powerpc/mm/radix: Fix small page at boundary when splitting powerpc/mm/radix: Fix overuse of small pages in splitting logic powerpc/mm/radix: Fix off-by-one in split mapping logic powerpc/ftrace: Handle large kernel configs powerpc/mm: Fix WARN_ON with THP NUMA migration selftests/powerpc: Fix out-of-tree build errors powerpc/time: no steal_time when CONFIG_PPC_SPLPAR is not selected powerpc/time: Only set CONFIG_ARCH_HAS_SCALED_CPUTIME on PPC64 powerpc/time: isolate scaled cputime accounting in dedicated functions. ...
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}