aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-14 18:17:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-14 18:17:12 -0400
commit5d89d9f502f9c33ed0270d716f238429861e1942 (patch)
tree6a353640e6836ca465f2dcf00323a7f8a793ae59 /tools/testing
parent50cff89837a43a7c62ac080de9742a298d6418b3 (diff)
parentfecf861e765b2f9ce1a0487c3940afaed80ef7a8 (diff)
Merge tag 'linux-kselftest-4.9-rc1-update' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull kselftest updates from Shuah Khan: "This update consists of: - Fixes and improvements to existing tests - Moving code from Documentation to selftests, samples, and tools: * Moves dnotify_test, prctl, ptp, vDSO, ia64, watchdog, and networking tests from Documentation to selftests. * Moves mic/mpssd, misc-devices/mei, timers, watchdog, auxdisplay, and blackfin examples from Documentation to samples. * Moves accounting, laptops/dslm, and pcmcia/crc32hash tools from Documentation to tools. * Deletes BUILD_DOCSRC and its dependencies" * tag 'linux-kselftest-4.9-rc1-update' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (21 commits) selftests/futex: Check ANSI terminal color support Doc: update 00-INDEX files to reflect the runnable code move samples: move blackfin gptimers-example from Documentation tools: move pcmcia crc32hash tool from Documentation tools: move laptops dslm tool from Documentation tools: move accounting tool from Documentation samples: move auxdisplay example code from Documentation samples: move watchdog example code from Documentation samples: move timers example code from Documentation samples: move misc-devices/mei example code from Documentation samples: move mic/mpssd example code from Documentation selftests: Move networking/timestamping from Documentation selftests: move watchdog tests from Documentation/watchdog selftests: move ia64 tests from Documentation/ia64 selftests: move vDSO tests from Documentation/vDSO selftests: move ptp tests from Documentation/ptp selftests: move prctl tests from Documentation/prctl selftests: move dnotify_test from Documentation/filesystems selftests/timers: Add missing error code assignment before test selftests/zram: replace ZRAM_LZ4_COMPRESS ...
Diffstat (limited to 'tools/testing')
-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/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/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/zram/README2
32 files changed, 2997 insertions, 5 deletions
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/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/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/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