aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-07 13:23:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-07 13:23:33 -0400
commitc90fca951e90ba470a3dc6087667edffcf8db21b (patch)
treeb131279a9290826e78884ee706cc0a4f1d82be4e /tools
parentc0ab85267e25e34ce8b7e4429f0ef01fa0795b80 (diff)
parentff5bc793e47b537bf3e904fada585e102c54dd8b (diff)
Merge tag 'powerpc-4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc updates from Michael Ellerman: "Notable changes: - Support for split PMD page table lock on 64-bit Book3S (Power8/9). - Add support for HAVE_RELIABLE_STACKTRACE, so we properly support live patching again. - Add support for patching barrier_nospec in copy_from_user() and syscall entry. - A couple of fixes for our data breakpoints on Book3S. - A series from Nick optimising TLB/mm handling with the Radix MMU. - Numerous small cleanups to squash sparse/gcc warnings from Mathieu Malaterre. - Several series optimising various parts of the 32-bit code from Christophe Leroy. - Removal of support for two old machines, "SBC834xE" and "C2K" ("GEFanuc,C2K"), which is why the diffstat has so many deletions. And many other small improvements & fixes. There's a few out-of-area changes. Some minor ftrace changes OK'ed by Steve, and a fix to our powernv cpuidle driver. Then there's a series touching mm, x86 and fs/proc/task_mmu.c, which cleans up some details around pkey support. It was ack'ed/reviewed by Ingo & Dave and has been in next for several weeks. Thanks to: Akshay Adiga, Alastair D'Silva, Alexey Kardashevskiy, Al Viro, Andrew Donnellan, Aneesh Kumar K.V, Anju T Sudhakar, Arnd Bergmann, Balbir Singh, Cédric Le Goater, Christophe Leroy, Christophe Lombard, Colin Ian King, Dave Hansen, Fabio Estevam, Finn Thain, Frederic Barrat, Gautham R. Shenoy, Haren Myneni, Hari Bathini, Ingo Molnar, Jonathan Neuschäfer, Josh Poimboeuf, Kamalesh Babulal, Madhavan Srinivasan, Mahesh Salgaonkar, Mark Greer, Mathieu Malaterre, Matthew Wilcox, Michael Neuling, Michal Suchanek, Naveen N. Rao, Nicholas Piggin, Nicolai Stange, Olof Johansson, Paul Gortmaker, Paul Mackerras, Peter Rosin, Pridhiviraj Paidipeddi, Ram Pai, Rashmica Gupta, Ravi Bangoria, Russell Currey, Sam Bobroff, Samuel Mendoza-Jonas, Segher Boessenkool, Shilpasri G Bhat, Simon Guo, Souptick Joarder, Stewart Smith, Thiago Jung Bauermann, Torsten Duwe, Vaibhav Jain, Wei Yongjun, Wolfram Sang, Yisheng Xie, YueHaibing" * tag 'powerpc-4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (251 commits) powerpc/64s/radix: Fix missing ptesync in flush_cache_vmap cpuidle: powernv: Fix promotion from snooze if next state disabled powerpc: fix build failure by disabling attribute-alias warning in pci_32 ocxl: Fix missing unlock on error in afu_ioctl_enable_p9_wait() powerpc-opal: fix spelling mistake "Uniterrupted" -> "Uninterrupted" powerpc: fix spelling mistake: "Usupported" -> "Unsupported" powerpc/pkeys: Detach execute_only key on !PROT_EXEC powerpc/powernv: copy/paste - Mask SO bit in CR powerpc: Remove core support for Marvell mv64x60 hostbridges powerpc/boot: Remove core support for Marvell mv64x60 hostbridges powerpc/boot: Remove support for Marvell mv64x60 i2c controller powerpc/boot: Remove support for Marvell MPSC serial controller powerpc/embedded6xx: Remove C2K board support powerpc/lib: optimise PPC32 memcmp powerpc/lib: optimise 32 bits __clear_user() powerpc/time: inline arch_vtime_task_switch() powerpc/Makefile: set -mcpu=860 flag for the 8xx powerpc: Implement csum_ipv6_magic in assembly powerpc/32: Optimise __csum_partial() powerpc/lib: Adjust .balign inside string functions for PPC32 ...
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/powerpc/Makefile1
-rw-r--r--tools/testing/selftests/powerpc/alignment/.gitignore1
-rw-r--r--tools/testing/selftests/powerpc/benchmarks/exec_target.c7
-rw-r--r--tools/testing/selftests/powerpc/context_switch/.gitignore1
-rw-r--r--tools/testing/selftests/powerpc/context_switch/Makefile5
-rw-r--r--tools/testing/selftests/powerpc/context_switch/cp_abort.c110
-rw-r--r--tools/testing/selftests/powerpc/include/reg.h1
-rw-r--r--tools/testing/selftests/powerpc/ptrace/.gitignore2
-rw-r--r--tools/testing/selftests/powerpc/ptrace/Makefile6
-rw-r--r--tools/testing/selftests/powerpc/ptrace/child.h139
-rw-r--r--tools/testing/selftests/powerpc/ptrace/core-pkey.c461
-rw-r--r--tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c195
-rw-r--r--tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c342
-rw-r--r--tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c327
-rw-r--r--tools/testing/selftests/powerpc/ptrace/ptrace.h38
-rw-r--r--tools/testing/selftests/powerpc/tm/.gitignore1
16 files changed, 1517 insertions, 120 deletions
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index f6b1338730db..201b598558b9 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -17,7 +17,6 @@ SUB_DIRS = alignment \
17 benchmarks \ 17 benchmarks \
18 cache_shape \ 18 cache_shape \
19 copyloops \ 19 copyloops \
20 context_switch \
21 dscr \ 20 dscr \
22 mm \ 21 mm \
23 pmu \ 22 pmu \
diff --git a/tools/testing/selftests/powerpc/alignment/.gitignore b/tools/testing/selftests/powerpc/alignment/.gitignore
index 1d980e3d7039..9d383073b7ad 100644
--- a/tools/testing/selftests/powerpc/alignment/.gitignore
+++ b/tools/testing/selftests/powerpc/alignment/.gitignore
@@ -3,3 +3,4 @@ copy_first_unaligned
3paste_unaligned 3paste_unaligned
4paste_last_unaligned 4paste_last_unaligned
5copy_paste_unaligned_common 5copy_paste_unaligned_common
6alignment_handler
diff --git a/tools/testing/selftests/powerpc/benchmarks/exec_target.c b/tools/testing/selftests/powerpc/benchmarks/exec_target.c
index 3c9c144192be..c14b0fc1edde 100644
--- a/tools/testing/selftests/powerpc/benchmarks/exec_target.c
+++ b/tools/testing/selftests/powerpc/benchmarks/exec_target.c
@@ -6,8 +6,11 @@
6 * Copyright 2018, Anton Blanchard, IBM Corp. 6 * Copyright 2018, Anton Blanchard, IBM Corp.
7 */ 7 */
8 8
9void _exit(int); 9#define _GNU_SOURCE
10#include <unistd.h>
11#include <sys/syscall.h>
12
10void _start(void) 13void _start(void)
11{ 14{
12 _exit(0); 15 syscall(SYS_exit, 0);
13} 16}
diff --git a/tools/testing/selftests/powerpc/context_switch/.gitignore b/tools/testing/selftests/powerpc/context_switch/.gitignore
deleted file mode 100644
index c1431af7b51c..000000000000
--- a/tools/testing/selftests/powerpc/context_switch/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
1cp_abort
diff --git a/tools/testing/selftests/powerpc/context_switch/Makefile b/tools/testing/selftests/powerpc/context_switch/Makefile
deleted file mode 100644
index e9351bb4285d..000000000000
--- a/tools/testing/selftests/powerpc/context_switch/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
1TEST_GEN_PROGS := cp_abort
2
3include ../../lib.mk
4
5$(TEST_GEN_PROGS): ../harness.c ../utils.c
diff --git a/tools/testing/selftests/powerpc/context_switch/cp_abort.c b/tools/testing/selftests/powerpc/context_switch/cp_abort.c
deleted file mode 100644
index 5a5b55afda0e..000000000000
--- a/tools/testing/selftests/powerpc/context_switch/cp_abort.c
+++ /dev/null
@@ -1,110 +0,0 @@
1/*
2 * Adapted from Anton Blanchard's context switch microbenchmark.
3 *
4 * Copyright 2009, Anton Blanchard, IBM Corporation.
5 * Copyright 2016, Mikey Neuling, Chris Smart, IBM Corporation.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * This program tests the copy paste abort functionality of a P9
13 * (or later) by setting up two processes on the same CPU, one
14 * which executes the copy instruction and the other which
15 * executes paste.
16 *
17 * The paste instruction should never succeed, as the cp_abort
18 * instruction is called by the kernel during a context switch.
19 *
20 */
21
22#define _GNU_SOURCE
23
24#include <stdio.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include "utils.h"
28#include <sched.h>
29
30#define READ_FD 0
31#define WRITE_FD 1
32
33#define NUM_LOOPS 1000
34
35/* This defines the "paste" instruction from Power ISA 3.0 Book II, section 4.4. */
36#define PASTE(RA, RB, L, RC) \
37 .long (0x7c00070c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10) | (RC) << (31-31))
38
39int paste(void *i)
40{
41 int cr;
42
43 asm volatile(str(PASTE(0, %1, 1, 1))";"
44 "mfcr %0;"
45 : "=r" (cr)
46 : "b" (i)
47 : "memory"
48 );
49 return cr;
50}
51
52/* This defines the "copy" instruction from Power ISA 3.0 Book II, section 4.4. */
53#define COPY(RA, RB, L) \
54 .long (0x7c00060c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10))
55
56void copy(void *i)
57{
58 asm volatile(str(COPY(0, %0, 1))";"
59 :
60 : "b" (i)
61 : "memory"
62 );
63}
64
65int test_cp_abort(void)
66{
67 /* 128 bytes for a full cache line */
68 char buf[128] __cacheline_aligned;
69 cpu_set_t cpuset;
70 int fd1[2], fd2[2], pid;
71 char c;
72
73 /* only run this test on a P9 or later */
74 SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
75
76 /*
77 * Run both processes on the same CPU, so that copy is more likely
78 * to leak into a paste.
79 */
80 CPU_ZERO(&cpuset);
81 CPU_SET(pick_online_cpu(), &cpuset);
82 FAIL_IF(sched_setaffinity(0, sizeof(cpuset), &cpuset));
83
84 FAIL_IF(pipe(fd1) || pipe(fd2));
85
86 pid = fork();
87 FAIL_IF(pid < 0);
88
89 if (!pid) {
90 for (int i = 0; i < NUM_LOOPS; i++) {
91 FAIL_IF((write(fd1[WRITE_FD], &c, 1)) != 1);
92 FAIL_IF((read(fd2[READ_FD], &c, 1)) != 1);
93 /* A paste succeeds if CR0 EQ bit is set */
94 FAIL_IF(paste(buf) & 0x20000000);
95 }
96 } else {
97 for (int i = 0; i < NUM_LOOPS; i++) {
98 FAIL_IF((read(fd1[READ_FD], &c, 1)) != 1);
99 copy(buf);
100 FAIL_IF((write(fd2[WRITE_FD], &c, 1) != 1));
101 }
102 }
103 return 0;
104
105}
106
107int main(int argc, char *argv[])
108{
109 return test_harness(test_cp_abort, "cp_abort");
110}
diff --git a/tools/testing/selftests/powerpc/include/reg.h b/tools/testing/selftests/powerpc/include/reg.h
index 4afdebcce4cd..7f348c059bc2 100644
--- a/tools/testing/selftests/powerpc/include/reg.h
+++ b/tools/testing/selftests/powerpc/include/reg.h
@@ -54,6 +54,7 @@
54#define SPRN_DSCR_PRIV 0x11 /* Privilege State DSCR */ 54#define SPRN_DSCR_PRIV 0x11 /* Privilege State DSCR */
55#define SPRN_DSCR 0x03 /* Data Stream Control Register */ 55#define SPRN_DSCR 0x03 /* Data Stream Control Register */
56#define SPRN_PPR 896 /* Program Priority Register */ 56#define SPRN_PPR 896 /* Program Priority Register */
57#define SPRN_AMR 13 /* Authority Mask Register - problem state */
57 58
58/* TEXASR register bits */ 59/* TEXASR register bits */
59#define TEXASR_FC 0xFE00000000000000 60#define TEXASR_FC 0xFE00000000000000
diff --git a/tools/testing/selftests/powerpc/ptrace/.gitignore b/tools/testing/selftests/powerpc/ptrace/.gitignore
index 349acfafc95b..07ec449a2767 100644
--- a/tools/testing/selftests/powerpc/ptrace/.gitignore
+++ b/tools/testing/selftests/powerpc/ptrace/.gitignore
@@ -8,3 +8,5 @@ ptrace-vsx
8ptrace-tm-vsx 8ptrace-tm-vsx
9ptrace-tm-spd-vsx 9ptrace-tm-spd-vsx
10ptrace-tm-spr 10ptrace-tm-spr
11ptrace-hwbreak
12perf-hwbreak
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile
index 480305266504..28f5b781a553 100644
--- a/tools/testing/selftests/powerpc/ptrace/Makefile
+++ b/tools/testing/selftests/powerpc/ptrace/Makefile
@@ -1,7 +1,8 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
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 4 ptrace-tm-spd-vsx ptrace-tm-spr ptrace-hwbreak ptrace-pkey core-pkey \
5 perf-hwbreak
5 6
6include ../../lib.mk 7include ../../lib.mk
7 8
@@ -9,6 +10,9 @@ all: $(TEST_PROGS)
9 10
10CFLAGS += -m64 -I../../../../../usr/include -I../tm -mhtm -fno-pie 11CFLAGS += -m64 -I../../../../../usr/include -I../tm -mhtm -fno-pie
11 12
13ptrace-pkey core-pkey: child.h
14ptrace-pkey core-pkey: LDLIBS += -pthread
15
12$(TEST_PROGS): ../harness.c ../utils.c ../lib/reg.S ptrace.h 16$(TEST_PROGS): ../harness.c ../utils.c ../lib/reg.S ptrace.h
13 17
14clean: 18clean:
diff --git a/tools/testing/selftests/powerpc/ptrace/child.h b/tools/testing/selftests/powerpc/ptrace/child.h
new file mode 100644
index 000000000000..d7275b7b33dc
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/child.h
@@ -0,0 +1,139 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Helper functions to sync execution between parent and child processes.
4 *
5 * Copyright 2018, Thiago Jung Bauermann, IBM Corporation.
6 */
7#include <stdio.h>
8#include <stdbool.h>
9#include <semaphore.h>
10
11/*
12 * Information in a shared memory location for synchronization between child and
13 * parent.
14 */
15struct child_sync {
16 /* The parent waits on this semaphore. */
17 sem_t sem_parent;
18
19 /* If true, the child should give up as well. */
20 bool parent_gave_up;
21
22 /* The child waits on this semaphore. */
23 sem_t sem_child;
24
25 /* If true, the parent should give up as well. */
26 bool child_gave_up;
27};
28
29#define CHILD_FAIL_IF(x, sync) \
30 do { \
31 if (x) { \
32 fprintf(stderr, \
33 "[FAIL] Test FAILED on line %d\n", __LINE__); \
34 (sync)->child_gave_up = true; \
35 prod_parent(sync); \
36 return 1; \
37 } \
38 } while (0)
39
40#define PARENT_FAIL_IF(x, sync) \
41 do { \
42 if (x) { \
43 fprintf(stderr, \
44 "[FAIL] Test FAILED on line %d\n", __LINE__); \
45 (sync)->parent_gave_up = true; \
46 prod_child(sync); \
47 return 1; \
48 } \
49 } while (0)
50
51#define PARENT_SKIP_IF_UNSUPPORTED(x, sync) \
52 do { \
53 if ((x) == -1 && (errno == ENODEV || errno == EINVAL)) { \
54 (sync)->parent_gave_up = true; \
55 prod_child(sync); \
56 SKIP_IF(1); \
57 } \
58 } while (0)
59
60int init_child_sync(struct child_sync *sync)
61{
62 int ret;
63
64 ret = sem_init(&sync->sem_parent, 1, 0);
65 if (ret) {
66 perror("Semaphore initialization failed");
67 return 1;
68 }
69
70 ret = sem_init(&sync->sem_child, 1, 0);
71 if (ret) {
72 perror("Semaphore initialization failed");
73 return 1;
74 }
75
76 return 0;
77}
78
79void destroy_child_sync(struct child_sync *sync)
80{
81 sem_destroy(&sync->sem_parent);
82 sem_destroy(&sync->sem_child);
83}
84
85int wait_child(struct child_sync *sync)
86{
87 int ret;
88
89 /* Wait until the child prods us. */
90 ret = sem_wait(&sync->sem_parent);
91 if (ret) {
92 perror("Error waiting for child");
93 return 1;
94 }
95
96 return sync->child_gave_up;
97}
98
99int prod_child(struct child_sync *sync)
100{
101 int ret;
102
103 /* Unblock the child now. */
104 ret = sem_post(&sync->sem_child);
105 if (ret) {
106 perror("Error prodding child");
107 return 1;
108 }
109
110 return 0;
111}
112
113int wait_parent(struct child_sync *sync)
114{
115 int ret;
116
117 /* Wait until the parent prods us. */
118 ret = sem_wait(&sync->sem_child);
119 if (ret) {
120 perror("Error waiting for parent");
121 return 1;
122 }
123
124 return sync->parent_gave_up;
125}
126
127int prod_parent(struct child_sync *sync)
128{
129 int ret;
130
131 /* Unblock the parent now. */
132 ret = sem_post(&sync->sem_parent);
133 if (ret) {
134 perror("Error prodding parent");
135 return 1;
136 }
137
138 return 0;
139}
diff --git a/tools/testing/selftests/powerpc/ptrace/core-pkey.c b/tools/testing/selftests/powerpc/ptrace/core-pkey.c
new file mode 100644
index 000000000000..36bc312b1f5c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/core-pkey.c
@@ -0,0 +1,461 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Ptrace test for Memory Protection Key registers
4 *
5 * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
6 * Copyright (C) 2018 IBM Corporation.
7 */
8#include <limits.h>
9#include <linux/kernel.h>
10#include <sys/mman.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <sys/time.h>
14#include <sys/resource.h>
15#include <fcntl.h>
16#include <unistd.h>
17#include "ptrace.h"
18#include "child.h"
19
20#ifndef __NR_pkey_alloc
21#define __NR_pkey_alloc 384
22#endif
23
24#ifndef __NR_pkey_free
25#define __NR_pkey_free 385
26#endif
27
28#ifndef NT_PPC_PKEY
29#define NT_PPC_PKEY 0x110
30#endif
31
32#ifndef PKEY_DISABLE_EXECUTE
33#define PKEY_DISABLE_EXECUTE 0x4
34#endif
35
36#define AMR_BITS_PER_PKEY 2
37#define PKEY_REG_BITS (sizeof(u64) * 8)
38#define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
39
40#define CORE_FILE_LIMIT (5 * 1024 * 1024) /* 5 MB should be enough */
41
42static const char core_pattern_file[] = "/proc/sys/kernel/core_pattern";
43
44static const char user_write[] = "[User Write (Running)]";
45static const char core_read_running[] = "[Core Read (Running)]";
46
47/* Information shared between the parent and the child. */
48struct shared_info {
49 struct child_sync child_sync;
50
51 /* AMR value the parent expects to read in the core file. */
52 unsigned long amr;
53
54 /* IAMR value the parent expects to read in the core file. */
55 unsigned long iamr;
56
57 /* UAMOR value the parent expects to read in the core file. */
58 unsigned long uamor;
59
60 /* When the child crashed. */
61 time_t core_time;
62};
63
64static int sys_pkey_alloc(unsigned long flags, unsigned long init_access_rights)
65{
66 return syscall(__NR_pkey_alloc, flags, init_access_rights);
67}
68
69static int sys_pkey_free(int pkey)
70{
71 return syscall(__NR_pkey_free, pkey);
72}
73
74static int increase_core_file_limit(void)
75{
76 struct rlimit rlim;
77 int ret;
78
79 ret = getrlimit(RLIMIT_CORE, &rlim);
80 FAIL_IF(ret);
81
82 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < CORE_FILE_LIMIT) {
83 rlim.rlim_cur = CORE_FILE_LIMIT;
84
85 if (rlim.rlim_max != RLIM_INFINITY &&
86 rlim.rlim_max < CORE_FILE_LIMIT)
87 rlim.rlim_max = CORE_FILE_LIMIT;
88
89 ret = setrlimit(RLIMIT_CORE, &rlim);
90 FAIL_IF(ret);
91 }
92
93 ret = getrlimit(RLIMIT_FSIZE, &rlim);
94 FAIL_IF(ret);
95
96 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < CORE_FILE_LIMIT) {
97 rlim.rlim_cur = CORE_FILE_LIMIT;
98
99 if (rlim.rlim_max != RLIM_INFINITY &&
100 rlim.rlim_max < CORE_FILE_LIMIT)
101 rlim.rlim_max = CORE_FILE_LIMIT;
102
103 ret = setrlimit(RLIMIT_FSIZE, &rlim);
104 FAIL_IF(ret);
105 }
106
107 return TEST_PASS;
108}
109
110static int child(struct shared_info *info)
111{
112 bool disable_execute = true;
113 int pkey1, pkey2, pkey3;
114 int *ptr, ret;
115
116 /* Wait until parent fills out the initial register values. */
117 ret = wait_parent(&info->child_sync);
118 if (ret)
119 return ret;
120
121 ret = increase_core_file_limit();
122 FAIL_IF(ret);
123
124 /* Get some pkeys so that we can change their bits in the AMR. */
125 pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
126 if (pkey1 < 0) {
127 pkey1 = sys_pkey_alloc(0, 0);
128 FAIL_IF(pkey1 < 0);
129
130 disable_execute = false;
131 }
132
133 pkey2 = sys_pkey_alloc(0, 0);
134 FAIL_IF(pkey2 < 0);
135
136 pkey3 = sys_pkey_alloc(0, 0);
137 FAIL_IF(pkey3 < 0);
138
139 info->amr |= 3ul << pkeyshift(pkey1) | 2ul << pkeyshift(pkey2);
140
141 if (disable_execute)
142 info->iamr |= 1ul << pkeyshift(pkey1);
143
144 info->uamor |= 3ul << pkeyshift(pkey1) | 3ul << pkeyshift(pkey2);
145
146 printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
147 user_write, info->amr, pkey1, pkey2, pkey3);
148
149 mtspr(SPRN_AMR, info->amr);
150
151 /*
152 * We won't use pkey3. This tests whether the kernel restores the UAMOR
153 * permissions after a key is freed.
154 */
155 sys_pkey_free(pkey3);
156
157 info->core_time = time(NULL);
158
159 /* Crash. */
160 ptr = 0;
161 *ptr = 1;
162
163 /* Shouldn't get here. */
164 FAIL_IF(true);
165
166 return TEST_FAIL;
167}
168
169/* Return file size if filename exists and pass sanity check, or zero if not. */
170static off_t try_core_file(const char *filename, struct shared_info *info,
171 pid_t pid)
172{
173 struct stat buf;
174 int ret;
175
176 ret = stat(filename, &buf);
177 if (ret == -1)
178 return TEST_FAIL;
179
180 /* Make sure we're not using a stale core file. */
181 return buf.st_mtime >= info->core_time ? buf.st_size : TEST_FAIL;
182}
183
184static Elf64_Nhdr *next_note(Elf64_Nhdr *nhdr)
185{
186 return (void *) nhdr + sizeof(*nhdr) +
187 __ALIGN_KERNEL(nhdr->n_namesz, 4) +
188 __ALIGN_KERNEL(nhdr->n_descsz, 4);
189}
190
191static int check_core_file(struct shared_info *info, Elf64_Ehdr *ehdr,
192 off_t core_size)
193{
194 unsigned long *regs;
195 Elf64_Phdr *phdr;
196 Elf64_Nhdr *nhdr;
197 size_t phdr_size;
198 void *p = ehdr, *note;
199 int ret;
200
201 ret = memcmp(ehdr->e_ident, ELFMAG, SELFMAG);
202 FAIL_IF(ret);
203
204 FAIL_IF(ehdr->e_type != ET_CORE);
205 FAIL_IF(ehdr->e_machine != EM_PPC64);
206 FAIL_IF(ehdr->e_phoff == 0 || ehdr->e_phnum == 0);
207
208 /*
209 * e_phnum is at most 65535 so calculating the size of the
210 * program header cannot overflow.
211 */
212 phdr_size = sizeof(*phdr) * ehdr->e_phnum;
213
214 /* Sanity check the program header table location. */
215 FAIL_IF(ehdr->e_phoff + phdr_size < ehdr->e_phoff);
216 FAIL_IF(ehdr->e_phoff + phdr_size > core_size);
217
218 /* Find the PT_NOTE segment. */
219 for (phdr = p + ehdr->e_phoff;
220 (void *) phdr < p + ehdr->e_phoff + phdr_size;
221 phdr += ehdr->e_phentsize)
222 if (phdr->p_type == PT_NOTE)
223 break;
224
225 FAIL_IF((void *) phdr >= p + ehdr->e_phoff + phdr_size);
226
227 /* Find the NT_PPC_PKEY note. */
228 for (nhdr = p + phdr->p_offset;
229 (void *) nhdr < p + phdr->p_offset + phdr->p_filesz;
230 nhdr = next_note(nhdr))
231 if (nhdr->n_type == NT_PPC_PKEY)
232 break;
233
234 FAIL_IF((void *) nhdr >= p + phdr->p_offset + phdr->p_filesz);
235 FAIL_IF(nhdr->n_descsz == 0);
236
237 p = nhdr;
238 note = p + sizeof(*nhdr) + __ALIGN_KERNEL(nhdr->n_namesz, 4);
239
240 regs = (unsigned long *) note;
241
242 printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
243 core_read_running, regs[0], regs[1], regs[2]);
244
245 FAIL_IF(regs[0] != info->amr);
246 FAIL_IF(regs[1] != info->iamr);
247 FAIL_IF(regs[2] != info->uamor);
248
249 return TEST_PASS;
250}
251
252static int parent(struct shared_info *info, pid_t pid)
253{
254 char *filenames, *filename[3];
255 int fd, i, ret, status;
256 unsigned long regs[3];
257 off_t core_size;
258 void *core;
259
260 /*
261 * Get the initial values for AMR, IAMR and UAMOR and communicate them
262 * to the child.
263 */
264 ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
265 PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync);
266 PARENT_FAIL_IF(ret, &info->child_sync);
267
268 info->amr = regs[0];
269 info->iamr = regs[1];
270 info->uamor = regs[2];
271
272 /* Wake up child so that it can set itself up. */
273 ret = prod_child(&info->child_sync);
274 PARENT_FAIL_IF(ret, &info->child_sync);
275
276 ret = wait(&status);
277 if (ret != pid) {
278 printf("Child's exit status not captured\n");
279 return TEST_FAIL;
280 } else if (!WIFSIGNALED(status) || !WCOREDUMP(status)) {
281 printf("Child didn't dump core\n");
282 return TEST_FAIL;
283 }
284
285 /* Construct array of core file names to try. */
286
287 filename[0] = filenames = malloc(PATH_MAX);
288 if (!filenames) {
289 perror("Error allocating memory");
290 return TEST_FAIL;
291 }
292
293 ret = snprintf(filename[0], PATH_MAX, "core-pkey.%d", pid);
294 if (ret < 0 || ret >= PATH_MAX) {
295 ret = TEST_FAIL;
296 goto out;
297 }
298
299 filename[1] = filename[0] + ret + 1;
300 ret = snprintf(filename[1], PATH_MAX - ret - 1, "core.%d", pid);
301 if (ret < 0 || ret >= PATH_MAX - ret - 1) {
302 ret = TEST_FAIL;
303 goto out;
304 }
305 filename[2] = "core";
306
307 for (i = 0; i < 3; i++) {
308 core_size = try_core_file(filename[i], info, pid);
309 if (core_size != TEST_FAIL)
310 break;
311 }
312
313 if (i == 3) {
314 printf("Couldn't find core file\n");
315 ret = TEST_FAIL;
316 goto out;
317 }
318
319 fd = open(filename[i], O_RDONLY);
320 if (fd == -1) {
321 perror("Error opening core file");
322 ret = TEST_FAIL;
323 goto out;
324 }
325
326 core = mmap(NULL, core_size, PROT_READ, MAP_PRIVATE, fd, 0);
327 if (core == (void *) -1) {
328 perror("Error mmaping core file");
329 ret = TEST_FAIL;
330 goto out;
331 }
332
333 ret = check_core_file(info, core, core_size);
334
335 munmap(core, core_size);
336 close(fd);
337 unlink(filename[i]);
338
339 out:
340 free(filenames);
341
342 return ret;
343}
344
345static int write_core_pattern(const char *core_pattern)
346{
347 size_t len = strlen(core_pattern), ret;
348 FILE *f;
349
350 f = fopen(core_pattern_file, "w");
351 if (!f) {
352 perror("Error writing to core_pattern file");
353 return TEST_FAIL;
354 }
355
356 ret = fwrite(core_pattern, 1, len, f);
357 fclose(f);
358 if (ret != len) {
359 perror("Error writing to core_pattern file");
360 return TEST_FAIL;
361 }
362
363 return TEST_PASS;
364}
365
366static int setup_core_pattern(char **core_pattern_, bool *changed_)
367{
368 FILE *f;
369 char *core_pattern;
370 int ret;
371
372 core_pattern = malloc(PATH_MAX);
373 if (!core_pattern) {
374 perror("Error allocating memory");
375 return TEST_FAIL;
376 }
377
378 f = fopen(core_pattern_file, "r");
379 if (!f) {
380 perror("Error opening core_pattern file");
381 ret = TEST_FAIL;
382 goto out;
383 }
384
385 ret = fread(core_pattern, 1, PATH_MAX, f);
386 fclose(f);
387 if (!ret) {
388 perror("Error reading core_pattern file");
389 ret = TEST_FAIL;
390 goto out;
391 }
392
393 /* Check whether we can predict the name of the core file. */
394 if (!strcmp(core_pattern, "core") || !strcmp(core_pattern, "core.%p"))
395 *changed_ = false;
396 else {
397 ret = write_core_pattern("core-pkey.%p");
398 if (ret)
399 goto out;
400
401 *changed_ = true;
402 }
403
404 *core_pattern_ = core_pattern;
405 ret = TEST_PASS;
406
407 out:
408 if (ret)
409 free(core_pattern);
410
411 return ret;
412}
413
414static int core_pkey(void)
415{
416 char *core_pattern;
417 bool changed_core_pattern;
418 struct shared_info *info;
419 int shm_id;
420 int ret;
421 pid_t pid;
422
423 ret = setup_core_pattern(&core_pattern, &changed_core_pattern);
424 if (ret)
425 return ret;
426
427 shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
428 info = shmat(shm_id, NULL, 0);
429
430 ret = init_child_sync(&info->child_sync);
431 if (ret)
432 return ret;
433
434 pid = fork();
435 if (pid < 0) {
436 perror("fork() failed");
437 ret = TEST_FAIL;
438 } else if (pid == 0)
439 ret = child(info);
440 else
441 ret = parent(info, pid);
442
443 shmdt(info);
444
445 if (pid) {
446 destroy_child_sync(&info->child_sync);
447 shmctl(shm_id, IPC_RMID, NULL);
448
449 if (changed_core_pattern)
450 write_core_pattern(core_pattern);
451 }
452
453 free(core_pattern);
454
455 return ret;
456}
457
458int main(int argc, char *argv[])
459{
460 return test_harness(core_pkey, "core_pkey");
461}
diff --git a/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c b/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c
new file mode 100644
index 000000000000..60df0b5e628a
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/perf-hwbreak.c
@@ -0,0 +1,195 @@
1/*
2 * perf events self profiling example test case for hw breakpoints.
3 *
4 * This tests perf PERF_TYPE_BREAKPOINT parameters
5 * 1) tests all variants of the break on read/write flags
6 * 2) tests exclude_user == 0 and 1
7 * 3) test array matches (if DAWR is supported))
8 * 4) test different numbers of breakpoints matches
9 *
10 * Configure this breakpoint, then read and write the data a number of
11 * times. Then check the output count from perf is as expected.
12 *
13 * Based on:
14 * http://ozlabs.org/~anton/junkcode/perf_events_example1.c
15 *
16 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version
21 * 2 of the License, or (at your option) any later version.
22 */
23
24#include <unistd.h>
25#include <assert.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/ioctl.h>
30#include <elf.h>
31#include <pthread.h>
32#include <sys/syscall.h>
33#include <linux/perf_event.h>
34#include <linux/hw_breakpoint.h>
35#include "utils.h"
36
37#define MAX_LOOPS 10000
38
39#define DAWR_LENGTH_MAX ((0x3f + 1) * 8)
40
41static inline int sys_perf_event_open(struct perf_event_attr *attr, pid_t pid,
42 int cpu, int group_fd,
43 unsigned long flags)
44{
45 attr->size = sizeof(*attr);
46 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
47}
48
49static inline bool breakpoint_test(int len)
50{
51 struct perf_event_attr attr;
52 int fd;
53
54 /* setup counters */
55 memset(&attr, 0, sizeof(attr));
56 attr.disabled = 1;
57 attr.type = PERF_TYPE_BREAKPOINT;
58 attr.bp_type = HW_BREAKPOINT_R;
59 /* bp_addr can point anywhere but needs to be aligned */
60 attr.bp_addr = (__u64)(&attr) & 0xfffffffffffff800;
61 attr.bp_len = len;
62 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
63 if (fd < 0)
64 return false;
65 close(fd);
66 return true;
67}
68
69static inline bool perf_breakpoint_supported(void)
70{
71 return breakpoint_test(4);
72}
73
74static inline bool dawr_supported(void)
75{
76 return breakpoint_test(DAWR_LENGTH_MAX);
77}
78
79static int runtestsingle(int readwriteflag, int exclude_user, int arraytest)
80{
81 int i,j;
82 struct perf_event_attr attr;
83 size_t res;
84 unsigned long long breaks, needed;
85 int readint;
86 int readintarraybig[2*DAWR_LENGTH_MAX/sizeof(int)];
87 int *readintalign;
88 volatile int *ptr;
89 int break_fd;
90 int loop_num = MAX_LOOPS - (rand() % 100); /* provide some variability */
91 volatile int *k;
92
93 /* align to 0x400 boundary as required by DAWR */
94 readintalign = (int *)(((unsigned long)readintarraybig + 0x7ff) &
95 0xfffffffffffff800);
96
97 ptr = &readint;
98 if (arraytest)
99 ptr = &readintalign[0];
100
101 /* setup counters */
102 memset(&attr, 0, sizeof(attr));
103 attr.disabled = 1;
104 attr.type = PERF_TYPE_BREAKPOINT;
105 attr.bp_type = readwriteflag;
106 attr.bp_addr = (__u64)ptr;
107 attr.bp_len = sizeof(int);
108 if (arraytest)
109 attr.bp_len = DAWR_LENGTH_MAX;
110 attr.exclude_user = exclude_user;
111 break_fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
112 if (break_fd < 0) {
113 perror("sys_perf_event_open");
114 exit(1);
115 }
116
117 /* start counters */
118 ioctl(break_fd, PERF_EVENT_IOC_ENABLE);
119
120 /* Test a bunch of reads and writes */
121 k = &readint;
122 for (i = 0; i < loop_num; i++) {
123 if (arraytest)
124 k = &(readintalign[i % (DAWR_LENGTH_MAX/sizeof(int))]);
125
126 j = *k;
127 *k = j;
128 }
129
130 /* stop counters */
131 ioctl(break_fd, PERF_EVENT_IOC_DISABLE);
132
133 /* read and check counters */
134 res = read(break_fd, &breaks, sizeof(unsigned long long));
135 assert(res == sizeof(unsigned long long));
136 /* we read and write each loop, so subtract the ones we are counting */
137 needed = 0;
138 if (readwriteflag & HW_BREAKPOINT_R)
139 needed += loop_num;
140 if (readwriteflag & HW_BREAKPOINT_W)
141 needed += loop_num;
142 needed = needed * (1 - exclude_user);
143 printf("TESTED: addr:0x%lx brks:% 8lld loops:% 8i rw:%i !user:%i array:%i\n",
144 (unsigned long int)ptr, breaks, loop_num, readwriteflag, exclude_user, arraytest);
145 if (breaks != needed) {
146 printf("FAILED: 0x%lx brks:%lld needed:%lli %i %i %i\n\n",
147 (unsigned long int)ptr, breaks, needed, loop_num, readwriteflag, exclude_user);
148 return 1;
149 }
150 close(break_fd);
151
152 return 0;
153}
154
155static int runtest(void)
156{
157 int rwflag;
158 int exclude_user;
159 int ret;
160
161 /*
162 * perf defines rwflag as two bits read and write and at least
163 * one must be set. So range 1-3.
164 */
165 for (rwflag = 1 ; rwflag < 4; rwflag++) {
166 for (exclude_user = 0 ; exclude_user < 2; exclude_user++) {
167 ret = runtestsingle(rwflag, exclude_user, 0);
168 if (ret)
169 return ret;
170
171 /* if we have the dawr, we can do an array test */
172 if (!dawr_supported())
173 continue;
174 ret = runtestsingle(rwflag, exclude_user, 1);
175 if (ret)
176 return ret;
177 }
178 }
179 return 0;
180}
181
182
183static int perf_hwbreak(void)
184{
185 srand ( time(NULL) );
186
187 SKIP_IF(!perf_breakpoint_supported());
188
189 return runtest();
190}
191
192int main(int argc, char *argv[], char **envp)
193{
194 return test_harness(perf_hwbreak, "perf_hwbreak");
195}
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c b/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c
new file mode 100644
index 000000000000..3066d310f32b
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c
@@ -0,0 +1,342 @@
1// SPDX-License-Identifier: GPL-2.0+
2
3/*
4 * Ptrace test for hw breakpoints
5 *
6 * Based on tools/testing/selftests/breakpoints/breakpoint_test.c
7 *
8 * This test forks and the parent then traces the child doing various
9 * types of ptrace enabled breakpoints
10 *
11 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
12 */
13
14#include <sys/ptrace.h>
15#include <unistd.h>
16#include <stddef.h>
17#include <sys/user.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <signal.h>
21#include <sys/types.h>
22#include <sys/wait.h>
23#include "ptrace.h"
24
25/* Breakpoint access modes */
26enum {
27 BP_X = 1,
28 BP_RW = 2,
29 BP_W = 4,
30};
31
32static pid_t child_pid;
33static struct ppc_debug_info dbginfo;
34
35static void get_dbginfo(void)
36{
37 int ret;
38
39 ret = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
40 if (ret) {
41 perror("Can't get breakpoint info\n");
42 exit(-1);
43 }
44}
45
46static bool hwbreak_present(void)
47{
48 return (dbginfo.num_data_bps != 0);
49}
50
51static bool dawr_present(void)
52{
53 return !!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
54}
55
56static void set_breakpoint_addr(void *addr)
57{
58 int ret;
59
60 ret = ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, addr);
61 if (ret) {
62 perror("Can't set breakpoint addr\n");
63 exit(-1);
64 }
65}
66
67static int set_hwbreakpoint_addr(void *addr, int range)
68{
69 int ret;
70
71 struct ppc_hw_breakpoint info;
72
73 info.version = 1;
74 info.trigger_type = PPC_BREAKPOINT_TRIGGER_RW;
75 info.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
76 if (range > 0)
77 info.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
78 info.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
79 info.addr = (__u64)addr;
80 info.addr2 = (__u64)addr + range;
81 info.condition_value = 0;
82
83 ret = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
84 if (ret < 0) {
85 perror("Can't set breakpoint\n");
86 exit(-1);
87 }
88 return ret;
89}
90
91static int del_hwbreakpoint_addr(int watchpoint_handle)
92{
93 int ret;
94
95 ret = ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, watchpoint_handle);
96 if (ret < 0) {
97 perror("Can't delete hw breakpoint\n");
98 exit(-1);
99 }
100 return ret;
101}
102
103#define DAWR_LENGTH_MAX 512
104
105/* Dummy variables to test read/write accesses */
106static unsigned long long
107 dummy_array[DAWR_LENGTH_MAX / sizeof(unsigned long long)]
108 __attribute__((aligned(512)));
109static unsigned long long *dummy_var = dummy_array;
110
111static void write_var(int len)
112{
113 long long *plval;
114 char *pcval;
115 short *psval;
116 int *pival;
117
118 switch (len) {
119 case 1:
120 pcval = (char *)dummy_var;
121 *pcval = 0xff;
122 break;
123 case 2:
124 psval = (short *)dummy_var;
125 *psval = 0xffff;
126 break;
127 case 4:
128 pival = (int *)dummy_var;
129 *pival = 0xffffffff;
130 break;
131 case 8:
132 plval = (long long *)dummy_var;
133 *plval = 0xffffffffffffffffLL;
134 break;
135 }
136}
137
138static void read_var(int len)
139{
140 char cval __attribute__((unused));
141 short sval __attribute__((unused));
142 int ival __attribute__((unused));
143 long long lval __attribute__((unused));
144
145 switch (len) {
146 case 1:
147 cval = *(char *)dummy_var;
148 break;
149 case 2:
150 sval = *(short *)dummy_var;
151 break;
152 case 4:
153 ival = *(int *)dummy_var;
154 break;
155 case 8:
156 lval = *(long long *)dummy_var;
157 break;
158 }
159}
160
161/*
162 * Do the r/w accesses to trigger the breakpoints. And run
163 * the usual traps.
164 */
165static void trigger_tests(void)
166{
167 int len, ret;
168
169 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
170 if (ret) {
171 perror("Can't be traced?\n");
172 return;
173 }
174
175 /* Wake up father so that it sets up the first test */
176 kill(getpid(), SIGUSR1);
177
178 /* Test write watchpoints */
179 for (len = 1; len <= sizeof(long); len <<= 1)
180 write_var(len);
181
182 /* Test read/write watchpoints (on read accesses) */
183 for (len = 1; len <= sizeof(long); len <<= 1)
184 read_var(len);
185
186 /* Test when breakpoint is unset */
187
188 /* Test write watchpoints */
189 for (len = 1; len <= sizeof(long); len <<= 1)
190 write_var(len);
191
192 /* Test read/write watchpoints (on read accesses) */
193 for (len = 1; len <= sizeof(long); len <<= 1)
194 read_var(len);
195}
196
197static void check_success(const char *msg)
198{
199 const char *msg2;
200 int status;
201
202 /* Wait for the child to SIGTRAP */
203 wait(&status);
204
205 msg2 = "Failed";
206
207 if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
208 msg2 = "Child process hit the breakpoint";
209 }
210
211 printf("%s Result: [%s]\n", msg, msg2);
212}
213
214static void launch_watchpoints(char *buf, int mode, int len,
215 struct ppc_debug_info *dbginfo, bool dawr)
216{
217 const char *mode_str;
218 unsigned long data = (unsigned long)(dummy_var);
219 int wh, range;
220
221 data &= ~0x7UL;
222
223 if (mode == BP_W) {
224 data |= (1UL << 1);
225 mode_str = "write";
226 } else {
227 data |= (1UL << 0);
228 data |= (1UL << 1);
229 mode_str = "read";
230 }
231
232 /* Set DABR_TRANSLATION bit */
233 data |= (1UL << 2);
234
235 /* use PTRACE_SET_DEBUGREG breakpoints */
236 set_breakpoint_addr((void *)data);
237 ptrace(PTRACE_CONT, child_pid, NULL, 0);
238 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
239 check_success(buf);
240 /* Unregister hw brkpoint */
241 set_breakpoint_addr(NULL);
242
243 data = (data & ~7); /* remove dabr control bits */
244
245 /* use PPC_PTRACE_SETHWDEBUG breakpoint */
246 if (!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
247 return; /* not supported */
248 wh = set_hwbreakpoint_addr((void *)data, 0);
249 ptrace(PTRACE_CONT, child_pid, NULL, 0);
250 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
251 check_success(buf);
252 /* Unregister hw brkpoint */
253 del_hwbreakpoint_addr(wh);
254
255 /* try a wider range */
256 range = 8;
257 if (dawr)
258 range = 512 - ((int)data & (DAWR_LENGTH_MAX - 1));
259 wh = set_hwbreakpoint_addr((void *)data, range);
260 ptrace(PTRACE_CONT, child_pid, NULL, 0);
261 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
262 check_success(buf);
263 /* Unregister hw brkpoint */
264 del_hwbreakpoint_addr(wh);
265}
266
267/* Set the breakpoints and check the child successfully trigger them */
268static int launch_tests(bool dawr)
269{
270 char buf[1024];
271 int len, i, status;
272
273 struct ppc_debug_info dbginfo;
274
275 i = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
276 if (i) {
277 perror("Can't set breakpoint info\n");
278 exit(-1);
279 }
280 if (!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
281 printf("WARNING: Kernel doesn't support PPC_PTRACE_SETHWDEBUG\n");
282
283 /* Write watchpoint */
284 for (len = 1; len <= sizeof(long); len <<= 1)
285 launch_watchpoints(buf, BP_W, len, &dbginfo, dawr);
286
287 /* Read-Write watchpoint */
288 for (len = 1; len <= sizeof(long); len <<= 1)
289 launch_watchpoints(buf, BP_RW, len, &dbginfo, dawr);
290
291 ptrace(PTRACE_CONT, child_pid, NULL, 0);
292
293 /*
294 * Now we have unregistered the breakpoint, access by child
295 * should not cause SIGTRAP.
296 */
297
298 wait(&status);
299
300 if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
301 printf("FAIL: Child process hit the breakpoint, which is not expected\n");
302 ptrace(PTRACE_CONT, child_pid, NULL, 0);
303 return TEST_FAIL;
304 }
305
306 if (WIFEXITED(status))
307 printf("Child exited normally\n");
308
309 return TEST_PASS;
310}
311
312static int ptrace_hwbreak(void)
313{
314 pid_t pid;
315 int ret;
316 bool dawr;
317
318 pid = fork();
319 if (!pid) {
320 trigger_tests();
321 return 0;
322 }
323
324 wait(NULL);
325
326 child_pid = pid;
327
328 get_dbginfo();
329 SKIP_IF(!hwbreak_present());
330 dawr = dawr_present();
331
332 ret = launch_tests(dawr);
333
334 wait(NULL);
335
336 return ret;
337}
338
339int main(int argc, char **argv, char **envp)
340{
341 return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
342}
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
new file mode 100644
index 000000000000..5cf631f792cc
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
@@ -0,0 +1,327 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Ptrace test for Memory Protection Key registers
4 *
5 * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
6 * Copyright (C) 2018 IBM Corporation.
7 */
8#include "ptrace.h"
9#include "child.h"
10
11#ifndef __NR_pkey_alloc
12#define __NR_pkey_alloc 384
13#endif
14
15#ifndef __NR_pkey_free
16#define __NR_pkey_free 385
17#endif
18
19#ifndef NT_PPC_PKEY
20#define NT_PPC_PKEY 0x110
21#endif
22
23#ifndef PKEY_DISABLE_EXECUTE
24#define PKEY_DISABLE_EXECUTE 0x4
25#endif
26
27#define AMR_BITS_PER_PKEY 2
28#define PKEY_REG_BITS (sizeof(u64) * 8)
29#define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
30
31static const char user_read[] = "[User Read (Running)]";
32static const char user_write[] = "[User Write (Running)]";
33static const char ptrace_read_running[] = "[Ptrace Read (Running)]";
34static const char ptrace_write_running[] = "[Ptrace Write (Running)]";
35
36/* Information shared between the parent and the child. */
37struct shared_info {
38 struct child_sync child_sync;
39
40 /* AMR value the parent expects to read from the child. */
41 unsigned long amr1;
42
43 /* AMR value the parent is expected to write to the child. */
44 unsigned long amr2;
45
46 /* AMR value that ptrace should refuse to write to the child. */
47 unsigned long amr3;
48
49 /* IAMR value the parent expects to read from the child. */
50 unsigned long expected_iamr;
51
52 /* UAMOR value the parent expects to read from the child. */
53 unsigned long expected_uamor;
54
55 /*
56 * IAMR and UAMOR values that ptrace should refuse to write to the child
57 * (even though they're valid ones) because userspace doesn't have
58 * access to those registers.
59 */
60 unsigned long new_iamr;
61 unsigned long new_uamor;
62};
63
64static int sys_pkey_alloc(unsigned long flags, unsigned long init_access_rights)
65{
66 return syscall(__NR_pkey_alloc, flags, init_access_rights);
67}
68
69static int sys_pkey_free(int pkey)
70{
71 return syscall(__NR_pkey_free, pkey);
72}
73
74static int child(struct shared_info *info)
75{
76 unsigned long reg;
77 bool disable_execute = true;
78 int pkey1, pkey2, pkey3;
79 int ret;
80
81 /* Wait until parent fills out the initial register values. */
82 ret = wait_parent(&info->child_sync);
83 if (ret)
84 return ret;
85
86 /* Get some pkeys so that we can change their bits in the AMR. */
87 pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
88 if (pkey1 < 0) {
89 pkey1 = sys_pkey_alloc(0, 0);
90 CHILD_FAIL_IF(pkey1 < 0, &info->child_sync);
91
92 disable_execute = false;
93 }
94
95 pkey2 = sys_pkey_alloc(0, 0);
96 CHILD_FAIL_IF(pkey2 < 0, &info->child_sync);
97
98 pkey3 = sys_pkey_alloc(0, 0);
99 CHILD_FAIL_IF(pkey3 < 0, &info->child_sync);
100
101 info->amr1 |= 3ul << pkeyshift(pkey1);
102 info->amr2 |= 3ul << pkeyshift(pkey2);
103 info->amr3 |= info->amr2 | 3ul << pkeyshift(pkey3);
104
105 if (disable_execute)
106 info->expected_iamr |= 1ul << pkeyshift(pkey1);
107
108 info->expected_uamor |= 3ul << pkeyshift(pkey1) |
109 3ul << pkeyshift(pkey2);
110 info->new_iamr |= 1ul << pkeyshift(pkey1) | 1ul << pkeyshift(pkey2);
111 info->new_uamor |= 3ul << pkeyshift(pkey1);
112
113 /*
114 * We won't use pkey3. We just want a plausible but invalid key to test
115 * whether ptrace will let us write to AMR bits we are not supposed to.
116 *
117 * This also tests whether the kernel restores the UAMOR permissions
118 * after a key is freed.
119 */
120 sys_pkey_free(pkey3);
121
122 printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
123 user_write, info->amr1, pkey1, pkey2, pkey3);
124
125 mtspr(SPRN_AMR, info->amr1);
126
127 /* Wait for parent to read our AMR value and write a new one. */
128 ret = prod_parent(&info->child_sync);
129 CHILD_FAIL_IF(ret, &info->child_sync);
130
131 ret = wait_parent(&info->child_sync);
132 if (ret)
133 return ret;
134
135 reg = mfspr(SPRN_AMR);
136
137 printf("%-30s AMR: %016lx\n", user_read, reg);
138
139 CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
140
141 /*
142 * Wait for parent to try to write an invalid AMR value.
143 */
144 ret = prod_parent(&info->child_sync);
145 CHILD_FAIL_IF(ret, &info->child_sync);
146
147 ret = wait_parent(&info->child_sync);
148 if (ret)
149 return ret;
150
151 reg = mfspr(SPRN_AMR);
152
153 printf("%-30s AMR: %016lx\n", user_read, reg);
154
155 CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
156
157 /*
158 * Wait for parent to try to write an IAMR and a UAMOR value. We can't
159 * verify them, but we can verify that the AMR didn't change.
160 */
161 ret = prod_parent(&info->child_sync);
162 CHILD_FAIL_IF(ret, &info->child_sync);
163
164 ret = wait_parent(&info->child_sync);
165 if (ret)
166 return ret;
167
168 reg = mfspr(SPRN_AMR);
169
170 printf("%-30s AMR: %016lx\n", user_read, reg);
171
172 CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
173
174 /* Now let parent now that we are finished. */
175
176 ret = prod_parent(&info->child_sync);
177 CHILD_FAIL_IF(ret, &info->child_sync);
178
179 return TEST_PASS;
180}
181
182static int parent(struct shared_info *info, pid_t pid)
183{
184 unsigned long regs[3];
185 int ret, status;
186
187 /*
188 * Get the initial values for AMR, IAMR and UAMOR and communicate them
189 * to the child.
190 */
191 ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
192 PARENT_SKIP_IF_UNSUPPORTED(ret, &info->child_sync);
193 PARENT_FAIL_IF(ret, &info->child_sync);
194
195 info->amr1 = info->amr2 = info->amr3 = regs[0];
196 info->expected_iamr = info->new_iamr = regs[1];
197 info->expected_uamor = info->new_uamor = regs[2];
198
199 /* Wake up child so that it can set itself up. */
200 ret = prod_child(&info->child_sync);
201 PARENT_FAIL_IF(ret, &info->child_sync);
202
203 ret = wait_child(&info->child_sync);
204 if (ret)
205 return ret;
206
207 /* Verify that we can read the pkey registers from the child. */
208 ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
209 PARENT_FAIL_IF(ret, &info->child_sync);
210
211 printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
212 ptrace_read_running, regs[0], regs[1], regs[2]);
213
214 PARENT_FAIL_IF(regs[0] != info->amr1, &info->child_sync);
215 PARENT_FAIL_IF(regs[1] != info->expected_iamr, &info->child_sync);
216 PARENT_FAIL_IF(regs[2] != info->expected_uamor, &info->child_sync);
217
218 /* Write valid AMR value in child. */
219 ret = ptrace_write_regs(pid, NT_PPC_PKEY, &info->amr2, 1);
220 PARENT_FAIL_IF(ret, &info->child_sync);
221
222 printf("%-30s AMR: %016lx\n", ptrace_write_running, info->amr2);
223
224 /* Wake up child so that it can verify it changed. */
225 ret = prod_child(&info->child_sync);
226 PARENT_FAIL_IF(ret, &info->child_sync);
227
228 ret = wait_child(&info->child_sync);
229 if (ret)
230 return ret;
231
232 /* Write invalid AMR value in child. */
233 ret = ptrace_write_regs(pid, NT_PPC_PKEY, &info->amr3, 1);
234 PARENT_FAIL_IF(ret, &info->child_sync);
235
236 printf("%-30s AMR: %016lx\n", ptrace_write_running, info->amr3);
237
238 /* Wake up child so that it can verify it didn't change. */
239 ret = prod_child(&info->child_sync);
240 PARENT_FAIL_IF(ret, &info->child_sync);
241
242 ret = wait_child(&info->child_sync);
243 if (ret)
244 return ret;
245
246 /* Try to write to IAMR. */
247 regs[0] = info->amr1;
248 regs[1] = info->new_iamr;
249 ret = ptrace_write_regs(pid, NT_PPC_PKEY, regs, 2);
250 PARENT_FAIL_IF(!ret, &info->child_sync);
251
252 printf("%-30s AMR: %016lx IAMR: %016lx\n",
253 ptrace_write_running, regs[0], regs[1]);
254
255 /* Try to write to IAMR and UAMOR. */
256 regs[2] = info->new_uamor;
257 ret = ptrace_write_regs(pid, NT_PPC_PKEY, regs, 3);
258 PARENT_FAIL_IF(!ret, &info->child_sync);
259
260 printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
261 ptrace_write_running, regs[0], regs[1], regs[2]);
262
263 /* Verify that all registers still have their expected values. */
264 ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
265 PARENT_FAIL_IF(ret, &info->child_sync);
266
267 printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
268 ptrace_read_running, regs[0], regs[1], regs[2]);
269
270 PARENT_FAIL_IF(regs[0] != info->amr2, &info->child_sync);
271 PARENT_FAIL_IF(regs[1] != info->expected_iamr, &info->child_sync);
272 PARENT_FAIL_IF(regs[2] != info->expected_uamor, &info->child_sync);
273
274 /* Wake up child so that it can verify AMR didn't change and wrap up. */
275 ret = prod_child(&info->child_sync);
276 PARENT_FAIL_IF(ret, &info->child_sync);
277
278 ret = wait(&status);
279 if (ret != pid) {
280 printf("Child's exit status not captured\n");
281 ret = TEST_PASS;
282 } else if (!WIFEXITED(status)) {
283 printf("Child exited abnormally\n");
284 ret = TEST_FAIL;
285 } else
286 ret = WEXITSTATUS(status) ? TEST_FAIL : TEST_PASS;
287
288 return ret;
289}
290
291static int ptrace_pkey(void)
292{
293 struct shared_info *info;
294 int shm_id;
295 int ret;
296 pid_t pid;
297
298 shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
299 info = shmat(shm_id, NULL, 0);
300
301 ret = init_child_sync(&info->child_sync);
302 if (ret)
303 return ret;
304
305 pid = fork();
306 if (pid < 0) {
307 perror("fork() failed");
308 ret = TEST_FAIL;
309 } else if (pid == 0)
310 ret = child(info);
311 else
312 ret = parent(info, pid);
313
314 shmdt(info);
315
316 if (pid) {
317 destroy_child_sync(&info->child_sync);
318 shmctl(shm_id, IPC_RMID, NULL);
319 }
320
321 return ret;
322}
323
324int main(int argc, char *argv[])
325{
326 return test_harness(ptrace_pkey, "ptrace_pkey");
327}
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace.h b/tools/testing/selftests/powerpc/ptrace/ptrace.h
index 19fb825270a1..34201cfa8335 100644
--- a/tools/testing/selftests/powerpc/ptrace/ptrace.h
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace.h
@@ -102,6 +102,44 @@ int cont_trace(pid_t child)
102 return TEST_PASS; 102 return TEST_PASS;
103} 103}
104 104
105int ptrace_read_regs(pid_t child, unsigned long type, unsigned long regs[],
106 int n)
107{
108 struct iovec iov;
109 long ret;
110
111 FAIL_IF(start_trace(child));
112
113 iov.iov_base = regs;
114 iov.iov_len = n * sizeof(unsigned long);
115
116 ret = ptrace(PTRACE_GETREGSET, child, type, &iov);
117 if (ret)
118 return ret;
119
120 FAIL_IF(stop_trace(child));
121
122 return TEST_PASS;
123}
124
125long ptrace_write_regs(pid_t child, unsigned long type, unsigned long regs[],
126 int n)
127{
128 struct iovec iov;
129 long ret;
130
131 FAIL_IF(start_trace(child));
132
133 iov.iov_base = regs;
134 iov.iov_len = n * sizeof(unsigned long);
135
136 ret = ptrace(PTRACE_SETREGSET, child, type, &iov);
137
138 FAIL_IF(stop_trace(child));
139
140 return ret;
141}
142
105/* TAR, PPR, DSCR */ 143/* TAR, PPR, DSCR */
106int show_tar_registers(pid_t child, unsigned long *out) 144int show_tar_registers(pid_t child, unsigned long *out)
107{ 145{
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore
index bb90d4b79524..c3ee8393dae8 100644
--- a/tools/testing/selftests/powerpc/tm/.gitignore
+++ b/tools/testing/selftests/powerpc/tm/.gitignore
@@ -14,3 +14,4 @@ tm-signal-context-chk-vsx
14tm-vmx-unavail 14tm-vmx-unavail
15tm-unavailable 15tm-unavailable
16tm-trap 16tm-trap
17tm-sigreturn