aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-10-16 07:04:34 -0400
committerIngo Molnar <mingo@kernel.org>2016-10-16 07:04:34 -0400
commit4d69f155d58d0f75c5404ea502178b1943a04755 (patch)
treefe5b7608f05f6951fce748ea1e93d942b52902bd /tools
parentc474e50711aa79b7bd0ea30b44744baca5650375 (diff)
parent1001354ca34179f3db924eb66672442a173147dc (diff)
Merge tag 'v4.9-rc1' into x86/fpu, to resolve conflict
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/accounting/.gitignore1
-rw-r--r--tools/accounting/Makefile9
-rw-r--r--tools/accounting/getdelays.c550
-rw-r--r--tools/arch/x86/include/asm/cpufeatures.h1
-rw-r--r--tools/arch/x86/lib/memcpy_64.S6
-rw-r--r--tools/build/Build2
-rw-r--r--tools/build/Build.include6
-rw-r--r--tools/build/Makefile8
-rw-r--r--tools/build/Makefile.build26
-rw-r--r--tools/build/Makefile.feature2
-rw-r--r--tools/build/Makefile.include4
-rw-r--r--tools/build/feature/Makefile10
-rw-r--r--tools/build/feature/test-cxx.cpp15
-rw-r--r--tools/hv/hv_kvp_daemon.c2
-rw-r--r--tools/hv/hv_vss_daemon.c3
-rw-r--r--tools/iio/iio_utils.c11
-rw-r--r--tools/iio/lsiio.c3
-rw-r--r--tools/include/uapi/linux/bpf.h4
-rw-r--r--tools/laptop/dslm/.gitignore1
-rw-r--r--tools/laptop/dslm/Makefile9
-rw-r--r--tools/laptop/dslm/dslm.c166
-rw-r--r--tools/lib/subcmd/pager.c16
-rw-r--r--tools/lib/subcmd/pager.h1
-rw-r--r--tools/lib/traceevent/kbuffer-parse.c1
-rw-r--r--tools/pcmcia/.gitignore1
-rw-r--r--tools/pcmcia/Makefile9
-rw-r--r--tools/pcmcia/crc32hash.c32
-rw-r--r--tools/perf/Documentation/perf-list.txt12
-rw-r--r--tools/perf/Documentation/tips.txt4
-rw-r--r--tools/perf/Makefile.perf34
-rw-r--r--tools/perf/arch/powerpc/util/header.c11
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c3
-rw-r--r--tools/perf/arch/x86/util/header.c24
-rw-r--r--tools/perf/builtin-list.c20
-rw-r--r--tools/perf/pmu-events/Build13
-rw-r--r--tools/perf/pmu-events/README147
-rw-r--r--tools/perf/pmu-events/jevents.c814
-rw-r--r--tools/perf/pmu-events/jevents.h18
-rw-r--r--tools/perf/pmu-events/jsmn.c313
-rw-r--r--tools/perf/pmu-events/jsmn.h67
-rw-r--r--tools/perf/pmu-events/json.c162
-rw-r--r--tools/perf/pmu-events/json.h38
-rw-r--r--tools/perf/pmu-events/pmu-events.h37
-rw-r--r--tools/perf/util/evlist.c12
-rw-r--r--tools/perf/util/evsel.c3
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.c38
-rw-r--r--tools/perf/util/machine.c6
-rw-r--r--tools/perf/util/parse-events.c8
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/pmu.c176
-rw-r--r--tools/perf/util/pmu.h6
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/strbuf.h3
-rw-r--r--tools/perf/util/thread.c9
-rw-r--r--tools/spi/Makefile2
-rw-r--r--tools/spi/spidev_test.c3
-rw-r--r--tools/testing/nvdimm/Kbuild1
-rw-r--r--tools/testing/nvdimm/config_check.c1
-rw-r--r--tools/testing/nvdimm/test/iomap.c151
-rw-r--r--tools/testing/nvdimm/test/nfit.c160
-rw-r--r--tools/testing/nvdimm/test/nfit_test.h12
-rw-r--r--tools/testing/radix-tree/Makefile3
-rw-r--r--tools/testing/radix-tree/iteration_check.c180
-rw-r--r--tools/testing/radix-tree/main.c1
-rw-r--r--tools/testing/radix-tree/regression1.c2
-rw-r--r--tools/testing/radix-tree/test.h1
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/filesystems/.gitignore1
-rw-r--r--tools/testing/selftests/filesystems/Makefile7
-rw-r--r--tools/testing/selftests/filesystems/dnotify_test.c34
-rwxr-xr-xtools/testing/selftests/futex/functional/run.sh2
-rwxr-xr-xtools/testing/selftests/futex/run.sh2
-rw-r--r--tools/testing/selftests/ia64/.gitignore1
-rw-r--r--tools/testing/selftests/ia64/Makefile8
-rw-r--r--tools/testing/selftests/ia64/aliasing-test.c263
-rw-r--r--tools/testing/selftests/networking/timestamping/.gitignore3
-rw-r--r--tools/testing/selftests/networking/timestamping/Makefile8
-rw-r--r--tools/testing/selftests/networking/timestamping/hwtstamp_config.c134
-rw-r--r--tools/testing/selftests/networking/timestamping/timestamping.c528
-rw-r--r--tools/testing/selftests/networking/timestamping/txtimestamp.c549
-rw-r--r--tools/testing/selftests/nsfs/Makefile12
-rw-r--r--tools/testing/selftests/nsfs/owner.c91
-rw-r--r--tools/testing/selftests/nsfs/pidns.c78
-rw-r--r--tools/testing/selftests/powerpc/Makefile1
-rw-r--r--tools/testing/selftests/powerpc/copyloops/asm/export.h1
-rw-r--r--tools/testing/selftests/powerpc/fpu_asm.h80
-rw-r--r--tools/testing/selftests/powerpc/gpr_asm.h96
-rw-r--r--tools/testing/selftests/powerpc/harness.c9
-rw-r--r--tools/testing/selftests/powerpc/math/.gitignore1
-rw-r--r--tools/testing/selftests/powerpc/math/Makefile5
-rw-r--r--tools/testing/selftests/powerpc/math/fpu_asm.S73
-rw-r--r--tools/testing/selftests/powerpc/math/vmx_asm.S85
-rw-r--r--tools/testing/selftests/powerpc/math/vsx_asm.S61
-rw-r--r--tools/testing/selftests/powerpc/math/vsx_preempt.c147
-rw-r--r--tools/testing/selftests/powerpc/signal/.gitignore2
-rw-r--r--tools/testing/selftests/powerpc/signal/Makefile13
-rw-r--r--tools/testing/selftests/powerpc/signal/signal.S50
-rw-r--r--tools/testing/selftests/powerpc/signal/signal.c111
-rw-r--r--tools/testing/selftests/powerpc/signal/signal_tm.c110
-rw-r--r--tools/testing/selftests/powerpc/stringloops/asm/export.h1
-rw-r--r--tools/testing/selftests/powerpc/tm/.gitignore4
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile8
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c92
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c90
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c110
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c125
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-signal.S114
-rw-r--r--tools/testing/selftests/powerpc/tm/tm.h27
-rw-r--r--tools/testing/selftests/powerpc/utils.h9
-rw-r--r--tools/testing/selftests/powerpc/vmx_asm.h96
-rw-r--r--tools/testing/selftests/powerpc/vsx_asm.h71
-rw-r--r--tools/testing/selftests/prctl/.gitignore3
-rw-r--r--tools/testing/selftests/prctl/Makefile15
-rw-r--r--tools/testing/selftests/prctl/disable-tsc-ctxt-sw-stress-test.c97
-rw-r--r--tools/testing/selftests/prctl/disable-tsc-on-off-stress-test.c96
-rw-r--r--tools/testing/selftests/prctl/disable-tsc-test.c95
-rw-r--r--tools/testing/selftests/ptp/.gitignore1
-rw-r--r--tools/testing/selftests/ptp/Makefile8
-rw-r--r--tools/testing/selftests/ptp/testptp.c523
-rw-r--r--tools/testing/selftests/ptp/testptp.mk33
-rw-r--r--tools/testing/selftests/timers/posix_timers.c4
-rw-r--r--tools/testing/selftests/vDSO/.gitignore2
-rw-r--r--tools/testing/selftests/vDSO/Makefile20
-rw-r--r--tools/testing/selftests/vDSO/parse_vdso.c269
-rw-r--r--tools/testing/selftests/vDSO/vdso_standalone_test_x86.c128
-rw-r--r--tools/testing/selftests/vDSO/vdso_test.c52
-rw-r--r--tools/testing/selftests/vm/.gitignore1
-rw-r--r--tools/testing/selftests/vm/Makefile4
-rw-r--r--tools/testing/selftests/vm/mlock-random-test.c293
-rw-r--r--tools/testing/selftests/vm/mlock2-tests.c63
-rw-r--r--tools/testing/selftests/vm/mlock2.h62
-rw-r--r--tools/testing/selftests/watchdog/.gitignore1
-rw-r--r--tools/testing/selftests/watchdog/Makefile8
-rw-r--r--tools/testing/selftests/watchdog/watchdog-test.c105
-rw-r--r--tools/testing/selftests/x86/Makefile3
-rw-r--r--tools/testing/selftests/x86/pkey-helpers.h219
-rw-r--r--tools/testing/selftests/x86/protection_keys.c1410
-rw-r--r--tools/testing/selftests/zram/README2
139 files changed, 9873 insertions, 358 deletions
diff --git a/tools/accounting/.gitignore b/tools/accounting/.gitignore
new file mode 100644
index 000000000000..86485203c4ae
--- /dev/null
+++ b/tools/accounting/.gitignore
@@ -0,0 +1 @@
getdelays
diff --git a/tools/accounting/Makefile b/tools/accounting/Makefile
new file mode 100644
index 000000000000..647c94a219bf
--- /dev/null
+++ b/tools/accounting/Makefile
@@ -0,0 +1,9 @@
1CC := $(CROSS_COMPILE)gcc
2CFLAGS := -I../../usr/include
3
4PROGS := getdelays
5
6all: $(PROGS)
7
8clean:
9 rm -fr $(PROGS)
diff --git a/tools/accounting/getdelays.c b/tools/accounting/getdelays.c
new file mode 100644
index 000000000000..b5ca536e56a8
--- /dev/null
+++ b/tools/accounting/getdelays.c
@@ -0,0 +1,550 @@
1/* getdelays.c
2 *
3 * Utility to get per-pid and per-tgid delay accounting statistics
4 * Also illustrates usage of the taskstats interface
5 *
6 * Copyright (C) Shailabh Nagar, IBM Corp. 2005
7 * Copyright (C) Balbir Singh, IBM Corp. 2006
8 * Copyright (c) Jay Lan, SGI. 2006
9 *
10 * Compile with
11 * gcc -I/usr/src/linux/include getdelays.c -o getdelays
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <errno.h>
17#include <unistd.h>
18#include <poll.h>
19#include <string.h>
20#include <fcntl.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sys/socket.h>
24#include <sys/wait.h>
25#include <signal.h>
26
27#include <linux/genetlink.h>
28#include <linux/taskstats.h>
29#include <linux/cgroupstats.h>
30
31/*
32 * Generic macros for dealing with netlink sockets. Might be duplicated
33 * elsewhere. It is recommended that commercial grade applications use
34 * libnl or libnetlink and use the interfaces provided by the library
35 */
36#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
37#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
38#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
39#define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
40
41#define err(code, fmt, arg...) \
42 do { \
43 fprintf(stderr, fmt, ##arg); \
44 exit(code); \
45 } while (0)
46
47int done;
48int rcvbufsz;
49char name[100];
50int dbg;
51int print_delays;
52int print_io_accounting;
53int print_task_context_switch_counts;
54
55#define PRINTF(fmt, arg...) { \
56 if (dbg) { \
57 printf(fmt, ##arg); \
58 } \
59 }
60
61/* Maximum size of response requested or message sent */
62#define MAX_MSG_SIZE 1024
63/* Maximum number of cpus expected to be specified in a cpumask */
64#define MAX_CPUS 32
65
66struct msgtemplate {
67 struct nlmsghdr n;
68 struct genlmsghdr g;
69 char buf[MAX_MSG_SIZE];
70};
71
72char cpumask[100+6*MAX_CPUS];
73
74static void usage(void)
75{
76 fprintf(stderr, "getdelays [-dilv] [-w logfile] [-r bufsize] "
77 "[-m cpumask] [-t tgid] [-p pid]\n");
78 fprintf(stderr, " -d: print delayacct stats\n");
79 fprintf(stderr, " -i: print IO accounting (works only with -p)\n");
80 fprintf(stderr, " -l: listen forever\n");
81 fprintf(stderr, " -v: debug on\n");
82 fprintf(stderr, " -C: container path\n");
83}
84
85/*
86 * Create a raw netlink socket and bind
87 */
88static int create_nl_socket(int protocol)
89{
90 int fd;
91 struct sockaddr_nl local;
92
93 fd = socket(AF_NETLINK, SOCK_RAW, protocol);
94 if (fd < 0)
95 return -1;
96
97 if (rcvbufsz)
98 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
99 &rcvbufsz, sizeof(rcvbufsz)) < 0) {
100 fprintf(stderr, "Unable to set socket rcv buf size to %d\n",
101 rcvbufsz);
102 goto error;
103 }
104
105 memset(&local, 0, sizeof(local));
106 local.nl_family = AF_NETLINK;
107
108 if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0)
109 goto error;
110
111 return fd;
112error:
113 close(fd);
114 return -1;
115}
116
117
118static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
119 __u8 genl_cmd, __u16 nla_type,
120 void *nla_data, int nla_len)
121{
122 struct nlattr *na;
123 struct sockaddr_nl nladdr;
124 int r, buflen;
125 char *buf;
126
127 struct msgtemplate msg;
128
129 msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
130 msg.n.nlmsg_type = nlmsg_type;
131 msg.n.nlmsg_flags = NLM_F_REQUEST;
132 msg.n.nlmsg_seq = 0;
133 msg.n.nlmsg_pid = nlmsg_pid;
134 msg.g.cmd = genl_cmd;
135 msg.g.version = 0x1;
136 na = (struct nlattr *) GENLMSG_DATA(&msg);
137 na->nla_type = nla_type;
138 na->nla_len = nla_len + 1 + NLA_HDRLEN;
139 memcpy(NLA_DATA(na), nla_data, nla_len);
140 msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
141
142 buf = (char *) &msg;
143 buflen = msg.n.nlmsg_len ;
144 memset(&nladdr, 0, sizeof(nladdr));
145 nladdr.nl_family = AF_NETLINK;
146 while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr,
147 sizeof(nladdr))) < buflen) {
148 if (r > 0) {
149 buf += r;
150 buflen -= r;
151 } else if (errno != EAGAIN)
152 return -1;
153 }
154 return 0;
155}
156
157
158/*
159 * Probe the controller in genetlink to find the family id
160 * for the TASKSTATS family
161 */
162static int get_family_id(int sd)
163{
164 struct {
165 struct nlmsghdr n;
166 struct genlmsghdr g;
167 char buf[256];
168 } ans;
169
170 int id = 0, rc;
171 struct nlattr *na;
172 int rep_len;
173
174 strcpy(name, TASKSTATS_GENL_NAME);
175 rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
176 CTRL_ATTR_FAMILY_NAME, (void *)name,
177 strlen(TASKSTATS_GENL_NAME)+1);
178 if (rc < 0)
179 return 0; /* sendto() failure? */
180
181 rep_len = recv(sd, &ans, sizeof(ans), 0);
182 if (ans.n.nlmsg_type == NLMSG_ERROR ||
183 (rep_len < 0) || !NLMSG_OK((&ans.n), rep_len))
184 return 0;
185
186 na = (struct nlattr *) GENLMSG_DATA(&ans);
187 na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
188 if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
189 id = *(__u16 *) NLA_DATA(na);
190 }
191 return id;
192}
193
194#define average_ms(t, c) (t / 1000000ULL / (c ? c : 1))
195
196static void print_delayacct(struct taskstats *t)
197{
198 printf("\n\nCPU %15s%15s%15s%15s%15s\n"
199 " %15llu%15llu%15llu%15llu%15.3fms\n"
200 "IO %15s%15s%15s\n"
201 " %15llu%15llu%15llums\n"
202 "SWAP %15s%15s%15s\n"
203 " %15llu%15llu%15llums\n"
204 "RECLAIM %12s%15s%15s\n"
205 " %15llu%15llu%15llums\n",
206 "count", "real total", "virtual total",
207 "delay total", "delay average",
208 (unsigned long long)t->cpu_count,
209 (unsigned long long)t->cpu_run_real_total,
210 (unsigned long long)t->cpu_run_virtual_total,
211 (unsigned long long)t->cpu_delay_total,
212 average_ms((double)t->cpu_delay_total, t->cpu_count),
213 "count", "delay total", "delay average",
214 (unsigned long long)t->blkio_count,
215 (unsigned long long)t->blkio_delay_total,
216 average_ms(t->blkio_delay_total, t->blkio_count),
217 "count", "delay total", "delay average",
218 (unsigned long long)t->swapin_count,
219 (unsigned long long)t->swapin_delay_total,
220 average_ms(t->swapin_delay_total, t->swapin_count),
221 "count", "delay total", "delay average",
222 (unsigned long long)t->freepages_count,
223 (unsigned long long)t->freepages_delay_total,
224 average_ms(t->freepages_delay_total, t->freepages_count));
225}
226
227static void task_context_switch_counts(struct taskstats *t)
228{
229 printf("\n\nTask %15s%15s\n"
230 " %15llu%15llu\n",
231 "voluntary", "nonvoluntary",
232 (unsigned long long)t->nvcsw, (unsigned long long)t->nivcsw);
233}
234
235static void print_cgroupstats(struct cgroupstats *c)
236{
237 printf("sleeping %llu, blocked %llu, running %llu, stopped %llu, "
238 "uninterruptible %llu\n", (unsigned long long)c->nr_sleeping,
239 (unsigned long long)c->nr_io_wait,
240 (unsigned long long)c->nr_running,
241 (unsigned long long)c->nr_stopped,
242 (unsigned long long)c->nr_uninterruptible);
243}
244
245
246static void print_ioacct(struct taskstats *t)
247{
248 printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
249 t->ac_comm,
250 (unsigned long long)t->read_bytes,
251 (unsigned long long)t->write_bytes,
252 (unsigned long long)t->cancelled_write_bytes);
253}
254
255int main(int argc, char *argv[])
256{
257 int c, rc, rep_len, aggr_len, len2;
258 int cmd_type = TASKSTATS_CMD_ATTR_UNSPEC;
259 __u16 id;
260 __u32 mypid;
261
262 struct nlattr *na;
263 int nl_sd = -1;
264 int len = 0;
265 pid_t tid = 0;
266 pid_t rtid = 0;
267
268 int fd = 0;
269 int count = 0;
270 int write_file = 0;
271 int maskset = 0;
272 char *logfile = NULL;
273 int loop = 0;
274 int containerset = 0;
275 char *containerpath = NULL;
276 int cfd = 0;
277 int forking = 0;
278 sigset_t sigset;
279
280 struct msgtemplate msg;
281
282 while (!forking) {
283 c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:c:");
284 if (c < 0)
285 break;
286
287 switch (c) {
288 case 'd':
289 printf("print delayacct stats ON\n");
290 print_delays = 1;
291 break;
292 case 'i':
293 printf("printing IO accounting\n");
294 print_io_accounting = 1;
295 break;
296 case 'q':
297 printf("printing task/process context switch rates\n");
298 print_task_context_switch_counts = 1;
299 break;
300 case 'C':
301 containerset = 1;
302 containerpath = optarg;
303 break;
304 case 'w':
305 logfile = strdup(optarg);
306 printf("write to file %s\n", logfile);
307 write_file = 1;
308 break;
309 case 'r':
310 rcvbufsz = atoi(optarg);
311 printf("receive buf size %d\n", rcvbufsz);
312 if (rcvbufsz < 0)
313 err(1, "Invalid rcv buf size\n");
314 break;
315 case 'm':
316 strncpy(cpumask, optarg, sizeof(cpumask));
317 cpumask[sizeof(cpumask) - 1] = '\0';
318 maskset = 1;
319 printf("cpumask %s maskset %d\n", cpumask, maskset);
320 break;
321 case 't':
322 tid = atoi(optarg);
323 if (!tid)
324 err(1, "Invalid tgid\n");
325 cmd_type = TASKSTATS_CMD_ATTR_TGID;
326 break;
327 case 'p':
328 tid = atoi(optarg);
329 if (!tid)
330 err(1, "Invalid pid\n");
331 cmd_type = TASKSTATS_CMD_ATTR_PID;
332 break;
333 case 'c':
334
335 /* Block SIGCHLD for sigwait() later */
336 if (sigemptyset(&sigset) == -1)
337 err(1, "Failed to empty sigset");
338 if (sigaddset(&sigset, SIGCHLD))
339 err(1, "Failed to set sigchld in sigset");
340 sigprocmask(SIG_BLOCK, &sigset, NULL);
341
342 /* fork/exec a child */
343 tid = fork();
344 if (tid < 0)
345 err(1, "Fork failed\n");
346 if (tid == 0)
347 if (execvp(argv[optind - 1],
348 &argv[optind - 1]) < 0)
349 exit(-1);
350
351 /* Set the command type and avoid further processing */
352 cmd_type = TASKSTATS_CMD_ATTR_PID;
353 forking = 1;
354 break;
355 case 'v':
356 printf("debug on\n");
357 dbg = 1;
358 break;
359 case 'l':
360 printf("listen forever\n");
361 loop = 1;
362 break;
363 default:
364 usage();
365 exit(-1);
366 }
367 }
368
369 if (write_file) {
370 fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC,
371 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
372 if (fd == -1) {
373 perror("Cannot open output file\n");
374 exit(1);
375 }
376 }
377
378 nl_sd = create_nl_socket(NETLINK_GENERIC);
379 if (nl_sd < 0)
380 err(1, "error creating Netlink socket\n");
381
382
383 mypid = getpid();
384 id = get_family_id(nl_sd);
385 if (!id) {
386 fprintf(stderr, "Error getting family id, errno %d\n", errno);
387 goto err;
388 }
389 PRINTF("family id %d\n", id);
390
391 if (maskset) {
392 rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
393 TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
394 &cpumask, strlen(cpumask) + 1);
395 PRINTF("Sent register cpumask, retval %d\n", rc);
396 if (rc < 0) {
397 fprintf(stderr, "error sending register cpumask\n");
398 goto err;
399 }
400 }
401
402 if (tid && containerset) {
403 fprintf(stderr, "Select either -t or -C, not both\n");
404 goto err;
405 }
406
407 /*
408 * If we forked a child, wait for it to exit. Cannot use waitpid()
409 * as all the delicious data would be reaped as part of the wait
410 */
411 if (tid && forking) {
412 int sig_received;
413 sigwait(&sigset, &sig_received);
414 }
415
416 if (tid) {
417 rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
418 cmd_type, &tid, sizeof(__u32));
419 PRINTF("Sent pid/tgid, retval %d\n", rc);
420 if (rc < 0) {
421 fprintf(stderr, "error sending tid/tgid cmd\n");
422 goto done;
423 }
424 }
425
426 if (containerset) {
427 cfd = open(containerpath, O_RDONLY);
428 if (cfd < 0) {
429 perror("error opening container file");
430 goto err;
431 }
432 rc = send_cmd(nl_sd, id, mypid, CGROUPSTATS_CMD_GET,
433 CGROUPSTATS_CMD_ATTR_FD, &cfd, sizeof(__u32));
434 if (rc < 0) {
435 perror("error sending cgroupstats command");
436 goto err;
437 }
438 }
439 if (!maskset && !tid && !containerset) {
440 usage();
441 goto err;
442 }
443
444 do {
445 rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
446 PRINTF("received %d bytes\n", rep_len);
447
448 if (rep_len < 0) {
449 fprintf(stderr, "nonfatal reply error: errno %d\n",
450 errno);
451 continue;
452 }
453 if (msg.n.nlmsg_type == NLMSG_ERROR ||
454 !NLMSG_OK((&msg.n), rep_len)) {
455 struct nlmsgerr *err = NLMSG_DATA(&msg);
456 fprintf(stderr, "fatal reply error, errno %d\n",
457 err->error);
458 goto done;
459 }
460
461 PRINTF("nlmsghdr size=%zu, nlmsg_len=%d, rep_len=%d\n",
462 sizeof(struct nlmsghdr), msg.n.nlmsg_len, rep_len);
463
464
465 rep_len = GENLMSG_PAYLOAD(&msg.n);
466
467 na = (struct nlattr *) GENLMSG_DATA(&msg);
468 len = 0;
469 while (len < rep_len) {
470 len += NLA_ALIGN(na->nla_len);
471 switch (na->nla_type) {
472 case TASKSTATS_TYPE_AGGR_TGID:
473 /* Fall through */
474 case TASKSTATS_TYPE_AGGR_PID:
475 aggr_len = NLA_PAYLOAD(na->nla_len);
476 len2 = 0;
477 /* For nested attributes, na follows */
478 na = (struct nlattr *) NLA_DATA(na);
479 done = 0;
480 while (len2 < aggr_len) {
481 switch (na->nla_type) {
482 case TASKSTATS_TYPE_PID:
483 rtid = *(int *) NLA_DATA(na);
484 if (print_delays)
485 printf("PID\t%d\n", rtid);
486 break;
487 case TASKSTATS_TYPE_TGID:
488 rtid = *(int *) NLA_DATA(na);
489 if (print_delays)
490 printf("TGID\t%d\n", rtid);
491 break;
492 case TASKSTATS_TYPE_STATS:
493 count++;
494 if (print_delays)
495 print_delayacct((struct taskstats *) NLA_DATA(na));
496 if (print_io_accounting)
497 print_ioacct((struct taskstats *) NLA_DATA(na));
498 if (print_task_context_switch_counts)
499 task_context_switch_counts((struct taskstats *) NLA_DATA(na));
500 if (fd) {
501 if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
502 err(1,"write error\n");
503 }
504 }
505 if (!loop)
506 goto done;
507 break;
508 case TASKSTATS_TYPE_NULL:
509 break;
510 default:
511 fprintf(stderr, "Unknown nested"
512 " nla_type %d\n",
513 na->nla_type);
514 break;
515 }
516 len2 += NLA_ALIGN(na->nla_len);
517 na = (struct nlattr *)((char *)na +
518 NLA_ALIGN(na->nla_len));
519 }
520 break;
521
522 case CGROUPSTATS_TYPE_CGROUP_STATS:
523 print_cgroupstats(NLA_DATA(na));
524 break;
525 default:
526 fprintf(stderr, "Unknown nla_type %d\n",
527 na->nla_type);
528 case TASKSTATS_TYPE_NULL:
529 break;
530 }
531 na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
532 }
533 } while (loop);
534done:
535 if (maskset) {
536 rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
537 TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
538 &cpumask, strlen(cpumask) + 1);
539 printf("Sent deregister mask, retval %d\n", rc);
540 if (rc < 0)
541 err(rc, "error sending deregister cpumask\n");
542 }
543err:
544 close(nl_sd);
545 if (fd)
546 close(fd);
547 if (cfd)
548 close(cfd);
549 return 0;
550}
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h
index 92a8308b96f6..1188bc849ee3 100644
--- a/tools/arch/x86/include/asm/cpufeatures.h
+++ b/tools/arch/x86/include/asm/cpufeatures.h
@@ -106,7 +106,6 @@
106#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ 106#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
107#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */ 107#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */
108#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ 108#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
109#define X86_FEATURE_MCE_RECOVERY ( 3*32+31) /* cpu has recoverable machine checks */
110 109
111/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ 110/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
112#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */ 111#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */
diff --git a/tools/arch/x86/lib/memcpy_64.S b/tools/arch/x86/lib/memcpy_64.S
index 2ec0b0abbfaa..49e6ebac7e73 100644
--- a/tools/arch/x86/lib/memcpy_64.S
+++ b/tools/arch/x86/lib/memcpy_64.S
@@ -181,11 +181,11 @@ ENDPROC(memcpy_orig)
181 181
182#ifndef CONFIG_UML 182#ifndef CONFIG_UML
183/* 183/*
184 * memcpy_mcsafe - memory copy with machine check exception handling 184 * memcpy_mcsafe_unrolled - memory copy with machine check exception handling
185 * Note that we only catch machine checks when reading the source addresses. 185 * Note that we only catch machine checks when reading the source addresses.
186 * Writes to target are posted and don't generate machine checks. 186 * Writes to target are posted and don't generate machine checks.
187 */ 187 */
188ENTRY(memcpy_mcsafe) 188ENTRY(memcpy_mcsafe_unrolled)
189 cmpl $8, %edx 189 cmpl $8, %edx
190 /* Less than 8 bytes? Go to byte copy loop */ 190 /* Less than 8 bytes? Go to byte copy loop */
191 jb .L_no_whole_words 191 jb .L_no_whole_words
@@ -273,7 +273,7 @@ ENTRY(memcpy_mcsafe)
273.L_done_memcpy_trap: 273.L_done_memcpy_trap:
274 xorq %rax, %rax 274 xorq %rax, %rax
275 ret 275 ret
276ENDPROC(memcpy_mcsafe) 276ENDPROC(memcpy_mcsafe_unrolled)
277 277
278 .section .fixup, "ax" 278 .section .fixup, "ax"
279 /* Return -EFAULT for any failure */ 279 /* Return -EFAULT for any failure */
diff --git a/tools/build/Build b/tools/build/Build
index 63a6c34c0c88..76d1a4960973 100644
--- a/tools/build/Build
+++ b/tools/build/Build
@@ -1 +1,3 @@
1hostprogs := fixdep
2
1fixdep-y := fixdep.o 3fixdep-y := fixdep.o
diff --git a/tools/build/Build.include b/tools/build/Build.include
index 4d000bc959b4..1dcb95e76f70 100644
--- a/tools/build/Build.include
+++ b/tools/build/Build.include
@@ -90,3 +90,9 @@ if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
90# - per object C flags 90# - per object C flags
91# - BUILD_STR macro to allow '-D"$(variable)"' constructs 91# - BUILD_STR macro to allow '-D"$(variable)"' constructs
92c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj)) 92c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj))
93cxx_flags = -Wp,-MD,$(depfile),-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXXFLAGS_$(basetarget).o) $(CXXFLAGS_$(obj))
94
95###
96## HOSTCC C flags
97
98host_c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CHOSTFLAGS) -D"BUILD_STR(s)=\#s" $(CHOSTFLAGS_$(basetarget).o) $(CHOSTFLAGS_$(obj))
diff --git a/tools/build/Makefile b/tools/build/Makefile
index 0d5a0e3a8fa9..8332959fbca4 100644
--- a/tools/build/Makefile
+++ b/tools/build/Makefile
@@ -14,6 +14,12 @@ endef
14$(call allow-override,CC,$(CROSS_COMPILE)gcc) 14$(call allow-override,CC,$(CROSS_COMPILE)gcc)
15$(call allow-override,LD,$(CROSS_COMPILE)ld) 15$(call allow-override,LD,$(CROSS_COMPILE)ld)
16 16
17HOSTCC ?= gcc
18HOSTLD ?= ld
19HOSTAR ?= ar
20
21export HOSTCC HOSTLD HOSTAR
22
17ifeq ($(V),1) 23ifeq ($(V),1)
18 Q = 24 Q =
19else 25else
@@ -36,7 +42,7 @@ $(OUTPUT)fixdep-in.o: FORCE
36 $(Q)$(MAKE) $(build)=fixdep 42 $(Q)$(MAKE) $(build)=fixdep
37 43
38$(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o 44$(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o
39 $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $< 45 $(QUIET_LINK)$(HOSTCC) $(LDFLAGS) -o $@ $<
40 46
41FORCE: 47FORCE:
42 48
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
index 27f3583193e6..99c0ccd2f176 100644
--- a/tools/build/Makefile.build
+++ b/tools/build/Makefile.build
@@ -58,6 +58,12 @@ quiet_cmd_mkdir = MKDIR $(dir $@)
58quiet_cmd_cc_o_c = CC $@ 58quiet_cmd_cc_o_c = CC $@
59 cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< 59 cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
60 60
61quiet_cmd_host_cc_o_c = HOSTCC $@
62 cmd_host_cc_o_c = $(HOSTCC) $(host_c_flags) -c -o $@ $<
63
64quiet_cmd_cxx_o_c = CXX $@
65 cmd_cxx_o_c = $(CXX) $(cxx_flags) -c -o $@ $<
66
61quiet_cmd_cpp_i_c = CPP $@ 67quiet_cmd_cpp_i_c = CPP $@
62 cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $< 68 cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $<
63 69
@@ -70,16 +76,28 @@ quiet_cmd_gen = GEN $@
70# If there's nothing to link, create empty $@ object. 76# If there's nothing to link, create empty $@ object.
71quiet_cmd_ld_multi = LD $@ 77quiet_cmd_ld_multi = LD $@
72 cmd_ld_multi = $(if $(strip $(obj-y)),\ 78 cmd_ld_multi = $(if $(strip $(obj-y)),\
73 $(LD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(AR) rcs $@) 79 $(LD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(AR) rcs $@)
80
81quiet_cmd_host_ld_multi = HOSTLD $@
82 cmd_host_ld_multi = $(if $(strip $(obj-y)),\
83 $(HOSTLD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(HOSTAR) rcs $@)
84
85ifneq ($(filter $(obj),$(hostprogs)),)
86 host = host_
87endif
74 88
75# Build rules 89# Build rules
76$(OUTPUT)%.o: %.c FORCE 90$(OUTPUT)%.o: %.c FORCE
77 $(call rule_mkdir) 91 $(call rule_mkdir)
78 $(call if_changed_dep,cc_o_c) 92 $(call if_changed_dep,$(host)cc_o_c)
93
94$(OUTPUT)%.o: %.cpp FORCE
95 $(call rule_mkdir)
96 $(call if_changed_dep,cxx_o_c)
79 97
80$(OUTPUT)%.o: %.S FORCE 98$(OUTPUT)%.o: %.S FORCE
81 $(call rule_mkdir) 99 $(call rule_mkdir)
82 $(call if_changed_dep,cc_o_c) 100 $(call if_changed_dep,$(host)cc_o_c)
83 101
84$(OUTPUT)%.i: %.c FORCE 102$(OUTPUT)%.i: %.c FORCE
85 $(call rule_mkdir) 103 $(call rule_mkdir)
@@ -119,7 +137,7 @@ $(sort $(subdir-obj-y)): $(subdir-y) ;
119 137
120$(in-target): $(obj-y) FORCE 138$(in-target): $(obj-y) FORCE
121 $(call rule_mkdir) 139 $(call rule_mkdir)
122 $(call if_changed,ld_multi) 140 $(call if_changed,$(host)ld_multi)
123 141
124__build: $(in-target) 142__build: $(in-target)
125 @: 143 @:
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index a120c6b755a9..ae52e029dd22 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -7,7 +7,7 @@ endif
7 7
8feature_check = $(eval $(feature_check_code)) 8feature_check = $(eval $(feature_check_code))
9define feature_check_code 9define feature_check_code
10 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) 10 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" CXXFLAGS="$(EXTRA_CXXFLAGS) $(FEATURE_CHECK_CXXFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
11endef 11endef
12 12
13feature_set = $(eval $(feature_set_code)) 13feature_set = $(eval $(feature_set_code))
diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include
index be630bed66d2..ad22e4e7bc59 100644
--- a/tools/build/Makefile.include
+++ b/tools/build/Makefile.include
@@ -1,10 +1,6 @@
1build := -f $(srctree)/tools/build/Makefile.build dir=. obj 1build := -f $(srctree)/tools/build/Makefile.build dir=. obj
2 2
3ifdef CROSS_COMPILE
4fixdep:
5else
6fixdep: 3fixdep:
7 $(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep 4 $(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
8endif
9 5
10.PHONY: fixdep 6.PHONY: fixdep
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index a0b29a311816..ac9c477a2a48 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -46,11 +46,13 @@ FILES= \
46 test-lzma.bin \ 46 test-lzma.bin \
47 test-bpf.bin \ 47 test-bpf.bin \
48 test-get_cpuid.bin \ 48 test-get_cpuid.bin \
49 test-sdt.bin 49 test-sdt.bin \
50 test-cxx.bin
50 51
51FILES := $(addprefix $(OUTPUT),$(FILES)) 52FILES := $(addprefix $(OUTPUT),$(FILES))
52 53
53CC := $(CROSS_COMPILE)gcc -MD 54CC := $(CROSS_COMPILE)gcc -MD
55CXX := $(CROSS_COMPILE)g++ -MD
54PKG_CONFIG := $(CROSS_COMPILE)pkg-config 56PKG_CONFIG := $(CROSS_COMPILE)pkg-config
55 57
56all: $(FILES) 58all: $(FILES)
@@ -58,6 +60,9 @@ all: $(FILES)
58__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS) 60__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
59 BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1 61 BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
60 62
63__BUILDXX = $(CXX) $(CXXFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS)
64 BUILDXX = $(__BUILDXX) > $(@:.bin=.make.output) 2>&1
65
61############################### 66###############################
62 67
63$(OUTPUT)test-all.bin: 68$(OUTPUT)test-all.bin:
@@ -217,6 +222,9 @@ $(OUTPUT)test-bpf.bin:
217$(OUTPUT)test-sdt.bin: 222$(OUTPUT)test-sdt.bin:
218 $(BUILD) 223 $(BUILD)
219 224
225$(OUTPUT)test-cxx.bin:
226 $(BUILDXX) -std=gnu++11
227
220-include $(OUTPUT)*.d 228-include $(OUTPUT)*.d
221 229
222############################### 230###############################
diff --git a/tools/build/feature/test-cxx.cpp b/tools/build/feature/test-cxx.cpp
new file mode 100644
index 000000000000..b1dee9a31d6c
--- /dev/null
+++ b/tools/build/feature/test-cxx.cpp
@@ -0,0 +1,15 @@
1#include <iostream>
2#include <memory>
3
4static void print_str(std::string s)
5{
6 std::cout << s << std::endl;
7}
8
9int main()
10{
11 std::string s("Hello World!");
12 print_str(std::move(s));
13 std::cout << "|" << s << "|" << std::endl;
14 return 0;
15}
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 0d9f48ec42bb..bc7adb84e679 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -1433,7 +1433,7 @@ int main(int argc, char *argv[])
1433 openlog("KVP", 0, LOG_USER); 1433 openlog("KVP", 0, LOG_USER);
1434 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); 1434 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1435 1435
1436 kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR); 1436 kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
1437 1437
1438 if (kvp_fd < 0) { 1438 if (kvp_fd < 0) {
1439 syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s", 1439 syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index 5d51d6ff08e6..e0829809c897 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -250,6 +250,9 @@ int main(int argc, char *argv[])
250 syslog(LOG_ERR, "/etc/fstab and /proc/mounts"); 250 syslog(LOG_ERR, "/etc/fstab and /proc/mounts");
251 } 251 }
252 break; 252 break;
253 case VSS_OP_HOT_BACKUP:
254 syslog(LOG_INFO, "VSS: op=CHECK HOT BACKUP\n");
255 break;
253 default: 256 default:
254 syslog(LOG_ERR, "Illegal op:%d\n", op); 257 syslog(LOG_ERR, "Illegal op:%d\n", op);
255 } 258 }
diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c
index 5eb6793f3972..7a6d61c6c012 100644
--- a/tools/iio/iio_utils.c
+++ b/tools/iio/iio_utils.c
@@ -121,10 +121,6 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
121 121
122 ret = -ENOENT; 122 ret = -ENOENT;
123 while (ent = readdir(dp), ent) 123 while (ent = readdir(dp), ent)
124 /*
125 * Do we allow devices to override a generic name with
126 * a specific one?
127 */
128 if ((strcmp(builtname, ent->d_name) == 0) || 124 if ((strcmp(builtname, ent->d_name) == 0) ||
129 (strcmp(builtname_generic, ent->d_name) == 0)) { 125 (strcmp(builtname_generic, ent->d_name) == 0)) {
130 ret = asprintf(&filename, 126 ret = asprintf(&filename,
@@ -178,6 +174,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
178 sysfsfp = 0; 174 sysfsfp = 0;
179 free(filename); 175 free(filename);
180 filename = 0; 176 filename = 0;
177
178 /*
179 * Avoid having a more generic entry overwriting
180 * the settings.
181 */
182 if (strcmp(builtname, ent->d_name) == 0)
183 break;
181 } 184 }
182 185
183error_close_sysfsfp: 186error_close_sysfsfp:
diff --git a/tools/iio/lsiio.c b/tools/iio/lsiio.c
index 3d650e668252..ab0f5cf16025 100644
--- a/tools/iio/lsiio.c
+++ b/tools/iio/lsiio.c
@@ -51,7 +51,8 @@ static int dump_channels(const char *dev_dir_name)
51 51
52 while (ent = readdir(dp), ent) 52 while (ent = readdir(dp), ent)
53 if (check_prefix(ent->d_name, "in_") && 53 if (check_prefix(ent->d_name, "in_") &&
54 check_postfix(ent->d_name, "_raw")) 54 (check_postfix(ent->d_name, "_raw") ||
55 check_postfix(ent->d_name, "_input")))
55 printf(" %-10s\n", ent->d_name); 56 printf(" %-10s\n", ent->d_name);
56 57
57 return (closedir(dp) == -1) ? -errno : 0; 58 return (closedir(dp) == -1) ? -errno : 0;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index da218fec6056..9e5fc168c8a3 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -339,7 +339,7 @@ enum bpf_func_id {
339 BPF_FUNC_skb_change_type, 339 BPF_FUNC_skb_change_type,
340 340
341 /** 341 /**
342 * bpf_skb_in_cgroup(skb, map, index) - Check cgroup2 membership of skb 342 * bpf_skb_under_cgroup(skb, map, index) - Check cgroup2 membership of skb
343 * @skb: pointer to skb 343 * @skb: pointer to skb
344 * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type 344 * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
345 * @index: index of the cgroup in the bpf_map 345 * @index: index of the cgroup in the bpf_map
@@ -348,7 +348,7 @@ enum bpf_func_id {
348 * == 1 skb succeeded the cgroup2 descendant test 348 * == 1 skb succeeded the cgroup2 descendant test
349 * < 0 error 349 * < 0 error
350 */ 350 */
351 BPF_FUNC_skb_in_cgroup, 351 BPF_FUNC_skb_under_cgroup,
352 352
353 /** 353 /**
354 * bpf_get_hash_recalc(skb) 354 * bpf_get_hash_recalc(skb)
diff --git a/tools/laptop/dslm/.gitignore b/tools/laptop/dslm/.gitignore
new file mode 100644
index 000000000000..9fc984e64386
--- /dev/null
+++ b/tools/laptop/dslm/.gitignore
@@ -0,0 +1 @@
dslm
diff --git a/tools/laptop/dslm/Makefile b/tools/laptop/dslm/Makefile
new file mode 100644
index 000000000000..ff613b31730b
--- /dev/null
+++ b/tools/laptop/dslm/Makefile
@@ -0,0 +1,9 @@
1CC := $(CROSS_COMPILE)gcc
2CFLAGS := -I../../usr/include
3
4PROGS := dslm
5
6all: $(PROGS)
7
8clean:
9 rm -fr $(PROGS)
diff --git a/tools/laptop/dslm/dslm.c b/tools/laptop/dslm/dslm.c
new file mode 100644
index 000000000000..d5dd2d4b04d8
--- /dev/null
+++ b/tools/laptop/dslm/dslm.c
@@ -0,0 +1,166 @@
1/*
2 * dslm.c
3 * Simple Disk Sleep Monitor
4 * by Bartek Kania
5 * Licensed under the GPL
6 */
7#include <unistd.h>
8#include <stdlib.h>
9#include <stdio.h>
10#include <fcntl.h>
11#include <errno.h>
12#include <time.h>
13#include <string.h>
14#include <signal.h>
15#include <sys/ioctl.h>
16#include <linux/hdreg.h>
17
18#ifdef DEBUG
19#define D(x) x
20#else
21#define D(x)
22#endif
23
24int endit = 0;
25
26/* Check if the disk is in powersave-mode
27 * Most of the code is stolen from hdparm.
28 * 1 = active, 0 = standby/sleep, -1 = unknown */
29static int check_powermode(int fd)
30{
31 unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
32 int state;
33
34 if (ioctl(fd, HDIO_DRIVE_CMD, &args)
35 && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
36 && ioctl(fd, HDIO_DRIVE_CMD, &args)) {
37 if (errno != EIO || args[0] != 0 || args[1] != 0) {
38 state = -1; /* "unknown"; */
39 } else
40 state = 0; /* "sleeping"; */
41 } else {
42 state = (args[2] == 255) ? 1 : 0;
43 }
44 D(printf(" drive state is: %d\n", state));
45
46 return state;
47}
48
49static char *state_name(int i)
50{
51 if (i == -1) return "unknown";
52 if (i == 0) return "sleeping";
53 if (i == 1) return "active";
54
55 return "internal error";
56}
57
58static char *myctime(time_t time)
59{
60 char *ts = ctime(&time);
61 ts[strlen(ts) - 1] = 0;
62
63 return ts;
64}
65
66static void measure(int fd)
67{
68 time_t start_time;
69 int last_state;
70 time_t last_time;
71 int curr_state;
72 time_t curr_time = 0;
73 time_t time_diff;
74 time_t active_time = 0;
75 time_t sleep_time = 0;
76 time_t unknown_time = 0;
77 time_t total_time = 0;
78 int changes = 0;
79 float tmp;
80
81 printf("Starting measurements\n");
82
83 last_state = check_powermode(fd);
84 start_time = last_time = time(0);
85 printf(" System is in state %s\n\n", state_name(last_state));
86
87 while(!endit) {
88 sleep(1);
89 curr_state = check_powermode(fd);
90
91 if (curr_state != last_state || endit) {
92 changes++;
93 curr_time = time(0);
94 time_diff = curr_time - last_time;
95
96 if (last_state == 1) active_time += time_diff;
97 else if (last_state == 0) sleep_time += time_diff;
98 else unknown_time += time_diff;
99
100 last_state = curr_state;
101 last_time = curr_time;
102
103 printf("%s: State-change to %s\n", myctime(curr_time),
104 state_name(curr_state));
105 }
106 }
107 changes--; /* Compensate for SIGINT */
108
109 total_time = time(0) - start_time;
110 printf("\nTotal running time: %lus\n", curr_time - start_time);
111 printf(" State changed %d times\n", changes);
112
113 tmp = (float)sleep_time / (float)total_time * 100;
114 printf(" Time in sleep state: %lus (%.2f%%)\n", sleep_time, tmp);
115 tmp = (float)active_time / (float)total_time * 100;
116 printf(" Time in active state: %lus (%.2f%%)\n", active_time, tmp);
117 tmp = (float)unknown_time / (float)total_time * 100;
118 printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
119}
120
121static void ender(int s)
122{
123 endit = 1;
124}
125
126static void usage(void)
127{
128 puts("usage: dslm [-w <time>] <disk>");
129 exit(0);
130}
131
132int main(int argc, char **argv)
133{
134 int fd;
135 char *disk = 0;
136 int settle_time = 60;
137
138 /* Parse the simple command-line */
139 if (argc == 2)
140 disk = argv[1];
141 else if (argc == 4) {
142 settle_time = atoi(argv[2]);
143 disk = argv[3];
144 } else
145 usage();
146
147 if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
148 printf("Can't open %s, because: %s\n", disk, strerror(errno));
149 exit(-1);
150 }
151
152 if (settle_time) {
153 printf("Waiting %d seconds for the system to settle down to "
154 "'normal'\n", settle_time);
155 sleep(settle_time);
156 } else
157 puts("Not waiting for system to settle down");
158
159 signal(SIGINT, ender);
160
161 measure(fd);
162
163 close(fd);
164
165 return 0;
166}
diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c
index d50f3b58606b..6518bea926d6 100644
--- a/tools/lib/subcmd/pager.c
+++ b/tools/lib/subcmd/pager.c
@@ -3,6 +3,7 @@
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include <signal.h> 5#include <signal.h>
6#include <sys/ioctl.h>
6#include "pager.h" 7#include "pager.h"
7#include "run-command.h" 8#include "run-command.h"
8#include "sigchain.h" 9#include "sigchain.h"
@@ -14,6 +15,7 @@
14 */ 15 */
15 16
16static int spawned_pager; 17static int spawned_pager;
18static int pager_columns;
17 19
18void pager_init(const char *pager_env) 20void pager_init(const char *pager_env)
19{ 21{
@@ -58,9 +60,12 @@ static void wait_for_pager_signal(int signo)
58void setup_pager(void) 60void setup_pager(void)
59{ 61{
60 const char *pager = getenv(subcmd_config.pager_env); 62 const char *pager = getenv(subcmd_config.pager_env);
63 struct winsize sz;
61 64
62 if (!isatty(1)) 65 if (!isatty(1))
63 return; 66 return;
67 if (ioctl(1, TIOCGWINSZ, &sz) == 0)
68 pager_columns = sz.ws_col;
64 if (!pager) 69 if (!pager)
65 pager = getenv("PAGER"); 70 pager = getenv("PAGER");
66 if (!(pager || access("/usr/bin/pager", X_OK))) 71 if (!(pager || access("/usr/bin/pager", X_OK)))
@@ -98,3 +103,14 @@ int pager_in_use(void)
98{ 103{
99 return spawned_pager; 104 return spawned_pager;
100} 105}
106
107int pager_get_columns(void)
108{
109 char *s;
110
111 s = getenv("COLUMNS");
112 if (s)
113 return atoi(s);
114
115 return (pager_columns ? pager_columns : 80) - 2;
116}
diff --git a/tools/lib/subcmd/pager.h b/tools/lib/subcmd/pager.h
index 8b83714ecf73..623f5542d05d 100644
--- a/tools/lib/subcmd/pager.h
+++ b/tools/lib/subcmd/pager.h
@@ -5,5 +5,6 @@ extern void pager_init(const char *pager_env);
5 5
6extern void setup_pager(void); 6extern void setup_pager(void);
7extern int pager_in_use(void); 7extern int pager_in_use(void);
8extern int pager_get_columns(void);
8 9
9#endif /* __SUBCMD_PAGER_H */ 10#endif /* __SUBCMD_PAGER_H */
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c
index 3bcada3ae05a..65984f1c2974 100644
--- a/tools/lib/traceevent/kbuffer-parse.c
+++ b/tools/lib/traceevent/kbuffer-parse.c
@@ -622,6 +622,7 @@ void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
622 622
623 /* Reset the buffer */ 623 /* Reset the buffer */
624 kbuffer_load_subbuffer(kbuf, kbuf->subbuffer); 624 kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
625 data = kbuffer_read_event(kbuf, ts);
625 626
626 while (kbuf->curr < offset) { 627 while (kbuf->curr < offset) {
627 data = kbuffer_next_event(kbuf, ts); 628 data = kbuffer_next_event(kbuf, ts);
diff --git a/tools/pcmcia/.gitignore b/tools/pcmcia/.gitignore
new file mode 100644
index 000000000000..53d081336757
--- /dev/null
+++ b/tools/pcmcia/.gitignore
@@ -0,0 +1 @@
crc32hash
diff --git a/tools/pcmcia/Makefile b/tools/pcmcia/Makefile
new file mode 100644
index 000000000000..81a7498c5cd9
--- /dev/null
+++ b/tools/pcmcia/Makefile
@@ -0,0 +1,9 @@
1CC := $(CROSS_COMPILE)gcc
2CFLAGS := -I../../usr/include
3
4PROGS := crc32hash
5
6all: $(PROGS)
7
8clean:
9 rm -fr $(PROGS)
diff --git a/tools/pcmcia/crc32hash.c b/tools/pcmcia/crc32hash.c
new file mode 100644
index 000000000000..44f8beea7260
--- /dev/null
+++ b/tools/pcmcia/crc32hash.c
@@ -0,0 +1,32 @@
1/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */
2/* Usage example:
3$ ./crc32hash "Dual Speed"
4*/
5
6#include <string.h>
7#include <stdio.h>
8#include <ctype.h>
9#include <stdlib.h>
10
11static unsigned int crc32(unsigned char const *p, unsigned int len)
12{
13 int i;
14 unsigned int crc = 0;
15 while (len--) {
16 crc ^= *p++;
17 for (i = 0; i < 8; i++)
18 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
19 }
20 return crc;
21}
22
23int main(int argc, char **argv) {
24 unsigned int result;
25 if (argc != 2) {
26 printf("no string passed as argument\n");
27 return -1;
28 }
29 result = crc32((unsigned char const *)argv[1], strlen(argv[1]));
30 printf("0x%x\n", result);
31 return 0;
32}
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index a126e97a8114..41857cce5e86 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,13 +8,23 @@ perf-list - List all symbolic event types
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf list' [hw|sw|cache|tracepoint|pmu|event_glob] 11'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|event_glob]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command displays the symbolic event types which can be selected in the 15This command displays the symbolic event types which can be selected in the
16various perf commands with the -e option. 16various perf commands with the -e option.
17 17
18OPTIONS
19-------
20--no-desc::
21Don't print descriptions.
22
23-v::
24--long-desc::
25Print longer event descriptions.
26
27
18[[EVENT_MODIFIERS]] 28[[EVENT_MODIFIERS]]
19EVENT MODIFIERS 29EVENT MODIFIERS
20--------------- 30---------------
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
index 5950b5a24efd..8a6479c0eac9 100644
--- a/tools/perf/Documentation/tips.txt
+++ b/tools/perf/Documentation/tips.txt
@@ -28,3 +28,7 @@ To change sampling frequency to 100 Hz: perf record -F 100
28See assembly instructions with percentage: perf annotate <symbol> 28See assembly instructions with percentage: perf annotate <symbol>
29If you prefer Intel style assembly, try: perf annotate -M intel 29If you prefer Intel style assembly, try: perf annotate -M intel
30For hierarchical output, try: perf report --hierarchy 30For hierarchical output, try: perf report --hierarchy
31Order by the overhead of source file name and line number: perf report -s srcline
32System-wide collection from all CPUs: perf record -a
33Show current config key-value pairs: perf config --list
34Show user configuration overrides: perf config --user --list
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index d710db16b963..982d6439bb07 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -144,6 +144,10 @@ $(call allow-override,LD,$(CROSS_COMPILE)ld)
144 144
145LD += $(EXTRA_LDFLAGS) 145LD += $(EXTRA_LDFLAGS)
146 146
147HOSTCC ?= gcc
148HOSTLD ?= ld
149HOSTAR ?= ar
150
147PKG_CONFIG = $(CROSS_COMPILE)pkg-config 151PKG_CONFIG = $(CROSS_COMPILE)pkg-config
148 152
149RM = rm -f 153RM = rm -f
@@ -345,8 +349,18 @@ strip: $(PROGRAMS) $(OUTPUT)perf
345PERF_IN := $(OUTPUT)perf-in.o 349PERF_IN := $(OUTPUT)perf-in.o
346 350
347export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK 351export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK
352export HOSTCC HOSTLD HOSTAR
348include $(srctree)/tools/build/Makefile.include 353include $(srctree)/tools/build/Makefile.include
349 354
355JEVENTS := $(OUTPUT)pmu-events/jevents
356JEVENTS_IN := $(OUTPUT)pmu-events/jevents-in.o
357
358PMU_EVENTS_IN := $(OUTPUT)pmu-events/pmu-events-in.o
359
360export JEVENTS
361
362build := -f $(srctree)/tools/build/Makefile.build dir=. obj
363
350$(PERF_IN): prepare FORCE 364$(PERF_IN): prepare FORCE
351 @(test -f ../../include/uapi/linux/perf_event.h && ( \ 365 @(test -f ../../include/uapi/linux/perf_event.h && ( \
352 (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ 366 (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \
@@ -443,9 +457,18 @@ $(PERF_IN): prepare FORCE
443 || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true 457 || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true
444 $(Q)$(MAKE) $(build)=perf 458 $(Q)$(MAKE) $(build)=perf
445 459
446$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) 460$(JEVENTS_IN): FORCE
461 $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=jevents
462
463$(JEVENTS): $(JEVENTS_IN)
464 $(QUIET_LINK)$(HOSTCC) $(JEVENTS_IN) -o $@
465
466$(PMU_EVENTS_IN): $(JEVENTS) FORCE
467 $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=pmu-events
468
469$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
447 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ 470 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \
448 $(PERF_IN) $(LIBS) -o $@ 471 $(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@
449 472
450$(GTK_IN): fixdep FORCE 473$(GTK_IN): fixdep FORCE
451 $(Q)$(MAKE) $(build)=gtk 474 $(Q)$(MAKE) $(build)=gtk
@@ -474,6 +497,8 @@ perf.spec $(SCRIPTS) \
474ifneq ($(OUTPUT),) 497ifneq ($(OUTPUT),)
475%.o: $(OUTPUT)%.o 498%.o: $(OUTPUT)%.o
476 @echo " # Redirected target $@ => $(OUTPUT)$@" 499 @echo " # Redirected target $@ => $(OUTPUT)$@"
500pmu-events/%.o: $(OUTPUT)pmu-events/%.o
501 @echo " # Redirected target $@ => $(OUTPUT)$@"
477util/%.o: $(OUTPUT)util/%.o 502util/%.o: $(OUTPUT)util/%.o
478 @echo " # Redirected target $@ => $(OUTPUT)$@" 503 @echo " # Redirected target $@ => $(OUTPUT)$@"
479bench/%.o: $(OUTPUT)bench/%.o 504bench/%.o: $(OUTPUT)bench/%.o
@@ -729,10 +754,11 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
729 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) 754 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
730 $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete 755 $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
731 $(Q)$(RM) $(OUTPUT).config-detected 756 $(Q)$(RM) $(OUTPUT).config-detected
732 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 757 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)pmu-events/jevents
733 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \ 758 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
734 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \ 759 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
735 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c 760 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
761 $(OUTPUT)pmu-events/pmu-events.c
736 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 762 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
737 $(python-clean) 763 $(python-clean)
738 764
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index f8ccee132867..9aaa6f5a9347 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -32,3 +32,14 @@ get_cpuid(char *buffer, size_t sz)
32 } 32 }
33 return -1; 33 return -1;
34} 34}
35
36char *
37get_cpuid_str(void)
38{
39 char *bufp;
40
41 if (asprintf(&bufp, "%.8lx", mfspr(SPRN_PVR)) < 0)
42 bufp = NULL;
43
44 return bufp;
45}
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index ed9d5d15d5b6..1030a6e504bb 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -82,7 +82,8 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
82 * 82 *
83 * In addition, we shouldn't specify an offset for kretprobes. 83 * In addition, we shouldn't specify an offset for kretprobes.
84 */ 84 */
85 if (pev->point.offset || pev->point.retprobe || !map || !sym) 85 if (pev->point.offset || (!pev->uprobes && pev->point.retprobe) ||
86 !map || !sym)
86 return; 87 return;
87 88
88 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); 89 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym);
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
index 146d12a1cec0..a74a48db26f5 100644
--- a/tools/perf/arch/x86/util/header.c
+++ b/tools/perf/arch/x86/util/header.c
@@ -19,8 +19,8 @@ cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
19 : "a" (op)); 19 : "a" (op));
20} 20}
21 21
22int 22static int
23get_cpuid(char *buffer, size_t sz) 23__get_cpuid(char *buffer, size_t sz, const char *fmt)
24{ 24{
25 unsigned int a, b, c, d, lvl; 25 unsigned int a, b, c, d, lvl;
26 int family = -1, model = -1, step = -1; 26 int family = -1, model = -1, step = -1;
@@ -48,7 +48,7 @@ get_cpuid(char *buffer, size_t sz)
48 if (family >= 0x6) 48 if (family >= 0x6)
49 model += ((a >> 16) & 0xf) << 4; 49 model += ((a >> 16) & 0xf) << 4;
50 } 50 }
51 nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step); 51 nb = scnprintf(buffer, sz, fmt, vendor, family, model, step);
52 52
53 /* look for end marker to ensure the entire data fit */ 53 /* look for end marker to ensure the entire data fit */
54 if (strchr(buffer, '$')) { 54 if (strchr(buffer, '$')) {
@@ -57,3 +57,21 @@ get_cpuid(char *buffer, size_t sz)
57 } 57 }
58 return -1; 58 return -1;
59} 59}
60
61int
62get_cpuid(char *buffer, size_t sz)
63{
64 return __get_cpuid(buffer, sz, "%s,%u,%u,%u$");
65}
66
67char *
68get_cpuid_str(void)
69{
70 char *buf = malloc(128);
71
72 if (__get_cpuid(buf, 128, "%s-%u-%X$") < 0) {
73 free(buf);
74 return NULL;
75 }
76 return buf;
77}
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 88ee419e5189..ba9322ff858b 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -16,16 +16,23 @@
16#include "util/pmu.h" 16#include "util/pmu.h"
17#include <subcmd/parse-options.h> 17#include <subcmd/parse-options.h>
18 18
19static bool desc_flag = true;
20
19int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 21int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
20{ 22{
21 int i; 23 int i;
22 bool raw_dump = false; 24 bool raw_dump = false;
25 bool long_desc_flag = false;
23 struct option list_options[] = { 26 struct option list_options[] = {
24 OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"), 27 OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"),
28 OPT_BOOLEAN('d', "desc", &desc_flag,
29 "Print extra event descriptions. --no-desc to not print."),
30 OPT_BOOLEAN('v', "long-desc", &long_desc_flag,
31 "Print longer event descriptions."),
25 OPT_END() 32 OPT_END()
26 }; 33 };
27 const char * const list_usage[] = { 34 const char * const list_usage[] = {
28 "perf list [hw|sw|cache|tracepoint|pmu|sdt|event_glob]", 35 "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|event_glob]",
29 NULL 36 NULL
30 }; 37 };
31 38
@@ -40,7 +47,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
40 printf("\nList of pre-defined events (to be used in -e):\n\n"); 47 printf("\nList of pre-defined events (to be used in -e):\n\n");
41 48
42 if (argc == 0) { 49 if (argc == 0) {
43 print_events(NULL, raw_dump); 50 print_events(NULL, raw_dump, !desc_flag, long_desc_flag);
44 return 0; 51 return 0;
45 } 52 }
46 53
@@ -61,14 +68,16 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
61 strcmp(argv[i], "hwcache") == 0) 68 strcmp(argv[i], "hwcache") == 0)
62 print_hwcache_events(NULL, raw_dump); 69 print_hwcache_events(NULL, raw_dump);
63 else if (strcmp(argv[i], "pmu") == 0) 70 else if (strcmp(argv[i], "pmu") == 0)
64 print_pmu_events(NULL, raw_dump); 71 print_pmu_events(NULL, raw_dump, !desc_flag,
72 long_desc_flag);
65 else if (strcmp(argv[i], "sdt") == 0) 73 else if (strcmp(argv[i], "sdt") == 0)
66 print_sdt_events(NULL, NULL, raw_dump); 74 print_sdt_events(NULL, NULL, raw_dump);
67 else if ((sep = strchr(argv[i], ':')) != NULL) { 75 else if ((sep = strchr(argv[i], ':')) != NULL) {
68 int sep_idx; 76 int sep_idx;
69 77
70 if (sep == NULL) { 78 if (sep == NULL) {
71 print_events(argv[i], raw_dump); 79 print_events(argv[i], raw_dump, !desc_flag,
80 long_desc_flag);
72 continue; 81 continue;
73 } 82 }
74 sep_idx = sep - argv[i]; 83 sep_idx = sep - argv[i];
@@ -90,7 +99,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
90 print_symbol_events(s, PERF_TYPE_SOFTWARE, 99 print_symbol_events(s, PERF_TYPE_SOFTWARE,
91 event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump); 100 event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump);
92 print_hwcache_events(s, raw_dump); 101 print_hwcache_events(s, raw_dump);
93 print_pmu_events(s, raw_dump); 102 print_pmu_events(s, raw_dump, !desc_flag,
103 long_desc_flag);
94 print_tracepoint_events(NULL, s, raw_dump); 104 print_tracepoint_events(NULL, s, raw_dump);
95 print_sdt_events(NULL, s, raw_dump); 105 print_sdt_events(NULL, s, raw_dump);
96 free(s); 106 free(s);
diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
new file mode 100644
index 000000000000..9213a1273697
--- /dev/null
+++ b/tools/perf/pmu-events/Build
@@ -0,0 +1,13 @@
1hostprogs := jevents
2
3jevents-y += json.o jsmn.o jevents.o
4pmu-events-y += pmu-events.o
5JDIR = pmu-events/arch/$(ARCH)
6JSON = $(shell [ -d $(JDIR) ] && \
7 find $(JDIR) -name '*.json' -o -name 'mapfile.csv')
8#
9# Locate/process JSON files in pmu-events/arch/
10# directory and create tables in pmu-events.c.
11#
12$(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JEVENTS)
13 $(Q)$(call echo-cmd,gen)$(JEVENTS) $(ARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V)
diff --git a/tools/perf/pmu-events/README b/tools/perf/pmu-events/README
new file mode 100644
index 000000000000..1408ade0d773
--- /dev/null
+++ b/tools/perf/pmu-events/README
@@ -0,0 +1,147 @@
1
2The contents of this directory allow users to specify PMU events in their
3CPUs by their symbolic names rather than raw event codes (see example below).
4
5The main program in this directory, is the 'jevents', which is built and
6executed _BEFORE_ the perf binary itself is built.
7
8The 'jevents' program tries to locate and process JSON files in the directory
9tree tools/perf/pmu-events/arch/foo.
10
11 - Regular files with '.json' extension in the name are assumed to be
12 JSON files, each of which describes a set of PMU events.
13
14 - Regular files with basename starting with 'mapfile.csv' are assumed
15 to be a CSV file that maps a specific CPU to its set of PMU events.
16 (see below for mapfile format)
17
18 - Directories are traversed, but all other files are ignored.
19
20The PMU events supported by a CPU model are expected to grouped into topics
21such as Pipelining, Cache, Memory, Floating-point etc. All events for a topic
22should be placed in a separate JSON file - where the file name identifies
23the topic. Eg: "Floating-point.json".
24
25All the topic JSON files for a CPU model/family should be in a separate
26sub directory. Thus for the Silvermont X86 CPU:
27
28 $ ls tools/perf/pmu-events/arch/x86/Silvermont_core
29 Cache.json Memory.json Virtual-Memory.json
30 Frontend.json Pipeline.json
31
32Using the JSON files and the mapfile, 'jevents' generates the C source file,
33'pmu-events.c', which encodes the two sets of tables:
34
35 - Set of 'PMU events tables' for all known CPUs in the architecture,
36 (one table like the following, per JSON file; table name 'pme_power8'
37 is derived from JSON file name, 'power8.json').
38
39 struct pmu_event pme_power8[] = {
40
41 ...
42
43 {
44 .name = "pm_1plus_ppc_cmpl",
45 .event = "event=0x100f2",
46 .desc = "1 or more ppc insts finished,",
47 },
48
49 ...
50 }
51
52 - A 'mapping table' that maps each CPU of the architecture, to its
53 'PMU events table'
54
55 struct pmu_events_map pmu_events_map[] = {
56 {
57 .cpuid = "004b0000",
58 .version = "1",
59 .type = "core",
60 .table = pme_power8
61 },
62 ...
63
64 };
65
66After the 'pmu-events.c' is generated, it is compiled and the resulting
67'pmu-events.o' is added to 'libperf.a' which is then used to build perf.
68
69NOTES:
70 1. Several CPUs can support same set of events and hence use a common
71 JSON file. Hence several entries in the pmu_events_map[] could map
72 to a single 'PMU events table'.
73
74 2. The 'pmu-events.h' has an extern declaration for the mapping table
75 and the generated 'pmu-events.c' defines this table.
76
77 3. _All_ known CPU tables for architecture are included in the perf
78 binary.
79
80At run time, perf determines the actual CPU it is running on, finds the
81matching events table and builds aliases for those events. This allows
82users to specify events by their name:
83
84 $ perf stat -e pm_1plus_ppc_cmpl sleep 1
85
86where 'pm_1plus_ppc_cmpl' is a Power8 PMU event.
87
88In case of errors when processing files in the tools/perf/pmu-events/arch
89directory, 'jevents' tries to create an empty mapping file to allow the perf
90build to succeed even if the PMU event aliases cannot be used.
91
92However some errors in processing may cause the perf build to fail.
93
94Mapfile format
95===============
96
97The mapfile enables multiple CPU models to share a single set of PMU events.
98It is required even if such mapping is 1:1.
99
100The mapfile.csv format is expected to be:
101
102 Header line
103 CPUID,Version,Dir/path/name,Type
104
105where:
106
107 Comma:
108 is the required field delimiter (i.e other fields cannot
109 have commas within them).
110
111 Comments:
112 Lines in which the first character is either '\n' or '#'
113 are ignored.
114
115 Header line
116 The header line is the first line in the file, which is
117 always _IGNORED_. It can empty.
118
119 CPUID:
120 CPUID is an arch-specific char string, that can be used
121 to identify CPU (and associate it with a set of PMU events
122 it supports). Multiple CPUIDS can point to the same
123 File/path/name.json.
124
125 Example:
126 CPUID == 'GenuineIntel-6-2E' (on x86).
127 CPUID == '004b0100' (PVR value in Powerpc)
128 Version:
129 is the Version of the mapfile.
130
131 Dir/path/name:
132 is the pathname to the directory containing the CPU's JSON
133 files, relative to the directory containing the mapfile.csv
134
135 Type:
136 indicates whether the events or "core" or "uncore" events.
137
138
139 Eg:
140
141 $ grep Silvermont tools/perf/pmu-events/arch/x86/mapfile.csv
142 GenuineIntel-6-37,V13,Silvermont_core,core
143 GenuineIntel-6-4D,V13,Silvermont_core,core
144 GenuineIntel-6-4C,V13,Silvermont_core,core
145
146 i.e the three CPU models use the JSON files (i.e PMU events) listed
147 in the directory 'tools/perf/pmu-events/arch/x86/Silvermont_core'.
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
new file mode 100644
index 000000000000..41611d7f9873
--- /dev/null
+++ b/tools/perf/pmu-events/jevents.c
@@ -0,0 +1,814 @@
1#define _XOPEN_SOURCE 500 /* needed for nftw() */
2#define _GNU_SOURCE /* needed for asprintf() */
3
4/* Parse event JSON files */
5
6/*
7 * Copyright (c) 2014, Intel Corporation
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
32*/
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <errno.h>
37#include <string.h>
38#include <ctype.h>
39#include <unistd.h>
40#include <stdarg.h>
41#include <libgen.h>
42#include <dirent.h>
43#include <sys/time.h> /* getrlimit */
44#include <sys/resource.h> /* getrlimit */
45#include <ftw.h>
46#include <sys/stat.h>
47#include "jsmn.h"
48#include "json.h"
49#include "jevents.h"
50
51#ifndef __maybe_unused
52#define __maybe_unused __attribute__((unused))
53#endif
54
55int verbose;
56char *prog;
57
58int eprintf(int level, int var, const char *fmt, ...)
59{
60
61 int ret;
62 va_list args;
63
64 if (var < level)
65 return 0;
66
67 va_start(args, fmt);
68
69 ret = vfprintf(stderr, fmt, args);
70
71 va_end(args);
72
73 return ret;
74}
75
76__attribute__((weak)) char *get_cpu_str(void)
77{
78 return NULL;
79}
80
81static void addfield(char *map, char **dst, const char *sep,
82 const char *a, jsmntok_t *bt)
83{
84 unsigned int len = strlen(a) + 1 + strlen(sep);
85 int olen = *dst ? strlen(*dst) : 0;
86 int blen = bt ? json_len(bt) : 0;
87 char *out;
88
89 out = realloc(*dst, len + olen + blen);
90 if (!out) {
91 /* Don't add field in this case */
92 return;
93 }
94 *dst = out;
95
96 if (!olen)
97 *(*dst) = 0;
98 else
99 strcat(*dst, sep);
100 strcat(*dst, a);
101 if (bt)
102 strncat(*dst, map + bt->start, blen);
103}
104
105static void fixname(char *s)
106{
107 for (; *s; s++)
108 *s = tolower(*s);
109}
110
111static void fixdesc(char *s)
112{
113 char *e = s + strlen(s);
114
115 /* Remove trailing dots that look ugly in perf list */
116 --e;
117 while (e >= s && isspace(*e))
118 --e;
119 if (*e == '.')
120 *e = 0;
121}
122
123static struct msrmap {
124 const char *num;
125 const char *pname;
126} msrmap[] = {
127 { "0x3F6", "ldlat=" },
128 { "0x1A6", "offcore_rsp=" },
129 { "0x1A7", "offcore_rsp=" },
130 { "0x3F7", "frontend=" },
131 { NULL, NULL }
132};
133
134static struct field {
135 const char *field;
136 const char *kernel;
137} fields[] = {
138 { "EventCode", "event=" },
139 { "UMask", "umask=" },
140 { "CounterMask", "cmask=" },
141 { "Invert", "inv=" },
142 { "AnyThread", "any=" },
143 { "EdgeDetect", "edge=" },
144 { "SampleAfterValue", "period=" },
145 { NULL, NULL }
146};
147
148static void cut_comma(char *map, jsmntok_t *newval)
149{
150 int i;
151
152 /* Cut off everything after comma */
153 for (i = newval->start; i < newval->end; i++) {
154 if (map[i] == ',')
155 newval->end = i;
156 }
157}
158
159static int match_field(char *map, jsmntok_t *field, int nz,
160 char **event, jsmntok_t *val)
161{
162 struct field *f;
163 jsmntok_t newval = *val;
164
165 for (f = fields; f->field; f++)
166 if (json_streq(map, field, f->field) && nz) {
167 cut_comma(map, &newval);
168 addfield(map, event, ",", f->kernel, &newval);
169 return 1;
170 }
171 return 0;
172}
173
174static struct msrmap *lookup_msr(char *map, jsmntok_t *val)
175{
176 jsmntok_t newval = *val;
177 static bool warned;
178 int i;
179
180 cut_comma(map, &newval);
181 for (i = 0; msrmap[i].num; i++)
182 if (json_streq(map, &newval, msrmap[i].num))
183 return &msrmap[i];
184 if (!warned) {
185 warned = true;
186 pr_err("%s: Unknown MSR in event file %.*s\n", prog,
187 json_len(val), map + val->start);
188 }
189 return NULL;
190}
191
192#define EXPECT(e, t, m) do { if (!(e)) { \
193 jsmntok_t *loc = (t); \
194 if (!(t)->start && (t) > tokens) \
195 loc = (t) - 1; \
196 pr_err("%s:%d: " m ", got %s\n", fn, \
197 json_line(map, loc), \
198 json_name(t)); \
199 goto out_free; \
200} } while (0)
201
202#define TOPIC_DEPTH 256
203static char *topic_array[TOPIC_DEPTH];
204static int topic_level;
205
206static char *get_topic(void)
207{
208 char *tp_old, *tp = NULL;
209 int i;
210
211 for (i = 0; i < topic_level + 1; i++) {
212 int n;
213
214 tp_old = tp;
215 n = asprintf(&tp, "%s%s", tp ?: "", topic_array[i]);
216 if (n < 0) {
217 pr_info("%s: asprintf() error %s\n", prog);
218 return NULL;
219 }
220 free(tp_old);
221 }
222
223 for (i = 0; i < (int) strlen(tp); i++) {
224 char c = tp[i];
225
226 if (c == '-')
227 tp[i] = ' ';
228 else if (c == '.') {
229 tp[i] = '\0';
230 break;
231 }
232 }
233
234 return tp;
235}
236
237static int add_topic(int level, char *bname)
238{
239 char *topic;
240
241 level -= 2;
242
243 if (level >= TOPIC_DEPTH)
244 return -EINVAL;
245
246 topic = strdup(bname);
247 if (!topic) {
248 pr_info("%s: strdup() error %s for file %s\n", prog,
249 strerror(errno), bname);
250 return -ENOMEM;
251 }
252
253 free(topic_array[topic_level]);
254 topic_array[topic_level] = topic;
255 topic_level = level;
256 return 0;
257}
258
259struct perf_entry_data {
260 FILE *outfp;
261 char *topic;
262};
263
264static int close_table;
265
266static void print_events_table_prefix(FILE *fp, const char *tblname)
267{
268 fprintf(fp, "struct pmu_event %s[] = {\n", tblname);
269 close_table = 1;
270}
271
272static int print_events_table_entry(void *data, char *name, char *event,
273 char *desc, char *long_desc)
274{
275 struct perf_entry_data *pd = data;
276 FILE *outfp = pd->outfp;
277 char *topic = pd->topic;
278
279 /*
280 * TODO: Remove formatting chars after debugging to reduce
281 * string lengths.
282 */
283 fprintf(outfp, "{\n");
284
285 fprintf(outfp, "\t.name = \"%s\",\n", name);
286 fprintf(outfp, "\t.event = \"%s\",\n", event);
287 fprintf(outfp, "\t.desc = \"%s\",\n", desc);
288 fprintf(outfp, "\t.topic = \"%s\",\n", topic);
289 if (long_desc && long_desc[0])
290 fprintf(outfp, "\t.long_desc = \"%s\",\n", long_desc);
291
292 fprintf(outfp, "},\n");
293
294 return 0;
295}
296
297static void print_events_table_suffix(FILE *outfp)
298{
299 fprintf(outfp, "{\n");
300
301 fprintf(outfp, "\t.name = 0,\n");
302 fprintf(outfp, "\t.event = 0,\n");
303 fprintf(outfp, "\t.desc = 0,\n");
304
305 fprintf(outfp, "},\n");
306 fprintf(outfp, "};\n");
307 close_table = 0;
308}
309
310static struct fixed {
311 const char *name;
312 const char *event;
313} fixed[] = {
314 { "inst_retired.any", "event=0xc0" },
315 { "inst_retired.any_p", "event=0xc0" },
316 { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03" },
317 { "cpu_clk_unhalted.thread", "event=0x3c" },
318 { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1" },
319 { NULL, NULL},
320};
321
322/*
323 * Handle different fixed counter encodings between JSON and perf.
324 */
325static char *real_event(const char *name, char *event)
326{
327 int i;
328
329 for (i = 0; fixed[i].name; i++)
330 if (!strcasecmp(name, fixed[i].name))
331 return (char *)fixed[i].event;
332 return event;
333}
334
335/* Call func with each event in the json file */
336int json_events(const char *fn,
337 int (*func)(void *data, char *name, char *event, char *desc,
338 char *long_desc),
339 void *data)
340{
341 int err = -EIO;
342 size_t size;
343 jsmntok_t *tokens, *tok;
344 int i, j, len;
345 char *map;
346
347 if (!fn)
348 return -ENOENT;
349
350 tokens = parse_json(fn, &map, &size, &len);
351 if (!tokens)
352 return -EIO;
353 EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array");
354 tok = tokens + 1;
355 for (i = 0; i < tokens->size; i++) {
356 char *event = NULL, *desc = NULL, *name = NULL;
357 char *long_desc = NULL;
358 char *extra_desc = NULL;
359 struct msrmap *msr = NULL;
360 jsmntok_t *msrval = NULL;
361 jsmntok_t *precise = NULL;
362 jsmntok_t *obj = tok++;
363
364 EXPECT(obj->type == JSMN_OBJECT, obj, "expected object");
365 for (j = 0; j < obj->size; j += 2) {
366 jsmntok_t *field, *val;
367 int nz;
368
369 field = tok + j;
370 EXPECT(field->type == JSMN_STRING, tok + j,
371 "Expected field name");
372 val = tok + j + 1;
373 EXPECT(val->type == JSMN_STRING, tok + j + 1,
374 "Expected string value");
375
376 nz = !json_streq(map, val, "0");
377 if (match_field(map, field, nz, &event, val)) {
378 /* ok */
379 } else if (json_streq(map, field, "EventName")) {
380 addfield(map, &name, "", "", val);
381 } else if (json_streq(map, field, "BriefDescription")) {
382 addfield(map, &desc, "", "", val);
383 fixdesc(desc);
384 } else if (json_streq(map, field,
385 "PublicDescription")) {
386 addfield(map, &long_desc, "", "", val);
387 fixdesc(long_desc);
388 } else if (json_streq(map, field, "PEBS") && nz) {
389 precise = val;
390 } else if (json_streq(map, field, "MSRIndex") && nz) {
391 msr = lookup_msr(map, val);
392 } else if (json_streq(map, field, "MSRValue")) {
393 msrval = val;
394 } else if (json_streq(map, field, "Errata") &&
395 !json_streq(map, val, "null")) {
396 addfield(map, &extra_desc, ". ",
397 " Spec update: ", val);
398 } else if (json_streq(map, field, "Data_LA") && nz) {
399 addfield(map, &extra_desc, ". ",
400 " Supports address when precise",
401 NULL);
402 }
403 /* ignore unknown fields */
404 }
405 if (precise && desc && !strstr(desc, "(Precise Event)")) {
406 if (json_streq(map, precise, "2"))
407 addfield(map, &extra_desc, " ",
408 "(Must be precise)", NULL);
409 else
410 addfield(map, &extra_desc, " ",
411 "(Precise event)", NULL);
412 }
413 if (desc && extra_desc)
414 addfield(map, &desc, " ", extra_desc, NULL);
415 if (long_desc && extra_desc)
416 addfield(map, &long_desc, " ", extra_desc, NULL);
417 if (msr != NULL)
418 addfield(map, &event, ",", msr->pname, msrval);
419 fixname(name);
420
421 err = func(data, name, real_event(name, event), desc, long_desc);
422 free(event);
423 free(desc);
424 free(name);
425 free(long_desc);
426 free(extra_desc);
427 if (err)
428 break;
429 tok += j;
430 }
431 EXPECT(tok - tokens == len, tok, "unexpected objects at end");
432 err = 0;
433out_free:
434 free_json(map, size, tokens);
435 return err;
436}
437
438static char *file_name_to_table_name(char *fname)
439{
440 unsigned int i;
441 int n;
442 int c;
443 char *tblname;
444
445 /*
446 * Ensure tablename starts with alphabetic character.
447 * Derive rest of table name from basename of the JSON file,
448 * replacing hyphens and stripping out .json suffix.
449 */
450 n = asprintf(&tblname, "pme_%s", basename(fname));
451 if (n < 0) {
452 pr_info("%s: asprintf() error %s for file %s\n", prog,
453 strerror(errno), fname);
454 return NULL;
455 }
456
457 for (i = 0; i < strlen(tblname); i++) {
458 c = tblname[i];
459
460 if (c == '-')
461 tblname[i] = '_';
462 else if (c == '.') {
463 tblname[i] = '\0';
464 break;
465 } else if (!isalnum(c) && c != '_') {
466 pr_err("%s: Invalid character '%c' in file name %s\n",
467 prog, c, basename(fname));
468 free(tblname);
469 tblname = NULL;
470 break;
471 }
472 }
473
474 return tblname;
475}
476
477static void print_mapping_table_prefix(FILE *outfp)
478{
479 fprintf(outfp, "struct pmu_events_map pmu_events_map[] = {\n");
480}
481
482static void print_mapping_table_suffix(FILE *outfp)
483{
484 /*
485 * Print the terminating, NULL entry.
486 */
487 fprintf(outfp, "{\n");
488 fprintf(outfp, "\t.cpuid = 0,\n");
489 fprintf(outfp, "\t.version = 0,\n");
490 fprintf(outfp, "\t.type = 0,\n");
491 fprintf(outfp, "\t.table = 0,\n");
492 fprintf(outfp, "},\n");
493
494 /* and finally, the closing curly bracket for the struct */
495 fprintf(outfp, "};\n");
496}
497
498static int process_mapfile(FILE *outfp, char *fpath)
499{
500 int n = 16384;
501 FILE *mapfp;
502 char *save = NULL;
503 char *line, *p;
504 int line_num;
505 char *tblname;
506
507 pr_info("%s: Processing mapfile %s\n", prog, fpath);
508
509 line = malloc(n);
510 if (!line)
511 return -1;
512
513 mapfp = fopen(fpath, "r");
514 if (!mapfp) {
515 pr_info("%s: Error %s opening %s\n", prog, strerror(errno),
516 fpath);
517 return -1;
518 }
519
520 print_mapping_table_prefix(outfp);
521
522 /* Skip first line (header) */
523 p = fgets(line, n, mapfp);
524 if (!p)
525 goto out;
526
527 line_num = 1;
528 while (1) {
529 char *cpuid, *version, *type, *fname;
530
531 line_num++;
532 p = fgets(line, n, mapfp);
533 if (!p)
534 break;
535
536 if (line[0] == '#' || line[0] == '\n')
537 continue;
538
539 if (line[strlen(line)-1] != '\n') {
540 /* TODO Deal with lines longer than 16K */
541 pr_info("%s: Mapfile %s: line %d too long, aborting\n",
542 prog, fpath, line_num);
543 return -1;
544 }
545 line[strlen(line)-1] = '\0';
546
547 cpuid = strtok_r(p, ",", &save);
548 version = strtok_r(NULL, ",", &save);
549 fname = strtok_r(NULL, ",", &save);
550 type = strtok_r(NULL, ",", &save);
551
552 tblname = file_name_to_table_name(fname);
553 fprintf(outfp, "{\n");
554 fprintf(outfp, "\t.cpuid = \"%s\",\n", cpuid);
555 fprintf(outfp, "\t.version = \"%s\",\n", version);
556 fprintf(outfp, "\t.type = \"%s\",\n", type);
557
558 /*
559 * CHECK: We can't use the type (eg "core") field in the
560 * table name. For us to do that, we need to somehow tweak
561 * the other caller of file_name_to_table(), process_json()
562 * to determine the type. process_json() file has no way
563 * of knowing these are "core" events unless file name has
564 * core in it. If filename has core in it, we can safely
565 * ignore the type field here also.
566 */
567 fprintf(outfp, "\t.table = %s\n", tblname);
568 fprintf(outfp, "},\n");
569 }
570
571out:
572 print_mapping_table_suffix(outfp);
573 return 0;
574}
575
576/*
577 * If we fail to locate/process JSON and map files, create a NULL mapping
578 * table. This would at least allow perf to build even if we can't find/use
579 * the aliases.
580 */
581static void create_empty_mapping(const char *output_file)
582{
583 FILE *outfp;
584
585 pr_info("%s: Creating empty pmu_events_map[] table\n", prog);
586
587 /* Truncate file to clear any partial writes to it */
588 outfp = fopen(output_file, "w");
589 if (!outfp) {
590 perror("fopen()");
591 _Exit(1);
592 }
593
594 fprintf(outfp, "#include \"../../pmu-events/pmu-events.h\"\n");
595 print_mapping_table_prefix(outfp);
596 print_mapping_table_suffix(outfp);
597 fclose(outfp);
598}
599
600static int get_maxfds(void)
601{
602 struct rlimit rlim;
603
604 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
605 return min((int)rlim.rlim_max / 2, 512);
606
607 return 512;
608}
609
610/*
611 * nftw() doesn't let us pass an argument to the processing function,
612 * so use a global variables.
613 */
614static FILE *eventsfp;
615static char *mapfile;
616
617static int process_one_file(const char *fpath, const struct stat *sb,
618 int typeflag, struct FTW *ftwbuf)
619{
620 char *tblname, *bname = (char *) fpath + ftwbuf->base;
621 int is_dir = typeflag == FTW_D;
622 int is_file = typeflag == FTW_F;
623 int level = ftwbuf->level;
624 int err = 0;
625
626 pr_debug("%s %d %7jd %-20s %s\n",
627 is_file ? "f" : is_dir ? "d" : "x",
628 level, sb->st_size, bname, fpath);
629
630 /* base dir */
631 if (level == 0)
632 return 0;
633
634 /* model directory, reset topic */
635 if (level == 1 && is_dir) {
636 if (close_table)
637 print_events_table_suffix(eventsfp);
638
639 /*
640 * Drop file name suffix. Replace hyphens with underscores.
641 * Fail if file name contains any alphanum characters besides
642 * underscores.
643 */
644 tblname = file_name_to_table_name(bname);
645 if (!tblname) {
646 pr_info("%s: Error determining table name for %s\n", prog,
647 bname);
648 return -1;
649 }
650
651 print_events_table_prefix(eventsfp, tblname);
652 return 0;
653 }
654
655 /*
656 * Save the mapfile name for now. We will process mapfile
657 * after processing all JSON files (so we can write out the
658 * mapping table after all PMU events tables).
659 *
660 * TODO: Allow for multiple mapfiles? Punt for now.
661 */
662 if (level == 1 && is_file) {
663 if (!strncmp(bname, "mapfile.csv", 11)) {
664 if (mapfile) {
665 pr_info("%s: Many mapfiles? Using %s, ignoring %s\n",
666 prog, mapfile, fpath);
667 } else {
668 mapfile = strdup(fpath);
669 }
670 return 0;
671 }
672
673 pr_info("%s: Ignoring file %s\n", prog, fpath);
674 return 0;
675 }
676
677 /*
678 * If the file name does not have a .json extension,
679 * ignore it. It could be a readme.txt for instance.
680 */
681 if (is_file) {
682 char *suffix = bname + strlen(bname) - 5;
683
684 if (strncmp(suffix, ".json", 5)) {
685 pr_info("%s: Ignoring file without .json suffix %s\n", prog,
686 fpath);
687 return 0;
688 }
689 }
690
691 if (level > 1 && add_topic(level, bname))
692 return -ENOMEM;
693
694 /*
695 * Assume all other files are JSON files.
696 *
697 * If mapfile refers to 'power7_core.json', we create a table
698 * named 'power7_core'. Any inconsistencies between the mapfile
699 * and directory tree could result in build failure due to table
700 * names not being found.
701 *
702 * Atleast for now, be strict with processing JSON file names.
703 * i.e. if JSON file name cannot be mapped to C-style table name,
704 * fail.
705 */
706 if (is_file) {
707 struct perf_entry_data data = {
708 .topic = get_topic(),
709 .outfp = eventsfp,
710 };
711
712 err = json_events(fpath, print_events_table_entry, &data);
713
714 free(data.topic);
715 }
716
717 return err;
718}
719
720#ifndef PATH_MAX
721#define PATH_MAX 4096
722#endif
723
724/*
725 * Starting in directory 'start_dirname', find the "mapfile.csv" and
726 * the set of JSON files for the architecture 'arch'.
727 *
728 * From each JSON file, create a C-style "PMU events table" from the
729 * JSON file (see struct pmu_event).
730 *
731 * From the mapfile, create a mapping between the CPU revisions and
732 * PMU event tables (see struct pmu_events_map).
733 *
734 * Write out the PMU events tables and the mapping table to pmu-event.c.
735 *
736 * If unable to process the JSON or arch files, create an empty mapping
737 * table so we can continue to build/use perf even if we cannot use the
738 * PMU event aliases.
739 */
740int main(int argc, char *argv[])
741{
742 int rc;
743 int maxfds;
744 char ldirname[PATH_MAX];
745
746 const char *arch;
747 const char *output_file;
748 const char *start_dirname;
749
750 prog = basename(argv[0]);
751 if (argc < 4) {
752 pr_err("Usage: %s <arch> <starting_dir> <output_file>\n", prog);
753 return 1;
754 }
755
756 arch = argv[1];
757 start_dirname = argv[2];
758 output_file = argv[3];
759
760 if (argc > 4)
761 verbose = atoi(argv[4]);
762
763 eventsfp = fopen(output_file, "w");
764 if (!eventsfp) {
765 pr_err("%s Unable to create required file %s (%s)\n",
766 prog, output_file, strerror(errno));
767 return 2;
768 }
769
770 /* Include pmu-events.h first */
771 fprintf(eventsfp, "#include \"../../pmu-events/pmu-events.h\"\n");
772
773 sprintf(ldirname, "%s/%s", start_dirname, arch);
774
775 /*
776 * The mapfile allows multiple CPUids to point to the same JSON file,
777 * so, not sure if there is a need for symlinks within the pmu-events
778 * directory.
779 *
780 * For now, treat symlinks of JSON files as regular files and create
781 * separate tables for each symlink (presumably, each symlink refers
782 * to specific version of the CPU).
783 */
784
785 maxfds = get_maxfds();
786 mapfile = NULL;
787 rc = nftw(ldirname, process_one_file, maxfds, 0);
788 if (rc && verbose) {
789 pr_info("%s: Error walking file tree %s\n", prog, ldirname);
790 goto empty_map;
791 } else if (rc) {
792 goto empty_map;
793 }
794
795 if (close_table)
796 print_events_table_suffix(eventsfp);
797
798 if (!mapfile) {
799 pr_info("%s: No CPU->JSON mapping?\n", prog);
800 goto empty_map;
801 }
802
803 if (process_mapfile(eventsfp, mapfile)) {
804 pr_info("%s: Error processing mapfile %s\n", prog, mapfile);
805 goto empty_map;
806 }
807
808 return 0;
809
810empty_map:
811 fclose(eventsfp);
812 create_empty_mapping(output_file);
813 return 0;
814}
diff --git a/tools/perf/pmu-events/jevents.h b/tools/perf/pmu-events/jevents.h
new file mode 100644
index 000000000000..b0eb2744b498
--- /dev/null
+++ b/tools/perf/pmu-events/jevents.h
@@ -0,0 +1,18 @@
1#ifndef JEVENTS_H
2#define JEVENTS_H 1
3
4int json_events(const char *fn,
5 int (*func)(void *data, char *name, char *event, char *desc,
6 char *long_desc),
7 void *data);
8char *get_cpu_str(void);
9
10#ifndef min
11#define min(x, y) ({ \
12 typeof(x) _min1 = (x); \
13 typeof(y) _min2 = (y); \
14 (void) (&_min1 == &_min2); \
15 _min1 < _min2 ? _min1 : _min2; })
16#endif
17
18#endif
diff --git a/tools/perf/pmu-events/jsmn.c b/tools/perf/pmu-events/jsmn.c
new file mode 100644
index 000000000000..11d1fa18bfa5
--- /dev/null
+++ b/tools/perf/pmu-events/jsmn.c
@@ -0,0 +1,313 @@
1/*
2 * Copyright (c) 2010 Serge A. Zaitsev
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 *
22 * Slightly modified by AK to not assume 0 terminated input.
23 */
24
25#include <stdlib.h>
26#include "jsmn.h"
27
28/*
29 * Allocates a fresh unused token from the token pool.
30 */
31static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
32 jsmntok_t *tokens, size_t num_tokens)
33{
34 jsmntok_t *tok;
35
36 if ((unsigned)parser->toknext >= num_tokens)
37 return NULL;
38 tok = &tokens[parser->toknext++];
39 tok->start = tok->end = -1;
40 tok->size = 0;
41 return tok;
42}
43
44/*
45 * Fills token type and boundaries.
46 */
47static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
48 int start, int end)
49{
50 token->type = type;
51 token->start = start;
52 token->end = end;
53 token->size = 0;
54}
55
56/*
57 * Fills next available token with JSON primitive.
58 */
59static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
60 size_t len,
61 jsmntok_t *tokens, size_t num_tokens)
62{
63 jsmntok_t *token;
64 int start;
65
66 start = parser->pos;
67
68 for (; parser->pos < len; parser->pos++) {
69 switch (js[parser->pos]) {
70#ifndef JSMN_STRICT
71 /*
72 * In strict mode primitive must be followed by ","
73 * or "}" or "]"
74 */
75 case ':':
76#endif
77 case '\t':
78 case '\r':
79 case '\n':
80 case ' ':
81 case ',':
82 case ']':
83 case '}':
84 goto found;
85 default:
86 break;
87 }
88 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
89 parser->pos = start;
90 return JSMN_ERROR_INVAL;
91 }
92 }
93#ifdef JSMN_STRICT
94 /*
95 * In strict mode primitive must be followed by a
96 * comma/object/array.
97 */
98 parser->pos = start;
99 return JSMN_ERROR_PART;
100#endif
101
102found:
103 token = jsmn_alloc_token(parser, tokens, num_tokens);
104 if (token == NULL) {
105 parser->pos = start;
106 return JSMN_ERROR_NOMEM;
107 }
108 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
109 parser->pos--; /* parent sees closing brackets */
110 return JSMN_SUCCESS;
111}
112
113/*
114 * Fills next token with JSON string.
115 */
116static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
117 size_t len,
118 jsmntok_t *tokens, size_t num_tokens)
119{
120 jsmntok_t *token;
121 int start = parser->pos;
122
123 /* Skip starting quote */
124 parser->pos++;
125
126 for (; parser->pos < len; parser->pos++) {
127 char c = js[parser->pos];
128
129 /* Quote: end of string */
130 if (c == '\"') {
131 token = jsmn_alloc_token(parser, tokens, num_tokens);
132 if (token == NULL) {
133 parser->pos = start;
134 return JSMN_ERROR_NOMEM;
135 }
136 jsmn_fill_token(token, JSMN_STRING, start+1,
137 parser->pos);
138 return JSMN_SUCCESS;
139 }
140
141 /* Backslash: Quoted symbol expected */
142 if (c == '\\') {
143 parser->pos++;
144 switch (js[parser->pos]) {
145 /* Allowed escaped symbols */
146 case '\"':
147 case '/':
148 case '\\':
149 case 'b':
150 case 'f':
151 case 'r':
152 case 'n':
153 case 't':
154 break;
155 /* Allows escaped symbol \uXXXX */
156 case 'u':
157 /* TODO */
158 break;
159 /* Unexpected symbol */
160 default:
161 parser->pos = start;
162 return JSMN_ERROR_INVAL;
163 }
164 }
165 }
166 parser->pos = start;
167 return JSMN_ERROR_PART;
168}
169
170/*
171 * Parse JSON string and fill tokens.
172 */
173jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
174 jsmntok_t *tokens, unsigned int num_tokens)
175{
176 jsmnerr_t r;
177 int i;
178 jsmntok_t *token;
179
180 for (; parser->pos < len; parser->pos++) {
181 char c;
182 jsmntype_t type;
183
184 c = js[parser->pos];
185 switch (c) {
186 case '{':
187 case '[':
188 token = jsmn_alloc_token(parser, tokens, num_tokens);
189 if (token == NULL)
190 return JSMN_ERROR_NOMEM;
191 if (parser->toksuper != -1)
192 tokens[parser->toksuper].size++;
193 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
194 token->start = parser->pos;
195 parser->toksuper = parser->toknext - 1;
196 break;
197 case '}':
198 case ']':
199 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
200 for (i = parser->toknext - 1; i >= 0; i--) {
201 token = &tokens[i];
202 if (token->start != -1 && token->end == -1) {
203 if (token->type != type)
204 return JSMN_ERROR_INVAL;
205 parser->toksuper = -1;
206 token->end = parser->pos + 1;
207 break;
208 }
209 }
210 /* Error if unmatched closing bracket */
211 if (i == -1)
212 return JSMN_ERROR_INVAL;
213 for (; i >= 0; i--) {
214 token = &tokens[i];
215 if (token->start != -1 && token->end == -1) {
216 parser->toksuper = i;
217 break;
218 }
219 }
220 break;
221 case '\"':
222 r = jsmn_parse_string(parser, js, len, tokens,
223 num_tokens);
224 if (r < 0)
225 return r;
226 if (parser->toksuper != -1)
227 tokens[parser->toksuper].size++;
228 break;
229 case '\t':
230 case '\r':
231 case '\n':
232 case ':':
233 case ',':
234 case ' ':
235 break;
236#ifdef JSMN_STRICT
237 /*
238 * In strict mode primitives are:
239 * numbers and booleans.
240 */
241 case '-':
242 case '0':
243 case '1':
244 case '2':
245 case '3':
246 case '4':
247 case '5':
248 case '6':
249 case '7':
250 case '8':
251 case '9':
252 case 't':
253 case 'f':
254 case 'n':
255#else
256 /*
257 * In non-strict mode every unquoted value
258 * is a primitive.
259 */
260 /*FALL THROUGH */
261 default:
262#endif
263 r = jsmn_parse_primitive(parser, js, len, tokens,
264 num_tokens);
265 if (r < 0)
266 return r;
267 if (parser->toksuper != -1)
268 tokens[parser->toksuper].size++;
269 break;
270
271#ifdef JSMN_STRICT
272 /* Unexpected char in strict mode */
273 default:
274 return JSMN_ERROR_INVAL;
275#endif
276 }
277 }
278
279 for (i = parser->toknext - 1; i >= 0; i--) {
280 /* Unmatched opened object or array */
281 if (tokens[i].start != -1 && tokens[i].end == -1)
282 return JSMN_ERROR_PART;
283 }
284
285 return JSMN_SUCCESS;
286}
287
288/*
289 * Creates a new parser based over a given buffer with an array of tokens
290 * available.
291 */
292void jsmn_init(jsmn_parser *parser)
293{
294 parser->pos = 0;
295 parser->toknext = 0;
296 parser->toksuper = -1;
297}
298
299const char *jsmn_strerror(jsmnerr_t err)
300{
301 switch (err) {
302 case JSMN_ERROR_NOMEM:
303 return "No enough tokens";
304 case JSMN_ERROR_INVAL:
305 return "Invalid character inside JSON string";
306 case JSMN_ERROR_PART:
307 return "The string is not a full JSON packet, more bytes expected";
308 case JSMN_SUCCESS:
309 return "Success";
310 default:
311 return "Unknown json error";
312 }
313}
diff --git a/tools/perf/pmu-events/jsmn.h b/tools/perf/pmu-events/jsmn.h
new file mode 100644
index 000000000000..d666b10cf25b
--- /dev/null
+++ b/tools/perf/pmu-events/jsmn.h
@@ -0,0 +1,67 @@
1#ifndef __JSMN_H_
2#define __JSMN_H_
3
4/*
5 * JSON type identifier. Basic types are:
6 * o Object
7 * o Array
8 * o String
9 * o Other primitive: number, boolean (true/false) or null
10 */
11typedef enum {
12 JSMN_PRIMITIVE = 0,
13 JSMN_OBJECT = 1,
14 JSMN_ARRAY = 2,
15 JSMN_STRING = 3
16} jsmntype_t;
17
18typedef enum {
19 /* Not enough tokens were provided */
20 JSMN_ERROR_NOMEM = -1,
21 /* Invalid character inside JSON string */
22 JSMN_ERROR_INVAL = -2,
23 /* The string is not a full JSON packet, more bytes expected */
24 JSMN_ERROR_PART = -3,
25 /* Everything was fine */
26 JSMN_SUCCESS = 0
27} jsmnerr_t;
28
29/*
30 * JSON token description.
31 * @param type type (object, array, string etc.)
32 * @param start start position in JSON data string
33 * @param end end position in JSON data string
34 */
35typedef struct {
36 jsmntype_t type;
37 int start;
38 int end;
39 int size;
40} jsmntok_t;
41
42/*
43 * JSON parser. Contains an array of token blocks available. Also stores
44 * the string being parsed now and current position in that string
45 */
46typedef struct {
47 unsigned int pos; /* offset in the JSON string */
48 int toknext; /* next token to allocate */
49 int toksuper; /* superior token node, e.g parent object or array */
50} jsmn_parser;
51
52/*
53 * Create JSON parser over an array of tokens
54 */
55void jsmn_init(jsmn_parser *parser);
56
57/*
58 * Run JSON parser. It parses a JSON data string into and array of tokens,
59 * each describing a single JSON object.
60 */
61jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
62 size_t len,
63 jsmntok_t *tokens, unsigned int num_tokens);
64
65const char *jsmn_strerror(jsmnerr_t err);
66
67#endif /* __JSMN_H_ */
diff --git a/tools/perf/pmu-events/json.c b/tools/perf/pmu-events/json.c
new file mode 100644
index 000000000000..f67bbb0aa36e
--- /dev/null
+++ b/tools/perf/pmu-events/json.c
@@ -0,0 +1,162 @@
1/* Parse JSON files using the JSMN parser. */
2
3/*
4 * Copyright (c) 2014, Intel Corporation
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29*/
30
31#include <stdlib.h>
32#include <string.h>
33#include <sys/mman.h>
34#include <sys/stat.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <errno.h>
38#include <unistd.h>
39#include "jsmn.h"
40#include "json.h"
41#include <linux/kernel.h>
42
43
44static char *mapfile(const char *fn, size_t *size)
45{
46 unsigned ps = sysconf(_SC_PAGESIZE);
47 struct stat st;
48 char *map = NULL;
49 int err;
50 int fd = open(fn, O_RDONLY);
51
52 if (fd < 0 && verbose && fn) {
53 pr_err("Error opening events file '%s': %s\n", fn,
54 strerror(errno));
55 }
56
57 if (fd < 0)
58 return NULL;
59 err = fstat(fd, &st);
60 if (err < 0)
61 goto out;
62 *size = st.st_size;
63 map = mmap(NULL,
64 (st.st_size + ps - 1) & ~(ps - 1),
65 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
66 if (map == MAP_FAILED)
67 map = NULL;
68out:
69 close(fd);
70 return map;
71}
72
73static void unmapfile(char *map, size_t size)
74{
75 unsigned ps = sysconf(_SC_PAGESIZE);
76 munmap(map, roundup(size, ps));
77}
78
79/*
80 * Parse json file using jsmn. Return array of tokens,
81 * and mapped file. Caller needs to free array.
82 */
83jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len)
84{
85 jsmn_parser parser;
86 jsmntok_t *tokens;
87 jsmnerr_t res;
88 unsigned sz;
89
90 *map = mapfile(fn, size);
91 if (!*map)
92 return NULL;
93 /* Heuristic */
94 sz = *size * 16;
95 tokens = malloc(sz);
96 if (!tokens)
97 goto error;
98 jsmn_init(&parser);
99 res = jsmn_parse(&parser, *map, *size, tokens,
100 sz / sizeof(jsmntok_t));
101 if (res != JSMN_SUCCESS) {
102 pr_err("%s: json error %s\n", fn, jsmn_strerror(res));
103 goto error_free;
104 }
105 if (len)
106 *len = parser.toknext;
107 return tokens;
108error_free:
109 free(tokens);
110error:
111 unmapfile(*map, *size);
112 return NULL;
113}
114
115void free_json(char *map, size_t size, jsmntok_t *tokens)
116{
117 free(tokens);
118 unmapfile(map, size);
119}
120
121static int countchar(char *map, char c, int end)
122{
123 int i;
124 int count = 0;
125 for (i = 0; i < end; i++)
126 if (map[i] == c)
127 count++;
128 return count;
129}
130
131/* Return line number of a jsmn token */
132int json_line(char *map, jsmntok_t *t)
133{
134 return countchar(map, '\n', t->start) + 1;
135}
136
137static const char * const jsmn_types[] = {
138 [JSMN_PRIMITIVE] = "primitive",
139 [JSMN_ARRAY] = "array",
140 [JSMN_OBJECT] = "object",
141 [JSMN_STRING] = "string"
142};
143
144#define LOOKUP(a, i) ((i) < (sizeof(a)/sizeof(*(a))) ? ((a)[i]) : "?")
145
146/* Return type name of a jsmn token */
147const char *json_name(jsmntok_t *t)
148{
149 return LOOKUP(jsmn_types, t->type);
150}
151
152int json_len(jsmntok_t *t)
153{
154 return t->end - t->start;
155}
156
157/* Is string t equal to s? */
158int json_streq(char *map, jsmntok_t *t, const char *s)
159{
160 unsigned len = json_len(t);
161 return len == strlen(s) && !strncasecmp(map + t->start, s, len);
162}
diff --git a/tools/perf/pmu-events/json.h b/tools/perf/pmu-events/json.h
new file mode 100644
index 000000000000..278ebd32cfb6
--- /dev/null
+++ b/tools/perf/pmu-events/json.h
@@ -0,0 +1,38 @@
1#ifndef JSON_H
2#define JSON_H 1
3
4#include "jsmn.h"
5
6jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len);
7void free_json(char *map, size_t size, jsmntok_t *tokens);
8int json_line(char *map, jsmntok_t *t);
9const char *json_name(jsmntok_t *t);
10int json_streq(char *map, jsmntok_t *t, const char *s);
11int json_len(jsmntok_t *t);
12
13extern int verbose;
14
15#include <stdbool.h>
16
17extern int eprintf(int level, int var, const char *fmt, ...);
18#define pr_fmt(fmt) fmt
19
20#define pr_err(fmt, ...) \
21 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
22
23#define pr_info(fmt, ...) \
24 eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__)
25
26#define pr_debug(fmt, ...) \
27 eprintf(2, verbose, pr_fmt(fmt), ##__VA_ARGS__)
28
29#ifndef roundup
30#define roundup(x, y) ( \
31{ \
32 const typeof(y) __y = y; \
33 (((x) + (__y - 1)) / __y) * __y; \
34} \
35)
36#endif
37
38#endif
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
new file mode 100644
index 000000000000..2eaef595d8a0
--- /dev/null
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -0,0 +1,37 @@
1#ifndef PMU_EVENTS_H
2#define PMU_EVENTS_H
3
4/*
5 * Describe each PMU event. Each CPU has a table of PMU events.
6 */
7struct pmu_event {
8 const char *name;
9 const char *event;
10 const char *desc;
11 const char *topic;
12 const char *long_desc;
13};
14
15/*
16 *
17 * Map a CPU to its table of PMU events. The CPU is identified by the
18 * cpuid field, which is an arch-specific identifier for the CPU.
19 * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
20 * must match the get_cpustr() in tools/perf/arch/xxx/util/header.c)
21 *
22 * The cpuid can contain any character other than the comma.
23 */
24struct pmu_events_map {
25 const char *cpuid;
26 const char *version;
27 const char *type; /* core, uncore etc */
28 struct pmu_event *table;
29};
30
31/*
32 * Global table mapping each known CPU for the architecture to its
33 * table of PMU events.
34 */
35extern struct pmu_events_map pmu_events_map[];
36
37#endif
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ea34c5a32c11..d92e02006fb8 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -384,15 +384,14 @@ void perf_evlist__toggle_enable(struct perf_evlist *evlist)
384static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, 384static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
385 struct perf_evsel *evsel, int cpu) 385 struct perf_evsel *evsel, int cpu)
386{ 386{
387 int thread, err; 387 int thread;
388 int nr_threads = perf_evlist__nr_threads(evlist, evsel); 388 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
389 389
390 if (!evsel->fd) 390 if (!evsel->fd)
391 return -EINVAL; 391 return -EINVAL;
392 392
393 for (thread = 0; thread < nr_threads; thread++) { 393 for (thread = 0; thread < nr_threads; thread++) {
394 err = ioctl(FD(evsel, cpu, thread), 394 int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
395 PERF_EVENT_IOC_ENABLE, 0);
396 if (err) 395 if (err)
397 return err; 396 return err;
398 } 397 }
@@ -403,14 +402,14 @@ static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
403 struct perf_evsel *evsel, 402 struct perf_evsel *evsel,
404 int thread) 403 int thread)
405{ 404{
406 int cpu, err; 405 int cpu;
407 int nr_cpus = cpu_map__nr(evlist->cpus); 406 int nr_cpus = cpu_map__nr(evlist->cpus);
408 407
409 if (!evsel->fd) 408 if (!evsel->fd)
410 return -EINVAL; 409 return -EINVAL;
411 410
412 for (cpu = 0; cpu < nr_cpus; cpu++) { 411 for (cpu = 0; cpu < nr_cpus; cpu++) {
413 err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0); 412 int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
414 if (err) 413 if (err)
415 return err; 414 return err;
416 } 415 }
@@ -1606,10 +1605,9 @@ void perf_evlist__close(struct perf_evlist *evlist)
1606 struct perf_evsel *evsel; 1605 struct perf_evsel *evsel;
1607 int ncpus = cpu_map__nr(evlist->cpus); 1606 int ncpus = cpu_map__nr(evlist->cpus);
1608 int nthreads = thread_map__nr(evlist->threads); 1607 int nthreads = thread_map__nr(evlist->threads);
1609 int n;
1610 1608
1611 evlist__for_each_entry_reverse(evlist, evsel) { 1609 evlist__for_each_entry_reverse(evlist, evsel) {
1612 n = evsel->cpus ? evsel->cpus->nr : ncpus; 1610 int n = evsel->cpus ? evsel->cpus->nr : ncpus;
1613 perf_evsel__close(evsel, n, nthreads); 1611 perf_evsel__close(evsel, n, nthreads);
1614 } 1612 }
1615} 1613}
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 380e84c3af3d..8bc271141d9d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -985,14 +985,13 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
985 985
986static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 986static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
987{ 987{
988 int cpu, thread;
989
990 if (evsel->system_wide) 988 if (evsel->system_wide)
991 nthreads = 1; 989 nthreads = 1;
992 990
993 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); 991 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
994 992
995 if (evsel->fd) { 993 if (evsel->fd) {
994 int cpu, thread;
996 for (cpu = 0; cpu < ncpus; cpu++) { 995 for (cpu = 0; cpu < ncpus; cpu++) {
997 for (thread = 0; thread < nthreads; thread++) { 996 for (thread = 0; thread < nthreads; thread++) {
998 FD(evsel, cpu, thread) = -1; 997 FD(evsel, cpu, thread) = -1;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d306ca118449..d30109b421ee 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -151,4 +151,5 @@ int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
151 */ 151 */
152int get_cpuid(char *buffer, size_t sz); 152int get_cpuid(char *buffer, size_t sz);
153 153
154char *get_cpuid_str(void);
154#endif /* __PERF_HEADER_H */ 155#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 7591a0c37473..16c06d3ae577 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -90,6 +90,7 @@ struct intel_pt_decoder {
90 bool pge; 90 bool pge;
91 bool have_tma; 91 bool have_tma;
92 bool have_cyc; 92 bool have_cyc;
93 bool fixup_last_mtc;
93 uint64_t pos; 94 uint64_t pos;
94 uint64_t last_ip; 95 uint64_t last_ip;
95 uint64_t ip; 96 uint64_t ip;
@@ -586,10 +587,31 @@ struct intel_pt_calc_cyc_to_tsc_info {
586 uint64_t tsc_timestamp; 587 uint64_t tsc_timestamp;
587 uint64_t timestamp; 588 uint64_t timestamp;
588 bool have_tma; 589 bool have_tma;
590 bool fixup_last_mtc;
589 bool from_mtc; 591 bool from_mtc;
590 double cbr_cyc_to_tsc; 592 double cbr_cyc_to_tsc;
591}; 593};
592 594
595/*
596 * MTC provides a 8-bit slice of CTC but the TMA packet only provides the lower
597 * 16 bits of CTC. If mtc_shift > 8 then some of the MTC bits are not in the CTC
598 * provided by the TMA packet. Fix-up the last_mtc calculated from the TMA
599 * packet by copying the missing bits from the current MTC assuming the least
600 * difference between the two, and that the current MTC comes after last_mtc.
601 */
602static void intel_pt_fixup_last_mtc(uint32_t mtc, int mtc_shift,
603 uint32_t *last_mtc)
604{
605 uint32_t first_missing_bit = 1U << (16 - mtc_shift);
606 uint32_t mask = ~(first_missing_bit - 1);
607
608 *last_mtc |= mtc & mask;
609 if (*last_mtc >= mtc) {
610 *last_mtc -= first_missing_bit;
611 *last_mtc &= 0xff;
612 }
613}
614
593static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) 615static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
594{ 616{
595 struct intel_pt_decoder *decoder = pkt_info->decoder; 617 struct intel_pt_decoder *decoder = pkt_info->decoder;
@@ -619,6 +641,11 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
619 return 0; 641 return 0;
620 642
621 mtc = pkt_info->packet.payload; 643 mtc = pkt_info->packet.payload;
644 if (decoder->mtc_shift > 8 && data->fixup_last_mtc) {
645 data->fixup_last_mtc = false;
646 intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift,
647 &data->last_mtc);
648 }
622 if (mtc > data->last_mtc) 649 if (mtc > data->last_mtc)
623 mtc_delta = mtc - data->last_mtc; 650 mtc_delta = mtc - data->last_mtc;
624 else 651 else
@@ -687,6 +714,7 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
687 714
688 data->ctc_delta = 0; 715 data->ctc_delta = 0;
689 data->have_tma = true; 716 data->have_tma = true;
717 data->fixup_last_mtc = true;
690 718
691 return 0; 719 return 0;
692 720
@@ -753,6 +781,7 @@ static void intel_pt_calc_cyc_to_tsc(struct intel_pt_decoder *decoder,
753 .tsc_timestamp = decoder->tsc_timestamp, 781 .tsc_timestamp = decoder->tsc_timestamp,
754 .timestamp = decoder->timestamp, 782 .timestamp = decoder->timestamp,
755 .have_tma = decoder->have_tma, 783 .have_tma = decoder->have_tma,
784 .fixup_last_mtc = decoder->fixup_last_mtc,
756 .from_mtc = from_mtc, 785 .from_mtc = from_mtc,
757 .cbr_cyc_to_tsc = 0, 786 .cbr_cyc_to_tsc = 0,
758 }; 787 };
@@ -1271,6 +1300,7 @@ static void intel_pt_calc_tma(struct intel_pt_decoder *decoder)
1271 } 1300 }
1272 decoder->ctc_delta = 0; 1301 decoder->ctc_delta = 0;
1273 decoder->have_tma = true; 1302 decoder->have_tma = true;
1303 decoder->fixup_last_mtc = true;
1274 intel_pt_log("CTC timestamp " x64_fmt " last MTC %#x CTC rem %#x\n", 1304 intel_pt_log("CTC timestamp " x64_fmt " last MTC %#x CTC rem %#x\n",
1275 decoder->ctc_timestamp, decoder->last_mtc, ctc_rem); 1305 decoder->ctc_timestamp, decoder->last_mtc, ctc_rem);
1276} 1306}
@@ -1285,6 +1315,12 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder)
1285 1315
1286 mtc = decoder->packet.payload; 1316 mtc = decoder->packet.payload;
1287 1317
1318 if (decoder->mtc_shift > 8 && decoder->fixup_last_mtc) {
1319 decoder->fixup_last_mtc = false;
1320 intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift,
1321 &decoder->last_mtc);
1322 }
1323
1288 if (mtc > decoder->last_mtc) 1324 if (mtc > decoder->last_mtc)
1289 mtc_delta = mtc - decoder->last_mtc; 1325 mtc_delta = mtc - decoder->last_mtc;
1290 else 1326 else
@@ -1353,6 +1389,8 @@ static void intel_pt_calc_cyc_timestamp(struct intel_pt_decoder *decoder)
1353 timestamp, decoder->timestamp); 1389 timestamp, decoder->timestamp);
1354 else 1390 else
1355 decoder->timestamp = timestamp; 1391 decoder->timestamp = timestamp;
1392
1393 decoder->timestamp_insn_cnt = 0;
1356} 1394}
1357 1395
1358/* Walk PSB+ packets when already in sync. */ 1396/* Walk PSB+ packets when already in sync. */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 18e4519abef2..df85b9efd80f 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1745,9 +1745,8 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1745 int max_stack) 1745 int max_stack)
1746{ 1746{
1747 struct ip_callchain *chain = sample->callchain; 1747 struct ip_callchain *chain = sample->callchain;
1748 int chain_nr = min(max_stack, (int)chain->nr); 1748 int chain_nr = min(max_stack, (int)chain->nr), i;
1749 u8 cpumode = PERF_RECORD_MISC_USER; 1749 u8 cpumode = PERF_RECORD_MISC_USER;
1750 int i, j, err;
1751 u64 ip; 1750 u64 ip;
1752 1751
1753 for (i = 0; i < chain_nr; i++) { 1752 for (i = 0; i < chain_nr; i++) {
@@ -1758,7 +1757,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1758 /* LBR only affects the user callchain */ 1757 /* LBR only affects the user callchain */
1759 if (i != chain_nr) { 1758 if (i != chain_nr) {
1760 struct branch_stack *lbr_stack = sample->branch_stack; 1759 struct branch_stack *lbr_stack = sample->branch_stack;
1761 int lbr_nr = lbr_stack->nr; 1760 int lbr_nr = lbr_stack->nr, j;
1762 /* 1761 /*
1763 * LBR callstack can only get user call chain. 1762 * LBR callstack can only get user call chain.
1764 * The mix_chain_nr is kernel call chain 1763 * The mix_chain_nr is kernel call chain
@@ -1772,6 +1771,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1772 int mix_chain_nr = i + 1 + lbr_nr + 1; 1771 int mix_chain_nr = i + 1 + lbr_nr + 1;
1773 1772
1774 for (j = 0; j < mix_chain_nr; j++) { 1773 for (j = 0; j < mix_chain_nr; j++) {
1774 int err;
1775 if (callchain_param.order == ORDER_CALLEE) { 1775 if (callchain_param.order == ORDER_CALLEE) {
1776 if (j < i + 1) 1776 if (j < i + 1)
1777 ip = chain->ips[j]; 1777 ip = chain->ips[j];
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 33546c3ac1fe..4e778eae1510 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -924,6 +924,7 @@ config_term_avail(int term_type, struct parse_events_error *err)
924 case PARSE_EVENTS__TERM_TYPE_CONFIG1: 924 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
925 case PARSE_EVENTS__TERM_TYPE_CONFIG2: 925 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
926 case PARSE_EVENTS__TERM_TYPE_NAME: 926 case PARSE_EVENTS__TERM_TYPE_NAME:
927 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
927 return true; 928 return true;
928 default: 929 default:
929 if (!err) 930 if (!err)
@@ -1458,7 +1459,7 @@ comp_pmu(const void *p1, const void *p2)
1458 struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1; 1459 struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1;
1459 struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2; 1460 struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2;
1460 1461
1461 return strcmp(pmu1->symbol, pmu2->symbol); 1462 return strcasecmp(pmu1->symbol, pmu2->symbol);
1462} 1463}
1463 1464
1464static void perf_pmu__parse_cleanup(void) 1465static void perf_pmu__parse_cleanup(void)
@@ -2263,7 +2264,8 @@ out_enomem:
2263/* 2264/*
2264 * Print the help text for the event symbols: 2265 * Print the help text for the event symbols:
2265 */ 2266 */
2266void print_events(const char *event_glob, bool name_only) 2267void print_events(const char *event_glob, bool name_only, bool quiet_flag,
2268 bool long_desc)
2267{ 2269{
2268 print_symbol_events(event_glob, PERF_TYPE_HARDWARE, 2270 print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
2269 event_symbols_hw, PERF_COUNT_HW_MAX, name_only); 2271 event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
@@ -2273,7 +2275,7 @@ void print_events(const char *event_glob, bool name_only)
2273 2275
2274 print_hwcache_events(event_glob, name_only); 2276 print_hwcache_events(event_glob, name_only);
2275 2277
2276 print_pmu_events(event_glob, name_only); 2278 print_pmu_events(event_glob, name_only, quiet_flag, long_desc);
2277 2279
2278 if (event_glob != NULL) 2280 if (event_glob != NULL)
2279 return; 2281 return;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8d09a976fca8..da246a3ddb69 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -172,7 +172,8 @@ void parse_events_update_lists(struct list_head *list_event,
172void parse_events_evlist_error(struct parse_events_evlist *data, 172void parse_events_evlist_error(struct parse_events_evlist *data,
173 int idx, const char *str); 173 int idx, const char *str);
174 174
175void print_events(const char *event_glob, bool name_only); 175void print_events(const char *event_glob, bool name_only, bool quiet,
176 bool long_desc);
176 177
177struct event_symbol { 178struct event_symbol {
178 const char *symbol; 179 const char *symbol;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2babcdf62839..b1474dcadfa2 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -12,6 +12,9 @@
12#include "pmu.h" 12#include "pmu.h"
13#include "parse-events.h" 13#include "parse-events.h"
14#include "cpumap.h" 14#include "cpumap.h"
15#include "header.h"
16#include "pmu-events/pmu-events.h"
17#include "cache.h"
15 18
16struct perf_pmu_format { 19struct perf_pmu_format {
17 char *name; 20 char *name;
@@ -220,7 +223,8 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
220} 223}
221 224
222static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 225static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
223 char *desc __maybe_unused, char *val) 226 char *desc, char *val, char *long_desc,
227 char *topic)
224{ 228{
225 struct perf_pmu_alias *alias; 229 struct perf_pmu_alias *alias;
226 int ret; 230 int ret;
@@ -253,6 +257,11 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
253 perf_pmu__parse_snapshot(alias, dir, name); 257 perf_pmu__parse_snapshot(alias, dir, name);
254 } 258 }
255 259
260 alias->desc = desc ? strdup(desc) : NULL;
261 alias->long_desc = long_desc ? strdup(long_desc) :
262 desc ? strdup(desc) : NULL;
263 alias->topic = topic ? strdup(topic) : NULL;
264
256 list_add_tail(&alias->list, list); 265 list_add_tail(&alias->list, list);
257 266
258 return 0; 267 return 0;
@@ -269,7 +278,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
269 278
270 buf[ret] = 0; 279 buf[ret] = 0;
271 280
272 return __perf_pmu__new_alias(list, dir, name, NULL, buf); 281 return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL);
273} 282}
274 283
275static inline bool pmu_alias_info_file(char *name) 284static inline bool pmu_alias_info_file(char *name)
@@ -473,6 +482,68 @@ static struct cpu_map *pmu_cpumask(const char *name)
473 return cpus; 482 return cpus;
474} 483}
475 484
485/*
486 * Return the CPU id as a raw string.
487 *
488 * Each architecture should provide a more precise id string that
489 * can be use to match the architecture's "mapfile".
490 */
491char * __weak get_cpuid_str(void)
492{
493 return NULL;
494}
495
496/*
497 * From the pmu_events_map, find the table of PMU events that corresponds
498 * to the current running CPU. Then, add all PMU events from that table
499 * as aliases.
500 */
501static void pmu_add_cpu_aliases(struct list_head *head)
502{
503 int i;
504 struct pmu_events_map *map;
505 struct pmu_event *pe;
506 char *cpuid;
507
508 cpuid = getenv("PERF_CPUID");
509 if (cpuid)
510 cpuid = strdup(cpuid);
511 if (!cpuid)
512 cpuid = get_cpuid_str();
513 if (!cpuid)
514 return;
515
516 pr_debug("Using CPUID %s\n", cpuid);
517
518 i = 0;
519 while (1) {
520 map = &pmu_events_map[i++];
521 if (!map->table)
522 goto out;
523
524 if (!strcmp(map->cpuid, cpuid))
525 break;
526 }
527
528 /*
529 * Found a matching PMU events table. Create aliases
530 */
531 i = 0;
532 while (1) {
533 pe = &map->table[i++];
534 if (!pe->name)
535 break;
536
537 /* need type casts to override 'const' */
538 __perf_pmu__new_alias(head, NULL, (char *)pe->name,
539 (char *)pe->desc, (char *)pe->event,
540 (char *)pe->long_desc, (char *)pe->topic);
541 }
542
543out:
544 free(cpuid);
545}
546
476struct perf_event_attr * __weak 547struct perf_event_attr * __weak
477perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 548perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
478{ 549{
@@ -497,6 +568,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
497 if (pmu_aliases(name, &aliases)) 568 if (pmu_aliases(name, &aliases))
498 return NULL; 569 return NULL;
499 570
571 if (!strcmp(name, "cpu"))
572 pmu_add_cpu_aliases(&aliases);
573
500 if (pmu_type(name, &type)) 574 if (pmu_type(name, &type))
501 return NULL; 575 return NULL;
502 576
@@ -983,21 +1057,63 @@ static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
983 return buf; 1057 return buf;
984} 1058}
985 1059
986static int cmp_string(const void *a, const void *b) 1060struct sevent {
1061 char *name;
1062 char *desc;
1063 char *topic;
1064};
1065
1066static int cmp_sevent(const void *a, const void *b)
987{ 1067{
988 const char * const *as = a; 1068 const struct sevent *as = a;
989 const char * const *bs = b; 1069 const struct sevent *bs = b;
990 return strcmp(*as, *bs); 1070
1071 /* Put extra events last */
1072 if (!!as->desc != !!bs->desc)
1073 return !!as->desc - !!bs->desc;
1074 if (as->topic && bs->topic) {
1075 int n = strcmp(as->topic, bs->topic);
1076
1077 if (n)
1078 return n;
1079 }
1080 return strcmp(as->name, bs->name);
991} 1081}
992 1082
993void print_pmu_events(const char *event_glob, bool name_only) 1083static void wordwrap(char *s, int start, int max, int corr)
1084{
1085 int column = start;
1086 int n;
1087
1088 while (*s) {
1089 int wlen = strcspn(s, " \t");
1090
1091 if (column + wlen >= max && column > start) {
1092 printf("\n%*s", start, "");
1093 column = start + corr;
1094 }
1095 n = printf("%s%.*s", column > start ? " " : "", wlen, s);
1096 if (n <= 0)
1097 break;
1098 s += wlen;
1099 column += n;
1100 while (isspace(*s))
1101 s++;
1102 }
1103}
1104
1105void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
1106 bool long_desc)
994{ 1107{
995 struct perf_pmu *pmu; 1108 struct perf_pmu *pmu;
996 struct perf_pmu_alias *alias; 1109 struct perf_pmu_alias *alias;
997 char buf[1024]; 1110 char buf[1024];
998 int printed = 0; 1111 int printed = 0;
999 int len, j; 1112 int len, j;
1000 char **aliases; 1113 struct sevent *aliases;
1114 int numdesc = 0;
1115 int columns = pager_get_columns();
1116 char *topic = NULL;
1001 1117
1002 pmu = NULL; 1118 pmu = NULL;
1003 len = 0; 1119 len = 0;
@@ -1007,14 +1123,15 @@ void print_pmu_events(const char *event_glob, bool name_only)
1007 if (pmu->selectable) 1123 if (pmu->selectable)
1008 len++; 1124 len++;
1009 } 1125 }
1010 aliases = zalloc(sizeof(char *) * len); 1126 aliases = zalloc(sizeof(struct sevent) * len);
1011 if (!aliases) 1127 if (!aliases)
1012 goto out_enomem; 1128 goto out_enomem;
1013 pmu = NULL; 1129 pmu = NULL;
1014 j = 0; 1130 j = 0;
1015 while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1131 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
1016 list_for_each_entry(alias, &pmu->aliases, list) { 1132 list_for_each_entry(alias, &pmu->aliases, list) {
1017 char *name = format_alias(buf, sizeof(buf), pmu, alias); 1133 char *name = alias->desc ? alias->name :
1134 format_alias(buf, sizeof(buf), pmu, alias);
1018 bool is_cpu = !strcmp(pmu->name, "cpu"); 1135 bool is_cpu = !strcmp(pmu->name, "cpu");
1019 1136
1020 if (event_glob != NULL && 1137 if (event_glob != NULL &&
@@ -1023,12 +1140,21 @@ void print_pmu_events(const char *event_glob, bool name_only)
1023 event_glob)))) 1140 event_glob))))
1024 continue; 1141 continue;
1025 1142
1026 if (is_cpu && !name_only) 1143 if (is_cpu && !name_only && !alias->desc)
1027 name = format_alias_or(buf, sizeof(buf), pmu, alias); 1144 name = format_alias_or(buf, sizeof(buf), pmu, alias);
1028 1145
1029 aliases[j] = strdup(name); 1146 aliases[j].name = name;
1030 if (aliases[j] == NULL) 1147 if (is_cpu && !name_only && !alias->desc)
1148 aliases[j].name = format_alias_or(buf,
1149 sizeof(buf),
1150 pmu, alias);
1151 aliases[j].name = strdup(aliases[j].name);
1152 if (!aliases[j].name)
1031 goto out_enomem; 1153 goto out_enomem;
1154
1155 aliases[j].desc = long_desc ? alias->long_desc :
1156 alias->desc;
1157 aliases[j].topic = alias->topic;
1032 j++; 1158 j++;
1033 } 1159 }
1034 if (pmu->selectable && 1160 if (pmu->selectable &&
@@ -1036,25 +1162,39 @@ void print_pmu_events(const char *event_glob, bool name_only)
1036 char *s; 1162 char *s;
1037 if (asprintf(&s, "%s//", pmu->name) < 0) 1163 if (asprintf(&s, "%s//", pmu->name) < 0)
1038 goto out_enomem; 1164 goto out_enomem;
1039 aliases[j] = s; 1165 aliases[j].name = s;
1040 j++; 1166 j++;
1041 } 1167 }
1042 } 1168 }
1043 len = j; 1169 len = j;
1044 qsort(aliases, len, sizeof(char *), cmp_string); 1170 qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
1045 for (j = 0; j < len; j++) { 1171 for (j = 0; j < len; j++) {
1046 if (name_only) { 1172 if (name_only) {
1047 printf("%s ", aliases[j]); 1173 printf("%s ", aliases[j].name);
1048 continue; 1174 continue;
1049 } 1175 }
1050 printf(" %-50s [Kernel PMU event]\n", aliases[j]); 1176 if (aliases[j].desc && !quiet_flag) {
1177 if (numdesc++ == 0)
1178 printf("\n");
1179 if (aliases[j].topic && (!topic ||
1180 strcmp(topic, aliases[j].topic))) {
1181 printf("%s%s:\n", topic ? "\n" : "",
1182 aliases[j].topic);
1183 topic = aliases[j].topic;
1184 }
1185 printf(" %-50s\n", aliases[j].name);
1186 printf("%*s", 8, "[");
1187 wordwrap(aliases[j].desc, 8, columns, 0);
1188 printf("]\n");
1189 } else
1190 printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
1051 printed++; 1191 printed++;
1052 } 1192 }
1053 if (printed && pager_in_use()) 1193 if (printed && pager_in_use())
1054 printf("\n"); 1194 printf("\n");
1055out_free: 1195out_free:
1056 for (j = 0; j < len; j++) 1196 for (j = 0; j < len; j++)
1057 zfree(&aliases[j]); 1197 zfree(&aliases[j].name);
1058 zfree(&aliases); 1198 zfree(&aliases);
1059 return; 1199 return;
1060 1200
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 743422ad900b..25712034c815 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -40,6 +40,9 @@ struct perf_pmu_info {
40 40
41struct perf_pmu_alias { 41struct perf_pmu_alias {
42 char *name; 42 char *name;
43 char *desc;
44 char *long_desc;
45 char *topic;
43 struct list_head terms; /* HEAD struct parse_events_term -> list */ 46 struct list_head terms; /* HEAD struct parse_events_term -> list */
44 struct list_head list; /* ELEM */ 47 struct list_head list; /* ELEM */
45 char unit[UNIT_MAX_LEN+1]; 48 char unit[UNIT_MAX_LEN+1];
@@ -71,7 +74,8 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
71 74
72struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 75struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
73 76
74void print_pmu_events(const char *event_glob, bool name_only); 77void print_pmu_events(const char *event_glob, bool name_only, bool quiet,
78 bool long_desc);
75bool pmu_have_event(const char *pname, const char *name); 79bool pmu_have_event(const char *pname, const char *name);
76 80
77int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 81int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcfbef07b92d..d281ae2b54e8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -213,7 +213,7 @@ static int convert_exec_to_group(const char *exec, char **result)
213 goto out; 213 goto out;
214 } 214 }
215 215
216 for (ptr2 = ptr1; ptr2 != '\0'; ptr2++) { 216 for (ptr2 = ptr1; *ptr2 != '\0'; ptr2++) {
217 if (!isalnum(*ptr2) && *ptr2 != '_') { 217 if (!isalnum(*ptr2) && *ptr2 != '_') {
218 *ptr2 = '\0'; 218 *ptr2 = '\0';
219 break; 219 break;
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index b268a6648a5d..318424ea561d 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -66,9 +66,8 @@ static inline ssize_t strbuf_avail(const struct strbuf *sb) {
66int strbuf_grow(struct strbuf *buf, size_t); 66int strbuf_grow(struct strbuf *buf, size_t);
67 67
68static inline int strbuf_setlen(struct strbuf *sb, size_t len) { 68static inline int strbuf_setlen(struct strbuf *sb, size_t len) {
69 int ret;
70 if (!sb->alloc) { 69 if (!sb->alloc) {
71 ret = strbuf_grow(sb, 0); 70 int ret = strbuf_grow(sb, 0);
72 if (ret) 71 if (ret)
73 return ret; 72 return ret;
74 } 73 }
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 8b10a55410a2..f5af87f66663 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -14,13 +14,12 @@
14 14
15int thread__init_map_groups(struct thread *thread, struct machine *machine) 15int thread__init_map_groups(struct thread *thread, struct machine *machine)
16{ 16{
17 struct thread *leader;
18 pid_t pid = thread->pid_; 17 pid_t pid = thread->pid_;
19 18
20 if (pid == thread->tid || pid == -1) { 19 if (pid == thread->tid || pid == -1) {
21 thread->mg = map_groups__new(machine); 20 thread->mg = map_groups__new(machine);
22 } else { 21 } else {
23 leader = __machine__findnew_thread(machine, pid, pid); 22 struct thread *leader = __machine__findnew_thread(machine, pid, pid);
24 if (leader) { 23 if (leader) {
25 thread->mg = map_groups__get(leader->mg); 24 thread->mg = map_groups__get(leader->mg);
26 thread__put(leader); 25 thread__put(leader);
@@ -130,11 +129,10 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
130 bool exec) 129 bool exec)
131{ 130{
132 struct comm *new, *curr = thread__comm(thread); 131 struct comm *new, *curr = thread__comm(thread);
133 int err;
134 132
135 /* Override the default :tid entry */ 133 /* Override the default :tid entry */
136 if (!thread->comm_set) { 134 if (!thread->comm_set) {
137 err = comm__override(curr, str, timestamp, exec); 135 int err = comm__override(curr, str, timestamp, exec);
138 if (err) 136 if (err)
139 return err; 137 return err;
140 } else { 138 } else {
@@ -270,10 +268,9 @@ static int thread__clone_map_groups(struct thread *thread,
270 268
271int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) 269int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
272{ 270{
273 int err;
274
275 if (parent->comm_set) { 271 if (parent->comm_set) {
276 const char *comm = thread__comm_str(parent); 272 const char *comm = thread__comm_str(parent);
273 int err;
277 if (!comm) 274 if (!comm)
278 return -ENOMEM; 275 return -ENOMEM;
279 err = thread__set_comm(thread, comm, timestamp); 276 err = thread__set_comm(thread, comm, timestamp);
diff --git a/tools/spi/Makefile b/tools/spi/Makefile
index cd0db62e4d9d..3815b18ba070 100644
--- a/tools/spi/Makefile
+++ b/tools/spi/Makefile
@@ -1,3 +1,5 @@
1CC = $(CROSS_COMPILE)gcc
2
1all: spidev_test spidev_fdx 3all: spidev_test spidev_fdx
2 4
3clean: 5clean:
diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c
index 8a73d8185316..f046b77cfefe 100644
--- a/tools/spi/spidev_test.c
+++ b/tools/spi/spidev_test.c
@@ -19,6 +19,7 @@
19#include <getopt.h> 19#include <getopt.h>
20#include <fcntl.h> 20#include <fcntl.h>
21#include <sys/ioctl.h> 21#include <sys/ioctl.h>
22#include <linux/ioctl.h>
22#include <sys/stat.h> 23#include <sys/stat.h>
23#include <linux/types.h> 24#include <linux/types.h>
24#include <linux/spi/spidev.h> 25#include <linux/spi/spidev.h>
@@ -284,7 +285,7 @@ static void parse_opts(int argc, char *argv[])
284 285
285static void transfer_escaped_string(int fd, char *str) 286static void transfer_escaped_string(int fd, char *str)
286{ 287{
287 size_t size = strlen(str + 1); 288 size_t size = strlen(str);
288 uint8_t *tx; 289 uint8_t *tx;
289 uint8_t *rx; 290 uint8_t *rx;
290 291
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index ad6dd0543019..582db95127ed 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -13,6 +13,7 @@ ldflags-y += --wrap=__release_region
13ldflags-y += --wrap=devm_memremap_pages 13ldflags-y += --wrap=devm_memremap_pages
14ldflags-y += --wrap=insert_resource 14ldflags-y += --wrap=insert_resource
15ldflags-y += --wrap=remove_resource 15ldflags-y += --wrap=remove_resource
16ldflags-y += --wrap=acpi_evaluate_object
16 17
17DRIVERS := ../../../drivers 18DRIVERS := ../../../drivers
18NVDIMM_SRC := $(DRIVERS)/nvdimm 19NVDIMM_SRC := $(DRIVERS)/nvdimm
diff --git a/tools/testing/nvdimm/config_check.c b/tools/testing/nvdimm/config_check.c
index 878daf3429e8..7dc5a0af9b54 100644
--- a/tools/testing/nvdimm/config_check.c
+++ b/tools/testing/nvdimm/config_check.c
@@ -1,4 +1,3 @@
1#include <linux/kconfig.h>
2#include <linux/bug.h> 1#include <linux/bug.h>
3 2
4void check(void) 3void check(void)
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c
index c29f8dca9e67..3ccef732fce9 100644
--- a/tools/testing/nvdimm/test/iomap.c
+++ b/tools/testing/nvdimm/test/iomap.c
@@ -17,6 +17,7 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/types.h> 18#include <linux/types.h>
19#include <linux/pfn_t.h> 19#include <linux/pfn_t.h>
20#include <linux/acpi.h>
20#include <linux/io.h> 21#include <linux/io.h>
21#include <linux/mm.h> 22#include <linux/mm.h>
22#include "nfit_test.h" 23#include "nfit_test.h"
@@ -73,7 +74,7 @@ void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
73 74
74 if (nfit_res) 75 if (nfit_res)
75 return (void __iomem *) nfit_res->buf + offset 76 return (void __iomem *) nfit_res->buf + offset
76 - nfit_res->res->start; 77 - nfit_res->res.start;
77 return fallback_fn(offset, size); 78 return fallback_fn(offset, size);
78} 79}
79 80
@@ -84,7 +85,7 @@ void __iomem *__wrap_devm_ioremap_nocache(struct device *dev,
84 85
85 if (nfit_res) 86 if (nfit_res)
86 return (void __iomem *) nfit_res->buf + offset 87 return (void __iomem *) nfit_res->buf + offset
87 - nfit_res->res->start; 88 - nfit_res->res.start;
88 return devm_ioremap_nocache(dev, offset, size); 89 return devm_ioremap_nocache(dev, offset, size);
89} 90}
90EXPORT_SYMBOL(__wrap_devm_ioremap_nocache); 91EXPORT_SYMBOL(__wrap_devm_ioremap_nocache);
@@ -95,7 +96,7 @@ void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
95 struct nfit_test_resource *nfit_res = get_nfit_res(offset); 96 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
96 97
97 if (nfit_res) 98 if (nfit_res)
98 return nfit_res->buf + offset - nfit_res->res->start; 99 return nfit_res->buf + offset - nfit_res->res.start;
99 return devm_memremap(dev, offset, size, flags); 100 return devm_memremap(dev, offset, size, flags);
100} 101}
101EXPORT_SYMBOL(__wrap_devm_memremap); 102EXPORT_SYMBOL(__wrap_devm_memremap);
@@ -107,7 +108,7 @@ void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res,
107 struct nfit_test_resource *nfit_res = get_nfit_res(offset); 108 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
108 109
109 if (nfit_res) 110 if (nfit_res)
110 return nfit_res->buf + offset - nfit_res->res->start; 111 return nfit_res->buf + offset - nfit_res->res.start;
111 return devm_memremap_pages(dev, res, ref, altmap); 112 return devm_memremap_pages(dev, res, ref, altmap);
112} 113}
113EXPORT_SYMBOL(__wrap_devm_memremap_pages); 114EXPORT_SYMBOL(__wrap_devm_memremap_pages);
@@ -128,7 +129,7 @@ void *__wrap_memremap(resource_size_t offset, size_t size,
128 struct nfit_test_resource *nfit_res = get_nfit_res(offset); 129 struct nfit_test_resource *nfit_res = get_nfit_res(offset);
129 130
130 if (nfit_res) 131 if (nfit_res)
131 return nfit_res->buf + offset - nfit_res->res->start; 132 return nfit_res->buf + offset - nfit_res->res.start;
132 return memremap(offset, size, flags); 133 return memremap(offset, size, flags);
133} 134}
134EXPORT_SYMBOL(__wrap_memremap); 135EXPORT_SYMBOL(__wrap_memremap);
@@ -174,6 +175,63 @@ void __wrap_memunmap(void *addr)
174} 175}
175EXPORT_SYMBOL(__wrap_memunmap); 176EXPORT_SYMBOL(__wrap_memunmap);
176 177
178static bool nfit_test_release_region(struct device *dev,
179 struct resource *parent, resource_size_t start,
180 resource_size_t n);
181
182static void nfit_devres_release(struct device *dev, void *data)
183{
184 struct resource *res = *((struct resource **) data);
185
186 WARN_ON(!nfit_test_release_region(NULL, &iomem_resource, res->start,
187 resource_size(res)));
188}
189
190static int match(struct device *dev, void *__res, void *match_data)
191{
192 struct resource *res = *((struct resource **) __res);
193 resource_size_t start = *((resource_size_t *) match_data);
194
195 return res->start == start;
196}
197
198static bool nfit_test_release_region(struct device *dev,
199 struct resource *parent, resource_size_t start,
200 resource_size_t n)
201{
202 if (parent == &iomem_resource) {
203 struct nfit_test_resource *nfit_res = get_nfit_res(start);
204
205 if (nfit_res) {
206 struct nfit_test_request *req;
207 struct resource *res = NULL;
208
209 if (dev) {
210 devres_release(dev, nfit_devres_release, match,
211 &start);
212 return true;
213 }
214
215 spin_lock(&nfit_res->lock);
216 list_for_each_entry(req, &nfit_res->requests, list)
217 if (req->res.start == start) {
218 res = &req->res;
219 list_del(&req->list);
220 break;
221 }
222 spin_unlock(&nfit_res->lock);
223
224 WARN(!res || resource_size(res) != n,
225 "%s: start: %llx n: %llx mismatch: %pr\n",
226 __func__, start, n, res);
227 if (res)
228 kfree(req);
229 return true;
230 }
231 }
232 return false;
233}
234
177static struct resource *nfit_test_request_region(struct device *dev, 235static struct resource *nfit_test_request_region(struct device *dev,
178 struct resource *parent, resource_size_t start, 236 struct resource *parent, resource_size_t start,
179 resource_size_t n, const char *name, int flags) 237 resource_size_t n, const char *name, int flags)
@@ -183,21 +241,57 @@ static struct resource *nfit_test_request_region(struct device *dev,
183 if (parent == &iomem_resource) { 241 if (parent == &iomem_resource) {
184 nfit_res = get_nfit_res(start); 242 nfit_res = get_nfit_res(start);
185 if (nfit_res) { 243 if (nfit_res) {
186 struct resource *res = nfit_res->res + 1; 244 struct nfit_test_request *req;
245 struct resource *res = NULL;
187 246
188 if (start + n > nfit_res->res->start 247 if (start + n > nfit_res->res.start
189 + resource_size(nfit_res->res)) { 248 + resource_size(&nfit_res->res)) {
190 pr_debug("%s: start: %llx n: %llx overflow: %pr\n", 249 pr_debug("%s: start: %llx n: %llx overflow: %pr\n",
191 __func__, start, n, 250 __func__, start, n,
192 nfit_res->res); 251 &nfit_res->res);
193 return NULL; 252 return NULL;
194 } 253 }
195 254
255 spin_lock(&nfit_res->lock);
256 list_for_each_entry(req, &nfit_res->requests, list)
257 if (start == req->res.start) {
258 res = &req->res;
259 break;
260 }
261 spin_unlock(&nfit_res->lock);
262
263 if (res) {
264 WARN(1, "%pr already busy\n", res);
265 return NULL;
266 }
267
268 req = kzalloc(sizeof(*req), GFP_KERNEL);
269 if (!req)
270 return NULL;
271 INIT_LIST_HEAD(&req->list);
272 res = &req->res;
273
196 res->start = start; 274 res->start = start;
197 res->end = start + n - 1; 275 res->end = start + n - 1;
198 res->name = name; 276 res->name = name;
199 res->flags = resource_type(parent); 277 res->flags = resource_type(parent);
200 res->flags |= IORESOURCE_BUSY | flags; 278 res->flags |= IORESOURCE_BUSY | flags;
279 spin_lock(&nfit_res->lock);
280 list_add(&req->list, &nfit_res->requests);
281 spin_unlock(&nfit_res->lock);
282
283 if (dev) {
284 struct resource **d;
285
286 d = devres_alloc(nfit_devres_release,
287 sizeof(struct resource *),
288 GFP_KERNEL);
289 if (!d)
290 return NULL;
291 *d = res;
292 devres_add(dev, d);
293 }
294
201 pr_debug("%s: %pr\n", __func__, res); 295 pr_debug("%s: %pr\n", __func__, res);
202 return res; 296 return res;
203 } 297 }
@@ -241,29 +335,10 @@ struct resource *__wrap___devm_request_region(struct device *dev,
241} 335}
242EXPORT_SYMBOL(__wrap___devm_request_region); 336EXPORT_SYMBOL(__wrap___devm_request_region);
243 337
244static bool nfit_test_release_region(struct resource *parent,
245 resource_size_t start, resource_size_t n)
246{
247 if (parent == &iomem_resource) {
248 struct nfit_test_resource *nfit_res = get_nfit_res(start);
249 if (nfit_res) {
250 struct resource *res = nfit_res->res + 1;
251
252 if (start != res->start || resource_size(res) != n)
253 pr_info("%s: start: %llx n: %llx mismatch: %pr\n",
254 __func__, start, n, res);
255 else
256 memset(res, 0, sizeof(*res));
257 return true;
258 }
259 }
260 return false;
261}
262
263void __wrap___release_region(struct resource *parent, resource_size_t start, 338void __wrap___release_region(struct resource *parent, resource_size_t start,
264 resource_size_t n) 339 resource_size_t n)
265{ 340{
266 if (!nfit_test_release_region(parent, start, n)) 341 if (!nfit_test_release_region(NULL, parent, start, n))
267 __release_region(parent, start, n); 342 __release_region(parent, start, n);
268} 343}
269EXPORT_SYMBOL(__wrap___release_region); 344EXPORT_SYMBOL(__wrap___release_region);
@@ -271,9 +346,25 @@ EXPORT_SYMBOL(__wrap___release_region);
271void __wrap___devm_release_region(struct device *dev, struct resource *parent, 346void __wrap___devm_release_region(struct device *dev, struct resource *parent,
272 resource_size_t start, resource_size_t n) 347 resource_size_t start, resource_size_t n)
273{ 348{
274 if (!nfit_test_release_region(parent, start, n)) 349 if (!nfit_test_release_region(dev, parent, start, n))
275 __devm_release_region(dev, parent, start, n); 350 __devm_release_region(dev, parent, start, n);
276} 351}
277EXPORT_SYMBOL(__wrap___devm_release_region); 352EXPORT_SYMBOL(__wrap___devm_release_region);
278 353
354acpi_status __wrap_acpi_evaluate_object(acpi_handle handle, acpi_string path,
355 struct acpi_object_list *p, struct acpi_buffer *buf)
356{
357 struct nfit_test_resource *nfit_res = get_nfit_res((long) handle);
358 union acpi_object **obj;
359
360 if (!nfit_res || strcmp(path, "_FIT") || !buf)
361 return acpi_evaluate_object(handle, path, p, buf);
362
363 obj = nfit_res->buf;
364 buf->length = sizeof(union acpi_object);
365 buf->pointer = *obj;
366 return AE_OK;
367}
368EXPORT_SYMBOL(__wrap_acpi_evaluate_object);
369
279MODULE_LICENSE("GPL v2"); 370MODULE_LICENSE("GPL v2");
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index f64c57bf1d4b..c9a6458cb63e 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -132,6 +132,8 @@ static u32 handle[NUM_DCR] = {
132 [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), 132 [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),
133}; 133};
134 134
135static unsigned long dimm_fail_cmd_flags[NUM_DCR];
136
135struct nfit_test { 137struct nfit_test {
136 struct acpi_nfit_desc acpi_desc; 138 struct acpi_nfit_desc acpi_desc;
137 struct platform_device pdev; 139 struct platform_device pdev;
@@ -154,11 +156,14 @@ struct nfit_test {
154 int (*alloc)(struct nfit_test *t); 156 int (*alloc)(struct nfit_test *t);
155 void (*setup)(struct nfit_test *t); 157 void (*setup)(struct nfit_test *t);
156 int setup_hotplug; 158 int setup_hotplug;
159 union acpi_object **_fit;
160 dma_addr_t _fit_dma;
157 struct ars_state { 161 struct ars_state {
158 struct nd_cmd_ars_status *ars_status; 162 struct nd_cmd_ars_status *ars_status;
159 unsigned long deadline; 163 unsigned long deadline;
160 spinlock_t lock; 164 spinlock_t lock;
161 } ars_state; 165 } ars_state;
166 struct device *dimm_dev[NUM_DCR];
162}; 167};
163 168
164static struct nfit_test *to_nfit_test(struct device *dev) 169static struct nfit_test *to_nfit_test(struct device *dev)
@@ -411,6 +416,9 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
411 if (i >= ARRAY_SIZE(handle)) 416 if (i >= ARRAY_SIZE(handle))
412 return -ENXIO; 417 return -ENXIO;
413 418
419 if ((1 << func) & dimm_fail_cmd_flags[i])
420 return -EIO;
421
414 switch (func) { 422 switch (func) {
415 case ND_CMD_GET_CONFIG_SIZE: 423 case ND_CMD_GET_CONFIG_SIZE:
416 rc = nfit_test_cmd_get_config_size(buf, buf_len); 424 rc = nfit_test_cmd_get_config_size(buf, buf_len);
@@ -428,6 +436,9 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
428 break; 436 break;
429 case ND_CMD_SMART_THRESHOLD: 437 case ND_CMD_SMART_THRESHOLD:
430 rc = nfit_test_cmd_smart_threshold(buf, buf_len); 438 rc = nfit_test_cmd_smart_threshold(buf, buf_len);
439 device_lock(&t->pdev.dev);
440 __acpi_nvdimm_notify(t->dimm_dev[i], 0x81);
441 device_unlock(&t->pdev.dev);
431 break; 442 break;
432 default: 443 default:
433 return -ENOTTY; 444 return -ENOTTY;
@@ -467,14 +478,12 @@ static struct nfit_test *instances[NUM_NFITS];
467static void release_nfit_res(void *data) 478static void release_nfit_res(void *data)
468{ 479{
469 struct nfit_test_resource *nfit_res = data; 480 struct nfit_test_resource *nfit_res = data;
470 struct resource *res = nfit_res->res;
471 481
472 spin_lock(&nfit_test_lock); 482 spin_lock(&nfit_test_lock);
473 list_del(&nfit_res->list); 483 list_del(&nfit_res->list);
474 spin_unlock(&nfit_test_lock); 484 spin_unlock(&nfit_test_lock);
475 485
476 vfree(nfit_res->buf); 486 vfree(nfit_res->buf);
477 kfree(res);
478 kfree(nfit_res); 487 kfree(nfit_res);
479} 488}
480 489
@@ -482,12 +491,11 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
482 void *buf) 491 void *buf)
483{ 492{
484 struct device *dev = &t->pdev.dev; 493 struct device *dev = &t->pdev.dev;
485 struct resource *res = kzalloc(sizeof(*res) * 2, GFP_KERNEL);
486 struct nfit_test_resource *nfit_res = kzalloc(sizeof(*nfit_res), 494 struct nfit_test_resource *nfit_res = kzalloc(sizeof(*nfit_res),
487 GFP_KERNEL); 495 GFP_KERNEL);
488 int rc; 496 int rc;
489 497
490 if (!res || !buf || !nfit_res) 498 if (!buf || !nfit_res)
491 goto err; 499 goto err;
492 rc = devm_add_action(dev, release_nfit_res, nfit_res); 500 rc = devm_add_action(dev, release_nfit_res, nfit_res);
493 if (rc) 501 if (rc)
@@ -496,10 +504,11 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
496 memset(buf, 0, size); 504 memset(buf, 0, size);
497 nfit_res->dev = dev; 505 nfit_res->dev = dev;
498 nfit_res->buf = buf; 506 nfit_res->buf = buf;
499 nfit_res->res = res; 507 nfit_res->res.start = *dma;
500 res->start = *dma; 508 nfit_res->res.end = *dma + size - 1;
501 res->end = *dma + size - 1; 509 nfit_res->res.name = "NFIT";
502 res->name = "NFIT"; 510 spin_lock_init(&nfit_res->lock);
511 INIT_LIST_HEAD(&nfit_res->requests);
503 spin_lock(&nfit_test_lock); 512 spin_lock(&nfit_test_lock);
504 list_add(&nfit_res->list, &t->resources); 513 list_add(&nfit_res->list, &t->resources);
505 spin_unlock(&nfit_test_lock); 514 spin_unlock(&nfit_test_lock);
@@ -508,7 +517,6 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma,
508 err: 517 err:
509 if (buf) 518 if (buf)
510 vfree(buf); 519 vfree(buf);
511 kfree(res);
512 kfree(nfit_res); 520 kfree(nfit_res);
513 return NULL; 521 return NULL;
514} 522}
@@ -533,13 +541,13 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
533 continue; 541 continue;
534 spin_lock(&nfit_test_lock); 542 spin_lock(&nfit_test_lock);
535 list_for_each_entry(n, &t->resources, list) { 543 list_for_each_entry(n, &t->resources, list) {
536 if (addr >= n->res->start && (addr < n->res->start 544 if (addr >= n->res.start && (addr < n->res.start
537 + resource_size(n->res))) { 545 + resource_size(&n->res))) {
538 nfit_res = n; 546 nfit_res = n;
539 break; 547 break;
540 } else if (addr >= (unsigned long) n->buf 548 } else if (addr >= (unsigned long) n->buf
541 && (addr < (unsigned long) n->buf 549 && (addr < (unsigned long) n->buf
542 + resource_size(n->res))) { 550 + resource_size(&n->res))) {
543 nfit_res = n; 551 nfit_res = n;
544 break; 552 break;
545 } 553 }
@@ -564,6 +572,86 @@ static int ars_state_init(struct device *dev, struct ars_state *ars_state)
564 return 0; 572 return 0;
565} 573}
566 574
575static void put_dimms(void *data)
576{
577 struct device **dimm_dev = data;
578 int i;
579
580 for (i = 0; i < NUM_DCR; i++)
581 if (dimm_dev[i])
582 device_unregister(dimm_dev[i]);
583}
584
585static struct class *nfit_test_dimm;
586
587static int dimm_name_to_id(struct device *dev)
588{
589 int dimm;
590
591 if (sscanf(dev_name(dev), "test_dimm%d", &dimm) != 1
592 || dimm >= NUM_DCR || dimm < 0)
593 return -ENXIO;
594 return dimm;
595}
596
597
598static ssize_t handle_show(struct device *dev, struct device_attribute *attr,
599 char *buf)
600{
601 int dimm = dimm_name_to_id(dev);
602
603 if (dimm < 0)
604 return dimm;
605
606 return sprintf(buf, "%#x", handle[dimm]);
607}
608DEVICE_ATTR_RO(handle);
609
610static ssize_t fail_cmd_show(struct device *dev, struct device_attribute *attr,
611 char *buf)
612{
613 int dimm = dimm_name_to_id(dev);
614
615 if (dimm < 0)
616 return dimm;
617
618 return sprintf(buf, "%#lx\n", dimm_fail_cmd_flags[dimm]);
619}
620
621static ssize_t fail_cmd_store(struct device *dev, struct device_attribute *attr,
622 const char *buf, size_t size)
623{
624 int dimm = dimm_name_to_id(dev);
625 unsigned long val;
626 ssize_t rc;
627
628 if (dimm < 0)
629 return dimm;
630
631 rc = kstrtol(buf, 0, &val);
632 if (rc)
633 return rc;
634
635 dimm_fail_cmd_flags[dimm] = val;
636 return size;
637}
638static DEVICE_ATTR_RW(fail_cmd);
639
640static struct attribute *nfit_test_dimm_attributes[] = {
641 &dev_attr_fail_cmd.attr,
642 &dev_attr_handle.attr,
643 NULL,
644};
645
646static struct attribute_group nfit_test_dimm_attribute_group = {
647 .attrs = nfit_test_dimm_attributes,
648};
649
650static const struct attribute_group *nfit_test_dimm_attribute_groups[] = {
651 &nfit_test_dimm_attribute_group,
652 NULL,
653};
654
567static int nfit_test0_alloc(struct nfit_test *t) 655static int nfit_test0_alloc(struct nfit_test *t)
568{ 656{
569 size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA 657 size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA
@@ -616,6 +704,21 @@ static int nfit_test0_alloc(struct nfit_test *t)
616 return -ENOMEM; 704 return -ENOMEM;
617 } 705 }
618 706
707 t->_fit = test_alloc(t, sizeof(union acpi_object **), &t->_fit_dma);
708 if (!t->_fit)
709 return -ENOMEM;
710
711 if (devm_add_action_or_reset(&t->pdev.dev, put_dimms, t->dimm_dev))
712 return -ENOMEM;
713 for (i = 0; i < NUM_DCR; i++) {
714 t->dimm_dev[i] = device_create_with_groups(nfit_test_dimm,
715 &t->pdev.dev, 0, NULL,
716 nfit_test_dimm_attribute_groups,
717 "test_dimm%d", i);
718 if (!t->dimm_dev[i])
719 return -ENOMEM;
720 }
721
619 return ars_state_init(&t->pdev.dev, &t->ars_state); 722 return ars_state_init(&t->pdev.dev, &t->ars_state);
620} 723}
621 724
@@ -1409,6 +1512,8 @@ static int nfit_test_probe(struct platform_device *pdev)
1409 struct acpi_nfit_desc *acpi_desc; 1512 struct acpi_nfit_desc *acpi_desc;
1410 struct device *dev = &pdev->dev; 1513 struct device *dev = &pdev->dev;
1411 struct nfit_test *nfit_test; 1514 struct nfit_test *nfit_test;
1515 struct nfit_mem *nfit_mem;
1516 union acpi_object *obj;
1412 int rc; 1517 int rc;
1413 1518
1414 nfit_test = to_nfit_test(&pdev->dev); 1519 nfit_test = to_nfit_test(&pdev->dev);
@@ -1476,14 +1581,30 @@ static int nfit_test_probe(struct platform_device *pdev)
1476 if (nfit_test->setup != nfit_test0_setup) 1581 if (nfit_test->setup != nfit_test0_setup)
1477 return 0; 1582 return 0;
1478 1583
1479 flush_work(&acpi_desc->work);
1480 nfit_test->setup_hotplug = 1; 1584 nfit_test->setup_hotplug = 1;
1481 nfit_test->setup(nfit_test); 1585 nfit_test->setup(nfit_test);
1482 1586
1483 rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf, 1587 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
1484 nfit_test->nfit_size); 1588 if (!obj)
1485 if (rc) 1589 return -ENOMEM;
1486 return rc; 1590 obj->type = ACPI_TYPE_BUFFER;
1591 obj->buffer.length = nfit_test->nfit_size;
1592 obj->buffer.pointer = nfit_test->nfit_buf;
1593 *(nfit_test->_fit) = obj;
1594 __acpi_nfit_notify(&pdev->dev, nfit_test, 0x80);
1595
1596 /* associate dimm devices with nfit_mem data for notification testing */
1597 mutex_lock(&acpi_desc->init_mutex);
1598 list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) {
1599 u32 nfit_handle = __to_nfit_memdev(nfit_mem)->device_handle;
1600 int i;
1601
1602 for (i = 0; i < NUM_DCR; i++)
1603 if (nfit_handle == handle[i])
1604 dev_set_drvdata(nfit_test->dimm_dev[i],
1605 nfit_mem);
1606 }
1607 mutex_unlock(&acpi_desc->init_mutex);
1487 1608
1488 return 0; 1609 return 0;
1489} 1610}
@@ -1518,6 +1639,10 @@ static __init int nfit_test_init(void)
1518{ 1639{
1519 int rc, i; 1640 int rc, i;
1520 1641
1642 nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm");
1643 if (IS_ERR(nfit_test_dimm))
1644 return PTR_ERR(nfit_test_dimm);
1645
1521 nfit_test_setup(nfit_test_lookup); 1646 nfit_test_setup(nfit_test_lookup);
1522 1647
1523 for (i = 0; i < NUM_NFITS; i++) { 1648 for (i = 0; i < NUM_NFITS; i++) {
@@ -1584,6 +1709,7 @@ static __exit void nfit_test_exit(void)
1584 for (i = 0; i < NUM_NFITS; i++) 1709 for (i = 0; i < NUM_NFITS; i++)
1585 platform_device_unregister(&instances[i]->pdev); 1710 platform_device_unregister(&instances[i]->pdev);
1586 nfit_test_teardown(); 1711 nfit_test_teardown();
1712 class_destroy(nfit_test_dimm);
1587} 1713}
1588 1714
1589module_init(nfit_test_init); 1715module_init(nfit_test_init);
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h
index 9f18e2a4a862..c281dd2e5e2d 100644
--- a/tools/testing/nvdimm/test/nfit_test.h
+++ b/tools/testing/nvdimm/test/nfit_test.h
@@ -13,11 +13,21 @@
13#ifndef __NFIT_TEST_H__ 13#ifndef __NFIT_TEST_H__
14#define __NFIT_TEST_H__ 14#define __NFIT_TEST_H__
15#include <linux/list.h> 15#include <linux/list.h>
16#include <linux/ioport.h>
17#include <linux/spinlock_types.h>
18
19struct nfit_test_request {
20 struct list_head list;
21 struct resource res;
22};
16 23
17struct nfit_test_resource { 24struct nfit_test_resource {
25 struct list_head requests;
18 struct list_head list; 26 struct list_head list;
19 struct resource *res; 27 struct resource res;
20 struct device *dev; 28 struct device *dev;
29 spinlock_t lock;
30 int req_count;
21 void *buf; 31 void *buf;
22}; 32};
23 33
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile
index 9d0919ed52a4..f2e07f2fd4b4 100644
--- a/tools/testing/radix-tree/Makefile
+++ b/tools/testing/radix-tree/Makefile
@@ -3,7 +3,8 @@ CFLAGS += -I. -g -O2 -Wall -D_LGPL_SOURCE
3LDFLAGS += -lpthread -lurcu 3LDFLAGS += -lpthread -lurcu
4TARGETS = main 4TARGETS = main
5OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \ 5OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \
6 regression1.o regression2.o regression3.o multiorder.o 6 regression1.o regression2.o regression3.o multiorder.o \
7 iteration_check.o
7 8
8targets: $(TARGETS) 9targets: $(TARGETS)
9 10
diff --git a/tools/testing/radix-tree/iteration_check.c b/tools/testing/radix-tree/iteration_check.c
new file mode 100644
index 000000000000..9adb8e7415a6
--- /dev/null
+++ b/tools/testing/radix-tree/iteration_check.c
@@ -0,0 +1,180 @@
1/*
2 * iteration_check.c: test races having to do with radix tree iteration
3 * Copyright (c) 2016 Intel Corporation
4 * Author: Ross Zwisler <ross.zwisler@linux.intel.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15#include <linux/radix-tree.h>
16#include <pthread.h>
17#include "test.h"
18
19#define NUM_THREADS 4
20#define TAG 0
21static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER;
22static pthread_t threads[NUM_THREADS];
23RADIX_TREE(tree, GFP_KERNEL);
24bool test_complete;
25
26/* relentlessly fill the tree with tagged entries */
27static void *add_entries_fn(void *arg)
28{
29 int pgoff;
30
31 while (!test_complete) {
32 for (pgoff = 0; pgoff < 100; pgoff++) {
33 pthread_mutex_lock(&tree_lock);
34 if (item_insert(&tree, pgoff) == 0)
35 item_tag_set(&tree, pgoff, TAG);
36 pthread_mutex_unlock(&tree_lock);
37 }
38 }
39
40 return NULL;
41}
42
43/*
44 * Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find
45 * things that have been removed and randomly resetting our iteration to the
46 * next chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and
47 * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a
48 * NULL 'slot' variable.
49 */
50static void *tagged_iteration_fn(void *arg)
51{
52 struct radix_tree_iter iter;
53 void **slot;
54
55 while (!test_complete) {
56 rcu_read_lock();
57 radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) {
58 void *entry;
59 int i;
60
61 /* busy wait to let removals happen */
62 for (i = 0; i < 1000000; i++)
63 ;
64
65 entry = radix_tree_deref_slot(slot);
66 if (unlikely(!entry))
67 continue;
68
69 if (radix_tree_deref_retry(entry)) {
70 slot = radix_tree_iter_retry(&iter);
71 continue;
72 }
73
74 if (rand() % 50 == 0)
75 slot = radix_tree_iter_next(&iter);
76 }
77 rcu_read_unlock();
78 }
79
80 return NULL;
81}
82
83/*
84 * Iterate over the entries, doing a radix_tree_iter_retry() as we find things
85 * that have been removed and randomly resetting our iteration to the next
86 * chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and
87 * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a
88 * NULL 'slot' variable.
89 */
90static void *untagged_iteration_fn(void *arg)
91{
92 struct radix_tree_iter iter;
93 void **slot;
94
95 while (!test_complete) {
96 rcu_read_lock();
97 radix_tree_for_each_slot(slot, &tree, &iter, 0) {
98 void *entry;
99 int i;
100
101 /* busy wait to let removals happen */
102 for (i = 0; i < 1000000; i++)
103 ;
104
105 entry = radix_tree_deref_slot(slot);
106 if (unlikely(!entry))
107 continue;
108
109 if (radix_tree_deref_retry(entry)) {
110 slot = radix_tree_iter_retry(&iter);
111 continue;
112 }
113
114 if (rand() % 50 == 0)
115 slot = radix_tree_iter_next(&iter);
116 }
117 rcu_read_unlock();
118 }
119
120 return NULL;
121}
122
123/*
124 * Randomly remove entries to help induce radix_tree_iter_retry() calls in the
125 * two iteration functions.
126 */
127static void *remove_entries_fn(void *arg)
128{
129 while (!test_complete) {
130 int pgoff;
131
132 pgoff = rand() % 100;
133
134 pthread_mutex_lock(&tree_lock);
135 item_delete(&tree, pgoff);
136 pthread_mutex_unlock(&tree_lock);
137 }
138
139 return NULL;
140}
141
142/* This is a unit test for a bug found by the syzkaller tester */
143void iteration_test(void)
144{
145 int i;
146
147 printf("Running iteration tests for 10 seconds\n");
148
149 srand(time(0));
150 test_complete = false;
151
152 if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) {
153 perror("pthread_create");
154 exit(1);
155 }
156 if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) {
157 perror("pthread_create");
158 exit(1);
159 }
160 if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) {
161 perror("pthread_create");
162 exit(1);
163 }
164 if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) {
165 perror("pthread_create");
166 exit(1);
167 }
168
169 sleep(10);
170 test_complete = true;
171
172 for (i = 0; i < NUM_THREADS; i++) {
173 if (pthread_join(threads[i], NULL)) {
174 perror("pthread_join");
175 exit(1);
176 }
177 }
178
179 item_kill_tree(&tree);
180}
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c
index b7619ff3b552..daa9010693e8 100644
--- a/tools/testing/radix-tree/main.c
+++ b/tools/testing/radix-tree/main.c
@@ -332,6 +332,7 @@ int main(int argc, char **argv)
332 regression1_test(); 332 regression1_test();
333 regression2_test(); 333 regression2_test();
334 regression3_test(); 334 regression3_test();
335 iteration_test();
335 single_thread_tests(long_run); 336 single_thread_tests(long_run);
336 337
337 sleep(1); 338 sleep(1);
diff --git a/tools/testing/radix-tree/regression1.c b/tools/testing/radix-tree/regression1.c
index 2d03a63bb79c..0d6813a61b37 100644
--- a/tools/testing/radix-tree/regression1.c
+++ b/tools/testing/radix-tree/regression1.c
@@ -43,7 +43,7 @@
43#include "regression.h" 43#include "regression.h"
44 44
45static RADIX_TREE(mt_tree, GFP_KERNEL); 45static RADIX_TREE(mt_tree, GFP_KERNEL);
46static pthread_mutex_t mt_lock; 46static pthread_mutex_t mt_lock = PTHREAD_MUTEX_INITIALIZER;
47 47
48struct page { 48struct page {
49 pthread_mutex_t lock; 49 pthread_mutex_t lock;
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h
index e85131369723..217fb2403f09 100644
--- a/tools/testing/radix-tree/test.h
+++ b/tools/testing/radix-tree/test.h
@@ -27,6 +27,7 @@ void item_kill_tree(struct radix_tree_root *root);
27 27
28void tag_check(void); 28void tag_check(void);
29void multiorder_checks(void); 29void multiorder_checks(void);
30void iteration_test(void);
30 31
31struct item * 32struct item *
32item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); 33item_tag_set(struct radix_tree_root *root, unsigned long index, int tag);
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index ff9e5f20a5a7..f770dba2a6f6 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -15,6 +15,7 @@ TARGETS += memory-hotplug
15TARGETS += mount 15TARGETS += mount
16TARGETS += mqueue 16TARGETS += mqueue
17TARGETS += net 17TARGETS += net
18TARGETS += nsfs
18TARGETS += powerpc 19TARGETS += powerpc
19TARGETS += pstore 20TARGETS += pstore
20TARGETS += ptrace 21TARGETS += ptrace
diff --git a/tools/testing/selftests/filesystems/.gitignore b/tools/testing/selftests/filesystems/.gitignore
new file mode 100644
index 000000000000..31d6e426b6d4
--- /dev/null
+++ b/tools/testing/selftests/filesystems/.gitignore
@@ -0,0 +1 @@
dnotify_test
diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile
new file mode 100644
index 000000000000..0ab11307b414
--- /dev/null
+++ b/tools/testing/selftests/filesystems/Makefile
@@ -0,0 +1,7 @@
1TEST_PROGS := dnotify_test
2all: $(TEST_PROGS)
3
4include ../lib.mk
5
6clean:
7 rm -fr $(TEST_PROGS)
diff --git a/tools/testing/selftests/filesystems/dnotify_test.c b/tools/testing/selftests/filesystems/dnotify_test.c
new file mode 100644
index 000000000000..8b37b4a1e18d
--- /dev/null
+++ b/tools/testing/selftests/filesystems/dnotify_test.c
@@ -0,0 +1,34 @@
1#define _GNU_SOURCE /* needed to get the defines */
2#include <fcntl.h> /* in glibc 2.2 this has the needed
3 values defined */
4#include <signal.h>
5#include <stdio.h>
6#include <unistd.h>
7
8static volatile int event_fd;
9
10static void handler(int sig, siginfo_t *si, void *data)
11{
12 event_fd = si->si_fd;
13}
14
15int main(void)
16{
17 struct sigaction act;
18 int fd;
19
20 act.sa_sigaction = handler;
21 sigemptyset(&act.sa_mask);
22 act.sa_flags = SA_SIGINFO;
23 sigaction(SIGRTMIN + 1, &act, NULL);
24
25 fd = open(".", O_RDONLY);
26 fcntl(fd, F_SETSIG, SIGRTMIN + 1);
27 fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
28 /* we will now be notified if any of the files
29 in "." is modified or new files are created */
30 while (1) {
31 pause();
32 printf("Got event on fd=%d\n", event_fd);
33 }
34}
diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh
index e87dbe2a0b0d..7ff002eed624 100755
--- a/tools/testing/selftests/futex/functional/run.sh
+++ b/tools/testing/selftests/futex/functional/run.sh
@@ -24,7 +24,7 @@
24 24
25# Test for a color capable console 25# Test for a color capable console
26if [ -z "$USE_COLOR" ]; then 26if [ -z "$USE_COLOR" ]; then
27 tput setf 7 27 tput setf 7 || tput setaf 7
28 if [ $? -eq 0 ]; then 28 if [ $? -eq 0 ]; then
29 USE_COLOR=1 29 USE_COLOR=1
30 tput sgr0 30 tput sgr0
diff --git a/tools/testing/selftests/futex/run.sh b/tools/testing/selftests/futex/run.sh
index 4126312ad64e..88bcb1767362 100755
--- a/tools/testing/selftests/futex/run.sh
+++ b/tools/testing/selftests/futex/run.sh
@@ -23,7 +23,7 @@
23 23
24# Test for a color capable shell and pass the result to the subdir scripts 24# Test for a color capable shell and pass the result to the subdir scripts
25USE_COLOR=0 25USE_COLOR=0
26tput setf 7 26tput setf 7 || tput setaf 7
27if [ $? -eq 0 ]; then 27if [ $? -eq 0 ]; then
28 USE_COLOR=1 28 USE_COLOR=1
29 tput sgr0 29 tput sgr0
diff --git a/tools/testing/selftests/ia64/.gitignore b/tools/testing/selftests/ia64/.gitignore
new file mode 100644
index 000000000000..ab806edc8732
--- /dev/null
+++ b/tools/testing/selftests/ia64/.gitignore
@@ -0,0 +1 @@
aliasing-test
diff --git a/tools/testing/selftests/ia64/Makefile b/tools/testing/selftests/ia64/Makefile
new file mode 100644
index 000000000000..2b3de2d3e945
--- /dev/null
+++ b/tools/testing/selftests/ia64/Makefile
@@ -0,0 +1,8 @@
1TEST_PROGS := aliasing-test
2
3all: $(TEST_PROGS)
4
5include ../lib.mk
6
7clean:
8 rm -fr $(TEST_PROGS)
diff --git a/tools/testing/selftests/ia64/aliasing-test.c b/tools/testing/selftests/ia64/aliasing-test.c
new file mode 100644
index 000000000000..62a190d45f38
--- /dev/null
+++ b/tools/testing/selftests/ia64/aliasing-test.c
@@ -0,0 +1,263 @@
1/*
2 * Exercise /dev/mem mmap cases that have been troublesome in the past
3 *
4 * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
5 * Bjorn Helgaas <bjorn.helgaas@hp.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/types.h>
15#include <dirent.h>
16#include <fcntl.h>
17#include <fnmatch.h>
18#include <string.h>
19#include <sys/ioctl.h>
20#include <sys/mman.h>
21#include <sys/stat.h>
22#include <unistd.h>
23#include <linux/pci.h>
24
25int sum;
26
27static int map_mem(char *path, off_t offset, size_t length, int touch)
28{
29 int fd, rc;
30 void *addr;
31 int *c;
32
33 fd = open(path, O_RDWR);
34 if (fd == -1) {
35 perror(path);
36 return -1;
37 }
38
39 if (fnmatch("/proc/bus/pci/*", path, 0) == 0) {
40 rc = ioctl(fd, PCIIOC_MMAP_IS_MEM);
41 if (rc == -1)
42 perror("PCIIOC_MMAP_IS_MEM ioctl");
43 }
44
45 addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
46 if (addr == MAP_FAILED)
47 return 1;
48
49 if (touch) {
50 c = (int *) addr;
51 while (c < (int *) (addr + length))
52 sum += *c++;
53 }
54
55 rc = munmap(addr, length);
56 if (rc == -1) {
57 perror("munmap");
58 return -1;
59 }
60
61 close(fd);
62 return 0;
63}
64
65static int scan_tree(char *path, char *file, off_t offset, size_t length, int touch)
66{
67 struct dirent **namelist;
68 char *name, *path2;
69 int i, n, r, rc = 0, result = 0;
70 struct stat buf;
71
72 n = scandir(path, &namelist, 0, alphasort);
73 if (n < 0) {
74 perror("scandir");
75 return -1;
76 }
77
78 for (i = 0; i < n; i++) {
79 name = namelist[i]->d_name;
80
81 if (fnmatch(".", name, 0) == 0)
82 goto skip;
83 if (fnmatch("..", name, 0) == 0)
84 goto skip;
85
86 path2 = malloc(strlen(path) + strlen(name) + 3);
87 strcpy(path2, path);
88 strcat(path2, "/");
89 strcat(path2, name);
90
91 if (fnmatch(file, name, 0) == 0) {
92 rc = map_mem(path2, offset, length, touch);
93 if (rc == 0)
94 fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable");
95 else if (rc > 0)
96 fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length);
97 else {
98 fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length);
99 return rc;
100 }
101 } else {
102 r = lstat(path2, &buf);
103 if (r == 0 && S_ISDIR(buf.st_mode)) {
104 rc = scan_tree(path2, file, offset, length, touch);
105 if (rc < 0)
106 return rc;
107 }
108 }
109
110 result |= rc;
111 free(path2);
112
113skip:
114 free(namelist[i]);
115 }
116 free(namelist);
117 return result;
118}
119
120char buf[1024];
121
122static int read_rom(char *path)
123{
124 int fd, rc;
125 size_t size = 0;
126
127 fd = open(path, O_RDWR);
128 if (fd == -1) {
129 perror(path);
130 return -1;
131 }
132
133 rc = write(fd, "1", 2);
134 if (rc <= 0) {
135 close(fd);
136 perror("write");
137 return -1;
138 }
139
140 do {
141 rc = read(fd, buf, sizeof(buf));
142 if (rc > 0)
143 size += rc;
144 } while (rc > 0);
145
146 close(fd);
147 return size;
148}
149
150static int scan_rom(char *path, char *file)
151{
152 struct dirent **namelist;
153 char *name, *path2;
154 int i, n, r, rc = 0, result = 0;
155 struct stat buf;
156
157 n = scandir(path, &namelist, 0, alphasort);
158 if (n < 0) {
159 perror("scandir");
160 return -1;
161 }
162
163 for (i = 0; i < n; i++) {
164 name = namelist[i]->d_name;
165
166 if (fnmatch(".", name, 0) == 0)
167 goto skip;
168 if (fnmatch("..", name, 0) == 0)
169 goto skip;
170
171 path2 = malloc(strlen(path) + strlen(name) + 3);
172 strcpy(path2, path);
173 strcat(path2, "/");
174 strcat(path2, name);
175
176 if (fnmatch(file, name, 0) == 0) {
177 rc = read_rom(path2);
178
179 /*
180 * It's OK if the ROM is unreadable. Maybe there
181 * is no ROM, or some other error occurred. The
182 * important thing is that no MCA happened.
183 */
184 if (rc > 0)
185 fprintf(stderr, "PASS: %s read %d bytes\n", path2, rc);
186 else {
187 fprintf(stderr, "PASS: %s not readable\n", path2);
188 return rc;
189 }
190 } else {
191 r = lstat(path2, &buf);
192 if (r == 0 && S_ISDIR(buf.st_mode)) {
193 rc = scan_rom(path2, file);
194 if (rc < 0)
195 return rc;
196 }
197 }
198
199 result |= rc;
200 free(path2);
201
202skip:
203 free(namelist[i]);
204 }
205 free(namelist);
206 return result;
207}
208
209int main(void)
210{
211 int rc;
212
213 if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0)
214 fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n");
215 else
216 fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n");
217
218 /*
219 * It's not safe to blindly read the VGA frame buffer. If you know
220 * how to poke the card the right way, it should respond, but it's
221 * not safe in general. Many machines, e.g., Intel chipsets, cover
222 * up a non-responding card by just returning -1, but others will
223 * report the failure as a machine check.
224 */
225 if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0)
226 fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n");
227 else
228 fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n");
229
230 if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0)
231 fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n");
232 else
233 fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n");
234
235 /*
236 * Often you can map all the individual pieces above (0-0xA0000,
237 * 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole
238 * thing at once. This is because the individual pieces use different
239 * attributes, and there's no single attribute supported over the
240 * whole region.
241 */
242 rc = map_mem("/dev/mem", 0, 1024*1024, 0);
243 if (rc == 0)
244 fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n");
245 else if (rc > 0)
246 fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n");
247 else
248 fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n");
249
250 scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
251 scan_tree("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
252 scan_tree("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
253 scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
254
255 scan_rom("/sys/devices", "rom");
256
257 scan_tree("/proc/bus/pci", "??.?", 0, 0xA0000, 1);
258 scan_tree("/proc/bus/pci", "??.?", 0xA0000, 0x20000, 0);
259 scan_tree("/proc/bus/pci", "??.?", 0xC0000, 0x40000, 1);
260 scan_tree("/proc/bus/pci", "??.?", 0, 1024*1024, 0);
261
262 return rc;
263}
diff --git a/tools/testing/selftests/networking/timestamping/.gitignore b/tools/testing/selftests/networking/timestamping/.gitignore
new file mode 100644
index 000000000000..9e69e982fb38
--- /dev/null
+++ b/tools/testing/selftests/networking/timestamping/.gitignore
@@ -0,0 +1,3 @@
1timestamping
2txtimestamp
3hwtstamp_config
diff --git a/tools/testing/selftests/networking/timestamping/Makefile b/tools/testing/selftests/networking/timestamping/Makefile
new file mode 100644
index 000000000000..ccbb9edbbbb9
--- /dev/null
+++ b/tools/testing/selftests/networking/timestamping/Makefile
@@ -0,0 +1,8 @@
1TEST_PROGS := hwtstamp_config timestamping txtimestamp
2
3all: $(TEST_PROGS)
4
5include ../../lib.mk
6
7clean:
8 rm -fr $(TEST_PROGS)
diff --git a/tools/testing/selftests/networking/timestamping/hwtstamp_config.c b/tools/testing/selftests/networking/timestamping/hwtstamp_config.c
new file mode 100644
index 000000000000..e8b685a7f15f
--- /dev/null
+++ b/tools/testing/selftests/networking/timestamping/hwtstamp_config.c
@@ -0,0 +1,134 @@
1/* Test program for SIOC{G,S}HWTSTAMP
2 * Copyright 2013 Solarflare Communications
3 * Author: Ben Hutchings
4 */
5
6#include <errno.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include <sys/socket.h>
12#include <sys/ioctl.h>
13
14#include <linux/if.h>
15#include <linux/net_tstamp.h>
16#include <linux/sockios.h>
17
18static int
19lookup_value(const char **names, int size, const char *name)
20{
21 int value;
22
23 for (value = 0; value < size; value++)
24 if (names[value] && strcasecmp(names[value], name) == 0)
25 return value;
26
27 return -1;
28}
29
30static const char *
31lookup_name(const char **names, int size, int value)
32{
33 return (value >= 0 && value < size) ? names[value] : NULL;
34}
35
36static void list_names(FILE *f, const char **names, int size)
37{
38 int value;
39
40 for (value = 0; value < size; value++)
41 if (names[value])
42 fprintf(f, " %s\n", names[value]);
43}
44
45static const char *tx_types[] = {
46#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name
47 TX_TYPE(OFF),
48 TX_TYPE(ON),
49 TX_TYPE(ONESTEP_SYNC)
50#undef TX_TYPE
51};
52#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0])))
53
54static const char *rx_filters[] = {
55#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name
56 RX_FILTER(NONE),
57 RX_FILTER(ALL),
58 RX_FILTER(SOME),
59 RX_FILTER(PTP_V1_L4_EVENT),
60 RX_FILTER(PTP_V1_L4_SYNC),
61 RX_FILTER(PTP_V1_L4_DELAY_REQ),
62 RX_FILTER(PTP_V2_L4_EVENT),
63 RX_FILTER(PTP_V2_L4_SYNC),
64 RX_FILTER(PTP_V2_L4_DELAY_REQ),
65 RX_FILTER(PTP_V2_L2_EVENT),
66 RX_FILTER(PTP_V2_L2_SYNC),
67 RX_FILTER(PTP_V2_L2_DELAY_REQ),
68 RX_FILTER(PTP_V2_EVENT),
69 RX_FILTER(PTP_V2_SYNC),
70 RX_FILTER(PTP_V2_DELAY_REQ),
71#undef RX_FILTER
72};
73#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0])))
74
75static void usage(void)
76{
77 fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n"
78 "tx_type is any of (case-insensitive):\n",
79 stderr);
80 list_names(stderr, tx_types, N_TX_TYPES);
81 fputs("rx_filter is any of (case-insensitive):\n", stderr);
82 list_names(stderr, rx_filters, N_RX_FILTERS);
83}
84
85int main(int argc, char **argv)
86{
87 struct ifreq ifr;
88 struct hwtstamp_config config;
89 const char *name;
90 int sock;
91
92 if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) {
93 usage();
94 return 2;
95 }
96
97 if (argc == 4) {
98 config.flags = 0;
99 config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]);
100 config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]);
101 if (config.tx_type < 0 || config.rx_filter < 0) {
102 usage();
103 return 2;
104 }
105 }
106
107 sock = socket(AF_INET, SOCK_DGRAM, 0);
108 if (sock < 0) {
109 perror("socket");
110 return 1;
111 }
112
113 strcpy(ifr.ifr_name, argv[1]);
114 ifr.ifr_data = (caddr_t)&config;
115
116 if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) {
117 perror("ioctl");
118 return 1;
119 }
120
121 printf("flags = %#x\n", config.flags);
122 name = lookup_name(tx_types, N_TX_TYPES, config.tx_type);
123 if (name)
124 printf("tx_type = %s\n", name);
125 else
126 printf("tx_type = %d\n", config.tx_type);
127 name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter);
128 if (name)
129 printf("rx_filter = %s\n", name);
130 else
131 printf("rx_filter = %d\n", config.rx_filter);
132
133 return 0;
134}
diff --git a/tools/testing/selftests/networking/timestamping/timestamping.c b/tools/testing/selftests/networking/timestamping/timestamping.c
new file mode 100644
index 000000000000..5cdfd743447b
--- /dev/null
+++ b/tools/testing/selftests/networking/timestamping/timestamping.c
@@ -0,0 +1,528 @@
1/*
2 * This program demonstrates how the various time stamping features in
3 * the Linux kernel work. It emulates the behavior of a PTP
4 * implementation in stand-alone master mode by sending PTPv1 Sync
5 * multicasts once every second. It looks for similar packets, but
6 * beyond that doesn't actually implement PTP.
7 *
8 * Outgoing packets are time stamped with SO_TIMESTAMPING with or
9 * without hardware support.
10 *
11 * Incoming packets are time stamped with SO_TIMESTAMPING with or
12 * without hardware support, SIOCGSTAMP[NS] (per-socket time stamp) and
13 * SO_TIMESTAMP[NS].
14 *
15 * Copyright (C) 2009 Intel Corporation.
16 * Author: Patrick Ohly <patrick.ohly@intel.com>
17 *
18 * This program is free software; you can redistribute it and/or modify it
19 * under the terms and conditions of the GNU General Public License,
20 * version 2, as published by the Free Software Foundation.
21 *
22 * This program is distributed in the hope it will be useful, but WITHOUT
23 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
25 * more details.
26 *
27 * You should have received a copy of the GNU General Public License along with
28 * this program; if not, write to the Free Software Foundation, Inc.,
29 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <errno.h>
35#include <string.h>
36
37#include <sys/time.h>
38#include <sys/socket.h>
39#include <sys/select.h>
40#include <sys/ioctl.h>
41#include <arpa/inet.h>
42#include <net/if.h>
43
44#include <asm/types.h>
45#include <linux/net_tstamp.h>
46#include <linux/errqueue.h>
47
48#ifndef SO_TIMESTAMPING
49# define SO_TIMESTAMPING 37
50# define SCM_TIMESTAMPING SO_TIMESTAMPING
51#endif
52
53#ifndef SO_TIMESTAMPNS
54# define SO_TIMESTAMPNS 35
55#endif
56
57#ifndef SIOCGSTAMPNS
58# define SIOCGSTAMPNS 0x8907
59#endif
60
61#ifndef SIOCSHWTSTAMP
62# define SIOCSHWTSTAMP 0x89b0
63#endif
64
65static void usage(const char *error)
66{
67 if (error)
68 printf("invalid option: %s\n", error);
69 printf("timestamping interface option*\n\n"
70 "Options:\n"
71 " IP_MULTICAST_LOOP - looping outgoing multicasts\n"
72 " SO_TIMESTAMP - normal software time stamping, ms resolution\n"
73 " SO_TIMESTAMPNS - more accurate software time stamping\n"
74 " SOF_TIMESTAMPING_TX_HARDWARE - hardware time stamping of outgoing packets\n"
75 " SOF_TIMESTAMPING_TX_SOFTWARE - software fallback for outgoing packets\n"
76 " SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n"
77 " SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n"
78 " SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n"
79 " SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n"
80 " SIOCGSTAMP - check last socket time stamp\n"
81 " SIOCGSTAMPNS - more accurate socket time stamp\n");
82 exit(1);
83}
84
85static void bail(const char *error)
86{
87 printf("%s: %s\n", error, strerror(errno));
88 exit(1);
89}
90
91static const unsigned char sync[] = {
92 0x00, 0x01, 0x00, 0x01,
93 0x5f, 0x44, 0x46, 0x4c,
94 0x54, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00,
97 0x01, 0x01,
98
99 /* fake uuid */
100 0x00, 0x01,
101 0x02, 0x03, 0x04, 0x05,
102
103 0x00, 0x01, 0x00, 0x37,
104 0x00, 0x00, 0x00, 0x08,
105 0x00, 0x00, 0x00, 0x00,
106 0x49, 0x05, 0xcd, 0x01,
107 0x29, 0xb1, 0x8d, 0xb0,
108 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x01,
110
111 /* fake uuid */
112 0x00, 0x01,
113 0x02, 0x03, 0x04, 0x05,
114
115 0x00, 0x00, 0x00, 0x37,
116 0x00, 0x00, 0x00, 0x04,
117 0x44, 0x46, 0x4c, 0x54,
118 0x00, 0x00, 0xf0, 0x60,
119 0x00, 0x01, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x01,
121 0x00, 0x00, 0xf0, 0x60,
122 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x04,
124 0x44, 0x46, 0x4c, 0x54,
125 0x00, 0x01,
126
127 /* fake uuid */
128 0x00, 0x01,
129 0x02, 0x03, 0x04, 0x05,
130
131 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00,
134 0x00, 0x00, 0x00, 0x00
135};
136
137static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len)
138{
139 struct timeval now;
140 int res;
141
142 res = sendto(sock, sync, sizeof(sync), 0,
143 addr, addr_len);
144 gettimeofday(&now, 0);
145 if (res < 0)
146 printf("%s: %s\n", "send", strerror(errno));
147 else
148 printf("%ld.%06ld: sent %d bytes\n",
149 (long)now.tv_sec, (long)now.tv_usec,
150 res);
151}
152
153static void printpacket(struct msghdr *msg, int res,
154 char *data,
155 int sock, int recvmsg_flags,
156 int siocgstamp, int siocgstampns)
157{
158 struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name;
159 struct cmsghdr *cmsg;
160 struct timeval tv;
161 struct timespec ts;
162 struct timeval now;
163
164 gettimeofday(&now, 0);
165
166 printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
167 (long)now.tv_sec, (long)now.tv_usec,
168 (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
169 res,
170 inet_ntoa(from_addr->sin_addr),
171 msg->msg_controllen);
172 for (cmsg = CMSG_FIRSTHDR(msg);
173 cmsg;
174 cmsg = CMSG_NXTHDR(msg, cmsg)) {
175 printf(" cmsg len %zu: ", cmsg->cmsg_len);
176 switch (cmsg->cmsg_level) {
177 case SOL_SOCKET:
178 printf("SOL_SOCKET ");
179 switch (cmsg->cmsg_type) {
180 case SO_TIMESTAMP: {
181 struct timeval *stamp =
182 (struct timeval *)CMSG_DATA(cmsg);
183 printf("SO_TIMESTAMP %ld.%06ld",
184 (long)stamp->tv_sec,
185 (long)stamp->tv_usec);
186 break;
187 }
188 case SO_TIMESTAMPNS: {
189 struct timespec *stamp =
190 (struct timespec *)CMSG_DATA(cmsg);
191 printf("SO_TIMESTAMPNS %ld.%09ld",
192 (long)stamp->tv_sec,
193 (long)stamp->tv_nsec);
194 break;
195 }
196 case SO_TIMESTAMPING: {
197 struct timespec *stamp =
198 (struct timespec *)CMSG_DATA(cmsg);
199 printf("SO_TIMESTAMPING ");
200 printf("SW %ld.%09ld ",
201 (long)stamp->tv_sec,
202 (long)stamp->tv_nsec);
203 stamp++;
204 /* skip deprecated HW transformed */
205 stamp++;
206 printf("HW raw %ld.%09ld",
207 (long)stamp->tv_sec,
208 (long)stamp->tv_nsec);
209 break;
210 }
211 default:
212 printf("type %d", cmsg->cmsg_type);
213 break;
214 }
215 break;
216 case IPPROTO_IP:
217 printf("IPPROTO_IP ");
218 switch (cmsg->cmsg_type) {
219 case IP_RECVERR: {
220 struct sock_extended_err *err =
221 (struct sock_extended_err *)CMSG_DATA(cmsg);
222 printf("IP_RECVERR ee_errno '%s' ee_origin %d => %s",
223 strerror(err->ee_errno),
224 err->ee_origin,
225#ifdef SO_EE_ORIGIN_TIMESTAMPING
226 err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING ?
227 "bounced packet" : "unexpected origin"
228#else
229 "probably SO_EE_ORIGIN_TIMESTAMPING"
230#endif
231 );
232 if (res < sizeof(sync))
233 printf(" => truncated data?!");
234 else if (!memcmp(sync, data + res - sizeof(sync),
235 sizeof(sync)))
236 printf(" => GOT OUR DATA BACK (HURRAY!)");
237 break;
238 }
239 case IP_PKTINFO: {
240 struct in_pktinfo *pktinfo =
241 (struct in_pktinfo *)CMSG_DATA(cmsg);
242 printf("IP_PKTINFO interface index %u",
243 pktinfo->ipi_ifindex);
244 break;
245 }
246 default:
247 printf("type %d", cmsg->cmsg_type);
248 break;
249 }
250 break;
251 default:
252 printf("level %d type %d",
253 cmsg->cmsg_level,
254 cmsg->cmsg_type);
255 break;
256 }
257 printf("\n");
258 }
259
260 if (siocgstamp) {
261 if (ioctl(sock, SIOCGSTAMP, &tv))
262 printf(" %s: %s\n", "SIOCGSTAMP", strerror(errno));
263 else
264 printf("SIOCGSTAMP %ld.%06ld\n",
265 (long)tv.tv_sec,
266 (long)tv.tv_usec);
267 }
268 if (siocgstampns) {
269 if (ioctl(sock, SIOCGSTAMPNS, &ts))
270 printf(" %s: %s\n", "SIOCGSTAMPNS", strerror(errno));
271 else
272 printf("SIOCGSTAMPNS %ld.%09ld\n",
273 (long)ts.tv_sec,
274 (long)ts.tv_nsec);
275 }
276}
277
278static void recvpacket(int sock, int recvmsg_flags,
279 int siocgstamp, int siocgstampns)
280{
281 char data[256];
282 struct msghdr msg;
283 struct iovec entry;
284 struct sockaddr_in from_addr;
285 struct {
286 struct cmsghdr cm;
287 char control[512];
288 } control;
289 int res;
290
291 memset(&msg, 0, sizeof(msg));
292 msg.msg_iov = &entry;
293 msg.msg_iovlen = 1;
294 entry.iov_base = data;
295 entry.iov_len = sizeof(data);
296 msg.msg_name = (caddr_t)&from_addr;
297 msg.msg_namelen = sizeof(from_addr);
298 msg.msg_control = &control;
299 msg.msg_controllen = sizeof(control);
300
301 res = recvmsg(sock, &msg, recvmsg_flags|MSG_DONTWAIT);
302 if (res < 0) {
303 printf("%s %s: %s\n",
304 "recvmsg",
305 (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
306 strerror(errno));
307 } else {
308 printpacket(&msg, res, data,
309 sock, recvmsg_flags,
310 siocgstamp, siocgstampns);
311 }
312}
313
314int main(int argc, char **argv)
315{
316 int so_timestamping_flags = 0;
317 int so_timestamp = 0;
318 int so_timestampns = 0;
319 int siocgstamp = 0;
320 int siocgstampns = 0;
321 int ip_multicast_loop = 0;
322 char *interface;
323 int i;
324 int enabled = 1;
325 int sock;
326 struct ifreq device;
327 struct ifreq hwtstamp;
328 struct hwtstamp_config hwconfig, hwconfig_requested;
329 struct sockaddr_in addr;
330 struct ip_mreq imr;
331 struct in_addr iaddr;
332 int val;
333 socklen_t len;
334 struct timeval next;
335
336 if (argc < 2)
337 usage(0);
338 interface = argv[1];
339
340 for (i = 2; i < argc; i++) {
341 if (!strcasecmp(argv[i], "SO_TIMESTAMP"))
342 so_timestamp = 1;
343 else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS"))
344 so_timestampns = 1;
345 else if (!strcasecmp(argv[i], "SIOCGSTAMP"))
346 siocgstamp = 1;
347 else if (!strcasecmp(argv[i], "SIOCGSTAMPNS"))
348 siocgstampns = 1;
349 else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP"))
350 ip_multicast_loop = 1;
351 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE"))
352 so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
353 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE"))
354 so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE;
355 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE"))
356 so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE;
357 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE"))
358 so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE;
359 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE"))
360 so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE;
361 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE"))
362 so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE;
363 else
364 usage(argv[i]);
365 }
366
367 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
368 if (sock < 0)
369 bail("socket");
370
371 memset(&device, 0, sizeof(device));
372 strncpy(device.ifr_name, interface, sizeof(device.ifr_name));
373 if (ioctl(sock, SIOCGIFADDR, &device) < 0)
374 bail("getting interface IP address");
375
376 memset(&hwtstamp, 0, sizeof(hwtstamp));
377 strncpy(hwtstamp.ifr_name, interface, sizeof(hwtstamp.ifr_name));
378 hwtstamp.ifr_data = (void *)&hwconfig;
379 memset(&hwconfig, 0, sizeof(hwconfig));
380 hwconfig.tx_type =
381 (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ?
382 HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
383 hwconfig.rx_filter =
384 (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ?
385 HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE;
386 hwconfig_requested = hwconfig;
387 if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) {
388 if ((errno == EINVAL || errno == ENOTSUP) &&
389 hwconfig_requested.tx_type == HWTSTAMP_TX_OFF &&
390 hwconfig_requested.rx_filter == HWTSTAMP_FILTER_NONE)
391 printf("SIOCSHWTSTAMP: disabling hardware time stamping not possible\n");
392 else
393 bail("SIOCSHWTSTAMP");
394 }
395 printf("SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n",
396 hwconfig_requested.tx_type, hwconfig.tx_type,
397 hwconfig_requested.rx_filter, hwconfig.rx_filter);
398
399 /* bind to PTP port */
400 addr.sin_family = AF_INET;
401 addr.sin_addr.s_addr = htonl(INADDR_ANY);
402 addr.sin_port = htons(319 /* PTP event port */);
403 if (bind(sock,
404 (struct sockaddr *)&addr,
405 sizeof(struct sockaddr_in)) < 0)
406 bail("bind");
407
408 /* set multicast group for outgoing packets */
409 inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */
410 addr.sin_addr = iaddr;
411 imr.imr_multiaddr.s_addr = iaddr.s_addr;
412 imr.imr_interface.s_addr =
413 ((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr;
414 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
415 &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0)
416 bail("set multicast");
417
418 /* join multicast group, loop our own packet */
419 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
420 &imr, sizeof(struct ip_mreq)) < 0)
421 bail("join multicast group");
422
423 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
424 &ip_multicast_loop, sizeof(enabled)) < 0) {
425 bail("loop multicast");
426 }
427
428 /* set socket options for time stamping */
429 if (so_timestamp &&
430 setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
431 &enabled, sizeof(enabled)) < 0)
432 bail("setsockopt SO_TIMESTAMP");
433
434 if (so_timestampns &&
435 setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS,
436 &enabled, sizeof(enabled)) < 0)
437 bail("setsockopt SO_TIMESTAMPNS");
438
439 if (so_timestamping_flags &&
440 setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING,
441 &so_timestamping_flags,
442 sizeof(so_timestamping_flags)) < 0)
443 bail("setsockopt SO_TIMESTAMPING");
444
445 /* request IP_PKTINFO for debugging purposes */
446 if (setsockopt(sock, SOL_IP, IP_PKTINFO,
447 &enabled, sizeof(enabled)) < 0)
448 printf("%s: %s\n", "setsockopt IP_PKTINFO", strerror(errno));
449
450 /* verify socket options */
451 len = sizeof(val);
452 if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0)
453 printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno));
454 else
455 printf("SO_TIMESTAMP %d\n", val);
456
457 if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0)
458 printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS",
459 strerror(errno));
460 else
461 printf("SO_TIMESTAMPNS %d\n", val);
462
463 if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) {
464 printf("%s: %s\n", "getsockopt SO_TIMESTAMPING",
465 strerror(errno));
466 } else {
467 printf("SO_TIMESTAMPING %d\n", val);
468 if (val != so_timestamping_flags)
469 printf(" not the expected value %d\n",
470 so_timestamping_flags);
471 }
472
473 /* send packets forever every five seconds */
474 gettimeofday(&next, 0);
475 next.tv_sec = (next.tv_sec + 1) / 5 * 5;
476 next.tv_usec = 0;
477 while (1) {
478 struct timeval now;
479 struct timeval delta;
480 long delta_us;
481 int res;
482 fd_set readfs, errorfs;
483
484 gettimeofday(&now, 0);
485 delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 +
486 (long)(next.tv_usec - now.tv_usec);
487 if (delta_us > 0) {
488 /* continue waiting for timeout or data */
489 delta.tv_sec = delta_us / 1000000;
490 delta.tv_usec = delta_us % 1000000;
491
492 FD_ZERO(&readfs);
493 FD_ZERO(&errorfs);
494 FD_SET(sock, &readfs);
495 FD_SET(sock, &errorfs);
496 printf("%ld.%06ld: select %ldus\n",
497 (long)now.tv_sec, (long)now.tv_usec,
498 delta_us);
499 res = select(sock + 1, &readfs, 0, &errorfs, &delta);
500 gettimeofday(&now, 0);
501 printf("%ld.%06ld: select returned: %d, %s\n",
502 (long)now.tv_sec, (long)now.tv_usec,
503 res,
504 res < 0 ? strerror(errno) : "success");
505 if (res > 0) {
506 if (FD_ISSET(sock, &readfs))
507 printf("ready for reading\n");
508 if (FD_ISSET(sock, &errorfs))
509 printf("has error\n");
510 recvpacket(sock, 0,
511 siocgstamp,
512 siocgstampns);
513 recvpacket(sock, MSG_ERRQUEUE,
514 siocgstamp,
515 siocgstampns);
516 }
517 } else {
518 /* write one packet */
519 sendpacket(sock,
520 (struct sockaddr *)&addr,
521 sizeof(addr));
522 next.tv_sec += 5;
523 continue;
524 }
525 }
526
527 return 0;
528}
diff --git a/tools/testing/selftests/networking/timestamping/txtimestamp.c b/tools/testing/selftests/networking/timestamping/txtimestamp.c
new file mode 100644
index 000000000000..5df07047ca86
--- /dev/null
+++ b/tools/testing/selftests/networking/timestamping/txtimestamp.c
@@ -0,0 +1,549 @@
1/*
2 * Copyright 2014 Google Inc.
3 * Author: willemb@google.com (Willem de Bruijn)
4 *
5 * Test software tx timestamping, including
6 *
7 * - SCHED, SND and ACK timestamps
8 * - RAW, UDP and TCP
9 * - IPv4 and IPv6
10 * - various packet sizes (to test GSO and TSO)
11 *
12 * Consult the command line arguments for help on running
13 * the various testcases.
14 *
15 * This test requires a dummy TCP server.
16 * A simple `nc6 [-u] -l -p $DESTPORT` will do
17 *
18 *
19 * This program is free software; you can redistribute it and/or modify it
20 * under the terms and conditions of the GNU General Public License,
21 * version 2, as published by the Free Software Foundation.
22 *
23 * This program is distributed in the hope it will be useful, but WITHOUT
24 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25 * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
26 * more details.
27 *
28 * You should have received a copy of the GNU General Public License along with
29 * this program; if not, write to the Free Software Foundation, Inc.,
30 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
31 */
32
33#define _GNU_SOURCE
34
35#include <arpa/inet.h>
36#include <asm/types.h>
37#include <error.h>
38#include <errno.h>
39#include <inttypes.h>
40#include <linux/errqueue.h>
41#include <linux/if_ether.h>
42#include <linux/net_tstamp.h>
43#include <netdb.h>
44#include <net/if.h>
45#include <netinet/in.h>
46#include <netinet/ip.h>
47#include <netinet/udp.h>
48#include <netinet/tcp.h>
49#include <netpacket/packet.h>
50#include <poll.h>
51#include <stdarg.h>
52#include <stdbool.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <sys/ioctl.h>
57#include <sys/select.h>
58#include <sys/socket.h>
59#include <sys/time.h>
60#include <sys/types.h>
61#include <time.h>
62#include <unistd.h>
63
64/* command line parameters */
65static int cfg_proto = SOCK_STREAM;
66static int cfg_ipproto = IPPROTO_TCP;
67static int cfg_num_pkts = 4;
68static int do_ipv4 = 1;
69static int do_ipv6 = 1;
70static int cfg_payload_len = 10;
71static bool cfg_show_payload;
72static bool cfg_do_pktinfo;
73static bool cfg_loop_nodata;
74static uint16_t dest_port = 9000;
75
76static struct sockaddr_in daddr;
77static struct sockaddr_in6 daddr6;
78static struct timespec ts_prev;
79
80static void __print_timestamp(const char *name, struct timespec *cur,
81 uint32_t key, int payload_len)
82{
83 if (!(cur->tv_sec | cur->tv_nsec))
84 return;
85
86 fprintf(stderr, " %s: %lu s %lu us (seq=%u, len=%u)",
87 name, cur->tv_sec, cur->tv_nsec / 1000,
88 key, payload_len);
89
90 if ((ts_prev.tv_sec | ts_prev.tv_nsec)) {
91 int64_t cur_ms, prev_ms;
92
93 cur_ms = (long) cur->tv_sec * 1000 * 1000;
94 cur_ms += cur->tv_nsec / 1000;
95
96 prev_ms = (long) ts_prev.tv_sec * 1000 * 1000;
97 prev_ms += ts_prev.tv_nsec / 1000;
98
99 fprintf(stderr, " (%+" PRId64 " us)", cur_ms - prev_ms);
100 }
101
102 ts_prev = *cur;
103 fprintf(stderr, "\n");
104}
105
106static void print_timestamp_usr(void)
107{
108 struct timespec ts;
109 struct timeval tv; /* avoid dependency on -lrt */
110
111 gettimeofday(&tv, NULL);
112 ts.tv_sec = tv.tv_sec;
113 ts.tv_nsec = tv.tv_usec * 1000;
114
115 __print_timestamp(" USR", &ts, 0, 0);
116}
117
118static void print_timestamp(struct scm_timestamping *tss, int tstype,
119 int tskey, int payload_len)
120{
121 const char *tsname;
122
123 switch (tstype) {
124 case SCM_TSTAMP_SCHED:
125 tsname = " ENQ";
126 break;
127 case SCM_TSTAMP_SND:
128 tsname = " SND";
129 break;
130 case SCM_TSTAMP_ACK:
131 tsname = " ACK";
132 break;
133 default:
134 error(1, 0, "unknown timestamp type: %u",
135 tstype);
136 }
137 __print_timestamp(tsname, &tss->ts[0], tskey, payload_len);
138}
139
140/* TODO: convert to check_and_print payload once API is stable */
141static void print_payload(char *data, int len)
142{
143 int i;
144
145 if (!len)
146 return;
147
148 if (len > 70)
149 len = 70;
150
151 fprintf(stderr, "payload: ");
152 for (i = 0; i < len; i++)
153 fprintf(stderr, "%02hhx ", data[i]);
154 fprintf(stderr, "\n");
155}
156
157static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr)
158{
159 char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN];
160
161 fprintf(stderr, " pktinfo: ifindex=%u src=%s dst=%s\n",
162 ifindex,
163 saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown",
164 daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown");
165}
166
167static void __poll(int fd)
168{
169 struct pollfd pollfd;
170 int ret;
171
172 memset(&pollfd, 0, sizeof(pollfd));
173 pollfd.fd = fd;
174 ret = poll(&pollfd, 1, 100);
175 if (ret != 1)
176 error(1, errno, "poll");
177}
178
179static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len)
180{
181 struct sock_extended_err *serr = NULL;
182 struct scm_timestamping *tss = NULL;
183 struct cmsghdr *cm;
184 int batch = 0;
185
186 for (cm = CMSG_FIRSTHDR(msg);
187 cm && cm->cmsg_len;
188 cm = CMSG_NXTHDR(msg, cm)) {
189 if (cm->cmsg_level == SOL_SOCKET &&
190 cm->cmsg_type == SCM_TIMESTAMPING) {
191 tss = (void *) CMSG_DATA(cm);
192 } else if ((cm->cmsg_level == SOL_IP &&
193 cm->cmsg_type == IP_RECVERR) ||
194 (cm->cmsg_level == SOL_IPV6 &&
195 cm->cmsg_type == IPV6_RECVERR)) {
196 serr = (void *) CMSG_DATA(cm);
197 if (serr->ee_errno != ENOMSG ||
198 serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
199 fprintf(stderr, "unknown ip error %d %d\n",
200 serr->ee_errno,
201 serr->ee_origin);
202 serr = NULL;
203 }
204 } else if (cm->cmsg_level == SOL_IP &&
205 cm->cmsg_type == IP_PKTINFO) {
206 struct in_pktinfo *info = (void *) CMSG_DATA(cm);
207 print_pktinfo(AF_INET, info->ipi_ifindex,
208 &info->ipi_spec_dst, &info->ipi_addr);
209 } else if (cm->cmsg_level == SOL_IPV6 &&
210 cm->cmsg_type == IPV6_PKTINFO) {
211 struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm);
212 print_pktinfo(AF_INET6, info6->ipi6_ifindex,
213 NULL, &info6->ipi6_addr);
214 } else
215 fprintf(stderr, "unknown cmsg %d,%d\n",
216 cm->cmsg_level, cm->cmsg_type);
217
218 if (serr && tss) {
219 print_timestamp(tss, serr->ee_info, serr->ee_data,
220 payload_len);
221 serr = NULL;
222 tss = NULL;
223 batch++;
224 }
225 }
226
227 if (batch > 1)
228 fprintf(stderr, "batched %d timestamps\n", batch);
229}
230
231static int recv_errmsg(int fd)
232{
233 static char ctrl[1024 /* overprovision*/];
234 static struct msghdr msg;
235 struct iovec entry;
236 static char *data;
237 int ret = 0;
238
239 data = malloc(cfg_payload_len);
240 if (!data)
241 error(1, 0, "malloc");
242
243 memset(&msg, 0, sizeof(msg));
244 memset(&entry, 0, sizeof(entry));
245 memset(ctrl, 0, sizeof(ctrl));
246
247 entry.iov_base = data;
248 entry.iov_len = cfg_payload_len;
249 msg.msg_iov = &entry;
250 msg.msg_iovlen = 1;
251 msg.msg_name = NULL;
252 msg.msg_namelen = 0;
253 msg.msg_control = ctrl;
254 msg.msg_controllen = sizeof(ctrl);
255
256 ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
257 if (ret == -1 && errno != EAGAIN)
258 error(1, errno, "recvmsg");
259
260 if (ret >= 0) {
261 __recv_errmsg_cmsg(&msg, ret);
262 if (cfg_show_payload)
263 print_payload(data, cfg_payload_len);
264 }
265
266 free(data);
267 return ret == -1;
268}
269
270static void do_test(int family, unsigned int opt)
271{
272 char *buf;
273 int fd, i, val = 1, total_len;
274
275 if (family == AF_INET6 && cfg_proto != SOCK_STREAM) {
276 /* due to lack of checksum generation code */
277 fprintf(stderr, "test: skipping datagram over IPv6\n");
278 return;
279 }
280
281 total_len = cfg_payload_len;
282 if (cfg_proto == SOCK_RAW) {
283 total_len += sizeof(struct udphdr);
284 if (cfg_ipproto == IPPROTO_RAW)
285 total_len += sizeof(struct iphdr);
286 }
287
288 buf = malloc(total_len);
289 if (!buf)
290 error(1, 0, "malloc");
291
292 fd = socket(family, cfg_proto, cfg_ipproto);
293 if (fd < 0)
294 error(1, errno, "socket");
295
296 if (cfg_proto == SOCK_STREAM) {
297 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
298 (char*) &val, sizeof(val)))
299 error(1, 0, "setsockopt no nagle");
300
301 if (family == PF_INET) {
302 if (connect(fd, (void *) &daddr, sizeof(daddr)))
303 error(1, errno, "connect ipv4");
304 } else {
305 if (connect(fd, (void *) &daddr6, sizeof(daddr6)))
306 error(1, errno, "connect ipv6");
307 }
308 }
309
310 if (cfg_do_pktinfo) {
311 if (family == AF_INET6) {
312 if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO,
313 &val, sizeof(val)))
314 error(1, errno, "setsockopt pktinfo ipv6");
315 } else {
316 if (setsockopt(fd, SOL_IP, IP_PKTINFO,
317 &val, sizeof(val)))
318 error(1, errno, "setsockopt pktinfo ipv4");
319 }
320 }
321
322 opt |= SOF_TIMESTAMPING_SOFTWARE |
323 SOF_TIMESTAMPING_OPT_CMSG |
324 SOF_TIMESTAMPING_OPT_ID;
325 if (cfg_loop_nodata)
326 opt |= SOF_TIMESTAMPING_OPT_TSONLY;
327
328 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
329 (char *) &opt, sizeof(opt)))
330 error(1, 0, "setsockopt timestamping");
331
332 for (i = 0; i < cfg_num_pkts; i++) {
333 memset(&ts_prev, 0, sizeof(ts_prev));
334 memset(buf, 'a' + i, total_len);
335
336 if (cfg_proto == SOCK_RAW) {
337 struct udphdr *udph;
338 int off = 0;
339
340 if (cfg_ipproto == IPPROTO_RAW) {
341 struct iphdr *iph = (void *) buf;
342
343 memset(iph, 0, sizeof(*iph));
344 iph->ihl = 5;
345 iph->version = 4;
346 iph->ttl = 2;
347 iph->daddr = daddr.sin_addr.s_addr;
348 iph->protocol = IPPROTO_UDP;
349 /* kernel writes saddr, csum, len */
350
351 off = sizeof(*iph);
352 }
353
354 udph = (void *) buf + off;
355 udph->source = ntohs(9000); /* random spoof */
356 udph->dest = ntohs(dest_port);
357 udph->len = ntohs(sizeof(*udph) + cfg_payload_len);
358 udph->check = 0; /* not allowed for IPv6 */
359 }
360
361 print_timestamp_usr();
362 if (cfg_proto != SOCK_STREAM) {
363 if (family == PF_INET)
364 val = sendto(fd, buf, total_len, 0, (void *) &daddr, sizeof(daddr));
365 else
366 val = sendto(fd, buf, total_len, 0, (void *) &daddr6, sizeof(daddr6));
367 } else {
368 val = send(fd, buf, cfg_payload_len, 0);
369 }
370 if (val != total_len)
371 error(1, errno, "send");
372
373 /* wait for all errors to be queued, else ACKs arrive OOO */
374 usleep(50 * 1000);
375
376 __poll(fd);
377
378 while (!recv_errmsg(fd)) {}
379 }
380
381 if (close(fd))
382 error(1, errno, "close");
383
384 free(buf);
385 usleep(400 * 1000);
386}
387
388static void __attribute__((noreturn)) usage(const char *filepath)
389{
390 fprintf(stderr, "\nUsage: %s [options] hostname\n"
391 "\nwhere options are:\n"
392 " -4: only IPv4\n"
393 " -6: only IPv6\n"
394 " -h: show this message\n"
395 " -I: request PKTINFO\n"
396 " -l N: send N bytes at a time\n"
397 " -n: set no-payload option\n"
398 " -r: use raw\n"
399 " -R: use raw (IP_HDRINCL)\n"
400 " -p N: connect to port N\n"
401 " -u: use udp\n"
402 " -x: show payload (up to 70 bytes)\n",
403 filepath);
404 exit(1);
405}
406
407static void parse_opt(int argc, char **argv)
408{
409 int proto_count = 0;
410 char c;
411
412 while ((c = getopt(argc, argv, "46hIl:np:rRux")) != -1) {
413 switch (c) {
414 case '4':
415 do_ipv6 = 0;
416 break;
417 case '6':
418 do_ipv4 = 0;
419 break;
420 case 'I':
421 cfg_do_pktinfo = true;
422 break;
423 case 'n':
424 cfg_loop_nodata = true;
425 break;
426 case 'r':
427 proto_count++;
428 cfg_proto = SOCK_RAW;
429 cfg_ipproto = IPPROTO_UDP;
430 break;
431 case 'R':
432 proto_count++;
433 cfg_proto = SOCK_RAW;
434 cfg_ipproto = IPPROTO_RAW;
435 break;
436 case 'u':
437 proto_count++;
438 cfg_proto = SOCK_DGRAM;
439 cfg_ipproto = IPPROTO_UDP;
440 break;
441 case 'l':
442 cfg_payload_len = strtoul(optarg, NULL, 10);
443 break;
444 case 'p':
445 dest_port = strtoul(optarg, NULL, 10);
446 break;
447 case 'x':
448 cfg_show_payload = true;
449 break;
450 case 'h':
451 default:
452 usage(argv[0]);
453 }
454 }
455
456 if (!cfg_payload_len)
457 error(1, 0, "payload may not be nonzero");
458 if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472)
459 error(1, 0, "udp packet might exceed expected MTU");
460 if (!do_ipv4 && !do_ipv6)
461 error(1, 0, "pass -4 or -6, not both");
462 if (proto_count > 1)
463 error(1, 0, "pass -r, -R or -u, not multiple");
464
465 if (optind != argc - 1)
466 error(1, 0, "missing required hostname argument");
467}
468
469static void resolve_hostname(const char *hostname)
470{
471 struct addrinfo *addrs, *cur;
472 int have_ipv4 = 0, have_ipv6 = 0;
473
474 if (getaddrinfo(hostname, NULL, NULL, &addrs))
475 error(1, errno, "getaddrinfo");
476
477 cur = addrs;
478 while (cur && !have_ipv4 && !have_ipv6) {
479 if (!have_ipv4 && cur->ai_family == AF_INET) {
480 memcpy(&daddr, cur->ai_addr, sizeof(daddr));
481 daddr.sin_port = htons(dest_port);
482 have_ipv4 = 1;
483 }
484 else if (!have_ipv6 && cur->ai_family == AF_INET6) {
485 memcpy(&daddr6, cur->ai_addr, sizeof(daddr6));
486 daddr6.sin6_port = htons(dest_port);
487 have_ipv6 = 1;
488 }
489 cur = cur->ai_next;
490 }
491 if (addrs)
492 freeaddrinfo(addrs);
493
494 do_ipv4 &= have_ipv4;
495 do_ipv6 &= have_ipv6;
496}
497
498static void do_main(int family)
499{
500 fprintf(stderr, "family: %s\n",
501 family == PF_INET ? "INET" : "INET6");
502
503 fprintf(stderr, "test SND\n");
504 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE);
505
506 fprintf(stderr, "test ENQ\n");
507 do_test(family, SOF_TIMESTAMPING_TX_SCHED);
508
509 fprintf(stderr, "test ENQ + SND\n");
510 do_test(family, SOF_TIMESTAMPING_TX_SCHED |
511 SOF_TIMESTAMPING_TX_SOFTWARE);
512
513 if (cfg_proto == SOCK_STREAM) {
514 fprintf(stderr, "\ntest ACK\n");
515 do_test(family, SOF_TIMESTAMPING_TX_ACK);
516
517 fprintf(stderr, "\ntest SND + ACK\n");
518 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE |
519 SOF_TIMESTAMPING_TX_ACK);
520
521 fprintf(stderr, "\ntest ENQ + SND + ACK\n");
522 do_test(family, SOF_TIMESTAMPING_TX_SCHED |
523 SOF_TIMESTAMPING_TX_SOFTWARE |
524 SOF_TIMESTAMPING_TX_ACK);
525 }
526}
527
528const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
529
530int main(int argc, char **argv)
531{
532 if (argc == 1)
533 usage(argv[0]);
534
535 parse_opt(argc, argv);
536 resolve_hostname(argv[argc - 1]);
537
538 fprintf(stderr, "protocol: %s\n", sock_names[cfg_proto]);
539 fprintf(stderr, "payload: %u\n", cfg_payload_len);
540 fprintf(stderr, "server port: %u\n", dest_port);
541 fprintf(stderr, "\n");
542
543 if (do_ipv4)
544 do_main(PF_INET);
545 if (do_ipv6)
546 do_main(PF_INET6);
547
548 return 0;
549}
diff --git a/tools/testing/selftests/nsfs/Makefile b/tools/testing/selftests/nsfs/Makefile
new file mode 100644
index 000000000000..2306054a901a
--- /dev/null
+++ b/tools/testing/selftests/nsfs/Makefile
@@ -0,0 +1,12 @@
1TEST_PROGS := owner pidns
2
3CFLAGS := -Wall -Werror
4
5all: owner pidns
6owner: owner.c
7pidns: pidns.c
8
9clean:
10 $(RM) owner pidns
11
12include ../lib.mk
diff --git a/tools/testing/selftests/nsfs/owner.c b/tools/testing/selftests/nsfs/owner.c
new file mode 100644
index 000000000000..437205f8b714
--- /dev/null
+++ b/tools/testing/selftests/nsfs/owner.c
@@ -0,0 +1,91 @@
1#define _GNU_SOURCE
2#include <sched.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <signal.h>
7#include <errno.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <sys/ioctl.h>
12#include <sys/prctl.h>
13#include <sys/wait.h>
14
15#define NSIO 0xb7
16#define NS_GET_USERNS _IO(NSIO, 0x1)
17
18#define pr_err(fmt, ...) \
19 ({ \
20 fprintf(stderr, "%s:%d:" fmt ": %m\n", \
21 __func__, __LINE__, ##__VA_ARGS__); \
22 1; \
23 })
24
25int main(int argc, char *argvp[])
26{
27 int pfd[2], ns, uns, init_uns;
28 struct stat st1, st2;
29 char path[128];
30 pid_t pid;
31 char c;
32
33 if (pipe(pfd))
34 return 1;
35
36 pid = fork();
37 if (pid < 0)
38 return pr_err("fork");
39 if (pid == 0) {
40 prctl(PR_SET_PDEATHSIG, SIGKILL);
41 if (unshare(CLONE_NEWUTS | CLONE_NEWUSER))
42 return pr_err("unshare");
43 close(pfd[0]);
44 close(pfd[1]);
45 while (1)
46 sleep(1);
47 return 0;
48 }
49 close(pfd[1]);
50 if (read(pfd[0], &c, 1) != 0)
51 return pr_err("Unable to read from pipe");
52 close(pfd[0]);
53
54 snprintf(path, sizeof(path), "/proc/%d/ns/uts", pid);
55 ns = open(path, O_RDONLY);
56 if (ns < 0)
57 return pr_err("Unable to open %s", path);
58
59 uns = ioctl(ns, NS_GET_USERNS);
60 if (uns < 0)
61 return pr_err("Unable to get an owning user namespace");
62
63 if (fstat(uns, &st1))
64 return pr_err("fstat");
65
66 snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
67 if (stat(path, &st2))
68 return pr_err("stat");
69
70 if (st1.st_ino != st2.st_ino)
71 return pr_err("NS_GET_USERNS returned a wrong namespace");
72
73 init_uns = ioctl(uns, NS_GET_USERNS);
74 if (uns < 0)
75 return pr_err("Unable to get an owning user namespace");
76
77 if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM)
78 return pr_err("Don't get EPERM");
79
80 if (unshare(CLONE_NEWUSER))
81 return pr_err("unshare");
82
83 if (ioctl(ns, NS_GET_USERNS) >= 0 || errno != EPERM)
84 return pr_err("Don't get EPERM");
85 if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM)
86 return pr_err("Don't get EPERM");
87
88 kill(pid, SIGKILL);
89 wait(NULL);
90 return 0;
91}
diff --git a/tools/testing/selftests/nsfs/pidns.c b/tools/testing/selftests/nsfs/pidns.c
new file mode 100644
index 000000000000..ae3a0d68e966
--- /dev/null
+++ b/tools/testing/selftests/nsfs/pidns.c
@@ -0,0 +1,78 @@
1#define _GNU_SOURCE
2#include <sched.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <signal.h>
7#include <errno.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <sys/ioctl.h>
12#include <sys/prctl.h>
13#include <sys/wait.h>
14
15#define pr_err(fmt, ...) \
16 ({ \
17 fprintf(stderr, "%s:%d:" fmt ": %m\n", \
18 __func__, __LINE__, ##__VA_ARGS__); \
19 1; \
20 })
21
22#define NSIO 0xb7
23#define NS_GET_USERNS _IO(NSIO, 0x1)
24#define NS_GET_PARENT _IO(NSIO, 0x2)
25
26#define __stack_aligned__ __attribute__((aligned(16)))
27struct cr_clone_arg {
28 char stack[128] __stack_aligned__;
29 char stack_ptr[0];
30};
31
32static int child(void *args)
33{
34 prctl(PR_SET_PDEATHSIG, SIGKILL);
35 while (1)
36 sleep(1);
37 exit(0);
38}
39
40int main(int argc, char *argv[])
41{
42 char *ns_strs[] = {"pid", "user"};
43 char path[] = "/proc/0123456789/ns/pid";
44 struct cr_clone_arg ca;
45 struct stat st1, st2;
46 int ns, pns, i;
47 pid_t pid;
48
49 pid = clone(child, ca.stack_ptr, CLONE_NEWUSER | CLONE_NEWPID | SIGCHLD, NULL);
50 if (pid < 0)
51 return pr_err("clone");
52
53 for (i = 0; i < 2; i++) {
54 snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns_strs[i]);
55 ns = open(path, O_RDONLY);
56 if (ns < 0)
57 return pr_err("Unable to open %s", path);
58
59 pns = ioctl(ns, NS_GET_PARENT);
60 if (pns < 0)
61 return pr_err("Unable to get a parent pidns");
62
63 snprintf(path, sizeof(path), "/proc/self/ns/%s", ns_strs[i]);
64 if (stat(path, &st2))
65 return pr_err("Unable to stat %s", path);
66 if (fstat(pns, &st1))
67 return pr_err("Unable to stat the parent pidns");
68 if (st1.st_ino != st2.st_ino)
69 return pr_err("NS_GET_PARENT returned a wrong namespace");
70
71 if (ioctl(pns, NS_GET_PARENT) >= 0 || errno != EPERM)
72 return pr_err("Don't get EPERM");;
73 }
74
75 kill(pid, SIGKILL);
76 wait(NULL);
77 return 0;
78}
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 1cc6d64c39b7..db54a33f850f 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -19,6 +19,7 @@ SUB_DIRS = alignment \
19 dscr \ 19 dscr \
20 mm \ 20 mm \
21 pmu \ 21 pmu \
22 signal \
22 primitives \ 23 primitives \
23 stringloops \ 24 stringloops \
24 switch_endian \ 25 switch_endian \
diff --git a/tools/testing/selftests/powerpc/copyloops/asm/export.h b/tools/testing/selftests/powerpc/copyloops/asm/export.h
new file mode 100644
index 000000000000..2d14a9b4248c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/asm/export.h
@@ -0,0 +1 @@
#define EXPORT_SYMBOL(x)
diff --git a/tools/testing/selftests/powerpc/fpu_asm.h b/tools/testing/selftests/powerpc/fpu_asm.h
new file mode 100644
index 000000000000..6a387d255e27
--- /dev/null
+++ b/tools/testing/selftests/powerpc/fpu_asm.h
@@ -0,0 +1,80 @@
1/*
2 * Copyright 2016, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#ifndef _SELFTESTS_POWERPC_FPU_ASM_H
11#define _SELFTESTS_POWERPC_FPU_ASM_H
12#include "basic_asm.h"
13
14#define PUSH_FPU(stack_size) \
15 stfd f31,(stack_size + STACK_FRAME_MIN_SIZE)(%r1); \
16 stfd f30,(stack_size + STACK_FRAME_MIN_SIZE - 8)(%r1); \
17 stfd f29,(stack_size + STACK_FRAME_MIN_SIZE - 16)(%r1); \
18 stfd f28,(stack_size + STACK_FRAME_MIN_SIZE - 24)(%r1); \
19 stfd f27,(stack_size + STACK_FRAME_MIN_SIZE - 32)(%r1); \
20 stfd f26,(stack_size + STACK_FRAME_MIN_SIZE - 40)(%r1); \
21 stfd f25,(stack_size + STACK_FRAME_MIN_SIZE - 48)(%r1); \
22 stfd f24,(stack_size + STACK_FRAME_MIN_SIZE - 56)(%r1); \
23 stfd f23,(stack_size + STACK_FRAME_MIN_SIZE - 64)(%r1); \
24 stfd f22,(stack_size + STACK_FRAME_MIN_SIZE - 72)(%r1); \
25 stfd f21,(stack_size + STACK_FRAME_MIN_SIZE - 80)(%r1); \
26 stfd f20,(stack_size + STACK_FRAME_MIN_SIZE - 88)(%r1); \
27 stfd f19,(stack_size + STACK_FRAME_MIN_SIZE - 96)(%r1); \
28 stfd f18,(stack_size + STACK_FRAME_MIN_SIZE - 104)(%r1); \
29 stfd f17,(stack_size + STACK_FRAME_MIN_SIZE - 112)(%r1); \
30 stfd f16,(stack_size + STACK_FRAME_MIN_SIZE - 120)(%r1); \
31 stfd f15,(stack_size + STACK_FRAME_MIN_SIZE - 128)(%r1); \
32 stfd f14,(stack_size + STACK_FRAME_MIN_SIZE - 136)(%r1);
33
34#define POP_FPU(stack_size) \
35 lfd f31,(stack_size + STACK_FRAME_MIN_SIZE)(%r1); \
36 lfd f30,(stack_size + STACK_FRAME_MIN_SIZE - 8)(%r1); \
37 lfd f29,(stack_size + STACK_FRAME_MIN_SIZE - 16)(%r1); \
38 lfd f28,(stack_size + STACK_FRAME_MIN_SIZE - 24)(%r1); \
39 lfd f27,(stack_size + STACK_FRAME_MIN_SIZE - 32)(%r1); \
40 lfd f26,(stack_size + STACK_FRAME_MIN_SIZE - 40)(%r1); \
41 lfd f25,(stack_size + STACK_FRAME_MIN_SIZE - 48)(%r1); \
42 lfd f24,(stack_size + STACK_FRAME_MIN_SIZE - 56)(%r1); \
43 lfd f23,(stack_size + STACK_FRAME_MIN_SIZE - 64)(%r1); \
44 lfd f22,(stack_size + STACK_FRAME_MIN_SIZE - 72)(%r1); \
45 lfd f21,(stack_size + STACK_FRAME_MIN_SIZE - 80)(%r1); \
46 lfd f20,(stack_size + STACK_FRAME_MIN_SIZE - 88)(%r1); \
47 lfd f19,(stack_size + STACK_FRAME_MIN_SIZE - 96)(%r1); \
48 lfd f18,(stack_size + STACK_FRAME_MIN_SIZE - 104)(%r1); \
49 lfd f17,(stack_size + STACK_FRAME_MIN_SIZE - 112)(%r1); \
50 lfd f16,(stack_size + STACK_FRAME_MIN_SIZE - 120)(%r1); \
51 lfd f15,(stack_size + STACK_FRAME_MIN_SIZE - 128)(%r1); \
52 lfd f14,(stack_size + STACK_FRAME_MIN_SIZE - 136)(%r1);
53
54/*
55 * Careful calling this, it will 'clobber' fpu (by design)
56 * Don't call this from C
57 */
58FUNC_START(load_fpu)
59 lfd f14,0(r3)
60 lfd f15,8(r3)
61 lfd f16,16(r3)
62 lfd f17,24(r3)
63 lfd f18,32(r3)
64 lfd f19,40(r3)
65 lfd f20,48(r3)
66 lfd f21,56(r3)
67 lfd f22,64(r3)
68 lfd f23,72(r3)
69 lfd f24,80(r3)
70 lfd f25,88(r3)
71 lfd f26,96(r3)
72 lfd f27,104(r3)
73 lfd f28,112(r3)
74 lfd f29,120(r3)
75 lfd f30,128(r3)
76 lfd f31,136(r3)
77 blr
78FUNC_END(load_fpu)
79
80#endif /* _SELFTESTS_POWERPC_FPU_ASM_H */
diff --git a/tools/testing/selftests/powerpc/gpr_asm.h b/tools/testing/selftests/powerpc/gpr_asm.h
new file mode 100644
index 000000000000..f6f38852d3a0
--- /dev/null
+++ b/tools/testing/selftests/powerpc/gpr_asm.h
@@ -0,0 +1,96 @@
1/*
2 * Copyright 2016, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#ifndef _SELFTESTS_POWERPC_GPR_ASM_H
11#define _SELFTESTS_POWERPC_GPR_ASM_H
12
13#include "basic_asm.h"
14
15#define __PUSH_NVREGS(top_pos); \
16 std r31,(top_pos)(%r1); \
17 std r30,(top_pos - 8)(%r1); \
18 std r29,(top_pos - 16)(%r1); \
19 std r28,(top_pos - 24)(%r1); \
20 std r27,(top_pos - 32)(%r1); \
21 std r26,(top_pos - 40)(%r1); \
22 std r25,(top_pos - 48)(%r1); \
23 std r24,(top_pos - 56)(%r1); \
24 std r23,(top_pos - 64)(%r1); \
25 std r22,(top_pos - 72)(%r1); \
26 std r21,(top_pos - 80)(%r1); \
27 std r20,(top_pos - 88)(%r1); \
28 std r19,(top_pos - 96)(%r1); \
29 std r18,(top_pos - 104)(%r1); \
30 std r17,(top_pos - 112)(%r1); \
31 std r16,(top_pos - 120)(%r1); \
32 std r15,(top_pos - 128)(%r1); \
33 std r14,(top_pos - 136)(%r1)
34
35#define __POP_NVREGS(top_pos); \
36 ld r31,(top_pos)(%r1); \
37 ld r30,(top_pos - 8)(%r1); \
38 ld r29,(top_pos - 16)(%r1); \
39 ld r28,(top_pos - 24)(%r1); \
40 ld r27,(top_pos - 32)(%r1); \
41 ld r26,(top_pos - 40)(%r1); \
42 ld r25,(top_pos - 48)(%r1); \
43 ld r24,(top_pos - 56)(%r1); \
44 ld r23,(top_pos - 64)(%r1); \
45 ld r22,(top_pos - 72)(%r1); \
46 ld r21,(top_pos - 80)(%r1); \
47 ld r20,(top_pos - 88)(%r1); \
48 ld r19,(top_pos - 96)(%r1); \
49 ld r18,(top_pos - 104)(%r1); \
50 ld r17,(top_pos - 112)(%r1); \
51 ld r16,(top_pos - 120)(%r1); \
52 ld r15,(top_pos - 128)(%r1); \
53 ld r14,(top_pos - 136)(%r1)
54
55#define PUSH_NVREGS(stack_size) \
56 __PUSH_NVREGS(stack_size + STACK_FRAME_MIN_SIZE)
57
58/* 18 NV FPU REGS */
59#define PUSH_NVREGS_BELOW_FPU(stack_size) \
60 __PUSH_NVREGS(stack_size + STACK_FRAME_MIN_SIZE - (18 * 8))
61
62#define POP_NVREGS(stack_size) \
63 __POP_NVREGS(stack_size + STACK_FRAME_MIN_SIZE)
64
65/* 18 NV FPU REGS */
66#define POP_NVREGS_BELOW_FPU(stack_size) \
67 __POP_NVREGS(stack_size + STACK_FRAME_MIN_SIZE - (18 * 8))
68
69/*
70 * Careful calling this, it will 'clobber' NVGPRs (by design)
71 * Don't call this from C
72 */
73FUNC_START(load_gpr)
74 ld r14,0(r3)
75 ld r15,8(r3)
76 ld r16,16(r3)
77 ld r17,24(r3)
78 ld r18,32(r3)
79 ld r19,40(r3)
80 ld r20,48(r3)
81 ld r21,56(r3)
82 ld r22,64(r3)
83 ld r23,72(r3)
84 ld r24,80(r3)
85 ld r25,88(r3)
86 ld r26,96(r3)
87 ld r27,104(r3)
88 ld r28,112(r3)
89 ld r29,120(r3)
90 ld r30,128(r3)
91 ld r31,136(r3)
92 blr
93FUNC_END(load_gpr)
94
95
96#endif /* _SELFTESTS_POWERPC_GPR_ASM_H */
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c
index 52f9be7f61f0..248a820048df 100644
--- a/tools/testing/selftests/powerpc/harness.c
+++ b/tools/testing/selftests/powerpc/harness.c
@@ -19,9 +19,9 @@
19#include "subunit.h" 19#include "subunit.h"
20#include "utils.h" 20#include "utils.h"
21 21
22#define TIMEOUT 120
23#define KILL_TIMEOUT 5 22#define KILL_TIMEOUT 5
24 23
24static uint64_t timeout = 120;
25 25
26int run_test(int (test_function)(void), char *name) 26int run_test(int (test_function)(void), char *name)
27{ 27{
@@ -44,7 +44,7 @@ int run_test(int (test_function)(void), char *name)
44 setpgid(pid, pid); 44 setpgid(pid, pid);
45 45
46 /* Wake us up in timeout seconds */ 46 /* Wake us up in timeout seconds */
47 alarm(TIMEOUT); 47 alarm(timeout);
48 terminated = false; 48 terminated = false;
49 49
50wait: 50wait:
@@ -94,6 +94,11 @@ static struct sigaction alarm_action = {
94 .sa_handler = alarm_handler, 94 .sa_handler = alarm_handler,
95}; 95};
96 96
97void test_harness_set_timeout(uint64_t time)
98{
99 timeout = time;
100}
101
97int test_harness(int (test_function)(void), char *name) 102int test_harness(int (test_function)(void), char *name)
98{ 103{
99 int rc; 104 int rc;
diff --git a/tools/testing/selftests/powerpc/math/.gitignore b/tools/testing/selftests/powerpc/math/.gitignore
index 4fe13a439fd7..50ded63e25b7 100644
--- a/tools/testing/selftests/powerpc/math/.gitignore
+++ b/tools/testing/selftests/powerpc/math/.gitignore
@@ -4,3 +4,4 @@ fpu_preempt
4vmx_preempt 4vmx_preempt
5fpu_signal 5fpu_signal
6vmx_signal 6vmx_signal
7vsx_preempt
diff --git a/tools/testing/selftests/powerpc/math/Makefile b/tools/testing/selftests/powerpc/math/Makefile
index 5b88875d5955..a505b66d408a 100644
--- a/tools/testing/selftests/powerpc/math/Makefile
+++ b/tools/testing/selftests/powerpc/math/Makefile
@@ -1,4 +1,4 @@
1TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal 1TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal vsx_preempt
2 2
3all: $(TEST_PROGS) 3all: $(TEST_PROGS)
4 4
@@ -13,6 +13,9 @@ vmx_syscall: vmx_asm.S
13vmx_preempt: vmx_asm.S 13vmx_preempt: vmx_asm.S
14vmx_signal: vmx_asm.S 14vmx_signal: vmx_asm.S
15 15
16vsx_preempt: CFLAGS += -mvsx
17vsx_preempt: vsx_asm.S
18
16include ../../lib.mk 19include ../../lib.mk
17 20
18clean: 21clean:
diff --git a/tools/testing/selftests/powerpc/math/fpu_asm.S b/tools/testing/selftests/powerpc/math/fpu_asm.S
index f3711d80e709..241f067a510f 100644
--- a/tools/testing/selftests/powerpc/math/fpu_asm.S
+++ b/tools/testing/selftests/powerpc/math/fpu_asm.S
@@ -8,70 +8,7 @@
8 */ 8 */
9 9
10#include "../basic_asm.h" 10#include "../basic_asm.h"
11 11#include "../fpu_asm.h"
12#define PUSH_FPU(pos) \
13 stfd f14,pos(sp); \
14 stfd f15,pos+8(sp); \
15 stfd f16,pos+16(sp); \
16 stfd f17,pos+24(sp); \
17 stfd f18,pos+32(sp); \
18 stfd f19,pos+40(sp); \
19 stfd f20,pos+48(sp); \
20 stfd f21,pos+56(sp); \
21 stfd f22,pos+64(sp); \
22 stfd f23,pos+72(sp); \
23 stfd f24,pos+80(sp); \
24 stfd f25,pos+88(sp); \
25 stfd f26,pos+96(sp); \
26 stfd f27,pos+104(sp); \
27 stfd f28,pos+112(sp); \
28 stfd f29,pos+120(sp); \
29 stfd f30,pos+128(sp); \
30 stfd f31,pos+136(sp);
31
32#define POP_FPU(pos) \
33 lfd f14,pos(sp); \
34 lfd f15,pos+8(sp); \
35 lfd f16,pos+16(sp); \
36 lfd f17,pos+24(sp); \
37 lfd f18,pos+32(sp); \
38 lfd f19,pos+40(sp); \
39 lfd f20,pos+48(sp); \
40 lfd f21,pos+56(sp); \
41 lfd f22,pos+64(sp); \
42 lfd f23,pos+72(sp); \
43 lfd f24,pos+80(sp); \
44 lfd f25,pos+88(sp); \
45 lfd f26,pos+96(sp); \
46 lfd f27,pos+104(sp); \
47 lfd f28,pos+112(sp); \
48 lfd f29,pos+120(sp); \
49 lfd f30,pos+128(sp); \
50 lfd f31,pos+136(sp);
51
52# Careful calling this, it will 'clobber' fpu (by design)
53# Don't call this from C
54FUNC_START(load_fpu)
55 lfd f14,0(r3)
56 lfd f15,8(r3)
57 lfd f16,16(r3)
58 lfd f17,24(r3)
59 lfd f18,32(r3)
60 lfd f19,40(r3)
61 lfd f20,48(r3)
62 lfd f21,56(r3)
63 lfd f22,64(r3)
64 lfd f23,72(r3)
65 lfd f24,80(r3)
66 lfd f25,88(r3)
67 lfd f26,96(r3)
68 lfd f27,104(r3)
69 lfd f28,112(r3)
70 lfd f29,120(r3)
71 lfd f30,128(r3)
72 lfd f31,136(r3)
73 blr
74FUNC_END(load_fpu)
75 12
76FUNC_START(check_fpu) 13FUNC_START(check_fpu)
77 mr r4,r3 14 mr r4,r3
@@ -138,9 +75,9 @@ FUNC_START(test_fpu)
138 # r4 holds pointer to the pid 75 # r4 holds pointer to the pid
139 # f14-f31 are non volatiles 76 # f14-f31 are non volatiles
140 PUSH_BASIC_STACK(256) 77 PUSH_BASIC_STACK(256)
78 PUSH_FPU(256)
141 std r3,STACK_FRAME_PARAM(0)(sp) # Address of darray 79 std r3,STACK_FRAME_PARAM(0)(sp) # Address of darray
142 std r4,STACK_FRAME_PARAM(1)(sp) # Address of pid 80 std r4,STACK_FRAME_PARAM(1)(sp) # Address of pid
143 PUSH_FPU(STACK_FRAME_LOCAL(2,0))
144 81
145 bl load_fpu 82 bl load_fpu
146 nop 83 nop
@@ -155,7 +92,7 @@ FUNC_START(test_fpu)
155 bl check_fpu 92 bl check_fpu
156 nop 93 nop
157 94
158 POP_FPU(STACK_FRAME_LOCAL(2,0)) 95 POP_FPU(256)
159 POP_BASIC_STACK(256) 96 POP_BASIC_STACK(256)
160 blr 97 blr
161FUNC_END(test_fpu) 98FUNC_END(test_fpu)
@@ -166,10 +103,10 @@ FUNC_END(test_fpu)
166# registers while running is not zero. 103# registers while running is not zero.
167FUNC_START(preempt_fpu) 104FUNC_START(preempt_fpu)
168 PUSH_BASIC_STACK(256) 105 PUSH_BASIC_STACK(256)
106 PUSH_FPU(256)
169 std r3,STACK_FRAME_PARAM(0)(sp) # double *darray 107 std r3,STACK_FRAME_PARAM(0)(sp) # double *darray
170 std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting 108 std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting
171 std r5,STACK_FRAME_PARAM(2)(sp) # int *running 109 std r5,STACK_FRAME_PARAM(2)(sp) # int *running
172 PUSH_FPU(STACK_FRAME_LOCAL(3,0))
173 110
174 bl load_fpu 111 bl load_fpu
175 nop 112 nop
@@ -192,7 +129,7 @@ FUNC_START(preempt_fpu)
192 cmpwi r5,0 129 cmpwi r5,0
193 bne 2b 130 bne 2b
194 131
1953: POP_FPU(STACK_FRAME_LOCAL(3,0)) 1323: POP_FPU(256)
196 POP_BASIC_STACK(256) 133 POP_BASIC_STACK(256)
197 blr 134 blr
198FUNC_END(preempt_fpu) 135FUNC_END(preempt_fpu)
diff --git a/tools/testing/selftests/powerpc/math/vmx_asm.S b/tools/testing/selftests/powerpc/math/vmx_asm.S
index 1b8c248b3ac1..fd74da488625 100644
--- a/tools/testing/selftests/powerpc/math/vmx_asm.S
+++ b/tools/testing/selftests/powerpc/math/vmx_asm.S
@@ -8,90 +8,7 @@
8 */ 8 */
9 9
10#include "../basic_asm.h" 10#include "../basic_asm.h"
11 11#include "../vmx_asm.h"
12# POS MUST BE 16 ALIGNED!
13#define PUSH_VMX(pos,reg) \
14 li reg,pos; \
15 stvx v20,reg,sp; \
16 addi reg,reg,16; \
17 stvx v21,reg,sp; \
18 addi reg,reg,16; \
19 stvx v22,reg,sp; \
20 addi reg,reg,16; \
21 stvx v23,reg,sp; \
22 addi reg,reg,16; \
23 stvx v24,reg,sp; \
24 addi reg,reg,16; \
25 stvx v25,reg,sp; \
26 addi reg,reg,16; \
27 stvx v26,reg,sp; \
28 addi reg,reg,16; \
29 stvx v27,reg,sp; \
30 addi reg,reg,16; \
31 stvx v28,reg,sp; \
32 addi reg,reg,16; \
33 stvx v29,reg,sp; \
34 addi reg,reg,16; \
35 stvx v30,reg,sp; \
36 addi reg,reg,16; \
37 stvx v31,reg,sp;
38
39# POS MUST BE 16 ALIGNED!
40#define POP_VMX(pos,reg) \
41 li reg,pos; \
42 lvx v20,reg,sp; \
43 addi reg,reg,16; \
44 lvx v21,reg,sp; \
45 addi reg,reg,16; \
46 lvx v22,reg,sp; \
47 addi reg,reg,16; \
48 lvx v23,reg,sp; \
49 addi reg,reg,16; \
50 lvx v24,reg,sp; \
51 addi reg,reg,16; \
52 lvx v25,reg,sp; \
53 addi reg,reg,16; \
54 lvx v26,reg,sp; \
55 addi reg,reg,16; \
56 lvx v27,reg,sp; \
57 addi reg,reg,16; \
58 lvx v28,reg,sp; \
59 addi reg,reg,16; \
60 lvx v29,reg,sp; \
61 addi reg,reg,16; \
62 lvx v30,reg,sp; \
63 addi reg,reg,16; \
64 lvx v31,reg,sp;
65
66# Carefull this will 'clobber' vmx (by design)
67# Don't call this from C
68FUNC_START(load_vmx)
69 li r5,0
70 lvx v20,r5,r3
71 addi r5,r5,16
72 lvx v21,r5,r3
73 addi r5,r5,16
74 lvx v22,r5,r3
75 addi r5,r5,16
76 lvx v23,r5,r3
77 addi r5,r5,16
78 lvx v24,r5,r3
79 addi r5,r5,16
80 lvx v25,r5,r3
81 addi r5,r5,16
82 lvx v26,r5,r3
83 addi r5,r5,16
84 lvx v27,r5,r3
85 addi r5,r5,16
86 lvx v28,r5,r3
87 addi r5,r5,16
88 lvx v29,r5,r3
89 addi r5,r5,16
90 lvx v30,r5,r3
91 addi r5,r5,16
92 lvx v31,r5,r3
93 blr
94FUNC_END(load_vmx)
95 12
96# Should be safe from C, only touches r4, r5 and v0,v1,v2 13# Should be safe from C, only touches r4, r5 and v0,v1,v2
97FUNC_START(check_vmx) 14FUNC_START(check_vmx)
diff --git a/tools/testing/selftests/powerpc/math/vsx_asm.S b/tools/testing/selftests/powerpc/math/vsx_asm.S
new file mode 100644
index 000000000000..a110dd882d5e
--- /dev/null
+++ b/tools/testing/selftests/powerpc/math/vsx_asm.S
@@ -0,0 +1,61 @@
1/*
2 * Copyright 2015, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include "../basic_asm.h"
11#include "../vsx_asm.h"
12
13#long check_vsx(vector int *r3);
14#This function wraps storeing VSX regs to the end of an array and a
15#call to a comparison function in C which boils down to a memcmp()
16FUNC_START(check_vsx)
17 PUSH_BASIC_STACK(32)
18 std r3,STACK_FRAME_PARAM(0)(sp)
19 addi r3, r3, 16 * 12 #Second half of array
20 bl store_vsx
21 ld r3,STACK_FRAME_PARAM(0)(sp)
22 bl vsx_memcmp
23 POP_BASIC_STACK(32)
24 blr
25FUNC_END(check_vsx)
26
27# int preempt_vmx(vector int *varray, int *threads_starting,
28# int *running);
29# On starting will (atomically) decrement threads_starting as a signal
30# that the VMX have been loaded with varray. Will proceed to check the
31# validity of the VMX registers while running is not zero.
32FUNC_START(preempt_vsx)
33 PUSH_BASIC_STACK(512)
34 std r3,STACK_FRAME_PARAM(0)(sp) # vector int *varray
35 std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting
36 std r5,STACK_FRAME_PARAM(2)(sp) # int *running
37
38 bl load_vsx
39 nop
40
41 sync
42 # Atomic DEC
43 ld r3,STACK_FRAME_PARAM(1)(sp)
441: lwarx r4,0,r3
45 addi r4,r4,-1
46 stwcx. r4,0,r3
47 bne- 1b
48
492: ld r3,STACK_FRAME_PARAM(0)(sp)
50 bl check_vsx
51 nop
52 cmpdi r3,0
53 bne 3f
54 ld r4,STACK_FRAME_PARAM(2)(sp)
55 ld r5,0(r4)
56 cmpwi r5,0
57 bne 2b
58
593: POP_BASIC_STACK(512)
60 blr
61FUNC_END(preempt_vsx)
diff --git a/tools/testing/selftests/powerpc/math/vsx_preempt.c b/tools/testing/selftests/powerpc/math/vsx_preempt.c
new file mode 100644
index 000000000000..6387f03a0a6a
--- /dev/null
+++ b/tools/testing/selftests/powerpc/math/vsx_preempt.c
@@ -0,0 +1,147 @@
1/*
2 * Copyright 2015, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * This test attempts to see if the VSX registers change across preemption.
10 * There is no way to be sure preemption happened so this test just
11 * uses many threads and a long wait. As such, a successful test
12 * doesn't mean much but a failure is bad.
13 */
14
15#include <stdio.h>
16#include <string.h>
17#include <unistd.h>
18#include <sys/syscall.h>
19#include <sys/time.h>
20#include <sys/types.h>
21#include <sys/wait.h>
22#include <stdlib.h>
23#include <pthread.h>
24
25#include "utils.h"
26
27/* Time to wait for workers to get preempted (seconds) */
28#define PREEMPT_TIME 20
29/*
30 * Factor by which to multiply number of online CPUs for total number of
31 * worker threads
32 */
33#define THREAD_FACTOR 8
34
35/*
36 * Ensure there is twice the number of non-volatile VMX regs!
37 * check_vmx() is going to use the other half as space to put the live
38 * registers before calling vsx_memcmp()
39 */
40__thread vector int varray[24] = {
41 {1, 2, 3, 4 }, {5, 6, 7, 8 }, {9, 10,11,12},
42 {13,14,15,16}, {17,18,19,20}, {21,22,23,24},
43 {25,26,27,28}, {29,30,31,32}, {33,34,35,36},
44 {37,38,39,40}, {41,42,43,44}, {45,46,47,48}
45};
46
47int threads_starting;
48int running;
49
50extern long preempt_vsx(vector int *varray, int *threads_starting, int *running);
51
52long vsx_memcmp(vector int *a) {
53 vector int zero = {0, 0, 0, 0};
54 int i;
55
56 FAIL_IF(a != varray);
57
58 for(i = 0; i < 12; i++) {
59 if (memcmp(&a[i + 12], &zero, sizeof(vector int)) == 0) {
60 fprintf(stderr, "Detected zero from the VSX reg %d\n", i + 12);
61 return 2;
62 }
63 }
64
65 if (memcmp(a, &a[12], 12 * sizeof(vector int))) {
66 long *p = (long *)a;
67 fprintf(stderr, "VSX mismatch\n");
68 for (i = 0; i < 24; i=i+2)
69 fprintf(stderr, "%d: 0x%08lx%08lx | 0x%08lx%08lx\n",
70 i/2 + i%2 + 20, p[i], p[i + 1], p[i + 24], p[i + 25]);
71 return 1;
72 }
73 return 0;
74}
75
76void *preempt_vsx_c(void *p)
77{
78 int i, j;
79 long rc;
80 srand(pthread_self());
81 for (i = 0; i < 12; i++)
82 for (j = 0; j < 4; j++) {
83 varray[i][j] = rand();
84 /* Don't want zero because it hides kernel problems */
85 if (varray[i][j] == 0)
86 j--;
87 }
88 rc = preempt_vsx(varray, &threads_starting, &running);
89 if (rc == 2)
90 fprintf(stderr, "Caught zeros in VSX compares\n");
91 return (void *)rc;
92}
93
94int test_preempt_vsx(void)
95{
96 int i, rc, threads;
97 pthread_t *tids;
98
99 threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR;
100 tids = malloc(threads * sizeof(pthread_t));
101 FAIL_IF(!tids);
102
103 running = true;
104 threads_starting = threads;
105 for (i = 0; i < threads; i++) {
106 rc = pthread_create(&tids[i], NULL, preempt_vsx_c, NULL);
107 FAIL_IF(rc);
108 }
109
110 setbuf(stdout, NULL);
111 /* Not really nessesary but nice to wait for every thread to start */
112 printf("\tWaiting for %d workers to start...", threads_starting);
113 while(threads_starting)
114 asm volatile("": : :"memory");
115 printf("done\n");
116
117 printf("\tWaiting for %d seconds to let some workers get preempted...", PREEMPT_TIME);
118 sleep(PREEMPT_TIME);
119 printf("done\n");
120
121 printf("\tStopping workers...");
122 /*
123 * Working are checking this value every loop. In preempt_vsx 'cmpwi r5,0; bne 2b'.
124 * r5 will have loaded the value of running.
125 */
126 running = 0;
127 for (i = 0; i < threads; i++) {
128 void *rc_p;
129 pthread_join(tids[i], &rc_p);
130
131 /*
132 * Harness will say the fail was here, look at why preempt_vsx
133 * returned
134 */
135 if ((long) rc_p)
136 printf("oops\n");
137 FAIL_IF((long) rc_p);
138 }
139 printf("done\n");
140
141 return 0;
142}
143
144int main(int argc, char *argv[])
145{
146 return test_harness(test_preempt_vsx, "vsx_preempt");
147}
diff --git a/tools/testing/selftests/powerpc/signal/.gitignore b/tools/testing/selftests/powerpc/signal/.gitignore
new file mode 100644
index 000000000000..1b89224a8aab
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/.gitignore
@@ -0,0 +1,2 @@
1signal
2signal_tm
diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile
new file mode 100644
index 000000000000..f0eef27458e2
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/Makefile
@@ -0,0 +1,13 @@
1TEST_PROGS := signal signal_tm
2
3all: $(TEST_PROGS)
4
5$(TEST_PROGS): ../harness.c ../utils.c signal.S
6
7CFLAGS += -maltivec
8signal_tm: CFLAGS += -mhtm
9
10include ../../lib.mk
11
12clean:
13 rm -f $(TEST_PROGS) *.o
diff --git a/tools/testing/selftests/powerpc/signal/signal.S b/tools/testing/selftests/powerpc/signal/signal.S
new file mode 100644
index 000000000000..7043d521df0a
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/signal.S
@@ -0,0 +1,50 @@
1/*
2 * Copyright 2015, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include "../basic_asm.h"
11
12/* long signal_self(pid_t pid, int sig); */
13FUNC_START(signal_self)
14 li r0,37 /* sys_kill */
15 /* r3 already has our pid in it */
16 /* r4 already has signal type in it */
17 sc
18 bc 4,3,1f
19 subfze r3,r3
201: blr
21FUNC_END(signal_self)
22
23/* long tm_signal_self(pid_t pid, int sig, int *ret); */
24FUNC_START(tm_signal_self)
25 PUSH_BASIC_STACK(8)
26 std r5,STACK_FRAME_PARAM(0)(sp) /* ret */
27 tbegin.
28 beq 1f
29 tsuspend.
30 li r0,37 /* sys_kill */
31 /* r3 already has our pid in it */
32 /* r4 already has signal type in it */
33 sc
34 ld r5,STACK_FRAME_PARAM(0)(sp) /* ret */
35 bc 4,3,2f
36 subfze r3,r3
372: std r3,0(r5)
38 tabort. 0
39 tresume. /* Be nice to some cleanup, jumps back to tbegin then to 1: */
40 /*
41 * Transaction should be proper doomed and we should never get
42 * here
43 */
44 li r3,1
45 POP_BASIC_STACK(8)
46 blr
471: li r3,0
48 POP_BASIC_STACK(8)
49 blr
50FUNC_END(tm_signal_self)
diff --git a/tools/testing/selftests/powerpc/signal/signal.c b/tools/testing/selftests/powerpc/signal/signal.c
new file mode 100644
index 000000000000..e7dedd28b3c2
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/signal.c
@@ -0,0 +1,111 @@
1/*
2 * Copyright 2016, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Sending one self a signal should always get delivered.
10 */
11
12#include <signal.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/types.h>
17#include <sys/wait.h>
18#include <unistd.h>
19
20#include <altivec.h>
21
22#include "utils.h"
23
24#define MAX_ATTEMPT 500000
25#define TIMEOUT 5
26
27extern long signal_self(pid_t pid, int sig);
28
29static sig_atomic_t signaled;
30static sig_atomic_t fail;
31
32static void signal_handler(int sig)
33{
34 if (sig == SIGUSR1)
35 signaled = 1;
36 else
37 fail = 1;
38}
39
40static int test_signal()
41{
42 int i;
43 struct sigaction act;
44 pid_t ppid = getpid();
45 pid_t pid;
46
47 act.sa_handler = signal_handler;
48 act.sa_flags = 0;
49 sigemptyset(&act.sa_mask);
50 if (sigaction(SIGUSR1, &act, NULL) < 0) {
51 perror("sigaction SIGUSR1");
52 exit(1);
53 }
54 if (sigaction(SIGALRM, &act, NULL) < 0) {
55 perror("sigaction SIGALRM");
56 exit(1);
57 }
58
59 /* Don't do this for MAX_ATTEMPT, its simply too long */
60 for(i = 0; i < 1000; i++) {
61 pid = fork();
62 if (pid == -1) {
63 perror("fork");
64 exit(1);
65 }
66 if (pid == 0) {
67 signal_self(ppid, SIGUSR1);
68 exit(1);
69 } else {
70 alarm(0); /* Disable any pending */
71 alarm(2);
72 while (!signaled && !fail)
73 asm volatile("": : :"memory");
74 if (!signaled) {
75 fprintf(stderr, "Didn't get signal from child\n");
76 FAIL_IF(1); /* For the line number */
77 }
78 /* Otherwise we'll loop too fast and fork() will eventually fail */
79 waitpid(pid, NULL, 0);
80 }
81 }
82
83 for (i = 0; i < MAX_ATTEMPT; i++) {
84 long rc;
85
86 alarm(0); /* Disable any pending */
87 signaled = 0;
88 alarm(TIMEOUT);
89 rc = signal_self(ppid, SIGUSR1);
90 if (rc) {
91 fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx",
92 i, fail, rc);
93 FAIL_IF(1); /* For the line number */
94 }
95 while (!signaled && !fail)
96 asm volatile("": : :"memory");
97 if (!signaled) {
98 fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx",
99 i, fail, rc);
100 FAIL_IF(1); /* For the line number */
101 }
102 }
103
104 return 0;
105}
106
107int main(void)
108{
109 test_harness_set_timeout(300);
110 return test_harness(test_signal, "signal");
111}
diff --git a/tools/testing/selftests/powerpc/signal/signal_tm.c b/tools/testing/selftests/powerpc/signal/signal_tm.c
new file mode 100644
index 000000000000..2e7451a37cc6
--- /dev/null
+++ b/tools/testing/selftests/powerpc/signal/signal_tm.c
@@ -0,0 +1,110 @@
1/*
2 * Copyright 2016, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Sending one self a signal should always get delivered.
10 */
11
12#include <errno.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16#include <signal.h>
17#include <unistd.h>
18
19#include <altivec.h>
20
21#include "utils.h"
22#include "../tm/tm.h"
23
24#define MAX_ATTEMPT 500000
25#define TIMEOUT 10
26
27extern long tm_signal_self(pid_t pid, int sig, long *ret);
28
29static sig_atomic_t signaled;
30static sig_atomic_t fail;
31
32static void signal_handler(int sig)
33{
34 if (tcheck_active()) {
35 fail = 2;
36 return;
37 }
38
39 if (sig == SIGUSR1)
40 signaled = 1;
41 else
42 fail = 1;
43}
44
45static int test_signal_tm()
46{
47 int i;
48 struct sigaction act;
49
50 act.sa_handler = signal_handler;
51 act.sa_flags = 0;
52 sigemptyset(&act.sa_mask);
53 if (sigaction(SIGUSR1, &act, NULL) < 0) {
54 perror("sigaction SIGUSR1");
55 exit(1);
56 }
57 if (sigaction(SIGALRM, &act, NULL) < 0) {
58 perror("sigaction SIGALRM");
59 exit(1);
60 }
61
62 SKIP_IF(!have_htm());
63
64 for (i = 0; i < MAX_ATTEMPT; i++) {
65 /*
66 * If anything bad happens in ASM and we fail to set ret
67 * because *handwave* TM this will cause failure
68 */
69 long ret = 0xdead;
70 long rc = 0xbeef;
71
72 alarm(0); /* Disable any pending */
73 signaled = 0;
74 alarm(TIMEOUT);
75 FAIL_IF(tcheck_transactional());
76 rc = tm_signal_self(getpid(), SIGUSR1, &ret);
77 if (ret == 0xdead)
78 /*
79 * This basically means the transaction aborted before we
80 * even got to the suspend... this is crazy but it
81 * happens.
82 * Yes this also means we might never make forward
83 * progress... the alarm() will trip eventually...
84 */
85 continue;
86
87 if (rc || ret) {
88 /* Ret is actually an errno */
89 printf("TEXASR 0x%016lx, TFIAR 0x%016lx\n",
90 __builtin_get_texasr(), __builtin_get_tfiar());
91 fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n",
92 i, fail, rc, ret);
93 FAIL_IF(ret);
94 }
95 while(!signaled && !fail)
96 asm volatile("": : :"memory");
97 if (!signaled) {
98 fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n",
99 i, fail, rc, ret);
100 FAIL_IF(fail); /* For the line number */
101 }
102 }
103
104 return 0;
105}
106
107int main(void)
108{
109 return test_harness(test_signal_tm, "signal_tm");
110}
diff --git a/tools/testing/selftests/powerpc/stringloops/asm/export.h b/tools/testing/selftests/powerpc/stringloops/asm/export.h
new file mode 100644
index 000000000000..2d14a9b4248c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/stringloops/asm/export.h
@@ -0,0 +1 @@
#define EXPORT_SYMBOL(x)
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore
index 82c0a9ce6e74..427621792229 100644
--- a/tools/testing/selftests/powerpc/tm/.gitignore
+++ b/tools/testing/selftests/powerpc/tm/.gitignore
@@ -7,3 +7,7 @@ tm-fork
7tm-tar 7tm-tar
8tm-tmspr 8tm-tmspr
9tm-exec 9tm-exec
10tm-signal-context-chk-fpu
11tm-signal-context-chk-gpr
12tm-signal-context-chk-vmx
13tm-signal-context-chk-vsx
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile
index 9d301d785d9e..c6c53c82fdd6 100644
--- a/tools/testing/selftests/powerpc/tm/Makefile
+++ b/tools/testing/selftests/powerpc/tm/Makefile
@@ -1,5 +1,8 @@
1SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu \
2 tm-signal-context-chk-vmx tm-signal-context-chk-vsx
3
1TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ 4TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \
2 tm-vmxcopy tm-fork tm-tar tm-tmspr tm-exec tm-execed 5 tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS)
3 6
4all: $(TEST_PROGS) 7all: $(TEST_PROGS)
5 8
@@ -11,6 +14,9 @@ tm-syscall: tm-syscall-asm.S
11tm-syscall: CFLAGS += -I../../../../../usr/include 14tm-syscall: CFLAGS += -I../../../../../usr/include
12tm-tmspr: CFLAGS += -pthread 15tm-tmspr: CFLAGS += -pthread
13 16
17$(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S
18$(SIGNAL_CONTEXT_CHK_TESTS): CFLAGS += -mhtm -m64 -mvsx
19
14include ../../lib.mk 20include ../../lib.mk
15 21
16clean: 22clean:
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c
new file mode 100644
index 000000000000..c760debbd5ad
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c
@@ -0,0 +1,92 @@
1/*
2 * Copyright 2016, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 *
10 * Test the kernel's signal frame code.
11 *
12 * The kernel sets up two sets of ucontexts if the signal was to be
13 * delivered while the thread was in a transaction.
14 * Expected behaviour is that the checkpointed state is in the user
15 * context passed to the signal handler. The speculated state can be
16 * accessed with the uc_link pointer.
17 *
18 * The rationale for this is that if TM unaware code (which linked
19 * against TM libs) installs a signal handler it will not know of the
20 * speculative nature of the 'live' registers and may infer the wrong
21 * thing.
22 */
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <signal.h>
27#include <unistd.h>
28
29#include <altivec.h>
30
31#include "utils.h"
32#include "tm.h"
33
34#define MAX_ATTEMPT 500000
35
36#define NV_FPU_REGS 18
37
38long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
39
40/* Be sure there are 2x as many as there are NV FPU regs (2x18) */
41static double fps[] = {
42 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
43 -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
44};
45
46static sig_atomic_t fail;
47
48static void signal_usr1(int signum, siginfo_t *info, void *uc)
49{
50 int i;
51 ucontext_t *ucp = uc;
52 ucontext_t *tm_ucp = ucp->uc_link;
53
54 for (i = 0; i < NV_FPU_REGS && !fail; i++) {
55 fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]);
56 fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + NV_FPU_REGS]);
57 if (fail)
58 printf("Failed on %d FP %g or %g\n", i, ucp->uc_mcontext.fp_regs[i + 14], tm_ucp->uc_mcontext.fp_regs[i + 14]);
59 }
60}
61
62static int tm_signal_context_chk_fpu()
63{
64 struct sigaction act;
65 int i;
66 long rc;
67 pid_t pid = getpid();
68
69 SKIP_IF(!have_htm());
70
71 act.sa_sigaction = signal_usr1;
72 sigemptyset(&act.sa_mask);
73 act.sa_flags = SA_SIGINFO;
74 if (sigaction(SIGUSR1, &act, NULL) < 0) {
75 perror("sigaction sigusr1");
76 exit(1);
77 }
78
79 i = 0;
80 while (i < MAX_ATTEMPT && !fail) {
81 rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL);
82 FAIL_IF(rc != pid);
83 i++;
84 }
85
86 return fail;
87}
88
89int main(void)
90{
91 return test_harness(tm_signal_context_chk_fpu, "tm_signal_context_chk_fpu");
92}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c
new file mode 100644
index 000000000000..df91330a08ef
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c
@@ -0,0 +1,90 @@
1/*
2 * Copyright 2016, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 *
10 * Test the kernel's signal frame code.
11 *
12 * The kernel sets up two sets of ucontexts if the signal was to be
13 * delivered while the thread was in a transaction.
14 * Expected behaviour is that the checkpointed state is in the user
15 * context passed to the signal handler. The speculated state can be
16 * accessed with the uc_link pointer.
17 *
18 * The rationale for this is that if TM unaware code (which linked
19 * against TM libs) installs a signal handler it will not know of the
20 * speculative nature of the 'live' registers and may infer the wrong
21 * thing.
22 */
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <signal.h>
27#include <unistd.h>
28
29#include <altivec.h>
30
31#include "utils.h"
32#include "tm.h"
33
34#define MAX_ATTEMPT 500000
35
36#define NV_GPR_REGS 18
37
38long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
39
40static sig_atomic_t fail;
41
42static long gps[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
43 -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18};
44
45static void signal_usr1(int signum, siginfo_t *info, void *uc)
46{
47 int i;
48 ucontext_t *ucp = uc;
49 ucontext_t *tm_ucp = ucp->uc_link;
50
51 for (i = 0; i < NV_GPR_REGS && !fail; i++) {
52 fail = (ucp->uc_mcontext.gp_regs[i + 14] != gps[i]);
53 fail |= (tm_ucp->uc_mcontext.gp_regs[i + 14] != gps[i + NV_GPR_REGS]);
54 if (fail)
55 printf("Failed on %d GPR %lu or %lu\n", i,
56 ucp->uc_mcontext.gp_regs[i + 14], tm_ucp->uc_mcontext.gp_regs[i + 14]);
57 }
58}
59
60static int tm_signal_context_chk_gpr()
61{
62 struct sigaction act;
63 int i;
64 long rc;
65 pid_t pid = getpid();
66
67 SKIP_IF(!have_htm());
68
69 act.sa_sigaction = signal_usr1;
70 sigemptyset(&act.sa_mask);
71 act.sa_flags = SA_SIGINFO;
72 if (sigaction(SIGUSR1, &act, NULL) < 0) {
73 perror("sigaction sigusr1");
74 exit(1);
75 }
76
77 i = 0;
78 while (i < MAX_ATTEMPT && !fail) {
79 rc = tm_signal_self_context_load(pid, gps, NULL, NULL, NULL);
80 FAIL_IF(rc != pid);
81 i++;
82 }
83
84 return fail;
85}
86
87int main(void)
88{
89 return test_harness(tm_signal_context_chk_gpr, "tm_signal_context_chk_gpr");
90}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c
new file mode 100644
index 000000000000..f0ee55fd5185
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c
@@ -0,0 +1,110 @@
1/*
2 * Copyright 2016, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 *
10 * Test the kernel's signal frame code.
11 *
12 * The kernel sets up two sets of ucontexts if the signal was to be
13 * delivered while the thread was in a transaction.
14 * Expected behaviour is that the checkpointed state is in the user
15 * context passed to the signal handler. The speculated state can be
16 * accessed with the uc_link pointer.
17 *
18 * The rationale for this is that if TM unaware code (which linked
19 * against TM libs) installs a signal handler it will not know of the
20 * speculative nature of the 'live' registers and may infer the wrong
21 * thing.
22 */
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <signal.h>
28#include <unistd.h>
29
30#include <altivec.h>
31
32#include "utils.h"
33#include "tm.h"
34
35#define MAX_ATTEMPT 500000
36
37#define NV_VMX_REGS 12
38
39long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
40
41static sig_atomic_t fail;
42
43vector int vms[] = {
44 {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
45 {13,14,15,16},{17,18,19,20},{21,22,23,24},
46 {25,26,27,28},{29,30,31,32},{33,34,35,36},
47 {37,38,39,40},{41,42,43,44},{45,46,47,48},
48 {-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10,-11,-12},
49 {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
50 {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
51 {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
52};
53
54static void signal_usr1(int signum, siginfo_t *info, void *uc)
55{
56 int i;
57 ucontext_t *ucp = uc;
58 ucontext_t *tm_ucp = ucp->uc_link;
59
60 for (i = 0; i < NV_VMX_REGS && !fail; i++) {
61 fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[i + 20],
62 &vms[i], sizeof(vector int));
63 fail |= memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[i + 20],
64 &vms[i + NV_VMX_REGS], sizeof (vector int));
65
66 if (fail) {
67 int j;
68
69 fprintf(stderr, "Failed on %d vmx 0x", i);
70 for (j = 0; j < 4; j++)
71 fprintf(stderr, "%04x", ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
72 fprintf(stderr, " vs 0x");
73 for (j = 0 ; j < 4; j++)
74 fprintf(stderr, "%04x", tm_ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
75 fprintf(stderr, "\n");
76 }
77 }
78}
79
80static int tm_signal_context_chk()
81{
82 struct sigaction act;
83 int i;
84 long rc;
85 pid_t pid = getpid();
86
87 SKIP_IF(!have_htm());
88
89 act.sa_sigaction = signal_usr1;
90 sigemptyset(&act.sa_mask);
91 act.sa_flags = SA_SIGINFO;
92 if (sigaction(SIGUSR1, &act, NULL) < 0) {
93 perror("sigaction sigusr1");
94 exit(1);
95 }
96
97 i = 0;
98 while (i < MAX_ATTEMPT && !fail) {
99 rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL);
100 FAIL_IF(rc != pid);
101 i++;
102 }
103
104 return fail;
105}
106
107int main(void)
108{
109 return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vmx");
110}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c
new file mode 100644
index 000000000000..b99c3d835957
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c
@@ -0,0 +1,125 @@
1/*
2 * Copyright 2016, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 *
10 * Test the kernel's signal frame code.
11 *
12 * The kernel sets up two sets of ucontexts if the signal was to be
13 * delivered while the thread was in a transaction.
14 * Expected behaviour is that the checkpointed state is in the user
15 * context passed to the signal handler. The speculated state can be
16 * accessed with the uc_link pointer.
17 *
18 * The rationale for this is that if TM unaware code (which linked
19 * against TM libs) installs a signal handler it will not know of the
20 * speculative nature of the 'live' registers and may infer the wrong
21 * thing.
22 */
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <signal.h>
28#include <unistd.h>
29
30#include <altivec.h>
31
32#include "utils.h"
33#include "tm.h"
34
35#define MAX_ATTEMPT 500000
36
37#define NV_VSX_REGS 12
38
39long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
40
41static sig_atomic_t fail;
42
43vector int vss[] = {
44 {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
45 {13,14,15,16},{17,18,19,20},{21,22,23,24},
46 {25,26,27,28},{29,30,31,32},{33,34,35,36},
47 {37,38,39,40},{41,42,43,44},{45,46,47,48},
48 {-1, -2, -3, -4 },{-5, -6, -7, -8 },{-9, -10,-11,-12},
49 {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
50 {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
51 {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
52};
53
54static void signal_usr1(int signum, siginfo_t *info, void *uc)
55{
56 int i;
57 uint8_t vsc[sizeof(vector int)];
58 uint8_t vst[sizeof(vector int)];
59 ucontext_t *ucp = uc;
60 ucontext_t *tm_ucp = ucp->uc_link;
61
62 /*
63 * The other half of the VSX regs will be after v_regs.
64 *
65 * In short, vmx_reserve array holds everything. v_regs is a 16
66 * byte aligned pointer at the start of vmx_reserve (vmx_reserve
67 * may or may not be 16 aligned) where the v_regs structure exists.
68 * (half of) The VSX regsters are directly after v_regs so the
69 * easiest way to find them below.
70 */
71 long *vsx_ptr = (long *)(ucp->uc_mcontext.v_regs + 1);
72 long *tm_vsx_ptr = (long *)(tm_ucp->uc_mcontext.v_regs + 1);
73 for (i = 0; i < NV_VSX_REGS && !fail; i++) {
74 memcpy(vsc, &ucp->uc_mcontext.fp_regs[i + 20], 8);
75 memcpy(vsc + 8, &vsx_ptr[20 + i], 8);
76 fail = memcmp(vsc, &vss[i], sizeof(vector int));
77 memcpy(vst, &tm_ucp->uc_mcontext.fp_regs[i + 20], 8);
78 memcpy(vst + 8, &tm_vsx_ptr[20 + i], 8);
79 fail |= memcmp(vst, &vss[i + NV_VSX_REGS], sizeof(vector int));
80
81 if (fail) {
82 int j;
83
84 fprintf(stderr, "Failed on %d vsx 0x", i);
85 for (j = 0; j < 16; j++)
86 fprintf(stderr, "%02x", vsc[j]);
87 fprintf(stderr, " vs 0x");
88 for (j = 0; j < 16; j++)
89 fprintf(stderr, "%02x", vst[j]);
90 fprintf(stderr, "\n");
91 }
92 }
93}
94
95static int tm_signal_context_chk()
96{
97 struct sigaction act;
98 int i;
99 long rc;
100 pid_t pid = getpid();
101
102 SKIP_IF(!have_htm());
103
104 act.sa_sigaction = signal_usr1;
105 sigemptyset(&act.sa_mask);
106 act.sa_flags = SA_SIGINFO;
107 if (sigaction(SIGUSR1, &act, NULL) < 0) {
108 perror("sigaction sigusr1");
109 exit(1);
110 }
111
112 i = 0;
113 while (i < MAX_ATTEMPT && !fail) {
114 rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vss);
115 FAIL_IF(rc != pid);
116 i++;
117 }
118
119 return fail;
120}
121
122int main(void)
123{
124 return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vsx");
125}
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal.S b/tools/testing/selftests/powerpc/tm/tm-signal.S
new file mode 100644
index 000000000000..4e13e8b3a96f
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-signal.S
@@ -0,0 +1,114 @@
1/*
2 * Copyright 2015, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include "../basic_asm.h"
11#include "../gpr_asm.h"
12#include "../fpu_asm.h"
13#include "../vmx_asm.h"
14#include "../vsx_asm.h"
15
16/*
17 * Large caveat here being that the caller cannot expect the
18 * signal to always be sent! The hardware can (AND WILL!) abort
19 * the transaction between the tbegin and the tsuspend (however
20 * unlikely it seems or infrequently it actually happens).
21 * You have been warned.
22 */
23/* long tm_signal_self(pid_t pid, long *gprs, double *fps, vector *vms, vector *vss); */
24FUNC_START(tm_signal_self_context_load)
25 PUSH_BASIC_STACK(512)
26 /*
27 * Don't strictly need to save and restore as it depends on if
28 * we're going to use them, however this reduces messy logic
29 */
30 PUSH_VMX(STACK_FRAME_LOCAL(5,0),r8)
31 PUSH_FPU(512)
32 PUSH_NVREGS_BELOW_FPU(512)
33 std r3, STACK_FRAME_PARAM(0)(sp) /* pid */
34 std r4, STACK_FRAME_PARAM(1)(sp) /* gps */
35 std r5, STACK_FRAME_PARAM(2)(sp) /* fps */
36 std r6, STACK_FRAME_PARAM(3)(sp) /* vms */
37 std r7, STACK_FRAME_PARAM(4)(sp) /* vss */
38
39 ld r3, STACK_FRAME_PARAM(1)(sp)
40 cmpdi r3, 0
41 beq skip_gpr_lc
42 bl load_gpr
43skip_gpr_lc:
44 ld r3, STACK_FRAME_PARAM(2)(sp)
45 cmpdi r3, 0
46 beq skip_fpu_lc
47 bl load_fpu
48skip_fpu_lc:
49 ld r3, STACK_FRAME_PARAM(3)(sp)
50 cmpdi r3, 0
51 beq skip_vmx_lc
52 bl load_vmx
53skip_vmx_lc:
54 ld r3, STACK_FRAME_PARAM(4)(sp)
55 cmpdi r3, 0
56 beq skip_vsx_lc
57 bl load_vsx
58skip_vsx_lc:
59 /*
60 * Set r3 (return value) before tbegin. Use the pid as a known
61 * 'all good' return value, zero is used to indicate a non-doomed
62 * transaction.
63 */
64 ld r3, STACK_FRAME_PARAM(0)(sp)
65 tbegin.
66 beq 1f
67 tsuspend. /* Can't enter a syscall transactionally */
68 ld r3, STACK_FRAME_PARAM(1)(sp)
69 cmpdi r3, 0
70 beq skip_gpr_lt
71 /* Get the second half of the array */
72 addi r3, r3, 8 * 18
73 bl load_gpr
74skip_gpr_lt:
75 ld r3, STACK_FRAME_PARAM(2)(sp)
76 cmpdi r3, 0
77 beq skip_fpu_lt
78 /* Get the second half of the array */
79 addi r3, r3, 8 * 18
80 bl load_fpu
81skip_fpu_lt:
82 ld r3, STACK_FRAME_PARAM(3)(sp)
83 cmpdi r3, 0
84 beq skip_vmx_lt
85 /* Get the second half of the array */
86 addi r3, r3, 16 * 12
87 bl load_vmx
88skip_vmx_lt:
89 ld r3, STACK_FRAME_PARAM(4)(sp)
90 cmpdi r3, 0
91 beq skip_vsx_lt
92 /* Get the second half of the array */
93 addi r3, r3, 16 * 12
94 bl load_vsx
95skip_vsx_lt:
96 li r0, 37 /* sys_kill */
97 ld r3, STACK_FRAME_PARAM(0)(sp) /* pid */
98 li r4, 10 /* SIGUSR1 */
99 sc /* Taking the signal will doom the transaction */
100 tabort. 0
101 tresume. /* Be super sure we abort */
102 /*
103 * This will cause us to resume doomed transaction and cause
104 * hardware to cleanup, we'll end up at 1: anything between
105 * tresume. and 1: shouldn't ever run.
106 */
107 li r3, 0
108 1:
109 POP_VMX(STACK_FRAME_LOCAL(5,0),r4)
110 POP_FPU(512)
111 POP_NVREGS_BELOW_FPU(512)
112 POP_BASIC_STACK(512)
113 blr
114FUNC_END(tm_signal_self_context_load)
diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h
index 60318bad7d7a..2c8da74304e7 100644
--- a/tools/testing/selftests/powerpc/tm/tm.h
+++ b/tools/testing/selftests/powerpc/tm/tm.h
@@ -52,4 +52,31 @@ static inline bool failure_is_nesting(void)
52 return (__builtin_get_texasru() & 0x400000); 52 return (__builtin_get_texasru() & 0x400000);
53} 53}
54 54
55static inline int tcheck(void)
56{
57 long cr;
58 asm volatile ("tcheck 0" : "=r"(cr) : : "cr0");
59 return (cr >> 28) & 4;
60}
61
62static inline bool tcheck_doomed(void)
63{
64 return tcheck() & 8;
65}
66
67static inline bool tcheck_active(void)
68{
69 return tcheck() & 4;
70}
71
72static inline bool tcheck_suspended(void)
73{
74 return tcheck() & 2;
75}
76
77static inline bool tcheck_transactional(void)
78{
79 return tcheck() & 6;
80}
81
55#endif /* _SELFTESTS_POWERPC_TM_TM_H */ 82#endif /* _SELFTESTS_POWERPC_TM_TM_H */
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
index fbd33e52ef8f..53405e8a52ab 100644
--- a/tools/testing/selftests/powerpc/utils.h
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -22,7 +22,7 @@ typedef uint32_t u32;
22typedef uint16_t u16; 22typedef uint16_t u16;
23typedef uint8_t u8; 23typedef uint8_t u8;
24 24
25 25void test_harness_set_timeout(uint64_t time);
26int test_harness(int (test_function)(void), char *name); 26int test_harness(int (test_function)(void), char *name);
27extern void *get_auxv_entry(int type); 27extern void *get_auxv_entry(int type);
28int pick_online_cpu(void); 28int pick_online_cpu(void);
@@ -32,10 +32,17 @@ static inline bool have_hwcap(unsigned long ftr)
32 return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr; 32 return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr;
33} 33}
34 34
35#ifdef AT_HWCAP2
35static inline bool have_hwcap2(unsigned long ftr2) 36static inline bool have_hwcap2(unsigned long ftr2)
36{ 37{
37 return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2; 38 return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2;
38} 39}
40#else
41static inline bool have_hwcap2(unsigned long ftr2)
42{
43 return false;
44}
45#endif
39 46
40/* Yes, this is evil */ 47/* Yes, this is evil */
41#define FAIL_IF(x) \ 48#define FAIL_IF(x) \
diff --git a/tools/testing/selftests/powerpc/vmx_asm.h b/tools/testing/selftests/powerpc/vmx_asm.h
new file mode 100644
index 000000000000..2eaaeca9cf1d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/vmx_asm.h
@@ -0,0 +1,96 @@
1/*
2 * Copyright 2015, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include "basic_asm.h"
11
12/* POS MUST BE 16 ALIGNED! */
13#define PUSH_VMX(pos,reg) \
14 li reg,pos; \
15 stvx v20,reg,%r1; \
16 addi reg,reg,16; \
17 stvx v21,reg,%r1; \
18 addi reg,reg,16; \
19 stvx v22,reg,%r1; \
20 addi reg,reg,16; \
21 stvx v23,reg,%r1; \
22 addi reg,reg,16; \
23 stvx v24,reg,%r1; \
24 addi reg,reg,16; \
25 stvx v25,reg,%r1; \
26 addi reg,reg,16; \
27 stvx v26,reg,%r1; \
28 addi reg,reg,16; \
29 stvx v27,reg,%r1; \
30 addi reg,reg,16; \
31 stvx v28,reg,%r1; \
32 addi reg,reg,16; \
33 stvx v29,reg,%r1; \
34 addi reg,reg,16; \
35 stvx v30,reg,%r1; \
36 addi reg,reg,16; \
37 stvx v31,reg,%r1;
38
39/* POS MUST BE 16 ALIGNED! */
40#define POP_VMX(pos,reg) \
41 li reg,pos; \
42 lvx v20,reg,%r1; \
43 addi reg,reg,16; \
44 lvx v21,reg,%r1; \
45 addi reg,reg,16; \
46 lvx v22,reg,%r1; \
47 addi reg,reg,16; \
48 lvx v23,reg,%r1; \
49 addi reg,reg,16; \
50 lvx v24,reg,%r1; \
51 addi reg,reg,16; \
52 lvx v25,reg,%r1; \
53 addi reg,reg,16; \
54 lvx v26,reg,%r1; \
55 addi reg,reg,16; \
56 lvx v27,reg,%r1; \
57 addi reg,reg,16; \
58 lvx v28,reg,%r1; \
59 addi reg,reg,16; \
60 lvx v29,reg,%r1; \
61 addi reg,reg,16; \
62 lvx v30,reg,%r1; \
63 addi reg,reg,16; \
64 lvx v31,reg,%r1;
65
66/*
67 * Careful this will 'clobber' vmx (by design)
68 * Don't call this from C
69 */
70FUNC_START(load_vmx)
71 li r5,0
72 lvx v20,r5,r3
73 addi r5,r5,16
74 lvx v21,r5,r3
75 addi r5,r5,16
76 lvx v22,r5,r3
77 addi r5,r5,16
78 lvx v23,r5,r3
79 addi r5,r5,16
80 lvx v24,r5,r3
81 addi r5,r5,16
82 lvx v25,r5,r3
83 addi r5,r5,16
84 lvx v26,r5,r3
85 addi r5,r5,16
86 lvx v27,r5,r3
87 addi r5,r5,16
88 lvx v28,r5,r3
89 addi r5,r5,16
90 lvx v29,r5,r3
91 addi r5,r5,16
92 lvx v30,r5,r3
93 addi r5,r5,16
94 lvx v31,r5,r3
95 blr
96FUNC_END(load_vmx)
diff --git a/tools/testing/selftests/powerpc/vsx_asm.h b/tools/testing/selftests/powerpc/vsx_asm.h
new file mode 100644
index 000000000000..d828bfb6ef2d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/vsx_asm.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright 2015, Cyril Bur, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include "basic_asm.h"
11
12/*
13 * Careful this will 'clobber' vsx (by design), VSX are always
14 * volatile though so unlike vmx this isn't so much of an issue
15 * Still should avoid calling from C
16 */
17FUNC_START(load_vsx)
18 li r5,0
19 lxvx vs20,r5,r3
20 addi r5,r5,16
21 lxvx vs21,r5,r3
22 addi r5,r5,16
23 lxvx vs22,r5,r3
24 addi r5,r5,16
25 lxvx vs23,r5,r3
26 addi r5,r5,16
27 lxvx vs24,r5,r3
28 addi r5,r5,16
29 lxvx vs25,r5,r3
30 addi r5,r5,16
31 lxvx vs26,r5,r3
32 addi r5,r5,16
33 lxvx vs27,r5,r3
34 addi r5,r5,16
35 lxvx vs28,r5,r3
36 addi r5,r5,16
37 lxvx vs29,r5,r3
38 addi r5,r5,16
39 lxvx vs30,r5,r3
40 addi r5,r5,16
41 lxvx vs31,r5,r3
42 blr
43FUNC_END(load_vsx)
44
45FUNC_START(store_vsx)
46 li r5,0
47 stxvx vs20,r5,r3
48 addi r5,r5,16
49 stxvx vs21,r5,r3
50 addi r5,r5,16
51 stxvx vs22,r5,r3
52 addi r5,r5,16
53 stxvx vs23,r5,r3
54 addi r5,r5,16
55 stxvx vs24,r5,r3
56 addi r5,r5,16
57 stxvx vs25,r5,r3
58 addi r5,r5,16
59 stxvx vs26,r5,r3
60 addi r5,r5,16
61 stxvx vs27,r5,r3
62 addi r5,r5,16
63 stxvx vs28,r5,r3
64 addi r5,r5,16
65 stxvx vs29,r5,r3
66 addi r5,r5,16
67 stxvx vs30,r5,r3
68 addi r5,r5,16
69 stxvx vs31,r5,r3
70 blr
71FUNC_END(store_vsx)
diff --git a/tools/testing/selftests/prctl/.gitignore b/tools/testing/selftests/prctl/.gitignore
new file mode 100644
index 000000000000..0b5c27447bf6
--- /dev/null
+++ b/tools/testing/selftests/prctl/.gitignore
@@ -0,0 +1,3 @@
1disable-tsc-ctxt-sw-stress-test
2disable-tsc-on-off-stress-test
3disable-tsc-test
diff --git a/tools/testing/selftests/prctl/Makefile b/tools/testing/selftests/prctl/Makefile
new file mode 100644
index 000000000000..35aa1c8f2df2
--- /dev/null
+++ b/tools/testing/selftests/prctl/Makefile
@@ -0,0 +1,15 @@
1ifndef CROSS_COMPILE
2uname_M := $(shell uname -m 2>/dev/null || echo not)
3ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
4
5ifeq ($(ARCH),x86)
6TEST_PROGS := disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test \
7 disable-tsc-test
8all: $(TEST_PROGS)
9
10include ../lib.mk
11
12clean:
13 rm -fr $(TEST_PROGS)
14endif
15endif
diff --git a/tools/testing/selftests/prctl/disable-tsc-ctxt-sw-stress-test.c b/tools/testing/selftests/prctl/disable-tsc-ctxt-sw-stress-test.c
new file mode 100644
index 000000000000..f7499d1c0415
--- /dev/null
+++ b/tools/testing/selftests/prctl/disable-tsc-ctxt-sw-stress-test.c
@@ -0,0 +1,97 @@
1/*
2 * Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...)
3 *
4 * Tests if the control register is updated correctly
5 * at context switches
6 *
7 * Warning: this test will cause a very high load for a few seconds
8 *
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <signal.h>
15#include <inttypes.h>
16#include <wait.h>
17
18
19#include <sys/prctl.h>
20#include <linux/prctl.h>
21
22/* Get/set the process' ability to use the timestamp counter instruction */
23#ifndef PR_GET_TSC
24#define PR_GET_TSC 25
25#define PR_SET_TSC 26
26# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
27# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
28#endif
29
30static uint64_t rdtsc(void)
31{
32uint32_t lo, hi;
33/* We cannot use "=A", since this would use %rax on x86_64 */
34__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
35return (uint64_t)hi << 32 | lo;
36}
37
38static void sigsegv_expect(int sig)
39{
40 /* */
41}
42
43static void segvtask(void)
44{
45 if (prctl(PR_SET_TSC, PR_TSC_SIGSEGV) < 0)
46 {
47 perror("prctl");
48 exit(0);
49 }
50 signal(SIGSEGV, sigsegv_expect);
51 alarm(10);
52 rdtsc();
53 fprintf(stderr, "FATAL ERROR, rdtsc() succeeded while disabled\n");
54 exit(0);
55}
56
57
58static void sigsegv_fail(int sig)
59{
60 fprintf(stderr, "FATAL ERROR, rdtsc() failed while enabled\n");
61 exit(0);
62}
63
64static void rdtsctask(void)
65{
66 if (prctl(PR_SET_TSC, PR_TSC_ENABLE) < 0)
67 {
68 perror("prctl");
69 exit(0);
70 }
71 signal(SIGSEGV, sigsegv_fail);
72 alarm(10);
73 for(;;) rdtsc();
74}
75
76
77int main(void)
78{
79 int n_tasks = 100, i;
80
81 fprintf(stderr, "[No further output means we're allright]\n");
82
83 for (i=0; i<n_tasks; i++)
84 if (fork() == 0)
85 {
86 if (i & 1)
87 segvtask();
88 else
89 rdtsctask();
90 }
91
92 for (i=0; i<n_tasks; i++)
93 wait(NULL);
94
95 exit(0);
96}
97
diff --git a/tools/testing/selftests/prctl/disable-tsc-on-off-stress-test.c b/tools/testing/selftests/prctl/disable-tsc-on-off-stress-test.c
new file mode 100644
index 000000000000..a06f027e9d16
--- /dev/null
+++ b/tools/testing/selftests/prctl/disable-tsc-on-off-stress-test.c
@@ -0,0 +1,96 @@
1/*
2 * Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...)
3 *
4 * Tests if the control register is updated correctly
5 * when set with prctl()
6 *
7 * Warning: this test will cause a very high load for a few seconds
8 *
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <signal.h>
15#include <inttypes.h>
16#include <wait.h>
17
18
19#include <sys/prctl.h>
20#include <linux/prctl.h>
21
22/* Get/set the process' ability to use the timestamp counter instruction */
23#ifndef PR_GET_TSC
24#define PR_GET_TSC 25
25#define PR_SET_TSC 26
26# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
27# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
28#endif
29
30/* snippet from wikipedia :-) */
31
32static uint64_t rdtsc(void)
33{
34uint32_t lo, hi;
35/* We cannot use "=A", since this would use %rax on x86_64 */
36__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
37return (uint64_t)hi << 32 | lo;
38}
39
40int should_segv = 0;
41
42static void sigsegv_cb(int sig)
43{
44 if (!should_segv)
45 {
46 fprintf(stderr, "FATAL ERROR, rdtsc() failed while enabled\n");
47 exit(0);
48 }
49 if (prctl(PR_SET_TSC, PR_TSC_ENABLE) < 0)
50 {
51 perror("prctl");
52 exit(0);
53 }
54 should_segv = 0;
55
56 rdtsc();
57}
58
59static void task(void)
60{
61 signal(SIGSEGV, sigsegv_cb);
62 alarm(10);
63 for(;;)
64 {
65 rdtsc();
66 if (should_segv)
67 {
68 fprintf(stderr, "FATAL ERROR, rdtsc() succeeded while disabled\n");
69 exit(0);
70 }
71 if (prctl(PR_SET_TSC, PR_TSC_SIGSEGV) < 0)
72 {
73 perror("prctl");
74 exit(0);
75 }
76 should_segv = 1;
77 }
78}
79
80
81int main(void)
82{
83 int n_tasks = 100, i;
84
85 fprintf(stderr, "[No further output means we're allright]\n");
86
87 for (i=0; i<n_tasks; i++)
88 if (fork() == 0)
89 task();
90
91 for (i=0; i<n_tasks; i++)
92 wait(NULL);
93
94 exit(0);
95}
96
diff --git a/tools/testing/selftests/prctl/disable-tsc-test.c b/tools/testing/selftests/prctl/disable-tsc-test.c
new file mode 100644
index 000000000000..8d494f7bebdb
--- /dev/null
+++ b/tools/testing/selftests/prctl/disable-tsc-test.c
@@ -0,0 +1,95 @@
1/*
2 * Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...)
3 *
4 * Basic test to test behaviour of PR_GET_TSC and PR_SET_TSC
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <signal.h>
11#include <inttypes.h>
12
13
14#include <sys/prctl.h>
15#include <linux/prctl.h>
16
17/* Get/set the process' ability to use the timestamp counter instruction */
18#ifndef PR_GET_TSC
19#define PR_GET_TSC 25
20#define PR_SET_TSC 26
21# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
22# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
23#endif
24
25const char *tsc_names[] =
26{
27 [0] = "[not set]",
28 [PR_TSC_ENABLE] = "PR_TSC_ENABLE",
29 [PR_TSC_SIGSEGV] = "PR_TSC_SIGSEGV",
30};
31
32static uint64_t rdtsc(void)
33{
34uint32_t lo, hi;
35/* We cannot use "=A", since this would use %rax on x86_64 */
36__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
37return (uint64_t)hi << 32 | lo;
38}
39
40static void sigsegv_cb(int sig)
41{
42 int tsc_val = 0;
43
44 printf("[ SIG_SEGV ]\n");
45 printf("prctl(PR_GET_TSC, &tsc_val); ");
46 fflush(stdout);
47
48 if ( prctl(PR_GET_TSC, &tsc_val) == -1)
49 perror("prctl");
50
51 printf("tsc_val == %s\n", tsc_names[tsc_val]);
52 printf("prctl(PR_SET_TSC, PR_TSC_ENABLE)\n");
53 fflush(stdout);
54 if ( prctl(PR_SET_TSC, PR_TSC_ENABLE) == -1)
55 perror("prctl");
56
57 printf("rdtsc() == ");
58}
59
60int main(void)
61{
62 int tsc_val = 0;
63
64 signal(SIGSEGV, sigsegv_cb);
65
66 printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
67 printf("prctl(PR_GET_TSC, &tsc_val); ");
68 fflush(stdout);
69
70 if ( prctl(PR_GET_TSC, &tsc_val) == -1)
71 perror("prctl");
72
73 printf("tsc_val == %s\n", tsc_names[tsc_val]);
74 printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
75 printf("prctl(PR_SET_TSC, PR_TSC_ENABLE)\n");
76 fflush(stdout);
77
78 if ( prctl(PR_SET_TSC, PR_TSC_ENABLE) == -1)
79 perror("prctl");
80
81 printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
82 printf("prctl(PR_SET_TSC, PR_TSC_SIGSEGV)\n");
83 fflush(stdout);
84
85 if ( prctl(PR_SET_TSC, PR_TSC_SIGSEGV) == -1)
86 perror("prctl");
87
88 printf("rdtsc() == ");
89 fflush(stdout);
90 printf("%llu\n", (unsigned long long)rdtsc());
91 fflush(stdout);
92
93 exit(EXIT_SUCCESS);
94}
95
diff --git a/tools/testing/selftests/ptp/.gitignore b/tools/testing/selftests/ptp/.gitignore
new file mode 100644
index 000000000000..f562e49d6917
--- /dev/null
+++ b/tools/testing/selftests/ptp/.gitignore
@@ -0,0 +1 @@
testptp
diff --git a/tools/testing/selftests/ptp/Makefile b/tools/testing/selftests/ptp/Makefile
new file mode 100644
index 000000000000..83dd42b2129e
--- /dev/null
+++ b/tools/testing/selftests/ptp/Makefile
@@ -0,0 +1,8 @@
1TEST_PROGS := testptp
2LDLIBS += -lrt
3all: $(TEST_PROGS)
4
5include ../lib.mk
6
7clean:
8 rm -fr $(TEST_PROGS)
diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c
new file mode 100644
index 000000000000..5d2eae16f7ee
--- /dev/null
+++ b/tools/testing/selftests/ptp/testptp.c
@@ -0,0 +1,523 @@
1/*
2 * PTP 1588 clock support - User space test program
3 *
4 * Copyright (C) 2010 OMICRON electronics GmbH
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20#define _GNU_SOURCE
21#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
22#include <errno.h>
23#include <fcntl.h>
24#include <inttypes.h>
25#include <math.h>
26#include <signal.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/ioctl.h>
31#include <sys/mman.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/timex.h>
35#include <sys/types.h>
36#include <time.h>
37#include <unistd.h>
38
39#include <linux/ptp_clock.h>
40
41#define DEVICE "/dev/ptp0"
42
43#ifndef ADJ_SETOFFSET
44#define ADJ_SETOFFSET 0x0100
45#endif
46
47#ifndef CLOCK_INVALID
48#define CLOCK_INVALID -1
49#endif
50
51/* clock_adjtime is not available in GLIBC < 2.14 */
52#if !__GLIBC_PREREQ(2, 14)
53#include <sys/syscall.h>
54static int clock_adjtime(clockid_t id, struct timex *tx)
55{
56 return syscall(__NR_clock_adjtime, id, tx);
57}
58#endif
59
60static clockid_t get_clockid(int fd)
61{
62#define CLOCKFD 3
63#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
64
65 return FD_TO_CLOCKID(fd);
66}
67
68static void handle_alarm(int s)
69{
70 printf("received signal %d\n", s);
71}
72
73static int install_handler(int signum, void (*handler)(int))
74{
75 struct sigaction action;
76 sigset_t mask;
77
78 /* Unblock the signal. */
79 sigemptyset(&mask);
80 sigaddset(&mask, signum);
81 sigprocmask(SIG_UNBLOCK, &mask, NULL);
82
83 /* Install the signal handler. */
84 action.sa_handler = handler;
85 action.sa_flags = 0;
86 sigemptyset(&action.sa_mask);
87 sigaction(signum, &action, NULL);
88
89 return 0;
90}
91
92static long ppb_to_scaled_ppm(int ppb)
93{
94 /*
95 * The 'freq' field in the 'struct timex' is in parts per
96 * million, but with a 16 bit binary fractional field.
97 * Instead of calculating either one of
98 *
99 * scaled_ppm = (ppb / 1000) << 16 [1]
100 * scaled_ppm = (ppb << 16) / 1000 [2]
101 *
102 * we simply use double precision math, in order to avoid the
103 * truncation in [1] and the possible overflow in [2].
104 */
105 return (long) (ppb * 65.536);
106}
107
108static int64_t pctns(struct ptp_clock_time *t)
109{
110 return t->sec * 1000000000LL + t->nsec;
111}
112
113static void usage(char *progname)
114{
115 fprintf(stderr,
116 "usage: %s [options]\n"
117 " -a val request a one-shot alarm after 'val' seconds\n"
118 " -A val request a periodic alarm every 'val' seconds\n"
119 " -c query the ptp clock's capabilities\n"
120 " -d name device to open\n"
121 " -e val read 'val' external time stamp events\n"
122 " -f val adjust the ptp clock frequency by 'val' ppb\n"
123 " -g get the ptp clock time\n"
124 " -h prints this message\n"
125 " -i val index for event/trigger\n"
126 " -k val measure the time offset between system and phc clock\n"
127 " for 'val' times (Maximum 25)\n"
128 " -l list the current pin configuration\n"
129 " -L pin,val configure pin index 'pin' with function 'val'\n"
130 " the channel index is taken from the '-i' option\n"
131 " 'val' specifies the auxiliary function:\n"
132 " 0 - none\n"
133 " 1 - external time stamp\n"
134 " 2 - periodic output\n"
135 " -p val enable output with a period of 'val' nanoseconds\n"
136 " -P val enable or disable (val=1|0) the system clock PPS\n"
137 " -s set the ptp clock time from the system time\n"
138 " -S set the system time from the ptp clock time\n"
139 " -t val shift the ptp clock time by 'val' seconds\n"
140 " -T val set the ptp clock time to 'val' seconds\n",
141 progname);
142}
143
144int main(int argc, char *argv[])
145{
146 struct ptp_clock_caps caps;
147 struct ptp_extts_event event;
148 struct ptp_extts_request extts_request;
149 struct ptp_perout_request perout_request;
150 struct ptp_pin_desc desc;
151 struct timespec ts;
152 struct timex tx;
153
154 static timer_t timerid;
155 struct itimerspec timeout;
156 struct sigevent sigevent;
157
158 struct ptp_clock_time *pct;
159 struct ptp_sys_offset *sysoff;
160
161
162 char *progname;
163 unsigned int i;
164 int c, cnt, fd;
165
166 char *device = DEVICE;
167 clockid_t clkid;
168 int adjfreq = 0x7fffffff;
169 int adjtime = 0;
170 int capabilities = 0;
171 int extts = 0;
172 int gettime = 0;
173 int index = 0;
174 int list_pins = 0;
175 int oneshot = 0;
176 int pct_offset = 0;
177 int n_samples = 0;
178 int periodic = 0;
179 int perout = -1;
180 int pin_index = -1, pin_func;
181 int pps = -1;
182 int seconds = 0;
183 int settime = 0;
184
185 int64_t t1, t2, tp;
186 int64_t interval, offset;
187
188 progname = strrchr(argv[0], '/');
189 progname = progname ? 1+progname : argv[0];
190 while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:lL:p:P:sSt:T:v"))) {
191 switch (c) {
192 case 'a':
193 oneshot = atoi(optarg);
194 break;
195 case 'A':
196 periodic = atoi(optarg);
197 break;
198 case 'c':
199 capabilities = 1;
200 break;
201 case 'd':
202 device = optarg;
203 break;
204 case 'e':
205 extts = atoi(optarg);
206 break;
207 case 'f':
208 adjfreq = atoi(optarg);
209 break;
210 case 'g':
211 gettime = 1;
212 break;
213 case 'i':
214 index = atoi(optarg);
215 break;
216 case 'k':
217 pct_offset = 1;
218 n_samples = atoi(optarg);
219 break;
220 case 'l':
221 list_pins = 1;
222 break;
223 case 'L':
224 cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func);
225 if (cnt != 2) {
226 usage(progname);
227 return -1;
228 }
229 break;
230 case 'p':
231 perout = atoi(optarg);
232 break;
233 case 'P':
234 pps = atoi(optarg);
235 break;
236 case 's':
237 settime = 1;
238 break;
239 case 'S':
240 settime = 2;
241 break;
242 case 't':
243 adjtime = atoi(optarg);
244 break;
245 case 'T':
246 settime = 3;
247 seconds = atoi(optarg);
248 break;
249 case 'h':
250 usage(progname);
251 return 0;
252 case '?':
253 default:
254 usage(progname);
255 return -1;
256 }
257 }
258
259 fd = open(device, O_RDWR);
260 if (fd < 0) {
261 fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
262 return -1;
263 }
264
265 clkid = get_clockid(fd);
266 if (CLOCK_INVALID == clkid) {
267 fprintf(stderr, "failed to read clock id\n");
268 return -1;
269 }
270
271 if (capabilities) {
272 if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
273 perror("PTP_CLOCK_GETCAPS");
274 } else {
275 printf("capabilities:\n"
276 " %d maximum frequency adjustment (ppb)\n"
277 " %d programmable alarms\n"
278 " %d external time stamp channels\n"
279 " %d programmable periodic signals\n"
280 " %d pulse per second\n"
281 " %d programmable pins\n"
282 " %d cross timestamping\n",
283 caps.max_adj,
284 caps.n_alarm,
285 caps.n_ext_ts,
286 caps.n_per_out,
287 caps.pps,
288 caps.n_pins,
289 caps.cross_timestamping);
290 }
291 }
292
293 if (0x7fffffff != adjfreq) {
294 memset(&tx, 0, sizeof(tx));
295 tx.modes = ADJ_FREQUENCY;
296 tx.freq = ppb_to_scaled_ppm(adjfreq);
297 if (clock_adjtime(clkid, &tx)) {
298 perror("clock_adjtime");
299 } else {
300 puts("frequency adjustment okay");
301 }
302 }
303
304 if (adjtime) {
305 memset(&tx, 0, sizeof(tx));
306 tx.modes = ADJ_SETOFFSET;
307 tx.time.tv_sec = adjtime;
308 tx.time.tv_usec = 0;
309 if (clock_adjtime(clkid, &tx) < 0) {
310 perror("clock_adjtime");
311 } else {
312 puts("time shift okay");
313 }
314 }
315
316 if (gettime) {
317 if (clock_gettime(clkid, &ts)) {
318 perror("clock_gettime");
319 } else {
320 printf("clock time: %ld.%09ld or %s",
321 ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
322 }
323 }
324
325 if (settime == 1) {
326 clock_gettime(CLOCK_REALTIME, &ts);
327 if (clock_settime(clkid, &ts)) {
328 perror("clock_settime");
329 } else {
330 puts("set time okay");
331 }
332 }
333
334 if (settime == 2) {
335 clock_gettime(clkid, &ts);
336 if (clock_settime(CLOCK_REALTIME, &ts)) {
337 perror("clock_settime");
338 } else {
339 puts("set time okay");
340 }
341 }
342
343 if (settime == 3) {
344 ts.tv_sec = seconds;
345 ts.tv_nsec = 0;
346 if (clock_settime(clkid, &ts)) {
347 perror("clock_settime");
348 } else {
349 puts("set time okay");
350 }
351 }
352
353 if (extts) {
354 memset(&extts_request, 0, sizeof(extts_request));
355 extts_request.index = index;
356 extts_request.flags = PTP_ENABLE_FEATURE;
357 if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
358 perror("PTP_EXTTS_REQUEST");
359 extts = 0;
360 } else {
361 puts("external time stamp request okay");
362 }
363 for (; extts; extts--) {
364 cnt = read(fd, &event, sizeof(event));
365 if (cnt != sizeof(event)) {
366 perror("read");
367 break;
368 }
369 printf("event index %u at %lld.%09u\n", event.index,
370 event.t.sec, event.t.nsec);
371 fflush(stdout);
372 }
373 /* Disable the feature again. */
374 extts_request.flags = 0;
375 if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
376 perror("PTP_EXTTS_REQUEST");
377 }
378 }
379
380 if (list_pins) {
381 int n_pins = 0;
382 if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
383 perror("PTP_CLOCK_GETCAPS");
384 } else {
385 n_pins = caps.n_pins;
386 }
387 for (i = 0; i < n_pins; i++) {
388 desc.index = i;
389 if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) {
390 perror("PTP_PIN_GETFUNC");
391 break;
392 }
393 printf("name %s index %u func %u chan %u\n",
394 desc.name, desc.index, desc.func, desc.chan);
395 }
396 }
397
398 if (oneshot) {
399 install_handler(SIGALRM, handle_alarm);
400 /* Create a timer. */
401 sigevent.sigev_notify = SIGEV_SIGNAL;
402 sigevent.sigev_signo = SIGALRM;
403 if (timer_create(clkid, &sigevent, &timerid)) {
404 perror("timer_create");
405 return -1;
406 }
407 /* Start the timer. */
408 memset(&timeout, 0, sizeof(timeout));
409 timeout.it_value.tv_sec = oneshot;
410 if (timer_settime(timerid, 0, &timeout, NULL)) {
411 perror("timer_settime");
412 return -1;
413 }
414 pause();
415 timer_delete(timerid);
416 }
417
418 if (periodic) {
419 install_handler(SIGALRM, handle_alarm);
420 /* Create a timer. */
421 sigevent.sigev_notify = SIGEV_SIGNAL;
422 sigevent.sigev_signo = SIGALRM;
423 if (timer_create(clkid, &sigevent, &timerid)) {
424 perror("timer_create");
425 return -1;
426 }
427 /* Start the timer. */
428 memset(&timeout, 0, sizeof(timeout));
429 timeout.it_interval.tv_sec = periodic;
430 timeout.it_value.tv_sec = periodic;
431 if (timer_settime(timerid, 0, &timeout, NULL)) {
432 perror("timer_settime");
433 return -1;
434 }
435 while (1) {
436 pause();
437 }
438 timer_delete(timerid);
439 }
440
441 if (perout >= 0) {
442 if (clock_gettime(clkid, &ts)) {
443 perror("clock_gettime");
444 return -1;
445 }
446 memset(&perout_request, 0, sizeof(perout_request));
447 perout_request.index = index;
448 perout_request.start.sec = ts.tv_sec + 2;
449 perout_request.start.nsec = 0;
450 perout_request.period.sec = 0;
451 perout_request.period.nsec = perout;
452 if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
453 perror("PTP_PEROUT_REQUEST");
454 } else {
455 puts("periodic output request okay");
456 }
457 }
458
459 if (pin_index >= 0) {
460 memset(&desc, 0, sizeof(desc));
461 desc.index = pin_index;
462 desc.func = pin_func;
463 desc.chan = index;
464 if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
465 perror("PTP_PIN_SETFUNC");
466 } else {
467 puts("set pin function okay");
468 }
469 }
470
471 if (pps != -1) {
472 int enable = pps ? 1 : 0;
473 if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
474 perror("PTP_ENABLE_PPS");
475 } else {
476 puts("pps for system time request okay");
477 }
478 }
479
480 if (pct_offset) {
481 if (n_samples <= 0 || n_samples > 25) {
482 puts("n_samples should be between 1 and 25");
483 usage(progname);
484 return -1;
485 }
486
487 sysoff = calloc(1, sizeof(*sysoff));
488 if (!sysoff) {
489 perror("calloc");
490 return -1;
491 }
492 sysoff->n_samples = n_samples;
493
494 if (ioctl(fd, PTP_SYS_OFFSET, sysoff))
495 perror("PTP_SYS_OFFSET");
496 else
497 puts("system and phc clock time offset request okay");
498
499 pct = &sysoff->ts[0];
500 for (i = 0; i < sysoff->n_samples; i++) {
501 t1 = pctns(pct+2*i);
502 tp = pctns(pct+2*i+1);
503 t2 = pctns(pct+2*i+2);
504 interval = t2 - t1;
505 offset = (t2 + t1) / 2 - tp;
506
507 printf("system time: %lld.%u\n",
508 (pct+2*i)->sec, (pct+2*i)->nsec);
509 printf("phc time: %lld.%u\n",
510 (pct+2*i+1)->sec, (pct+2*i+1)->nsec);
511 printf("system time: %lld.%u\n",
512 (pct+2*i+2)->sec, (pct+2*i+2)->nsec);
513 printf("system/phc clock time offset is %" PRId64 " ns\n"
514 "system clock time delay is %" PRId64 " ns\n",
515 offset, interval);
516 }
517
518 free(sysoff);
519 }
520
521 close(fd);
522 return 0;
523}
diff --git a/tools/testing/selftests/ptp/testptp.mk b/tools/testing/selftests/ptp/testptp.mk
new file mode 100644
index 000000000000..4ef2d9755421
--- /dev/null
+++ b/tools/testing/selftests/ptp/testptp.mk
@@ -0,0 +1,33 @@
1# PTP 1588 clock support - User space test program
2#
3# Copyright (C) 2010 OMICRON electronics GmbH
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19CC = $(CROSS_COMPILE)gcc
20INC = -I$(KBUILD_OUTPUT)/usr/include
21CFLAGS = -Wall $(INC)
22LDLIBS = -lrt
23PROGS = testptp
24
25all: $(PROGS)
26
27testptp: testptp.o
28
29clean:
30 rm -f testptp.o
31
32distclean: clean
33 rm -f $(PROGS)
diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c
index 5a246a02dff3..15cf56d32155 100644
--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -122,7 +122,7 @@ static int check_itimer(int which)
122 else if (which == ITIMER_REAL) 122 else if (which == ITIMER_REAL)
123 idle_loop(); 123 idle_loop();
124 124
125 gettimeofday(&end, NULL); 125 err = gettimeofday(&end, NULL);
126 if (err < 0) { 126 if (err < 0) {
127 perror("Can't call gettimeofday()\n"); 127 perror("Can't call gettimeofday()\n");
128 return -1; 128 return -1;
@@ -175,7 +175,7 @@ static int check_timer_create(int which)
175 175
176 user_loop(); 176 user_loop();
177 177
178 gettimeofday(&end, NULL); 178 err = gettimeofday(&end, NULL);
179 if (err < 0) { 179 if (err < 0) {
180 perror("Can't call gettimeofday()\n"); 180 perror("Can't call gettimeofday()\n");
181 return -1; 181 return -1;
diff --git a/tools/testing/selftests/vDSO/.gitignore b/tools/testing/selftests/vDSO/.gitignore
new file mode 100644
index 000000000000..133bf9ee986c
--- /dev/null
+++ b/tools/testing/selftests/vDSO/.gitignore
@@ -0,0 +1,2 @@
1vdso_test
2vdso_standalone_test_x86
diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile
new file mode 100644
index 000000000000..706b68b1c372
--- /dev/null
+++ b/tools/testing/selftests/vDSO/Makefile
@@ -0,0 +1,20 @@
1ifndef CROSS_COMPILE
2CFLAGS := -std=gnu99
3CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector
4ifeq ($(CONFIG_X86_32),y)
5LDLIBS += -lgcc_s
6endif
7
8TEST_PROGS := vdso_test vdso_standalone_test_x86
9
10all: $(TEST_PROGS)
11vdso_test: parse_vdso.c vdso_test.c
12vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
13 $(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \
14 vdso_standalone_test_x86.c parse_vdso.c \
15 -o vdso_standalone_test_x86
16
17include ../lib.mk
18clean:
19 rm -fr $(TEST_PROGS)
20endif
diff --git a/tools/testing/selftests/vDSO/parse_vdso.c b/tools/testing/selftests/vDSO/parse_vdso.c
new file mode 100644
index 000000000000..1dbb4b87268f
--- /dev/null
+++ b/tools/testing/selftests/vDSO/parse_vdso.c
@@ -0,0 +1,269 @@
1/*
2 * parse_vdso.c: Linux reference vDSO parser
3 * Written by Andrew Lutomirski, 2011-2014.
4 *
5 * This code is meant to be linked in to various programs that run on Linux.
6 * As such, it is available with as few restrictions as possible. This file
7 * is licensed under the Creative Commons Zero License, version 1.0,
8 * available at http://creativecommons.org/publicdomain/zero/1.0/legalcode
9 *
10 * The vDSO is a regular ELF DSO that the kernel maps into user space when
11 * it starts a program. It works equally well in statically and dynamically
12 * linked binaries.
13 *
14 * This code is tested on x86. In principle it should work on any
15 * architecture that has a vDSO.
16 */
17
18#include <stdbool.h>
19#include <stdint.h>
20#include <string.h>
21#include <limits.h>
22#include <elf.h>
23
24/*
25 * To use this vDSO parser, first call one of the vdso_init_* functions.
26 * If you've already parsed auxv, then pass the value of AT_SYSINFO_EHDR
27 * to vdso_init_from_sysinfo_ehdr. Otherwise pass auxv to vdso_init_from_auxv.
28 * Then call vdso_sym for each symbol you want. For example, to look up
29 * gettimeofday on x86_64, use:
30 *
31 * <some pointer> = vdso_sym("LINUX_2.6", "gettimeofday");
32 * or
33 * <some pointer> = vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
34 *
35 * vdso_sym will return 0 if the symbol doesn't exist or if the init function
36 * failed or was not called. vdso_sym is a little slow, so its return value
37 * should be cached.
38 *
39 * vdso_sym is threadsafe; the init functions are not.
40 *
41 * These are the prototypes:
42 */
43extern void vdso_init_from_auxv(void *auxv);
44extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
45extern void *vdso_sym(const char *version, const char *name);
46
47
48/* And here's the code. */
49#ifndef ELF_BITS
50# if ULONG_MAX > 0xffffffffUL
51# define ELF_BITS 64
52# else
53# define ELF_BITS 32
54# endif
55#endif
56
57#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
58#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
59#define ELF(x) ELF_BITS_XFORM(ELF_BITS, x)
60
61static struct vdso_info
62{
63 bool valid;
64
65 /* Load information */
66 uintptr_t load_addr;
67 uintptr_t load_offset; /* load_addr - recorded vaddr */
68
69 /* Symbol table */
70 ELF(Sym) *symtab;
71 const char *symstrings;
72 ELF(Word) *bucket, *chain;
73 ELF(Word) nbucket, nchain;
74
75 /* Version table */
76 ELF(Versym) *versym;
77 ELF(Verdef) *verdef;
78} vdso_info;
79
80/* Straight from the ELF specification. */
81static unsigned long elf_hash(const unsigned char *name)
82{
83 unsigned long h = 0, g;
84 while (*name)
85 {
86 h = (h << 4) + *name++;
87 if (g = h & 0xf0000000)
88 h ^= g >> 24;
89 h &= ~g;
90 }
91 return h;
92}
93
94void vdso_init_from_sysinfo_ehdr(uintptr_t base)
95{
96 size_t i;
97 bool found_vaddr = false;
98
99 vdso_info.valid = false;
100
101 vdso_info.load_addr = base;
102
103 ELF(Ehdr) *hdr = (ELF(Ehdr)*)base;
104 if (hdr->e_ident[EI_CLASS] !=
105 (ELF_BITS == 32 ? ELFCLASS32 : ELFCLASS64)) {
106 return; /* Wrong ELF class -- check ELF_BITS */
107 }
108
109 ELF(Phdr) *pt = (ELF(Phdr)*)(vdso_info.load_addr + hdr->e_phoff);
110 ELF(Dyn) *dyn = 0;
111
112 /*
113 * We need two things from the segment table: the load offset
114 * and the dynamic table.
115 */
116 for (i = 0; i < hdr->e_phnum; i++)
117 {
118 if (pt[i].p_type == PT_LOAD && !found_vaddr) {
119 found_vaddr = true;
120 vdso_info.load_offset = base
121 + (uintptr_t)pt[i].p_offset
122 - (uintptr_t)pt[i].p_vaddr;
123 } else if (pt[i].p_type == PT_DYNAMIC) {
124 dyn = (ELF(Dyn)*)(base + pt[i].p_offset);
125 }
126 }
127
128 if (!found_vaddr || !dyn)
129 return; /* Failed */
130
131 /*
132 * Fish out the useful bits of the dynamic table.
133 */
134 ELF(Word) *hash = 0;
135 vdso_info.symstrings = 0;
136 vdso_info.symtab = 0;
137 vdso_info.versym = 0;
138 vdso_info.verdef = 0;
139 for (i = 0; dyn[i].d_tag != DT_NULL; i++) {
140 switch (dyn[i].d_tag) {
141 case DT_STRTAB:
142 vdso_info.symstrings = (const char *)
143 ((uintptr_t)dyn[i].d_un.d_ptr
144 + vdso_info.load_offset);
145 break;
146 case DT_SYMTAB:
147 vdso_info.symtab = (ELF(Sym) *)
148 ((uintptr_t)dyn[i].d_un.d_ptr
149 + vdso_info.load_offset);
150 break;
151 case DT_HASH:
152 hash = (ELF(Word) *)
153 ((uintptr_t)dyn[i].d_un.d_ptr
154 + vdso_info.load_offset);
155 break;
156 case DT_VERSYM:
157 vdso_info.versym = (ELF(Versym) *)
158 ((uintptr_t)dyn[i].d_un.d_ptr
159 + vdso_info.load_offset);
160 break;
161 case DT_VERDEF:
162 vdso_info.verdef = (ELF(Verdef) *)
163 ((uintptr_t)dyn[i].d_un.d_ptr
164 + vdso_info.load_offset);
165 break;
166 }
167 }
168 if (!vdso_info.symstrings || !vdso_info.symtab || !hash)
169 return; /* Failed */
170
171 if (!vdso_info.verdef)
172 vdso_info.versym = 0;
173
174 /* Parse the hash table header. */
175 vdso_info.nbucket = hash[0];
176 vdso_info.nchain = hash[1];
177 vdso_info.bucket = &hash[2];
178 vdso_info.chain = &hash[vdso_info.nbucket + 2];
179
180 /* That's all we need. */
181 vdso_info.valid = true;
182}
183
184static bool vdso_match_version(ELF(Versym) ver,
185 const char *name, ELF(Word) hash)
186{
187 /*
188 * This is a helper function to check if the version indexed by
189 * ver matches name (which hashes to hash).
190 *
191 * The version definition table is a mess, and I don't know how
192 * to do this in better than linear time without allocating memory
193 * to build an index. I also don't know why the table has
194 * variable size entries in the first place.
195 *
196 * For added fun, I can't find a comprehensible specification of how
197 * to parse all the weird flags in the table.
198 *
199 * So I just parse the whole table every time.
200 */
201
202 /* First step: find the version definition */
203 ver &= 0x7fff; /* Apparently bit 15 means "hidden" */
204 ELF(Verdef) *def = vdso_info.verdef;
205 while(true) {
206 if ((def->vd_flags & VER_FLG_BASE) == 0
207 && (def->vd_ndx & 0x7fff) == ver)
208 break;
209
210 if (def->vd_next == 0)
211 return false; /* No definition. */
212
213 def = (ELF(Verdef) *)((char *)def + def->vd_next);
214 }
215
216 /* Now figure out whether it matches. */
217 ELF(Verdaux) *aux = (ELF(Verdaux)*)((char *)def + def->vd_aux);
218 return def->vd_hash == hash
219 && !strcmp(name, vdso_info.symstrings + aux->vda_name);
220}
221
222void *vdso_sym(const char *version, const char *name)
223{
224 unsigned long ver_hash;
225 if (!vdso_info.valid)
226 return 0;
227
228 ver_hash = elf_hash(version);
229 ELF(Word) chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket];
230
231 for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) {
232 ELF(Sym) *sym = &vdso_info.symtab[chain];
233
234 /* Check for a defined global or weak function w/ right name. */
235 if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
236 continue;
237 if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL &&
238 ELF64_ST_BIND(sym->st_info) != STB_WEAK)
239 continue;
240 if (sym->st_shndx == SHN_UNDEF)
241 continue;
242 if (strcmp(name, vdso_info.symstrings + sym->st_name))
243 continue;
244
245 /* Check symbol version. */
246 if (vdso_info.versym
247 && !vdso_match_version(vdso_info.versym[chain],
248 version, ver_hash))
249 continue;
250
251 return (void *)(vdso_info.load_offset + sym->st_value);
252 }
253
254 return 0;
255}
256
257void vdso_init_from_auxv(void *auxv)
258{
259 ELF(auxv_t) *elf_auxv = auxv;
260 for (int i = 0; elf_auxv[i].a_type != AT_NULL; i++)
261 {
262 if (elf_auxv[i].a_type == AT_SYSINFO_EHDR) {
263 vdso_init_from_sysinfo_ehdr(elf_auxv[i].a_un.a_val);
264 return;
265 }
266 }
267
268 vdso_info.valid = false;
269}
diff --git a/tools/testing/selftests/vDSO/vdso_standalone_test_x86.c b/tools/testing/selftests/vDSO/vdso_standalone_test_x86.c
new file mode 100644
index 000000000000..93b0ebf8cc38
--- /dev/null
+++ b/tools/testing/selftests/vDSO/vdso_standalone_test_x86.c
@@ -0,0 +1,128 @@
1/*
2 * vdso_test.c: Sample code to test parse_vdso.c on x86
3 * Copyright (c) 2011-2014 Andy Lutomirski
4 * Subject to the GNU General Public License, version 2
5 *
6 * You can amuse yourself by compiling with:
7 * gcc -std=gnu99 -nostdlib
8 * -Os -fno-asynchronous-unwind-tables -flto -lgcc_s
9 * vdso_standalone_test_x86.c parse_vdso.c
10 * to generate a small binary. On x86_64, you can omit -lgcc_s
11 * if you want the binary to be completely standalone.
12 */
13
14#include <sys/syscall.h>
15#include <sys/time.h>
16#include <unistd.h>
17#include <stdint.h>
18
19extern void *vdso_sym(const char *version, const char *name);
20extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
21extern void vdso_init_from_auxv(void *auxv);
22
23/* We need a libc functions... */
24int strcmp(const char *a, const char *b)
25{
26 /* This implementation is buggy: it never returns -1. */
27 while (*a || *b) {
28 if (*a != *b)
29 return 1;
30 if (*a == 0 || *b == 0)
31 return 1;
32 a++;
33 b++;
34 }
35
36 return 0;
37}
38
39/* ...and two syscalls. This is x86-specific. */
40static inline long x86_syscall3(long nr, long a0, long a1, long a2)
41{
42 long ret;
43#ifdef __x86_64__
44 asm volatile ("syscall" : "=a" (ret) : "a" (nr),
45 "D" (a0), "S" (a1), "d" (a2) :
46 "cc", "memory", "rcx",
47 "r8", "r9", "r10", "r11" );
48#else
49 asm volatile ("int $0x80" : "=a" (ret) : "a" (nr),
50 "b" (a0), "c" (a1), "d" (a2) :
51 "cc", "memory" );
52#endif
53 return ret;
54}
55
56static inline long linux_write(int fd, const void *data, size_t len)
57{
58 return x86_syscall3(__NR_write, fd, (long)data, (long)len);
59}
60
61static inline void linux_exit(int code)
62{
63 x86_syscall3(__NR_exit, code, 0, 0);
64}
65
66void to_base10(char *lastdig, time_t n)
67{
68 while (n) {
69 *lastdig = (n % 10) + '0';
70 n /= 10;
71 lastdig--;
72 }
73}
74
75__attribute__((externally_visible)) void c_main(void **stack)
76{
77 /* Parse the stack */
78 long argc = (long)*stack;
79 stack += argc + 2;
80
81 /* Now we're pointing at the environment. Skip it. */
82 while(*stack)
83 stack++;
84 stack++;
85
86 /* Now we're pointing at auxv. Initialize the vDSO parser. */
87 vdso_init_from_auxv((void *)stack);
88
89 /* Find gettimeofday. */
90 typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
91 gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
92
93 if (!gtod)
94 linux_exit(1);
95
96 struct timeval tv;
97 long ret = gtod(&tv, 0);
98
99 if (ret == 0) {
100 char buf[] = "The time is .000000\n";
101 to_base10(buf + 31, tv.tv_sec);
102 to_base10(buf + 38, tv.tv_usec);
103 linux_write(1, buf, sizeof(buf) - 1);
104 } else {
105 linux_exit(ret);
106 }
107
108 linux_exit(0);
109}
110
111/*
112 * This is the real entry point. It passes the initial stack into
113 * the C entry point.
114 */
115asm (
116 ".text\n"
117 ".global _start\n"
118 ".type _start,@function\n"
119 "_start:\n\t"
120#ifdef __x86_64__
121 "mov %rsp,%rdi\n\t"
122 "jmp c_main"
123#else
124 "push %esp\n\t"
125 "call c_main\n\t"
126 "int $3"
127#endif
128 );
diff --git a/tools/testing/selftests/vDSO/vdso_test.c b/tools/testing/selftests/vDSO/vdso_test.c
new file mode 100644
index 000000000000..8daeb7d7032c
--- /dev/null
+++ b/tools/testing/selftests/vDSO/vdso_test.c
@@ -0,0 +1,52 @@
1/*
2 * vdso_test.c: Sample code to test parse_vdso.c
3 * Copyright (c) 2014 Andy Lutomirski
4 * Subject to the GNU General Public License, version 2
5 *
6 * Compile with:
7 * gcc -std=gnu99 vdso_test.c parse_vdso.c
8 *
9 * Tested on x86, 32-bit and 64-bit. It may work on other architectures, too.
10 */
11
12#include <stdint.h>
13#include <elf.h>
14#include <stdio.h>
15#include <sys/auxv.h>
16#include <sys/time.h>
17
18extern void *vdso_sym(const char *version, const char *name);
19extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
20extern void vdso_init_from_auxv(void *auxv);
21
22int main(int argc, char **argv)
23{
24 unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
25 if (!sysinfo_ehdr) {
26 printf("AT_SYSINFO_EHDR is not present!\n");
27 return 0;
28 }
29
30 vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
31
32 /* Find gettimeofday. */
33 typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
34 gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
35
36 if (!gtod) {
37 printf("Could not find __vdso_gettimeofday\n");
38 return 1;
39 }
40
41 struct timeval tv;
42 long ret = gtod(&tv, 0);
43
44 if (ret == 0) {
45 printf("The time is %lld.%06lld\n",
46 (long long)tv.tv_sec, (long long)tv.tv_usec);
47 } else {
48 printf("__vdso_gettimeofday failed\n");
49 }
50
51 return 0;
52}
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
index a937a9d26b60..142c565bb351 100644
--- a/tools/testing/selftests/vm/.gitignore
+++ b/tools/testing/selftests/vm/.gitignore
@@ -7,3 +7,4 @@ mlock2-tests
7on-fault-limit 7on-fault-limit
8transhuge-stress 8transhuge-stress
9userfaultfd 9userfaultfd
10mlock-intersect-test
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index e4bb1de1d526..bbab7f4664ac 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -10,6 +10,7 @@ BINARIES += on-fault-limit
10BINARIES += thuge-gen 10BINARIES += thuge-gen
11BINARIES += transhuge-stress 11BINARIES += transhuge-stress
12BINARIES += userfaultfd 12BINARIES += userfaultfd
13BINARIES += mlock-random-test
13 14
14all: $(BINARIES) 15all: $(BINARIES)
15%: %.c 16%: %.c
@@ -17,6 +18,9 @@ all: $(BINARIES)
17userfaultfd: userfaultfd.c ../../../../usr/include/linux/kernel.h 18userfaultfd: userfaultfd.c ../../../../usr/include/linux/kernel.h
18 $(CC) $(CFLAGS) -O2 -o $@ $< -lpthread 19 $(CC) $(CFLAGS) -O2 -o $@ $< -lpthread
19 20
21mlock-random-test: mlock-random-test.c
22 $(CC) $(CFLAGS) -o $@ $< -lcap
23
20../../../../usr/include/linux/kernel.h: 24../../../../usr/include/linux/kernel.h:
21 make -C ../../../.. headers_install 25 make -C ../../../.. headers_install
22 26
diff --git a/tools/testing/selftests/vm/mlock-random-test.c b/tools/testing/selftests/vm/mlock-random-test.c
new file mode 100644
index 000000000000..83de4f58d262
--- /dev/null
+++ b/tools/testing/selftests/vm/mlock-random-test.c
@@ -0,0 +1,293 @@
1/*
2 * It tests the mlock/mlock2() when they are invoked
3 * on randomly memory region.
4 */
5#include <unistd.h>
6#include <sys/resource.h>
7#include <sys/capability.h>
8#include <sys/mman.h>
9#include <fcntl.h>
10#include <string.h>
11#include <sys/ipc.h>
12#include <sys/shm.h>
13#include <time.h>
14#include "mlock2.h"
15
16#define CHUNK_UNIT (128 * 1024)
17#define MLOCK_RLIMIT_SIZE (CHUNK_UNIT * 2)
18#define MLOCK_WITHIN_LIMIT_SIZE CHUNK_UNIT
19#define MLOCK_OUTOF_LIMIT_SIZE (CHUNK_UNIT * 3)
20
21#define TEST_LOOP 100
22#define PAGE_ALIGN(size, ps) (((size) + ((ps) - 1)) & ~((ps) - 1))
23
24int set_cap_limits(rlim_t max)
25{
26 struct rlimit new;
27 cap_t cap = cap_init();
28
29 new.rlim_cur = max;
30 new.rlim_max = max;
31 if (setrlimit(RLIMIT_MEMLOCK, &new)) {
32 perror("setrlimit() returns error\n");
33 return -1;
34 }
35
36 /* drop capabilities including CAP_IPC_LOCK */
37 if (cap_set_proc(cap)) {
38 perror("cap_set_proc() returns error\n");
39 return -2;
40 }
41
42 return 0;
43}
44
45int get_proc_locked_vm_size(void)
46{
47 FILE *f;
48 int ret = -1;
49 char line[1024] = {0};
50 unsigned long lock_size = 0;
51
52 f = fopen("/proc/self/status", "r");
53 if (!f) {
54 perror("fopen");
55 return -1;
56 }
57
58 while (fgets(line, 1024, f)) {
59 if (strstr(line, "VmLck")) {
60 ret = sscanf(line, "VmLck:\t%8lu kB", &lock_size);
61 if (ret <= 0) {
62 printf("sscanf() on VmLck error: %s: %d\n",
63 line, ret);
64 fclose(f);
65 return -1;
66 }
67 fclose(f);
68 return (int)(lock_size << 10);
69 }
70 }
71
72 perror("cann't parse VmLck in /proc/self/status\n");
73 fclose(f);
74 return -1;
75}
76
77/*
78 * Get the MMUPageSize of the memory region including input
79 * address from proc file.
80 *
81 * return value: on error case, 0 will be returned.
82 * Otherwise the page size(in bytes) is returned.
83 */
84int get_proc_page_size(unsigned long addr)
85{
86 FILE *smaps;
87 char *line;
88 unsigned long mmupage_size = 0;
89 size_t size;
90
91 smaps = seek_to_smaps_entry(addr);
92 if (!smaps) {
93 printf("Unable to parse /proc/self/smaps\n");
94 return 0;
95 }
96
97 while (getline(&line, &size, smaps) > 0) {
98 if (!strstr(line, "MMUPageSize")) {
99 free(line);
100 line = NULL;
101 size = 0;
102 continue;
103 }
104
105 /* found the MMUPageSize of this section */
106 if (sscanf(line, "MMUPageSize: %8lu kB",
107 &mmupage_size) < 1) {
108 printf("Unable to parse smaps entry for Size:%s\n",
109 line);
110 break;
111 }
112
113 }
114 free(line);
115 if (smaps)
116 fclose(smaps);
117 return mmupage_size << 10;
118}
119
120/*
121 * Test mlock/mlock2() on provided memory chunk.
122 * It expects the mlock/mlock2() to be successful (within rlimit)
123 *
124 * With allocated memory chunk [p, p + alloc_size), this
125 * test will choose start/len randomly to perform mlock/mlock2
126 * [start, start + len] memory range. The range is within range
127 * of the allocated chunk.
128 *
129 * The memory region size alloc_size is within the rlimit.
130 * So we always expect a success of mlock/mlock2.
131 *
132 * VmLck is assumed to be 0 before this test.
133 *
134 * return value: 0 - success
135 * else: failure
136 */
137int test_mlock_within_limit(char *p, int alloc_size)
138{
139 int i;
140 int ret = 0;
141 int locked_vm_size = 0;
142 struct rlimit cur;
143 int page_size = 0;
144
145 getrlimit(RLIMIT_MEMLOCK, &cur);
146 if (cur.rlim_cur < alloc_size) {
147 printf("alloc_size[%d] < %u rlimit,lead to mlock failure\n",
148 alloc_size, (unsigned int)cur.rlim_cur);
149 return -1;
150 }
151
152 srand(time(NULL));
153 for (i = 0; i < TEST_LOOP; i++) {
154 /*
155 * - choose mlock/mlock2 randomly
156 * - choose lock_size randomly but lock_size < alloc_size
157 * - choose start_offset randomly but p+start_offset+lock_size
158 * < p+alloc_size
159 */
160 int is_mlock = !!(rand() % 2);
161 int lock_size = rand() % alloc_size;
162 int start_offset = rand() % (alloc_size - lock_size);
163
164 if (is_mlock)
165 ret = mlock(p + start_offset, lock_size);
166 else
167 ret = mlock2_(p + start_offset, lock_size,
168 MLOCK_ONFAULT);
169
170 if (ret) {
171 printf("%s() failure at |%p(%d)| mlock:|%p(%d)|\n",
172 is_mlock ? "mlock" : "mlock2",
173 p, alloc_size,
174 p + start_offset, lock_size);
175 return ret;
176 }
177 }
178
179 /*
180 * Check VmLck left by the tests.
181 */
182 locked_vm_size = get_proc_locked_vm_size();
183 page_size = get_proc_page_size((unsigned long)p);
184 if (page_size == 0) {
185 printf("cannot get proc MMUPageSize\n");
186 return -1;
187 }
188
189 if (locked_vm_size > PAGE_ALIGN(alloc_size, page_size) + page_size) {
190 printf("test_mlock_within_limit() left VmLck:%d on %d chunk\n",
191 locked_vm_size, alloc_size);
192 return -1;
193 }
194
195 return 0;
196}
197
198
199/*
200 * We expect the mlock/mlock2() to be fail (outof limitation)
201 *
202 * With allocated memory chunk [p, p + alloc_size), this
203 * test will randomly choose start/len and perform mlock/mlock2
204 * on [start, start+len] range.
205 *
206 * The memory region size alloc_size is above the rlimit.
207 * And the len to be locked is higher than rlimit.
208 * So we always expect a failure of mlock/mlock2.
209 * No locked page number should be increased as a side effect.
210 *
211 * return value: 0 - success
212 * else: failure
213 */
214int test_mlock_outof_limit(char *p, int alloc_size)
215{
216 int i;
217 int ret = 0;
218 int locked_vm_size = 0, old_locked_vm_size = 0;
219 struct rlimit cur;
220
221 getrlimit(RLIMIT_MEMLOCK, &cur);
222 if (cur.rlim_cur >= alloc_size) {
223 printf("alloc_size[%d] >%u rlimit, violates test condition\n",
224 alloc_size, (unsigned int)cur.rlim_cur);
225 return -1;
226 }
227
228 old_locked_vm_size = get_proc_locked_vm_size();
229 srand(time(NULL));
230 for (i = 0; i < TEST_LOOP; i++) {
231 int is_mlock = !!(rand() % 2);
232 int lock_size = (rand() % (alloc_size - cur.rlim_cur))
233 + cur.rlim_cur;
234 int start_offset = rand() % (alloc_size - lock_size);
235
236 if (is_mlock)
237 ret = mlock(p + start_offset, lock_size);
238 else
239 ret = mlock2_(p + start_offset, lock_size,
240 MLOCK_ONFAULT);
241 if (ret == 0) {
242 printf("%s() succeeds? on %p(%d) mlock%p(%d)\n",
243 is_mlock ? "mlock" : "mlock2",
244 p, alloc_size,
245 p + start_offset, lock_size);
246 return -1;
247 }
248 }
249
250 locked_vm_size = get_proc_locked_vm_size();
251 if (locked_vm_size != old_locked_vm_size) {
252 printf("tests leads to new mlocked page: old[%d], new[%d]\n",
253 old_locked_vm_size,
254 locked_vm_size);
255 return -1;
256 }
257
258 return 0;
259}
260
261int main(int argc, char **argv)
262{
263 char *p = NULL;
264 int ret = 0;
265
266 if (set_cap_limits(MLOCK_RLIMIT_SIZE))
267 return -1;
268
269 p = malloc(MLOCK_WITHIN_LIMIT_SIZE);
270 if (p == NULL) {
271 perror("malloc() failure\n");
272 return -1;
273 }
274 ret = test_mlock_within_limit(p, MLOCK_WITHIN_LIMIT_SIZE);
275 if (ret)
276 return ret;
277 munlock(p, MLOCK_WITHIN_LIMIT_SIZE);
278 free(p);
279
280
281 p = malloc(MLOCK_OUTOF_LIMIT_SIZE);
282 if (p == NULL) {
283 perror("malloc() failure\n");
284 return -1;
285 }
286 ret = test_mlock_outof_limit(p, MLOCK_OUTOF_LIMIT_SIZE);
287 if (ret)
288 return ret;
289 munlock(p, MLOCK_OUTOF_LIMIT_SIZE);
290 free(p);
291
292 return 0;
293}
diff --git a/tools/testing/selftests/vm/mlock2-tests.c b/tools/testing/selftests/vm/mlock2-tests.c
index 02ca5e0177c5..ff0cda2b19c9 100644
--- a/tools/testing/selftests/vm/mlock2-tests.c
+++ b/tools/testing/selftests/vm/mlock2-tests.c
@@ -1,33 +1,12 @@
1#define _GNU_SOURCE 1#define _GNU_SOURCE
2#include <sys/mman.h> 2#include <sys/mman.h>
3#include <stdint.h> 3#include <stdint.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h> 4#include <unistd.h>
7#include <string.h> 5#include <string.h>
8#include <sys/time.h> 6#include <sys/time.h>
9#include <sys/resource.h> 7#include <sys/resource.h>
10#include <syscall.h>
11#include <errno.h>
12#include <stdbool.h> 8#include <stdbool.h>
13 9#include "mlock2.h"
14#ifndef MLOCK_ONFAULT
15#define MLOCK_ONFAULT 1
16#endif
17
18#ifndef MCL_ONFAULT
19#define MCL_ONFAULT (MCL_FUTURE << 1)
20#endif
21
22static int mlock2_(void *start, size_t len, int flags)
23{
24#ifdef __NR_mlock2
25 return syscall(__NR_mlock2, start, len, flags);
26#else
27 errno = ENOSYS;
28 return -1;
29#endif
30}
31 10
32struct vm_boundaries { 11struct vm_boundaries {
33 unsigned long start; 12 unsigned long start;
@@ -138,46 +117,6 @@ static uint64_t get_kpageflags(unsigned long pfn)
138 return flags; 117 return flags;
139} 118}
140 119
141static FILE *seek_to_smaps_entry(unsigned long addr)
142{
143 FILE *file;
144 char *line = NULL;
145 size_t size = 0;
146 unsigned long start, end;
147 char perms[5];
148 unsigned long offset;
149 char dev[32];
150 unsigned long inode;
151 char path[BUFSIZ];
152
153 file = fopen("/proc/self/smaps", "r");
154 if (!file) {
155 perror("fopen smaps");
156 _exit(1);
157 }
158
159 while (getline(&line, &size, file) > 0) {
160 if (sscanf(line, "%lx-%lx %s %lx %s %lu %s\n",
161 &start, &end, perms, &offset, dev, &inode, path) < 6)
162 goto next;
163
164 if (start <= addr && addr < end)
165 goto out;
166
167next:
168 free(line);
169 line = NULL;
170 size = 0;
171 }
172
173 fclose(file);
174 file = NULL;
175
176out:
177 free(line);
178 return file;
179}
180
181#define VMFLAGS "VmFlags:" 120#define VMFLAGS "VmFlags:"
182 121
183static bool is_vmflag_set(unsigned long addr, const char *vmflag) 122static bool is_vmflag_set(unsigned long addr, const char *vmflag)
diff --git a/tools/testing/selftests/vm/mlock2.h b/tools/testing/selftests/vm/mlock2.h
new file mode 100644
index 000000000000..7ee062929d3e
--- /dev/null
+++ b/tools/testing/selftests/vm/mlock2.h
@@ -0,0 +1,62 @@
1#include <syscall.h>
2#include <errno.h>
3#include <stdio.h>
4#include <stdlib.h>
5
6#ifndef MLOCK_ONFAULT
7#define MLOCK_ONFAULT 1
8#endif
9
10#ifndef MCL_ONFAULT
11#define MCL_ONFAULT (MCL_FUTURE << 1)
12#endif
13
14static int mlock2_(void *start, size_t len, int flags)
15{
16#ifdef __NR_mlock2
17 return syscall(__NR_mlock2, start, len, flags);
18#else
19 errno = ENOSYS;
20 return -1;
21#endif
22}
23
24static FILE *seek_to_smaps_entry(unsigned long addr)
25{
26 FILE *file;
27 char *line = NULL;
28 size_t size = 0;
29 unsigned long start, end;
30 char perms[5];
31 unsigned long offset;
32 char dev[32];
33 unsigned long inode;
34 char path[BUFSIZ];
35
36 file = fopen("/proc/self/smaps", "r");
37 if (!file) {
38 perror("fopen smaps");
39 _exit(1);
40 }
41
42 while (getline(&line, &size, file) > 0) {
43 if (sscanf(line, "%lx-%lx %s %lx %s %lu %s\n",
44 &start, &end, perms, &offset, dev, &inode, path) < 6)
45 goto next;
46
47 if (start <= addr && addr < end)
48 goto out;
49
50next:
51 free(line);
52 line = NULL;
53 size = 0;
54 }
55
56 fclose(file);
57 file = NULL;
58
59out:
60 free(line);
61 return file;
62}
diff --git a/tools/testing/selftests/watchdog/.gitignore b/tools/testing/selftests/watchdog/.gitignore
new file mode 100644
index 000000000000..5aac51575c7e
--- /dev/null
+++ b/tools/testing/selftests/watchdog/.gitignore
@@ -0,0 +1 @@
watchdog-test
diff --git a/tools/testing/selftests/watchdog/Makefile b/tools/testing/selftests/watchdog/Makefile
new file mode 100644
index 000000000000..f863c664e3d1
--- /dev/null
+++ b/tools/testing/selftests/watchdog/Makefile
@@ -0,0 +1,8 @@
1TEST_PROGS := watchdog-test
2
3all: $(TEST_PROGS)
4
5include ../lib.mk
6
7clean:
8 rm -fr $(TEST_PROGS)
diff --git a/tools/testing/selftests/watchdog/watchdog-test.c b/tools/testing/selftests/watchdog/watchdog-test.c
new file mode 100644
index 000000000000..6983d05097e2
--- /dev/null
+++ b/tools/testing/selftests/watchdog/watchdog-test.c
@@ -0,0 +1,105 @@
1/*
2 * Watchdog Driver Test Program
3 */
4
5#include <errno.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10#include <fcntl.h>
11#include <signal.h>
12#include <sys/ioctl.h>
13#include <linux/types.h>
14#include <linux/watchdog.h>
15
16int fd;
17const char v = 'V';
18
19/*
20 * This function simply sends an IOCTL to the driver, which in turn ticks
21 * the PC Watchdog card to reset its internal timer so it doesn't trigger
22 * a computer reset.
23 */
24static void keep_alive(void)
25{
26 int dummy;
27
28 printf(".");
29 ioctl(fd, WDIOC_KEEPALIVE, &dummy);
30}
31
32/*
33 * The main program. Run the program with "-d" to disable the card,
34 * or "-e" to enable the card.
35 */
36
37static void term(int sig)
38{
39 int ret = write(fd, &v, 1);
40
41 close(fd);
42 if (ret < 0)
43 printf("\nStopping watchdog ticks failed (%d)...\n", errno);
44 else
45 printf("\nStopping watchdog ticks...\n");
46 exit(0);
47}
48
49int main(int argc, char *argv[])
50{
51 int flags;
52 unsigned int ping_rate = 1;
53 int ret;
54
55 setbuf(stdout, NULL);
56
57 fd = open("/dev/watchdog", O_WRONLY);
58
59 if (fd == -1) {
60 printf("Watchdog device not enabled.\n");
61 exit(-1);
62 }
63
64 if (argc > 1) {
65 if (!strncasecmp(argv[1], "-d", 2)) {
66 flags = WDIOS_DISABLECARD;
67 ioctl(fd, WDIOC_SETOPTIONS, &flags);
68 printf("Watchdog card disabled.\n");
69 goto end;
70 } else if (!strncasecmp(argv[1], "-e", 2)) {
71 flags = WDIOS_ENABLECARD;
72 ioctl(fd, WDIOC_SETOPTIONS, &flags);
73 printf("Watchdog card enabled.\n");
74 goto end;
75 } else if (!strncasecmp(argv[1], "-t", 2) && argv[2]) {
76 flags = atoi(argv[2]);
77 ioctl(fd, WDIOC_SETTIMEOUT, &flags);
78 printf("Watchdog timeout set to %u seconds.\n", flags);
79 goto end;
80 } else if (!strncasecmp(argv[1], "-p", 2) && argv[2]) {
81 ping_rate = strtoul(argv[2], NULL, 0);
82 printf("Watchdog ping rate set to %u seconds.\n", ping_rate);
83 } else {
84 printf("-d to disable, -e to enable, -t <n> to set " \
85 "the timeout,\n-p <n> to set the ping rate, and \n");
86 printf("run by itself to tick the card.\n");
87 goto end;
88 }
89 }
90
91 printf("Watchdog Ticking Away!\n");
92
93 signal(SIGINT, term);
94
95 while(1) {
96 keep_alive();
97 sleep(ping_rate);
98 }
99end:
100 ret = write(fd, &v, 1);
101 if (ret < 0)
102 printf("Stopping watchdog ticks failed (%d)...\n", errno);
103 close(fd);
104 return 0;
105}
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index 4f747ee07f10..a89f80a5b711 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -5,7 +5,8 @@ include ../lib.mk
5.PHONY: all all_32 all_64 warn_32bit_failure clean 5.PHONY: all all_32 all_64 warn_32bit_failure clean
6 6
7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ 7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \
8 check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test 8 check_initial_reg_state sigreturn ldt_gdt iopl \
9 protection_keys
9TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ 10TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
10 test_FCMOV test_FCOMI test_FISTTP \ 11 test_FCMOV test_FCOMI test_FISTTP \
11 vdso_restorer 12 vdso_restorer
diff --git a/tools/testing/selftests/x86/pkey-helpers.h b/tools/testing/selftests/x86/pkey-helpers.h
new file mode 100644
index 000000000000..b20293956eec
--- /dev/null
+++ b/tools/testing/selftests/x86/pkey-helpers.h
@@ -0,0 +1,219 @@
1#ifndef _PKEYS_HELPER_H
2#define _PKEYS_HELPER_H
3#define _GNU_SOURCE
4#include <string.h>
5#include <stdarg.h>
6#include <stdio.h>
7#include <stdint.h>
8#include <stdbool.h>
9#include <signal.h>
10#include <assert.h>
11#include <stdlib.h>
12#include <ucontext.h>
13#include <sys/mman.h>
14
15#define NR_PKEYS 16
16#define PKRU_BITS_PER_PKEY 2
17
18#ifndef DEBUG_LEVEL
19#define DEBUG_LEVEL 0
20#endif
21#define DPRINT_IN_SIGNAL_BUF_SIZE 4096
22extern int dprint_in_signal;
23extern char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
24static inline void sigsafe_printf(const char *format, ...)
25{
26 va_list ap;
27
28 va_start(ap, format);
29 if (!dprint_in_signal) {
30 vprintf(format, ap);
31 } else {
32 int len = vsnprintf(dprint_in_signal_buffer,
33 DPRINT_IN_SIGNAL_BUF_SIZE,
34 format, ap);
35 /*
36 * len is amount that would have been printed,
37 * but actual write is truncated at BUF_SIZE.
38 */
39 if (len > DPRINT_IN_SIGNAL_BUF_SIZE)
40 len = DPRINT_IN_SIGNAL_BUF_SIZE;
41 write(1, dprint_in_signal_buffer, len);
42 }
43 va_end(ap);
44}
45#define dprintf_level(level, args...) do { \
46 if (level <= DEBUG_LEVEL) \
47 sigsafe_printf(args); \
48 fflush(NULL); \
49} while (0)
50#define dprintf0(args...) dprintf_level(0, args)
51#define dprintf1(args...) dprintf_level(1, args)
52#define dprintf2(args...) dprintf_level(2, args)
53#define dprintf3(args...) dprintf_level(3, args)
54#define dprintf4(args...) dprintf_level(4, args)
55
56extern unsigned int shadow_pkru;
57static inline unsigned int __rdpkru(void)
58{
59 unsigned int eax, edx;
60 unsigned int ecx = 0;
61 unsigned int pkru;
62
63 asm volatile(".byte 0x0f,0x01,0xee\n\t"
64 : "=a" (eax), "=d" (edx)
65 : "c" (ecx));
66 pkru = eax;
67 return pkru;
68}
69
70static inline unsigned int _rdpkru(int line)
71{
72 unsigned int pkru = __rdpkru();
73
74 dprintf4("rdpkru(line=%d) pkru: %x shadow: %x\n",
75 line, pkru, shadow_pkru);
76 assert(pkru == shadow_pkru);
77
78 return pkru;
79}
80
81#define rdpkru() _rdpkru(__LINE__)
82
83static inline void __wrpkru(unsigned int pkru)
84{
85 unsigned int eax = pkru;
86 unsigned int ecx = 0;
87 unsigned int edx = 0;
88
89 dprintf4("%s() changing %08x to %08x\n", __func__, __rdpkru(), pkru);
90 asm volatile(".byte 0x0f,0x01,0xef\n\t"
91 : : "a" (eax), "c" (ecx), "d" (edx));
92 assert(pkru == __rdpkru());
93}
94
95static inline void wrpkru(unsigned int pkru)
96{
97 dprintf4("%s() changing %08x to %08x\n", __func__, __rdpkru(), pkru);
98 /* will do the shadow check for us: */
99 rdpkru();
100 __wrpkru(pkru);
101 shadow_pkru = pkru;
102 dprintf4("%s(%08x) pkru: %08x\n", __func__, pkru, __rdpkru());
103}
104
105/*
106 * These are technically racy. since something could
107 * change PKRU between the read and the write.
108 */
109static inline void __pkey_access_allow(int pkey, int do_allow)
110{
111 unsigned int pkru = rdpkru();
112 int bit = pkey * 2;
113
114 if (do_allow)
115 pkru &= (1<<bit);
116 else
117 pkru |= (1<<bit);
118
119 dprintf4("pkru now: %08x\n", rdpkru());
120 wrpkru(pkru);
121}
122
123static inline void __pkey_write_allow(int pkey, int do_allow_write)
124{
125 long pkru = rdpkru();
126 int bit = pkey * 2 + 1;
127
128 if (do_allow_write)
129 pkru &= (1<<bit);
130 else
131 pkru |= (1<<bit);
132
133 wrpkru(pkru);
134 dprintf4("pkru now: %08x\n", rdpkru());
135}
136
137#define PROT_PKEY0 0x10 /* protection key value (bit 0) */
138#define PROT_PKEY1 0x20 /* protection key value (bit 1) */
139#define PROT_PKEY2 0x40 /* protection key value (bit 2) */
140#define PROT_PKEY3 0x80 /* protection key value (bit 3) */
141
142#define PAGE_SIZE 4096
143#define MB (1<<20)
144
145static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
146 unsigned int *ecx, unsigned int *edx)
147{
148 /* ecx is often an input as well as an output. */
149 asm volatile(
150 "cpuid;"
151 : "=a" (*eax),
152 "=b" (*ebx),
153 "=c" (*ecx),
154 "=d" (*edx)
155 : "0" (*eax), "2" (*ecx));
156}
157
158/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */
159#define X86_FEATURE_PKU (1<<3) /* Protection Keys for Userspace */
160#define X86_FEATURE_OSPKE (1<<4) /* OS Protection Keys Enable */
161
162static inline int cpu_has_pku(void)
163{
164 unsigned int eax;
165 unsigned int ebx;
166 unsigned int ecx;
167 unsigned int edx;
168
169 eax = 0x7;
170 ecx = 0x0;
171 __cpuid(&eax, &ebx, &ecx, &edx);
172
173 if (!(ecx & X86_FEATURE_PKU)) {
174 dprintf2("cpu does not have PKU\n");
175 return 0;
176 }
177 if (!(ecx & X86_FEATURE_OSPKE)) {
178 dprintf2("cpu does not have OSPKE\n");
179 return 0;
180 }
181 return 1;
182}
183
184#define XSTATE_PKRU_BIT (9)
185#define XSTATE_PKRU 0x200
186
187int pkru_xstate_offset(void)
188{
189 unsigned int eax;
190 unsigned int ebx;
191 unsigned int ecx;
192 unsigned int edx;
193 int xstate_offset;
194 int xstate_size;
195 unsigned long XSTATE_CPUID = 0xd;
196 int leaf;
197
198 /* assume that XSTATE_PKRU is set in XCR0 */
199 leaf = XSTATE_PKRU_BIT;
200 {
201 eax = XSTATE_CPUID;
202 ecx = leaf;
203 __cpuid(&eax, &ebx, &ecx, &edx);
204
205 if (leaf == XSTATE_PKRU_BIT) {
206 xstate_offset = ebx;
207 xstate_size = eax;
208 }
209 }
210
211 if (xstate_size == 0) {
212 printf("could not find size/offset of PKRU in xsave state\n");
213 return 0;
214 }
215
216 return xstate_offset;
217}
218
219#endif /* _PKEYS_HELPER_H */
diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c
new file mode 100644
index 000000000000..bdd58c78902e
--- /dev/null
+++ b/tools/testing/selftests/x86/protection_keys.c
@@ -0,0 +1,1410 @@
1/*
2 * Tests x86 Memory Protection Keys (see Documentation/x86/protection-keys.txt)
3 *
4 * There are examples in here of:
5 * * how to set protection keys on memory
6 * * how to set/clear bits in PKRU (the rights register)
7 * * how to handle SEGV_PKRU signals and extract pkey-relevant
8 * information from the siginfo
9 *
10 * Things to add:
11 * make sure KSM and KSM COW breaking works
12 * prefault pages in at malloc, or not
13 * protect MPX bounds tables with protection keys?
14 * make sure VMA splitting/merging is working correctly
15 * OOMs can destroy mm->mmap (see exit_mmap()), so make sure it is immune to pkeys
16 * look for pkey "leaks" where it is still set on a VMA but "freed" back to the kernel
17 * do a plain mprotect() to a mprotect_pkey() area and make sure the pkey sticks
18 *
19 * Compile like this:
20 * gcc -o protection_keys -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
21 * gcc -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
22 */
23#define _GNU_SOURCE
24#include <errno.h>
25#include <linux/futex.h>
26#include <sys/time.h>
27#include <sys/syscall.h>
28#include <string.h>
29#include <stdio.h>
30#include <stdint.h>
31#include <stdbool.h>
32#include <signal.h>
33#include <assert.h>
34#include <stdlib.h>
35#include <ucontext.h>
36#include <sys/mman.h>
37#include <sys/types.h>
38#include <sys/wait.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41#include <unistd.h>
42#include <sys/ptrace.h>
43#include <setjmp.h>
44
45#include "pkey-helpers.h"
46
47int iteration_nr = 1;
48int test_nr;
49
50unsigned int shadow_pkru;
51
52#define HPAGE_SIZE (1UL<<21)
53#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
54#define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1))
55#define ALIGN_DOWN(x, align_to) ((x) & ~((align_to)-1))
56#define ALIGN_PTR_UP(p, ptr_align_to) ((typeof(p))ALIGN_UP((unsigned long)(p), ptr_align_to))
57#define ALIGN_PTR_DOWN(p, ptr_align_to) ((typeof(p))ALIGN_DOWN((unsigned long)(p), ptr_align_to))
58#define __stringify_1(x...) #x
59#define __stringify(x...) __stringify_1(x)
60
61#define PTR_ERR_ENOTSUP ((void *)-ENOTSUP)
62
63int dprint_in_signal;
64char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
65
66extern void abort_hooks(void);
67#define pkey_assert(condition) do { \
68 if (!(condition)) { \
69 dprintf0("assert() at %s::%d test_nr: %d iteration: %d\n", \
70 __FILE__, __LINE__, \
71 test_nr, iteration_nr); \
72 dprintf0("errno at assert: %d", errno); \
73 abort_hooks(); \
74 assert(condition); \
75 } \
76} while (0)
77#define raw_assert(cond) assert(cond)
78
79void cat_into_file(char *str, char *file)
80{
81 int fd = open(file, O_RDWR);
82 int ret;
83
84 dprintf2("%s(): writing '%s' to '%s'\n", __func__, str, file);
85 /*
86 * these need to be raw because they are called under
87 * pkey_assert()
88 */
89 raw_assert(fd >= 0);
90 ret = write(fd, str, strlen(str));
91 if (ret != strlen(str)) {
92 perror("write to file failed");
93 fprintf(stderr, "filename: '%s' str: '%s'\n", file, str);
94 raw_assert(0);
95 }
96 close(fd);
97}
98
99#if CONTROL_TRACING > 0
100static int warned_tracing;
101int tracing_root_ok(void)
102{
103 if (geteuid() != 0) {
104 if (!warned_tracing)
105 fprintf(stderr, "WARNING: not run as root, "
106 "can not do tracing control\n");
107 warned_tracing = 1;
108 return 0;
109 }
110 return 1;
111}
112#endif
113
114void tracing_on(void)
115{
116#if CONTROL_TRACING > 0
117#define TRACEDIR "/sys/kernel/debug/tracing"
118 char pidstr[32];
119
120 if (!tracing_root_ok())
121 return;
122
123 sprintf(pidstr, "%d", getpid());
124 cat_into_file("0", TRACEDIR "/tracing_on");
125 cat_into_file("\n", TRACEDIR "/trace");
126 if (1) {
127 cat_into_file("function_graph", TRACEDIR "/current_tracer");
128 cat_into_file("1", TRACEDIR "/options/funcgraph-proc");
129 } else {
130 cat_into_file("nop", TRACEDIR "/current_tracer");
131 }
132 cat_into_file(pidstr, TRACEDIR "/set_ftrace_pid");
133 cat_into_file("1", TRACEDIR "/tracing_on");
134 dprintf1("enabled tracing\n");
135#endif
136}
137
138void tracing_off(void)
139{
140#if CONTROL_TRACING > 0
141 if (!tracing_root_ok())
142 return;
143 cat_into_file("0", "/sys/kernel/debug/tracing/tracing_on");
144#endif
145}
146
147void abort_hooks(void)
148{
149 fprintf(stderr, "running %s()...\n", __func__);
150 tracing_off();
151#ifdef SLEEP_ON_ABORT
152 sleep(SLEEP_ON_ABORT);
153#endif
154}
155
156static inline void __page_o_noops(void)
157{
158 /* 8-bytes of instruction * 512 bytes = 1 page */
159 asm(".rept 512 ; nopl 0x7eeeeeee(%eax) ; .endr");
160}
161
162/*
163 * This attempts to have roughly a page of instructions followed by a few
164 * instructions that do a write, and another page of instructions. That
165 * way, we are pretty sure that the write is in the second page of
166 * instructions and has at least a page of padding behind it.
167 *
168 * *That* lets us be sure to madvise() away the write instruction, which
169 * will then fault, which makes sure that the fault code handles
170 * execute-only memory properly.
171 */
172__attribute__((__aligned__(PAGE_SIZE)))
173void lots_o_noops_around_write(int *write_to_me)
174{
175 dprintf3("running %s()\n", __func__);
176 __page_o_noops();
177 /* Assume this happens in the second page of instructions: */
178 *write_to_me = __LINE__;
179 /* pad out by another page: */
180 __page_o_noops();
181 dprintf3("%s() done\n", __func__);
182}
183
184/* Define some kernel-like types */
185#define u8 uint8_t
186#define u16 uint16_t
187#define u32 uint32_t
188#define u64 uint64_t
189
190#ifdef __i386__
191#define SYS_mprotect_key 380
192#define SYS_pkey_alloc 381
193#define SYS_pkey_free 382
194#define REG_IP_IDX REG_EIP
195#define si_pkey_offset 0x18
196#else
197#define SYS_mprotect_key 329
198#define SYS_pkey_alloc 330
199#define SYS_pkey_free 331
200#define REG_IP_IDX REG_RIP
201#define si_pkey_offset 0x20
202#endif
203
204void dump_mem(void *dumpme, int len_bytes)
205{
206 char *c = (void *)dumpme;
207 int i;
208
209 for (i = 0; i < len_bytes; i += sizeof(u64)) {
210 u64 *ptr = (u64 *)(c + i);
211 dprintf1("dump[%03d][@%p]: %016jx\n", i, ptr, *ptr);
212 }
213}
214
215#define __SI_FAULT (3 << 16)
216#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */
217#define SEGV_PKUERR (__SI_FAULT|4)
218
219static char *si_code_str(int si_code)
220{
221 if (si_code & SEGV_MAPERR)
222 return "SEGV_MAPERR";
223 if (si_code & SEGV_ACCERR)
224 return "SEGV_ACCERR";
225 if (si_code & SEGV_BNDERR)
226 return "SEGV_BNDERR";
227 if (si_code & SEGV_PKUERR)
228 return "SEGV_PKUERR";
229 return "UNKNOWN";
230}
231
232int pkru_faults;
233int last_si_pkey = -1;
234void signal_handler(int signum, siginfo_t *si, void *vucontext)
235{
236 ucontext_t *uctxt = vucontext;
237 int trapno;
238 unsigned long ip;
239 char *fpregs;
240 u32 *pkru_ptr;
241 u64 si_pkey;
242 u32 *si_pkey_ptr;
243 int pkru_offset;
244 fpregset_t fpregset;
245
246 dprint_in_signal = 1;
247 dprintf1(">>>>===============SIGSEGV============================\n");
248 dprintf1("%s()::%d, pkru: 0x%x shadow: %x\n", __func__, __LINE__,
249 __rdpkru(), shadow_pkru);
250
251 trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
252 ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
253 fpregset = uctxt->uc_mcontext.fpregs;
254 fpregs = (void *)fpregset;
255
256 dprintf2("%s() trapno: %d ip: 0x%lx info->si_code: %s/%d\n", __func__,
257 trapno, ip, si_code_str(si->si_code), si->si_code);
258#ifdef __i386__
259 /*
260 * 32-bit has some extra padding so that userspace can tell whether
261 * the XSTATE header is present in addition to the "legacy" FPU
262 * state. We just assume that it is here.
263 */
264 fpregs += 0x70;
265#endif
266 pkru_offset = pkru_xstate_offset();
267 pkru_ptr = (void *)(&fpregs[pkru_offset]);
268
269 dprintf1("siginfo: %p\n", si);
270 dprintf1(" fpregs: %p\n", fpregs);
271 /*
272 * If we got a PKRU fault, we *HAVE* to have at least one bit set in
273 * here.
274 */
275 dprintf1("pkru_xstate_offset: %d\n", pkru_xstate_offset());
276 if (DEBUG_LEVEL > 4)
277 dump_mem(pkru_ptr - 128, 256);
278 pkey_assert(*pkru_ptr);
279
280 si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset);
281 dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr);
282 dump_mem(si_pkey_ptr - 8, 24);
283 si_pkey = *si_pkey_ptr;
284 pkey_assert(si_pkey < NR_PKEYS);
285 last_si_pkey = si_pkey;
286
287 if ((si->si_code == SEGV_MAPERR) ||
288 (si->si_code == SEGV_ACCERR) ||
289 (si->si_code == SEGV_BNDERR)) {
290 printf("non-PK si_code, exiting...\n");
291 exit(4);
292 }
293
294 dprintf1("signal pkru from xsave: %08x\n", *pkru_ptr);
295 /* need __rdpkru() version so we do not do shadow_pkru checking */
296 dprintf1("signal pkru from pkru: %08x\n", __rdpkru());
297 dprintf1("si_pkey from siginfo: %jx\n", si_pkey);
298 *(u64 *)pkru_ptr = 0x00000000;
299 dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n");
300 pkru_faults++;
301 dprintf1("<<<<==================================================\n");
302 return;
303 if (trapno == 14) {
304 fprintf(stderr,
305 "ERROR: In signal handler, page fault, trapno = %d, ip = %016lx\n",
306 trapno, ip);
307 fprintf(stderr, "si_addr %p\n", si->si_addr);
308 fprintf(stderr, "REG_ERR: %lx\n",
309 (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]);
310 exit(1);
311 } else {
312 fprintf(stderr, "unexpected trap %d! at 0x%lx\n", trapno, ip);
313 fprintf(stderr, "si_addr %p\n", si->si_addr);
314 fprintf(stderr, "REG_ERR: %lx\n",
315 (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]);
316 exit(2);
317 }
318 dprint_in_signal = 0;
319}
320
321int wait_all_children(void)
322{
323 int status;
324 return waitpid(-1, &status, 0);
325}
326
327void sig_chld(int x)
328{
329 dprint_in_signal = 1;
330 dprintf2("[%d] SIGCHLD: %d\n", getpid(), x);
331 dprint_in_signal = 0;
332}
333
334void setup_sigsegv_handler(void)
335{
336 int r, rs;
337 struct sigaction newact;
338 struct sigaction oldact;
339
340 /* #PF is mapped to sigsegv */
341 int signum = SIGSEGV;
342
343 newact.sa_handler = 0;
344 newact.sa_sigaction = signal_handler;
345
346 /*sigset_t - signals to block while in the handler */
347 /* get the old signal mask. */
348 rs = sigprocmask(SIG_SETMASK, 0, &newact.sa_mask);
349 pkey_assert(rs == 0);
350
351 /* call sa_sigaction, not sa_handler*/
352 newact.sa_flags = SA_SIGINFO;
353
354 newact.sa_restorer = 0; /* void(*)(), obsolete */
355 r = sigaction(signum, &newact, &oldact);
356 r = sigaction(SIGALRM, &newact, &oldact);
357 pkey_assert(r == 0);
358}
359
360void setup_handlers(void)
361{
362 signal(SIGCHLD, &sig_chld);
363 setup_sigsegv_handler();
364}
365
366pid_t fork_lazy_child(void)
367{
368 pid_t forkret;
369
370 forkret = fork();
371 pkey_assert(forkret >= 0);
372 dprintf3("[%d] fork() ret: %d\n", getpid(), forkret);
373
374 if (!forkret) {
375 /* in the child */
376 while (1) {
377 dprintf1("child sleeping...\n");
378 sleep(30);
379 }
380 }
381 return forkret;
382}
383
384void davecmp(void *_a, void *_b, int len)
385{
386 int i;
387 unsigned long *a = _a;
388 unsigned long *b = _b;
389
390 for (i = 0; i < len / sizeof(*a); i++) {
391 if (a[i] == b[i])
392 continue;
393
394 dprintf3("[%3d]: a: %016lx b: %016lx\n", i, a[i], b[i]);
395 }
396}
397
398void dumpit(char *f)
399{
400 int fd = open(f, O_RDONLY);
401 char buf[100];
402 int nr_read;
403
404 dprintf2("maps fd: %d\n", fd);
405 do {
406 nr_read = read(fd, &buf[0], sizeof(buf));
407 write(1, buf, nr_read);
408 } while (nr_read > 0);
409 close(fd);
410}
411
412#define PKEY_DISABLE_ACCESS 0x1
413#define PKEY_DISABLE_WRITE 0x2
414
415u32 pkey_get(int pkey, unsigned long flags)
416{
417 u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
418 u32 pkru = __rdpkru();
419 u32 shifted_pkru;
420 u32 masked_pkru;
421
422 dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n",
423 __func__, pkey, flags, 0, 0);
424 dprintf2("%s() raw pkru: %x\n", __func__, pkru);
425
426 shifted_pkru = (pkru >> (pkey * PKRU_BITS_PER_PKEY));
427 dprintf2("%s() shifted_pkru: %x\n", __func__, shifted_pkru);
428 masked_pkru = shifted_pkru & mask;
429 dprintf2("%s() masked pkru: %x\n", __func__, masked_pkru);
430 /*
431 * shift down the relevant bits to the lowest two, then
432 * mask off all the other high bits.
433 */
434 return masked_pkru;
435}
436
437int pkey_set(int pkey, unsigned long rights, unsigned long flags)
438{
439 u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
440 u32 old_pkru = __rdpkru();
441 u32 new_pkru;
442
443 /* make sure that 'rights' only contains the bits we expect: */
444 assert(!(rights & ~mask));
445
446 /* copy old pkru */
447 new_pkru = old_pkru;
448 /* mask out bits from pkey in old value: */
449 new_pkru &= ~(mask << (pkey * PKRU_BITS_PER_PKEY));
450 /* OR in new bits for pkey: */
451 new_pkru |= (rights << (pkey * PKRU_BITS_PER_PKEY));
452
453 __wrpkru(new_pkru);
454
455 dprintf3("%s(pkey=%d, rights=%lx, flags=%lx) = %x pkru now: %x old_pkru: %x\n",
456 __func__, pkey, rights, flags, 0, __rdpkru(), old_pkru);
457 return 0;
458}
459
460void pkey_disable_set(int pkey, int flags)
461{
462 unsigned long syscall_flags = 0;
463 int ret;
464 int pkey_rights;
465 u32 orig_pkru;
466
467 dprintf1("START->%s(%d, 0x%x)\n", __func__,
468 pkey, flags);
469 pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
470
471 pkey_rights = pkey_get(pkey, syscall_flags);
472
473 dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
474 pkey, pkey, pkey_rights);
475 pkey_assert(pkey_rights >= 0);
476
477 pkey_rights |= flags;
478
479 ret = pkey_set(pkey, pkey_rights, syscall_flags);
480 assert(!ret);
481 /*pkru and flags have the same format */
482 shadow_pkru |= flags << (pkey * 2);
483 dprintf1("%s(%d) shadow: 0x%x\n", __func__, pkey, shadow_pkru);
484
485 pkey_assert(ret >= 0);
486
487 pkey_rights = pkey_get(pkey, syscall_flags);
488 dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
489 pkey, pkey, pkey_rights);
490
491 dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru());
492 if (flags)
493 pkey_assert(rdpkru() > orig_pkru);
494 dprintf1("END<---%s(%d, 0x%x)\n", __func__,
495 pkey, flags);
496}
497
498void pkey_disable_clear(int pkey, int flags)
499{
500 unsigned long syscall_flags = 0;
501 int ret;
502 int pkey_rights = pkey_get(pkey, syscall_flags);
503 u32 orig_pkru = rdpkru();
504
505 pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
506
507 dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
508 pkey, pkey, pkey_rights);
509 pkey_assert(pkey_rights >= 0);
510
511 pkey_rights |= flags;
512
513 ret = pkey_set(pkey, pkey_rights, 0);
514 /* pkru and flags have the same format */
515 shadow_pkru &= ~(flags << (pkey * 2));
516 pkey_assert(ret >= 0);
517
518 pkey_rights = pkey_get(pkey, syscall_flags);
519 dprintf1("%s(%d) pkey_get(%d): %x\n", __func__,
520 pkey, pkey, pkey_rights);
521
522 dprintf1("%s(%d) pkru: 0x%x\n", __func__, pkey, rdpkru());
523 if (flags)
524 assert(rdpkru() > orig_pkru);
525}
526
527void pkey_write_allow(int pkey)
528{
529 pkey_disable_clear(pkey, PKEY_DISABLE_WRITE);
530}
531void pkey_write_deny(int pkey)
532{
533 pkey_disable_set(pkey, PKEY_DISABLE_WRITE);
534}
535void pkey_access_allow(int pkey)
536{
537 pkey_disable_clear(pkey, PKEY_DISABLE_ACCESS);
538}
539void pkey_access_deny(int pkey)
540{
541 pkey_disable_set(pkey, PKEY_DISABLE_ACCESS);
542}
543
544int sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
545 unsigned long pkey)
546{
547 int sret;
548
549 dprintf2("%s(0x%p, %zx, prot=%lx, pkey=%lx)\n", __func__,
550 ptr, size, orig_prot, pkey);
551
552 errno = 0;
553 sret = syscall(SYS_mprotect_key, ptr, size, orig_prot, pkey);
554 if (errno) {
555 dprintf2("SYS_mprotect_key sret: %d\n", sret);
556 dprintf2("SYS_mprotect_key prot: 0x%lx\n", orig_prot);
557 dprintf2("SYS_mprotect_key failed, errno: %d\n", errno);
558 if (DEBUG_LEVEL >= 2)
559 perror("SYS_mprotect_pkey");
560 }
561 return sret;
562}
563
564int sys_pkey_alloc(unsigned long flags, unsigned long init_val)
565{
566 int ret = syscall(SYS_pkey_alloc, flags, init_val);
567 dprintf1("%s(flags=%lx, init_val=%lx) syscall ret: %d errno: %d\n",
568 __func__, flags, init_val, ret, errno);
569 return ret;
570}
571
572int alloc_pkey(void)
573{
574 int ret;
575 unsigned long init_val = 0x0;
576
577 dprintf1("alloc_pkey()::%d, pkru: 0x%x shadow: %x\n",
578 __LINE__, __rdpkru(), shadow_pkru);
579 ret = sys_pkey_alloc(0, init_val);
580 /*
581 * pkey_alloc() sets PKRU, so we need to reflect it in
582 * shadow_pkru:
583 */
584 dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n",
585 __LINE__, ret, __rdpkru(), shadow_pkru);
586 if (ret) {
587 /* clear both the bits: */
588 shadow_pkru &= ~(0x3 << (ret * 2));
589 dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n",
590 __LINE__, ret, __rdpkru(), shadow_pkru);
591 /*
592 * move the new state in from init_val
593 * (remember, we cheated and init_val == pkru format)
594 */
595 shadow_pkru |= (init_val << (ret * 2));
596 }
597 dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n",
598 __LINE__, ret, __rdpkru(), shadow_pkru);
599 dprintf1("alloc_pkey()::%d errno: %d\n", __LINE__, errno);
600 /* for shadow checking: */
601 rdpkru();
602 dprintf4("alloc_pkey()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n",
603 __LINE__, ret, __rdpkru(), shadow_pkru);
604 return ret;
605}
606
607int sys_pkey_free(unsigned long pkey)
608{
609 int ret = syscall(SYS_pkey_free, pkey);
610 dprintf1("%s(pkey=%ld) syscall ret: %d\n", __func__, pkey, ret);
611 return ret;
612}
613
614/*
615 * I had a bug where pkey bits could be set by mprotect() but
616 * not cleared. This ensures we get lots of random bit sets
617 * and clears on the vma and pte pkey bits.
618 */
619int alloc_random_pkey(void)
620{
621 int max_nr_pkey_allocs;
622 int ret;
623 int i;
624 int alloced_pkeys[NR_PKEYS];
625 int nr_alloced = 0;
626 int random_index;
627 memset(alloced_pkeys, 0, sizeof(alloced_pkeys));
628
629 /* allocate every possible key and make a note of which ones we got */
630 max_nr_pkey_allocs = NR_PKEYS;
631 max_nr_pkey_allocs = 1;
632 for (i = 0; i < max_nr_pkey_allocs; i++) {
633 int new_pkey = alloc_pkey();
634 if (new_pkey < 0)
635 break;
636 alloced_pkeys[nr_alloced++] = new_pkey;
637 }
638
639 pkey_assert(nr_alloced > 0);
640 /* select a random one out of the allocated ones */
641 random_index = rand() % nr_alloced;
642 ret = alloced_pkeys[random_index];
643 /* now zero it out so we don't free it next */
644 alloced_pkeys[random_index] = 0;
645
646 /* go through the allocated ones that we did not want and free them */
647 for (i = 0; i < nr_alloced; i++) {
648 int free_ret;
649 if (!alloced_pkeys[i])
650 continue;
651 free_ret = sys_pkey_free(alloced_pkeys[i]);
652 pkey_assert(!free_ret);
653 }
654 dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__,
655 __LINE__, ret, __rdpkru(), shadow_pkru);
656 return ret;
657}
658
659int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
660 unsigned long pkey)
661{
662 int nr_iterations = random() % 100;
663 int ret;
664
665 while (0) {
666 int rpkey = alloc_random_pkey();
667 ret = sys_mprotect_pkey(ptr, size, orig_prot, pkey);
668 dprintf1("sys_mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n",
669 ptr, size, orig_prot, pkey, ret);
670 if (nr_iterations-- < 0)
671 break;
672
673 dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__,
674 __LINE__, ret, __rdpkru(), shadow_pkru);
675 sys_pkey_free(rpkey);
676 dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__,
677 __LINE__, ret, __rdpkru(), shadow_pkru);
678 }
679 pkey_assert(pkey < NR_PKEYS);
680
681 ret = sys_mprotect_pkey(ptr, size, orig_prot, pkey);
682 dprintf1("mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n",
683 ptr, size, orig_prot, pkey, ret);
684 pkey_assert(!ret);
685 dprintf1("%s()::%d, ret: %d pkru: 0x%x shadow: 0x%x\n", __func__,
686 __LINE__, ret, __rdpkru(), shadow_pkru);
687 return ret;
688}
689
690struct pkey_malloc_record {
691 void *ptr;
692 long size;
693};
694struct pkey_malloc_record *pkey_malloc_records;
695long nr_pkey_malloc_records;
696void record_pkey_malloc(void *ptr, long size)
697{
698 long i;
699 struct pkey_malloc_record *rec = NULL;
700
701 for (i = 0; i < nr_pkey_malloc_records; i++) {
702 rec = &pkey_malloc_records[i];
703 /* find a free record */
704 if (rec)
705 break;
706 }
707 if (!rec) {
708 /* every record is full */
709 size_t old_nr_records = nr_pkey_malloc_records;
710 size_t new_nr_records = (nr_pkey_malloc_records * 2 + 1);
711 size_t new_size = new_nr_records * sizeof(struct pkey_malloc_record);
712 dprintf2("new_nr_records: %zd\n", new_nr_records);
713 dprintf2("new_size: %zd\n", new_size);
714 pkey_malloc_records = realloc(pkey_malloc_records, new_size);
715 pkey_assert(pkey_malloc_records != NULL);
716 rec = &pkey_malloc_records[nr_pkey_malloc_records];
717 /*
718 * realloc() does not initialize memory, so zero it from
719 * the first new record all the way to the end.
720 */
721 for (i = 0; i < new_nr_records - old_nr_records; i++)
722 memset(rec + i, 0, sizeof(*rec));
723 }
724 dprintf3("filling malloc record[%d/%p]: {%p, %ld}\n",
725 (int)(rec - pkey_malloc_records), rec, ptr, size);
726 rec->ptr = ptr;
727 rec->size = size;
728 nr_pkey_malloc_records++;
729}
730
731void free_pkey_malloc(void *ptr)
732{
733 long i;
734 int ret;
735 dprintf3("%s(%p)\n", __func__, ptr);
736 for (i = 0; i < nr_pkey_malloc_records; i++) {
737 struct pkey_malloc_record *rec = &pkey_malloc_records[i];
738 dprintf4("looking for ptr %p at record[%ld/%p]: {%p, %ld}\n",
739 ptr, i, rec, rec->ptr, rec->size);
740 if ((ptr < rec->ptr) ||
741 (ptr >= rec->ptr + rec->size))
742 continue;
743
744 dprintf3("found ptr %p at record[%ld/%p]: {%p, %ld}\n",
745 ptr, i, rec, rec->ptr, rec->size);
746 nr_pkey_malloc_records--;
747 ret = munmap(rec->ptr, rec->size);
748 dprintf3("munmap ret: %d\n", ret);
749 pkey_assert(!ret);
750 dprintf3("clearing rec->ptr, rec: %p\n", rec);
751 rec->ptr = NULL;
752 dprintf3("done clearing rec->ptr, rec: %p\n", rec);
753 return;
754 }
755 pkey_assert(false);
756}
757
758
759void *malloc_pkey_with_mprotect(long size, int prot, u16 pkey)
760{
761 void *ptr;
762 int ret;
763
764 rdpkru();
765 dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
766 size, prot, pkey);
767 pkey_assert(pkey < NR_PKEYS);
768 ptr = mmap(NULL, size, prot, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
769 pkey_assert(ptr != (void *)-1);
770 ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey);
771 pkey_assert(!ret);
772 record_pkey_malloc(ptr, size);
773 rdpkru();
774
775 dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr);
776 return ptr;
777}
778
779void *malloc_pkey_anon_huge(long size, int prot, u16 pkey)
780{
781 int ret;
782 void *ptr;
783
784 dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
785 size, prot, pkey);
786 /*
787 * Guarantee we can fit at least one huge page in the resulting
788 * allocation by allocating space for 2:
789 */
790 size = ALIGN_UP(size, HPAGE_SIZE * 2);
791 ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
792 pkey_assert(ptr != (void *)-1);
793 record_pkey_malloc(ptr, size);
794 mprotect_pkey(ptr, size, prot, pkey);
795
796 dprintf1("unaligned ptr: %p\n", ptr);
797 ptr = ALIGN_PTR_UP(ptr, HPAGE_SIZE);
798 dprintf1(" aligned ptr: %p\n", ptr);
799 ret = madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE);
800 dprintf1("MADV_HUGEPAGE ret: %d\n", ret);
801 ret = madvise(ptr, HPAGE_SIZE, MADV_WILLNEED);
802 dprintf1("MADV_WILLNEED ret: %d\n", ret);
803 memset(ptr, 0, HPAGE_SIZE);
804
805 dprintf1("mmap()'d thp for pkey %d @ %p\n", pkey, ptr);
806 return ptr;
807}
808
809int hugetlb_setup_ok;
810#define GET_NR_HUGE_PAGES 10
811void setup_hugetlbfs(void)
812{
813 int err;
814 int fd;
815 int validated_nr_pages;
816 int i;
817 char buf[] = "123";
818
819 if (geteuid() != 0) {
820 fprintf(stderr, "WARNING: not run as root, can not do hugetlb test\n");
821 return;
822 }
823
824 cat_into_file(__stringify(GET_NR_HUGE_PAGES), "/proc/sys/vm/nr_hugepages");
825
826 /*
827 * Now go make sure that we got the pages and that they
828 * are 2M pages. Someone might have made 1G the default.
829 */
830 fd = open("/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages", O_RDONLY);
831 if (fd < 0) {
832 perror("opening sysfs 2M hugetlb config");
833 return;
834 }
835
836 /* -1 to guarantee leaving the trailing \0 */
837 err = read(fd, buf, sizeof(buf)-1);
838 close(fd);
839 if (err <= 0) {
840 perror("reading sysfs 2M hugetlb config");
841 return;
842 }
843
844 if (atoi(buf) != GET_NR_HUGE_PAGES) {
845 fprintf(stderr, "could not confirm 2M pages, got: '%s' expected %d\n",
846 buf, GET_NR_HUGE_PAGES);
847 return;
848 }
849
850 hugetlb_setup_ok = 1;
851}
852
853void *malloc_pkey_hugetlb(long size, int prot, u16 pkey)
854{
855 void *ptr;
856 int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB;
857
858 if (!hugetlb_setup_ok)
859 return PTR_ERR_ENOTSUP;
860
861 dprintf1("doing %s(%ld, %x, %x)\n", __func__, size, prot, pkey);
862 size = ALIGN_UP(size, HPAGE_SIZE * 2);
863 pkey_assert(pkey < NR_PKEYS);
864 ptr = mmap(NULL, size, PROT_NONE, flags, -1, 0);
865 pkey_assert(ptr != (void *)-1);
866 mprotect_pkey(ptr, size, prot, pkey);
867
868 record_pkey_malloc(ptr, size);
869
870 dprintf1("mmap()'d hugetlbfs for pkey %d @ %p\n", pkey, ptr);
871 return ptr;
872}
873
874void *malloc_pkey_mmap_dax(long size, int prot, u16 pkey)
875{
876 void *ptr;
877 int fd;
878
879 dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
880 size, prot, pkey);
881 pkey_assert(pkey < NR_PKEYS);
882 fd = open("/dax/foo", O_RDWR);
883 pkey_assert(fd >= 0);
884
885 ptr = mmap(0, size, prot, MAP_SHARED, fd, 0);
886 pkey_assert(ptr != (void *)-1);
887
888 mprotect_pkey(ptr, size, prot, pkey);
889
890 record_pkey_malloc(ptr, size);
891
892 dprintf1("mmap()'d for pkey %d @ %p\n", pkey, ptr);
893 close(fd);
894 return ptr;
895}
896
897void *(*pkey_malloc[])(long size, int prot, u16 pkey) = {
898
899 malloc_pkey_with_mprotect,
900 malloc_pkey_anon_huge,
901 malloc_pkey_hugetlb
902/* can not do direct with the pkey_mprotect() API:
903 malloc_pkey_mmap_direct,
904 malloc_pkey_mmap_dax,
905*/
906};
907
908void *malloc_pkey(long size, int prot, u16 pkey)
909{
910 void *ret;
911 static int malloc_type;
912 int nr_malloc_types = ARRAY_SIZE(pkey_malloc);
913
914 pkey_assert(pkey < NR_PKEYS);
915
916 while (1) {
917 pkey_assert(malloc_type < nr_malloc_types);
918
919 ret = pkey_malloc[malloc_type](size, prot, pkey);
920 pkey_assert(ret != (void *)-1);
921
922 malloc_type++;
923 if (malloc_type >= nr_malloc_types)
924 malloc_type = (random()%nr_malloc_types);
925
926 /* try again if the malloc_type we tried is unsupported */
927 if (ret == PTR_ERR_ENOTSUP)
928 continue;
929
930 break;
931 }
932
933 dprintf3("%s(%ld, prot=%x, pkey=%x) returning: %p\n", __func__,
934 size, prot, pkey, ret);
935 return ret;
936}
937
938int last_pkru_faults;
939void expected_pk_fault(int pkey)
940{
941 dprintf2("%s(): last_pkru_faults: %d pkru_faults: %d\n",
942 __func__, last_pkru_faults, pkru_faults);
943 dprintf2("%s(%d): last_si_pkey: %d\n", __func__, pkey, last_si_pkey);
944 pkey_assert(last_pkru_faults + 1 == pkru_faults);
945 pkey_assert(last_si_pkey == pkey);
946 /*
947 * The signal handler shold have cleared out PKRU to let the
948 * test program continue. We now have to restore it.
949 */
950 if (__rdpkru() != 0)
951 pkey_assert(0);
952
953 __wrpkru(shadow_pkru);
954 dprintf1("%s() set PKRU=%x to restore state after signal nuked it\n",
955 __func__, shadow_pkru);
956 last_pkru_faults = pkru_faults;
957 last_si_pkey = -1;
958}
959
960void do_not_expect_pk_fault(void)
961{
962 pkey_assert(last_pkru_faults == pkru_faults);
963}
964
965int test_fds[10] = { -1 };
966int nr_test_fds;
967void __save_test_fd(int fd)
968{
969 pkey_assert(fd >= 0);
970 pkey_assert(nr_test_fds < ARRAY_SIZE(test_fds));
971 test_fds[nr_test_fds] = fd;
972 nr_test_fds++;
973}
974
975int get_test_read_fd(void)
976{
977 int test_fd = open("/etc/passwd", O_RDONLY);
978 __save_test_fd(test_fd);
979 return test_fd;
980}
981
982void close_test_fds(void)
983{
984 int i;
985
986 for (i = 0; i < nr_test_fds; i++) {
987 if (test_fds[i] < 0)
988 continue;
989 close(test_fds[i]);
990 test_fds[i] = -1;
991 }
992 nr_test_fds = 0;
993}
994
995#define barrier() __asm__ __volatile__("": : :"memory")
996__attribute__((noinline)) int read_ptr(int *ptr)
997{
998 /*
999 * Keep GCC from optimizing this away somehow
1000 */
1001 barrier();
1002 return *ptr;
1003}
1004
1005void test_read_of_write_disabled_region(int *ptr, u16 pkey)
1006{
1007 int ptr_contents;
1008
1009 dprintf1("disabling write access to PKEY[1], doing read\n");
1010 pkey_write_deny(pkey);
1011 ptr_contents = read_ptr(ptr);
1012 dprintf1("*ptr: %d\n", ptr_contents);
1013 dprintf1("\n");
1014}
1015void test_read_of_access_disabled_region(int *ptr, u16 pkey)
1016{
1017 int ptr_contents;
1018
1019 dprintf1("disabling access to PKEY[%02d], doing read @ %p\n", pkey, ptr);
1020 rdpkru();
1021 pkey_access_deny(pkey);
1022 ptr_contents = read_ptr(ptr);
1023 dprintf1("*ptr: %d\n", ptr_contents);
1024 expected_pk_fault(pkey);
1025}
1026void test_write_of_write_disabled_region(int *ptr, u16 pkey)
1027{
1028 dprintf1("disabling write access to PKEY[%02d], doing write\n", pkey);
1029 pkey_write_deny(pkey);
1030 *ptr = __LINE__;
1031 expected_pk_fault(pkey);
1032}
1033void test_write_of_access_disabled_region(int *ptr, u16 pkey)
1034{
1035 dprintf1("disabling access to PKEY[%02d], doing write\n", pkey);
1036 pkey_access_deny(pkey);
1037 *ptr = __LINE__;
1038 expected_pk_fault(pkey);
1039}
1040void test_kernel_write_of_access_disabled_region(int *ptr, u16 pkey)
1041{
1042 int ret;
1043 int test_fd = get_test_read_fd();
1044
1045 dprintf1("disabling access to PKEY[%02d], "
1046 "having kernel read() to buffer\n", pkey);
1047 pkey_access_deny(pkey);
1048 ret = read(test_fd, ptr, 1);
1049 dprintf1("read ret: %d\n", ret);
1050 pkey_assert(ret);
1051}
1052void test_kernel_write_of_write_disabled_region(int *ptr, u16 pkey)
1053{
1054 int ret;
1055 int test_fd = get_test_read_fd();
1056
1057 pkey_write_deny(pkey);
1058 ret = read(test_fd, ptr, 100);
1059 dprintf1("read ret: %d\n", ret);
1060 if (ret < 0 && (DEBUG_LEVEL > 0))
1061 perror("verbose read result (OK for this to be bad)");
1062 pkey_assert(ret);
1063}
1064
1065void test_kernel_gup_of_access_disabled_region(int *ptr, u16 pkey)
1066{
1067 int pipe_ret, vmsplice_ret;
1068 struct iovec iov;
1069 int pipe_fds[2];
1070
1071 pipe_ret = pipe(pipe_fds);
1072
1073 pkey_assert(pipe_ret == 0);
1074 dprintf1("disabling access to PKEY[%02d], "
1075 "having kernel vmsplice from buffer\n", pkey);
1076 pkey_access_deny(pkey);
1077 iov.iov_base = ptr;
1078 iov.iov_len = PAGE_SIZE;
1079 vmsplice_ret = vmsplice(pipe_fds[1], &iov, 1, SPLICE_F_GIFT);
1080 dprintf1("vmsplice() ret: %d\n", vmsplice_ret);
1081 pkey_assert(vmsplice_ret == -1);
1082
1083 close(pipe_fds[0]);
1084 close(pipe_fds[1]);
1085}
1086
1087void test_kernel_gup_write_to_write_disabled_region(int *ptr, u16 pkey)
1088{
1089 int ignored = 0xdada;
1090 int futex_ret;
1091 int some_int = __LINE__;
1092
1093 dprintf1("disabling write to PKEY[%02d], "
1094 "doing futex gunk in buffer\n", pkey);
1095 *ptr = some_int;
1096 pkey_write_deny(pkey);
1097 futex_ret = syscall(SYS_futex, ptr, FUTEX_WAIT, some_int-1, NULL,
1098 &ignored, ignored);
1099 if (DEBUG_LEVEL > 0)
1100 perror("futex");
1101 dprintf1("futex() ret: %d\n", futex_ret);
1102}
1103
1104/* Assumes that all pkeys other than 'pkey' are unallocated */
1105void test_pkey_syscalls_on_non_allocated_pkey(int *ptr, u16 pkey)
1106{
1107 int err;
1108 int i;
1109
1110 /* Note: 0 is the default pkey, so don't mess with it */
1111 for (i = 1; i < NR_PKEYS; i++) {
1112 if (pkey == i)
1113 continue;
1114
1115 dprintf1("trying get/set/free to non-allocated pkey: %2d\n", i);
1116 err = sys_pkey_free(i);
1117 pkey_assert(err);
1118
1119 /* not enforced when pkey_get() is not a syscall
1120 err = pkey_get(i, 0);
1121 pkey_assert(err < 0);
1122 */
1123
1124 err = sys_pkey_free(i);
1125 pkey_assert(err);
1126
1127 err = sys_mprotect_pkey(ptr, PAGE_SIZE, PROT_READ, i);
1128 pkey_assert(err);
1129 }
1130}
1131
1132/* Assumes that all pkeys other than 'pkey' are unallocated */
1133void test_pkey_syscalls_bad_args(int *ptr, u16 pkey)
1134{
1135 int err;
1136 int bad_flag = (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE) + 1;
1137 int bad_pkey = NR_PKEYS+99;
1138
1139 /* not enforced when pkey_get() is not a syscall
1140 err = pkey_get(bad_pkey, bad_flag);
1141 pkey_assert(err < 0);
1142 */
1143
1144 /* pass a known-invalid pkey in: */
1145 err = sys_mprotect_pkey(ptr, PAGE_SIZE, PROT_READ, bad_pkey);
1146 pkey_assert(err);
1147}
1148
1149/* Assumes that all pkeys other than 'pkey' are unallocated */
1150void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
1151{
1152 unsigned long flags;
1153 unsigned long init_val;
1154 int err;
1155 int allocated_pkeys[NR_PKEYS] = {0};
1156 int nr_allocated_pkeys = 0;
1157 int i;
1158
1159 for (i = 0; i < NR_PKEYS*2; i++) {
1160 int new_pkey;
1161 dprintf1("%s() alloc loop: %d\n", __func__, i);
1162 new_pkey = alloc_pkey();
1163 dprintf4("%s()::%d, err: %d pkru: 0x%x shadow: 0x%x\n", __func__,
1164 __LINE__, err, __rdpkru(), shadow_pkru);
1165 rdpkru(); /* for shadow checking */
1166 dprintf2("%s() errno: %d ENOSPC: %d\n", __func__, errno, ENOSPC);
1167 if ((new_pkey == -1) && (errno == ENOSPC)) {
1168 dprintf2("%s() failed to allocate pkey after %d tries\n",
1169 __func__, nr_allocated_pkeys);
1170 break;
1171 }
1172 pkey_assert(nr_allocated_pkeys < NR_PKEYS);
1173 allocated_pkeys[nr_allocated_pkeys++] = new_pkey;
1174 }
1175
1176 dprintf3("%s()::%d\n", __func__, __LINE__);
1177
1178 /*
1179 * ensure it did not reach the end of the loop without
1180 * failure:
1181 */
1182 pkey_assert(i < NR_PKEYS*2);
1183
1184 /*
1185 * There are 16 pkeys supported in hardware. One is taken
1186 * up for the default (0) and another can be taken up by
1187 * an execute-only mapping. Ensure that we can allocate
1188 * at least 14 (16-2).
1189 */
1190 pkey_assert(i >= NR_PKEYS-2);
1191
1192 for (i = 0; i < nr_allocated_pkeys; i++) {
1193 err = sys_pkey_free(allocated_pkeys[i]);
1194 pkey_assert(!err);
1195 rdpkru(); /* for shadow checking */
1196 }
1197}
1198
1199void test_ptrace_of_child(int *ptr, u16 pkey)
1200{
1201 __attribute__((__unused__)) int peek_result;
1202 pid_t child_pid;
1203 void *ignored = 0;
1204 long ret;
1205 int status;
1206 /*
1207 * This is the "control" for our little expermient. Make sure
1208 * we can always access it when ptracing.
1209 */
1210 int *plain_ptr_unaligned = malloc(HPAGE_SIZE);
1211 int *plain_ptr = ALIGN_PTR_UP(plain_ptr_unaligned, PAGE_SIZE);
1212
1213 /*
1214 * Fork a child which is an exact copy of this process, of course.
1215 * That means we can do all of our tests via ptrace() and then plain
1216 * memory access and ensure they work differently.
1217 */
1218 child_pid = fork_lazy_child();
1219 dprintf1("[%d] child pid: %d\n", getpid(), child_pid);
1220
1221 ret = ptrace(PTRACE_ATTACH, child_pid, ignored, ignored);
1222 if (ret)
1223 perror("attach");
1224 dprintf1("[%d] attach ret: %ld %d\n", getpid(), ret, __LINE__);
1225 pkey_assert(ret != -1);
1226 ret = waitpid(child_pid, &status, WUNTRACED);
1227 if ((ret != child_pid) || !(WIFSTOPPED(status))) {
1228 fprintf(stderr, "weird waitpid result %ld stat %x\n",
1229 ret, status);
1230 pkey_assert(0);
1231 }
1232 dprintf2("waitpid ret: %ld\n", ret);
1233 dprintf2("waitpid status: %d\n", status);
1234
1235 pkey_access_deny(pkey);
1236 pkey_write_deny(pkey);
1237
1238 /* Write access, untested for now:
1239 ret = ptrace(PTRACE_POKEDATA, child_pid, peek_at, data);
1240 pkey_assert(ret != -1);
1241 dprintf1("poke at %p: %ld\n", peek_at, ret);
1242 */
1243
1244 /*
1245 * Try to access the pkey-protected "ptr" via ptrace:
1246 */
1247 ret = ptrace(PTRACE_PEEKDATA, child_pid, ptr, ignored);
1248 /* expect it to work, without an error: */
1249 pkey_assert(ret != -1);
1250 /* Now access from the current task, and expect an exception: */
1251 peek_result = read_ptr(ptr);
1252 expected_pk_fault(pkey);
1253
1254 /*
1255 * Try to access the NON-pkey-protected "plain_ptr" via ptrace:
1256 */
1257 ret = ptrace(PTRACE_PEEKDATA, child_pid, plain_ptr, ignored);
1258 /* expect it to work, without an error: */
1259 pkey_assert(ret != -1);
1260 /* Now access from the current task, and expect NO exception: */
1261 peek_result = read_ptr(plain_ptr);
1262 do_not_expect_pk_fault();
1263
1264 ret = ptrace(PTRACE_DETACH, child_pid, ignored, 0);
1265 pkey_assert(ret != -1);
1266
1267 ret = kill(child_pid, SIGKILL);
1268 pkey_assert(ret != -1);
1269
1270 wait(&status);
1271
1272 free(plain_ptr_unaligned);
1273}
1274
1275void test_executing_on_unreadable_memory(int *ptr, u16 pkey)
1276{
1277 void *p1;
1278 int scratch;
1279 int ptr_contents;
1280 int ret;
1281
1282 p1 = ALIGN_PTR_UP(&lots_o_noops_around_write, PAGE_SIZE);
1283 dprintf3("&lots_o_noops: %p\n", &lots_o_noops_around_write);
1284 /* lots_o_noops_around_write should be page-aligned already */
1285 assert(p1 == &lots_o_noops_around_write);
1286
1287 /* Point 'p1' at the *second* page of the function: */
1288 p1 += PAGE_SIZE;
1289
1290 madvise(p1, PAGE_SIZE, MADV_DONTNEED);
1291 lots_o_noops_around_write(&scratch);
1292 ptr_contents = read_ptr(p1);
1293 dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
1294
1295 ret = mprotect_pkey(p1, PAGE_SIZE, PROT_EXEC, (u64)pkey);
1296 pkey_assert(!ret);
1297 pkey_access_deny(pkey);
1298
1299 dprintf2("pkru: %x\n", rdpkru());
1300
1301 /*
1302 * Make sure this is an *instruction* fault
1303 */
1304 madvise(p1, PAGE_SIZE, MADV_DONTNEED);
1305 lots_o_noops_around_write(&scratch);
1306 do_not_expect_pk_fault();
1307 ptr_contents = read_ptr(p1);
1308 dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
1309 expected_pk_fault(pkey);
1310}
1311
1312void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey)
1313{
1314 int size = PAGE_SIZE;
1315 int sret;
1316
1317 if (cpu_has_pku()) {
1318 dprintf1("SKIP: %s: no CPU support\n", __func__);
1319 return;
1320 }
1321
1322 sret = syscall(SYS_mprotect_key, ptr, size, PROT_READ, pkey);
1323 pkey_assert(sret < 0);
1324}
1325
1326void (*pkey_tests[])(int *ptr, u16 pkey) = {
1327 test_read_of_write_disabled_region,
1328 test_read_of_access_disabled_region,
1329 test_write_of_write_disabled_region,
1330 test_write_of_access_disabled_region,
1331 test_kernel_write_of_access_disabled_region,
1332 test_kernel_write_of_write_disabled_region,
1333 test_kernel_gup_of_access_disabled_region,
1334 test_kernel_gup_write_to_write_disabled_region,
1335 test_executing_on_unreadable_memory,
1336 test_ptrace_of_child,
1337 test_pkey_syscalls_on_non_allocated_pkey,
1338 test_pkey_syscalls_bad_args,
1339 test_pkey_alloc_exhaust,
1340};
1341
1342void run_tests_once(void)
1343{
1344 int *ptr;
1345 int prot = PROT_READ|PROT_WRITE;
1346
1347 for (test_nr = 0; test_nr < ARRAY_SIZE(pkey_tests); test_nr++) {
1348 int pkey;
1349 int orig_pkru_faults = pkru_faults;
1350
1351 dprintf1("======================\n");
1352 dprintf1("test %d preparing...\n", test_nr);
1353
1354 tracing_on();
1355 pkey = alloc_random_pkey();
1356 dprintf1("test %d starting with pkey: %d\n", test_nr, pkey);
1357 ptr = malloc_pkey(PAGE_SIZE, prot, pkey);
1358 dprintf1("test %d starting...\n", test_nr);
1359 pkey_tests[test_nr](ptr, pkey);
1360 dprintf1("freeing test memory: %p\n", ptr);
1361 free_pkey_malloc(ptr);
1362 sys_pkey_free(pkey);
1363
1364 dprintf1("pkru_faults: %d\n", pkru_faults);
1365 dprintf1("orig_pkru_faults: %d\n", orig_pkru_faults);
1366
1367 tracing_off();
1368 close_test_fds();
1369
1370 printf("test %2d PASSED (itertation %d)\n", test_nr, iteration_nr);
1371 dprintf1("======================\n\n");
1372 }
1373 iteration_nr++;
1374}
1375
1376void pkey_setup_shadow(void)
1377{
1378 shadow_pkru = __rdpkru();
1379}
1380
1381int main(void)
1382{
1383 int nr_iterations = 22;
1384
1385 setup_handlers();
1386
1387 printf("has pku: %d\n", cpu_has_pku());
1388
1389 if (!cpu_has_pku()) {
1390 int size = PAGE_SIZE;
1391 int *ptr;
1392
1393 printf("running PKEY tests for unsupported CPU/OS\n");
1394
1395 ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
1396 assert(ptr != (void *)-1);
1397 test_mprotect_pkey_on_unsupported_cpu(ptr, 1);
1398 exit(0);
1399 }
1400
1401 pkey_setup_shadow();
1402 printf("startup pkru: %x\n", rdpkru());
1403 setup_hugetlbfs();
1404
1405 while (nr_iterations-- > 0)
1406 run_tests_once();
1407
1408 printf("done (all tests OK)\n");
1409 return 0;
1410}
diff --git a/tools/testing/selftests/zram/README b/tools/testing/selftests/zram/README
index eb17917c8a3a..7972cc512408 100644
--- a/tools/testing/selftests/zram/README
+++ b/tools/testing/selftests/zram/README
@@ -13,7 +13,7 @@ Statistics for individual zram devices are exported through sysfs nodes at
13 13
14Kconfig required: 14Kconfig required:
15CONFIG_ZRAM=y 15CONFIG_ZRAM=y
16CONFIG_ZRAM_LZ4_COMPRESS=y 16CONFIG_CRYPTO_LZ4=y
17CONFIG_ZPOOL=y 17CONFIG_ZPOOL=y
18CONFIG_ZSMALLOC=y 18CONFIG_ZSMALLOC=y
19 19