aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/lguest/lguest.c10
-rw-r--r--tools/lib/traceevent/parse-filter.c4
-rw-r--r--tools/perf/builtin-stat.c7
-rw-r--r--tools/perf/util/evsel.c23
-rw-r--r--tools/testing/selftests/Makefile1
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/jitter.sh90
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh121
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf.sh96
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh5
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh59
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm.sh24
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE042
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcuperf/CFcommon2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcuperf/TREE20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcuperf/TREE5423
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh52
-rw-r--r--tools/testing/selftests/sigaltstack/Makefile8
-rw-r--r--tools/testing/selftests/sigaltstack/sas.c176
-rw-r--r--tools/testing/selftests/x86/Makefile1
-rw-r--r--tools/testing/selftests/x86/fsgsbase.c398
-rw-r--r--tools/testing/selftests/x86/ldt_gdt.c250
23 files changed, 1347 insertions, 28 deletions
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c
index 80159e6811c2..d9836c5eb694 100644
--- a/tools/lguest/lguest.c
+++ b/tools/lguest/lguest.c
@@ -3351,12 +3351,18 @@ int main(int argc, char *argv[])
3351 /* Boot protocol version: 2.07 supports the fields for lguest. */ 3351 /* Boot protocol version: 2.07 supports the fields for lguest. */
3352 boot->hdr.version = 0x207; 3352 boot->hdr.version = 0x207;
3353 3353
3354 /* The hardware_subarch value of "1" tells the Guest it's an lguest. */ 3354 /* X86_SUBARCH_LGUEST tells the Guest it's an lguest. */
3355 boot->hdr.hardware_subarch = 1; 3355 boot->hdr.hardware_subarch = X86_SUBARCH_LGUEST;
3356 3356
3357 /* Tell the entry path not to try to reload segment registers. */ 3357 /* Tell the entry path not to try to reload segment registers. */
3358 boot->hdr.loadflags |= KEEP_SEGMENTS; 3358 boot->hdr.loadflags |= KEEP_SEGMENTS;
3359 3359
3360 /* We don't support tboot: */
3361 boot->tboot_addr = 0;
3362
3363 /* Ensure this is 0 to prevent APM from loading: */
3364 boot->apm_bios_info.version = 0;
3365
3360 /* We tell the kernel to initialize the Guest. */ 3366 /* We tell the kernel to initialize the Guest. */
3361 tell_kernel(start); 3367 tell_kernel(start);
3362 3368
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index 0144b3d1bb77..88cccea3ca99 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -1164,11 +1164,11 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1164 current_op = current_exp; 1164 current_op = current_exp;
1165 1165
1166 ret = collapse_tree(current_op, parg, error_str); 1166 ret = collapse_tree(current_op, parg, error_str);
1167 /* collapse_tree() may free current_op, and updates parg accordingly */
1168 current_op = NULL;
1167 if (ret < 0) 1169 if (ret < 0)
1168 goto fail; 1170 goto fail;
1169 1171
1170 *parg = current_op;
1171
1172 free(token); 1172 free(token);
1173 return 0; 1173 return 0;
1174 1174
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index efdd23221c16..ee7ada78d86f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -537,6 +537,7 @@ static int __run_perf_stat(int argc, const char **argv)
537 perf_evlist__set_leader(evsel_list); 537 perf_evlist__set_leader(evsel_list);
538 538
539 evlist__for_each(evsel_list, counter) { 539 evlist__for_each(evsel_list, counter) {
540try_again:
540 if (create_perf_stat_counter(counter) < 0) { 541 if (create_perf_stat_counter(counter) < 0) {
541 /* 542 /*
542 * PPC returns ENXIO for HW counters until 2.6.37 543 * PPC returns ENXIO for HW counters until 2.6.37
@@ -553,7 +554,11 @@ static int __run_perf_stat(int argc, const char **argv)
553 if ((counter->leader != counter) || 554 if ((counter->leader != counter) ||
554 !(counter->leader->nr_members > 1)) 555 !(counter->leader->nr_members > 1))
555 continue; 556 continue;
556 } 557 } else if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) {
558 if (verbose)
559 ui__warning("%s\n", msg);
560 goto try_again;
561 }
557 562
558 perf_evsel__open_strerror(counter, &target, 563 perf_evsel__open_strerror(counter, &target,
559 errno, msg, sizeof(msg)); 564 errno, msg, sizeof(msg));
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a23f54793e51..964c7c3602c0 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -2274,6 +2274,8 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
2274bool perf_evsel__fallback(struct perf_evsel *evsel, int err, 2274bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
2275 char *msg, size_t msgsize) 2275 char *msg, size_t msgsize)
2276{ 2276{
2277 int paranoid;
2278
2277 if ((err == ENOENT || err == ENXIO || err == ENODEV) && 2279 if ((err == ENOENT || err == ENXIO || err == ENODEV) &&
2278 evsel->attr.type == PERF_TYPE_HARDWARE && 2280 evsel->attr.type == PERF_TYPE_HARDWARE &&
2279 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { 2281 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
@@ -2293,6 +2295,22 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
2293 2295
2294 zfree(&evsel->name); 2296 zfree(&evsel->name);
2295 return true; 2297 return true;
2298 } else if (err == EACCES && !evsel->attr.exclude_kernel &&
2299 (paranoid = perf_event_paranoid()) > 1) {
2300 const char *name = perf_evsel__name(evsel);
2301 char *new_name;
2302
2303 if (asprintf(&new_name, "%s%su", name, strchr(name, ':') ? "" : ":") < 0)
2304 return false;
2305
2306 if (evsel->name)
2307 free(evsel->name);
2308 evsel->name = new_name;
2309 scnprintf(msg, msgsize,
2310"kernel.perf_event_paranoid=%d, trying to fall back to excluding kernel samples", paranoid);
2311 evsel->attr.exclude_kernel = 1;
2312
2313 return true;
2296 } 2314 }
2297 2315
2298 return false; 2316 return false;
@@ -2311,12 +2329,13 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
2311 "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n" 2329 "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
2312 "which controls use of the performance events system by\n" 2330 "which controls use of the performance events system by\n"
2313 "unprivileged users (without CAP_SYS_ADMIN).\n\n" 2331 "unprivileged users (without CAP_SYS_ADMIN).\n\n"
2314 "The default value is 1:\n\n" 2332 "The current value is %d:\n\n"
2315 " -1: Allow use of (almost) all events by all users\n" 2333 " -1: Allow use of (almost) all events by all users\n"
2316 ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n" 2334 ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n"
2317 ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n" 2335 ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n"
2318 ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN", 2336 ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN",
2319 target->system_wide ? "system-wide " : ""); 2337 target->system_wide ? "system-wide " : "",
2338 perf_event_paranoid());
2320 case ENOENT: 2339 case ENOENT:
2321 return scnprintf(msg, size, "The %s event is not supported.", 2340 return scnprintf(msg, size, "The %s event is not supported.",
2322 perf_evsel__name(evsel)); 2341 perf_evsel__name(evsel));
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index b04afc3295df..ff9e5f20a5a7 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -19,6 +19,7 @@ TARGETS += powerpc
19TARGETS += pstore 19TARGETS += pstore
20TARGETS += ptrace 20TARGETS += ptrace
21TARGETS += seccomp 21TARGETS += seccomp
22TARGETS += sigaltstack
22TARGETS += size 23TARGETS += size
23TARGETS += static_keys 24TARGETS += static_keys
24TARGETS += sysctl 25TARGETS += sysctl
diff --git a/tools/testing/selftests/rcutorture/bin/jitter.sh b/tools/testing/selftests/rcutorture/bin/jitter.sh
new file mode 100755
index 000000000000..3633828375e3
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/bin/jitter.sh
@@ -0,0 +1,90 @@
1#!/bin/bash
2#
3# Alternate sleeping and spinning on randomly selected CPUs. The purpose
4# of this script is to inflict random OS jitter on a concurrently running
5# test.
6#
7# Usage: jitter.sh me duration [ sleepmax [ spinmax ] ]
8#
9# me: Random-number-generator seed salt.
10# duration: Time to run in seconds.
11# sleepmax: Maximum microseconds to sleep, defaults to one second.
12# spinmax: Maximum microseconds to spin, defaults to one millisecond.
13#
14# This program is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License as published by
16# the Free Software Foundation; either version 2 of the License, or
17# (at your option) any later version.
18#
19# This program is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22# GNU General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License
25# along with this program; if not, you can access it online at
26# http://www.gnu.org/licenses/gpl-2.0.html.
27#
28# Copyright (C) IBM Corporation, 2016
29#
30# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
31
32me=$(($1 * 1000))
33duration=$2
34sleepmax=${3-1000000}
35spinmax=${4-1000}
36
37n=1
38
39starttime=`awk 'BEGIN { print systime(); }' < /dev/null`
40
41while :
42do
43 # Check for done.
44 t=`awk -v s=$starttime 'BEGIN { print systime() - s; }' < /dev/null`
45 if test "$t" -gt "$duration"
46 then
47 exit 0;
48 fi
49
50 # Set affinity to randomly selected CPU
51 cpus=`ls /sys/devices/system/cpu/*/online |
52 sed -e 's,/[^/]*$,,' -e 's/^[^0-9]*//' |
53 grep -v '^0*$'`
54 cpumask=`awk -v cpus="$cpus" -v me=$me -v n=$n 'BEGIN {
55 srand(n + me + systime());
56 ncpus = split(cpus, ca);
57 curcpu = ca[int(rand() * ncpus + 1)];
58 mask = lshift(1, curcpu);
59 if (mask + 0 <= 0)
60 mask = 1;
61 printf("%#x\n", mask);
62 }' < /dev/null`
63 n=$(($n+1))
64 if ! taskset -p $cpumask $$ > /dev/null 2>&1
65 then
66 echo taskset failure: '"taskset -p ' $cpumask $$ '"'
67 exit 1
68 fi
69
70 # Sleep a random duration
71 sleeptime=`awk -v me=$me -v n=$n -v sleepmax=$sleepmax 'BEGIN {
72 srand(n + me + systime());
73 printf("%06d", int(rand() * sleepmax));
74 }' < /dev/null`
75 n=$(($n+1))
76 sleep .$sleeptime
77
78 # Spin a random duration
79 limit=`awk -v me=$me -v n=$n -v spinmax=$spinmax 'BEGIN {
80 srand(n + me + systime());
81 printf("%06d", int(rand() * spinmax));
82 }' < /dev/null`
83 n=$(($n+1))
84 for i in {1..$limit}
85 do
86 echo > /dev/null
87 done
88done
89
90exit 1
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh
new file mode 100755
index 000000000000..f79b0e9e84fc
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh
@@ -0,0 +1,121 @@
1#!/bin/bash
2#
3# Analyze a given results directory for rcuperf performance measurements,
4# looking for ftrace data. Exits with 0 if data was found, analyzed, and
5# printed. Intended to be invoked from kvm-recheck-rcuperf.sh after
6# argument checking.
7#
8# Usage: kvm-recheck-rcuperf-ftrace.sh resdir
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, you can access it online at
22# http://www.gnu.org/licenses/gpl-2.0.html.
23#
24# Copyright (C) IBM Corporation, 2016
25#
26# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
27
28i="$1"
29. tools/testing/selftests/rcutorture/bin/functions.sh
30
31if test "`grep -c 'rcu_exp_grace_period.*start' < $i/console.log`" -lt 100
32then
33 exit 10
34fi
35
36sed -e 's/^\[[^]]*]//' < $i/console.log |
37grep 'us : rcu_exp_grace_period' |
38sed -e 's/us : / : /' |
39tr -d '\015' |
40awk '
41$8 == "start" {
42 if (starttask != "")
43 nlost++;
44 starttask = $1;
45 starttime = $3;
46 startseq = $7;
47}
48
49$8 == "end" {
50 if (starttask == $1 && startseq == $7) {
51 curgpdur = $3 - starttime;
52 gptimes[++n] = curgpdur;
53 gptaskcnt[starttask]++;
54 sum += curgpdur;
55 if (curgpdur > 1000)
56 print "Long GP " starttime "us to " $3 "us (" curgpdur "us)";
57 starttask = "";
58 } else {
59 # Lost a message or some such, reset.
60 starttask = "";
61 nlost++;
62 }
63}
64
65$8 == "done" {
66 piggybackcnt[$1]++;
67}
68
69END {
70 newNR = asort(gptimes);
71 if (newNR <= 0) {
72 print "No ftrace records found???"
73 exit 10;
74 }
75 pct50 = int(newNR * 50 / 100);
76 if (pct50 < 1)
77 pct50 = 1;
78 pct90 = int(newNR * 90 / 100);
79 if (pct90 < 1)
80 pct90 = 1;
81 pct99 = int(newNR * 99 / 100);
82 if (pct99 < 1)
83 pct99 = 1;
84 div = 10 ** int(log(gptimes[pct90]) / log(10) + .5) / 100;
85 print "Histogram bucket size: " div;
86 last = gptimes[1] - 10;
87 count = 0;
88 for (i = 1; i <= newNR; i++) {
89 current = div * int(gptimes[i] / div);
90 if (last == current) {
91 count++;
92 } else {
93 if (count > 0)
94 print last, count;
95 count = 1;
96 last = current;
97 }
98 }
99 if (count > 0)
100 print last, count;
101 print "Distribution of grace periods across tasks:";
102 for (i in gptaskcnt) {
103 print "\t" i, gptaskcnt[i];
104 nbatches += gptaskcnt[i];
105 }
106 ngps = nbatches;
107 print "Distribution of piggybacking across tasks:";
108 for (i in piggybackcnt) {
109 print "\t" i, piggybackcnt[i];
110 ngps += piggybackcnt[i];
111 }
112 print "Average grace-period duration: " sum / newNR " microseconds";
113 print "Minimum grace-period duration: " gptimes[1];
114 print "50th percentile grace-period duration: " gptimes[pct50];
115 print "90th percentile grace-period duration: " gptimes[pct90];
116 print "99th percentile grace-period duration: " gptimes[pct99];
117 print "Maximum grace-period duration: " gptimes[newNR];
118 print "Grace periods: " ngps + 0 " Batches: " nbatches + 0 " Ratio: " ngps / nbatches " Lost: " nlost + 0;
119 print "Computed from ftrace data.";
120}'
121exit 0
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf.sh
new file mode 100755
index 000000000000..8f3121afc716
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf.sh
@@ -0,0 +1,96 @@
1#!/bin/bash
2#
3# Analyze a given results directory for rcuperf performance measurements.
4#
5# Usage: kvm-recheck-rcuperf.sh resdir
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 as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, you can access it online at
19# http://www.gnu.org/licenses/gpl-2.0.html.
20#
21# Copyright (C) IBM Corporation, 2016
22#
23# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
24
25i="$1"
26if test -d $i
27then
28 :
29else
30 echo Unreadable results directory: $i
31 exit 1
32fi
33PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH
34. tools/testing/selftests/rcutorture/bin/functions.sh
35
36if kvm-recheck-rcuperf-ftrace.sh $i
37then
38 # ftrace data was successfully analyzed, call it good!
39 exit 0
40fi
41
42configfile=`echo $i | sed -e 's/^.*\///'`
43
44sed -e 's/^\[[^]]*]//' < $i/console.log |
45awk '
46/-perf: .* gps: .* batches:/ {
47 ngps = $9;
48 nbatches = $11;
49}
50
51/-perf: .*writer-duration/ {
52 gptimes[++n] = $5 / 1000.;
53 sum += $5 / 1000.;
54}
55
56END {
57 newNR = asort(gptimes);
58 if (newNR <= 0) {
59 print "No rcuperf records found???"
60 exit;
61 }
62 pct50 = int(newNR * 50 / 100);
63 if (pct50 < 1)
64 pct50 = 1;
65 pct90 = int(newNR * 90 / 100);
66 if (pct90 < 1)
67 pct90 = 1;
68 pct99 = int(newNR * 99 / 100);
69 if (pct99 < 1)
70 pct99 = 1;
71 div = 10 ** int(log(gptimes[pct90]) / log(10) + .5) / 100;
72 print "Histogram bucket size: " div;
73 last = gptimes[1] - 10;
74 count = 0;
75 for (i = 1; i <= newNR; i++) {
76 current = div * int(gptimes[i] / div);
77 if (last == current) {
78 count++;
79 } else {
80 if (count > 0)
81 print last, count;
82 count = 1;
83 last = current;
84 }
85 }
86 if (count > 0)
87 print last, count;
88 print "Average grace-period duration: " sum / newNR " microseconds";
89 print "Minimum grace-period duration: " gptimes[1];
90 print "50th percentile grace-period duration: " gptimes[pct50];
91 print "90th percentile grace-period duration: " gptimes[pct90];
92 print "99th percentile grace-period duration: " gptimes[pct99];
93 print "Maximum grace-period duration: " gptimes[newNR];
94 print "Grace periods: " ngps + 0 " Batches: " nbatches + 0 " Ratio: " ngps / nbatches;
95 print "Computed from rcuperf printk output.";
96}'
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
index d86bdd6b6cc2..f659346d3358 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
@@ -48,7 +48,10 @@ do
48 cat $i/Make.oldconfig.err 48 cat $i/Make.oldconfig.err
49 fi 49 fi
50 parse-build.sh $i/Make.out $configfile 50 parse-build.sh $i/Make.out $configfile
51 parse-torture.sh $i/console.log $configfile 51 if test "$TORTURE_SUITE" != rcuperf
52 then
53 parse-torture.sh $i/console.log $configfile
54 fi
52 parse-console.sh $i/console.log $configfile 55 parse-console.sh $i/console.log $configfile
53 if test -r $i/Warnings 56 if test -r $i/Warnings
54 then 57 then
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index 0f80eefb0bfd..4109f306d855 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -6,7 +6,7 @@
6# Execute this in the source tree. Do not run it as a background task 6# Execute this in the source tree. Do not run it as a background task
7# because qemu does not seem to like that much. 7# because qemu does not seem to like that much.
8# 8#
9# Usage: kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args 9# Usage: kvm-test-1-run.sh config builddir resdir seconds qemu-args boot_args
10# 10#
11# qemu-args defaults to "-enable-kvm -soundhw pcspk -nographic", along with 11# qemu-args defaults to "-enable-kvm -soundhw pcspk -nographic", along with
12# arguments specifying the number of CPUs and other 12# arguments specifying the number of CPUs and other
@@ -91,25 +91,33 @@ fi
91# CONFIG_PCMCIA=n 91# CONFIG_PCMCIA=n
92# CONFIG_CARDBUS=n 92# CONFIG_CARDBUS=n
93# CONFIG_YENTA=n 93# CONFIG_YENTA=n
94if kvm-build.sh $config_template $builddir $T 94base_resdir=`echo $resdir | sed -e 's/\.[0-9]\+$//'`
95if test "$base_resdir" != "$resdir" -a -f $base_resdir/bzImage -a -f $base_resdir/vmlinux
95then 96then
97 # Rerunning previous test, so use that test's kernel.
98 QEMU="`identify_qemu $base_resdir/vmlinux`"
99 KERNEL=$base_resdir/bzImage
100 ln -s $base_resdir/Make*.out $resdir # for kvm-recheck.sh
101 ln -s $base_resdir/.config $resdir # for kvm-recheck.sh
102elif kvm-build.sh $config_template $builddir $T
103then
104 # Had to build a kernel for this test.
96 QEMU="`identify_qemu $builddir/vmlinux`" 105 QEMU="`identify_qemu $builddir/vmlinux`"
97 BOOT_IMAGE="`identify_boot_image $QEMU`" 106 BOOT_IMAGE="`identify_boot_image $QEMU`"
98 cp $builddir/Make*.out $resdir 107 cp $builddir/Make*.out $resdir
108 cp $builddir/vmlinux $resdir
99 cp $builddir/.config $resdir 109 cp $builddir/.config $resdir
100 if test -n "$BOOT_IMAGE" 110 if test -n "$BOOT_IMAGE"
101 then 111 then
102 cp $builddir/$BOOT_IMAGE $resdir 112 cp $builddir/$BOOT_IMAGE $resdir
113 KERNEL=$resdir/bzImage
103 else 114 else
104 echo No identifiable boot image, not running KVM, see $resdir. 115 echo No identifiable boot image, not running KVM, see $resdir.
105 echo Do the torture scripts know about your architecture? 116 echo Do the torture scripts know about your architecture?
106 fi 117 fi
107 parse-build.sh $resdir/Make.out $title 118 parse-build.sh $resdir/Make.out $title
108 if test -f $builddir.wait
109 then
110 mv $builddir.wait $builddir.ready
111 fi
112else 119else
120 # Build failed.
113 cp $builddir/Make*.out $resdir 121 cp $builddir/Make*.out $resdir
114 cp $builddir/.config $resdir || : 122 cp $builddir/.config $resdir || :
115 echo Build failed, not running KVM, see $resdir. 123 echo Build failed, not running KVM, see $resdir.
@@ -119,12 +127,15 @@ else
119 fi 127 fi
120 exit 1 128 exit 1
121fi 129fi
130if test -f $builddir.wait
131then
132 mv $builddir.wait $builddir.ready
133fi
122while test -f $builddir.ready 134while test -f $builddir.ready
123do 135do
124 sleep 1 136 sleep 1
125done 137done
126minutes=$4 138seconds=$4
127seconds=$(($minutes * 60))
128qemu_args=$5 139qemu_args=$5
129boot_args=$6 140boot_args=$6
130 141
@@ -167,15 +178,26 @@ then
167 exit 0 178 exit 0
168fi 179fi
169echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log 180echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log
170echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd 181echo $QEMU $qemu_args -m 512 -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
171( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) & 182( $QEMU $qemu_args -m 512 -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) &
172qemu_pid=$!
173commandcompleted=0 183commandcompleted=0
174echo Monitoring qemu job at pid $qemu_pid 184sleep 10 # Give qemu's pid a chance to reach the file
185if test -s "$resdir/qemu_pid"
186then
187 qemu_pid=`cat "$resdir/qemu_pid"`
188 echo Monitoring qemu job at pid $qemu_pid
189else
190 qemu_pid=""
191 echo Monitoring qemu job at yet-as-unknown pid
192fi
175while : 193while :
176do 194do
195 if test -z "$qemu_pid" -a -s "$resdir/qemu_pid"
196 then
197 qemu_pid=`cat "$resdir/qemu_pid"`
198 fi
177 kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null` 199 kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
178 if kill -0 $qemu_pid > /dev/null 2>&1 200 if test -z "$qemu_pid" || kill -0 "$qemu_pid" > /dev/null 2>&1
179 then 201 then
180 if test $kruntime -ge $seconds 202 if test $kruntime -ge $seconds
181 then 203 then
@@ -195,12 +217,16 @@ do
195 ps -fp $killpid >> $resdir/Warnings 2>&1 217 ps -fp $killpid >> $resdir/Warnings 2>&1
196 fi 218 fi
197 else 219 else
198 echo ' ---' `date`: Kernel done 220 echo ' ---' `date`: "Kernel done"
199 fi 221 fi
200 break 222 break
201 fi 223 fi
202done 224done
203if test $commandcompleted -eq 0 225if test -z "$qemu_pid" -a -s "$resdir/qemu_pid"
226then
227 qemu_pid=`cat "$resdir/qemu_pid"`
228fi
229if test $commandcompleted -eq 0 -a -n "$qemu_pid"
204then 230then
205 echo Grace period for qemu job at pid $qemu_pid 231 echo Grace period for qemu job at pid $qemu_pid
206 while : 232 while :
@@ -220,6 +246,9 @@ then
220 fi 246 fi
221 sleep 1 247 sleep 1
222 done 248 done
249elif test -z "$qemu_pid"
250then
251 echo Unknown PID, cannot kill qemu command
223fi 252fi
224 253
225parse-torture.sh $resdir/console.log $title 254parse-torture.sh $resdir/console.log $title
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index 4a431767f77a..0d598145873e 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -34,7 +34,7 @@ T=/tmp/kvm.sh.$$
34trap 'rm -rf $T' 0 34trap 'rm -rf $T' 0
35mkdir $T 35mkdir $T
36 36
37dur=30 37dur=$((30*60))
38dryrun="" 38dryrun=""
39KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM 39KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
40PATH=${KVM}/bin:$PATH; export PATH 40PATH=${KVM}/bin:$PATH; export PATH
@@ -48,6 +48,7 @@ resdir=""
48configs="" 48configs=""
49cpus=0 49cpus=0
50ds=`date +%Y.%m.%d-%H:%M:%S` 50ds=`date +%Y.%m.%d-%H:%M:%S`
51jitter=0
51 52
52. functions.sh 53. functions.sh
53 54
@@ -63,6 +64,7 @@ usage () {
63 echo " --dryrun sched|script" 64 echo " --dryrun sched|script"
64 echo " --duration minutes" 65 echo " --duration minutes"
65 echo " --interactive" 66 echo " --interactive"
67 echo " --jitter N [ maxsleep (us) [ maxspin (us) ] ]"
66 echo " --kmake-arg kernel-make-arguments" 68 echo " --kmake-arg kernel-make-arguments"
67 echo " --mac nn:nn:nn:nn:nn:nn" 69 echo " --mac nn:nn:nn:nn:nn:nn"
68 echo " --no-initrd" 70 echo " --no-initrd"
@@ -116,12 +118,17 @@ do
116 ;; 118 ;;
117 --duration) 119 --duration)
118 checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error' 120 checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error'
119 dur=$2 121 dur=$(($2*60))
120 shift 122 shift
121 ;; 123 ;;
122 --interactive) 124 --interactive)
123 TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE 125 TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE
124 ;; 126 ;;
127 --jitter)
128 checkarg --jitter "(# threads [ sleep [ spin ] ])" $# "$2" '^-\{,1\}[0-9]\+\( \+[0-9]\+\)\{,2\} *$' '^error$'
129 jitter="$2"
130 shift
131 ;;
125 --kmake-arg) 132 --kmake-arg)
126 checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$' 133 checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$'
127 TORTURE_KMAKE_ARG="$2" 134 TORTURE_KMAKE_ARG="$2"
@@ -156,7 +163,7 @@ do
156 shift 163 shift
157 ;; 164 ;;
158 --torture) 165 --torture)
159 checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--' 166 checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--'
160 TORTURE_SUITE=$2 167 TORTURE_SUITE=$2
161 shift 168 shift
162 ;; 169 ;;
@@ -299,6 +306,7 @@ awk < $T/cfgcpu.pack \
299 -v CONFIGDIR="$CONFIGFRAG/" \ 306 -v CONFIGDIR="$CONFIGFRAG/" \
300 -v KVM="$KVM" \ 307 -v KVM="$KVM" \
301 -v ncpus=$cpus \ 308 -v ncpus=$cpus \
309 -v jitter="$jitter" \
302 -v rd=$resdir/$ds/ \ 310 -v rd=$resdir/$ds/ \
303 -v dur=$dur \ 311 -v dur=$dur \
304 -v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \ 312 -v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \
@@ -359,6 +367,16 @@ function dump(first, pastlast, batchnum)
359 print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log"; 367 print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log";
360 print "fi" 368 print "fi"
361 } 369 }
370 njitter = 0;
371 split(jitter, ja);
372 if (ja[1] == -1 && ncpus == 0)
373 njitter = 1;
374 else if (ja[1] == -1)
375 njitter = ncpus;
376 else
377 njitter = ja[1];
378 for (j = 0; j < njitter; j++)
379 print "jitter.sh " j " " dur " " ja[2] " " ja[3] "&"
362 print "wait" 380 print "wait"
363 print "if test -z \"$TORTURE_BUILDONLY\"" 381 print "if test -z \"$TORTURE_BUILDONLY\""
364 print "then" 382 print "then"
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
index 39a2c6d7d7ec..17cbe098b115 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
@@ -14,7 +14,7 @@ CONFIG_HOTPLUG_CPU=n
14CONFIG_SUSPEND=n 14CONFIG_SUSPEND=n
15CONFIG_HIBERNATION=n 15CONFIG_HIBERNATION=n
16CONFIG_RCU_FANOUT=4 16CONFIG_RCU_FANOUT=4
17CONFIG_RCU_FANOUT_LEAF=4 17CONFIG_RCU_FANOUT_LEAF=3
18CONFIG_RCU_NOCB_CPU=n 18CONFIG_RCU_NOCB_CPU=n
19CONFIG_DEBUG_LOCK_ALLOC=n 19CONFIG_DEBUG_LOCK_ALLOC=n
20CONFIG_DEBUG_OBJECTS_RCU_HEAD=n 20CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
index 0fc8a3428938..e34c33430447 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
@@ -1 +1 @@
rcutorture.torture_type=rcu_bh rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST b/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST
new file mode 100644
index 000000000000..c9f56cf20775
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST
@@ -0,0 +1 @@
TREE
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/CFcommon b/tools/testing/selftests/rcutorture/configs/rcuperf/CFcommon
new file mode 100644
index 000000000000..a09816b8c0f3
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/CFcommon
@@ -0,0 +1,2 @@
1CONFIG_RCU_PERF_TEST=y
2CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/TREE b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE
new file mode 100644
index 000000000000..a312f671a29a
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE
@@ -0,0 +1,20 @@
1CONFIG_SMP=y
2CONFIG_PREEMPT_NONE=n
3CONFIG_PREEMPT_VOLUNTARY=n
4CONFIG_PREEMPT=y
5#CHECK#CONFIG_PREEMPT_RCU=y
6CONFIG_HZ_PERIODIC=n
7CONFIG_NO_HZ_IDLE=y
8CONFIG_NO_HZ_FULL=n
9CONFIG_RCU_FAST_NO_HZ=n
10CONFIG_RCU_TRACE=n
11CONFIG_HOTPLUG_CPU=n
12CONFIG_SUSPEND=n
13CONFIG_HIBERNATION=n
14CONFIG_RCU_NOCB_CPU=n
15CONFIG_DEBUG_LOCK_ALLOC=n
16CONFIG_PROVE_LOCKING=n
17CONFIG_RCU_BOOST=n
18CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
19CONFIG_RCU_EXPERT=y
20CONFIG_RCU_TRACE=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54 b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54
new file mode 100644
index 000000000000..985fb170d13c
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54
@@ -0,0 +1,23 @@
1CONFIG_SMP=y
2CONFIG_NR_CPUS=54
3CONFIG_PREEMPT_NONE=n
4CONFIG_PREEMPT_VOLUNTARY=n
5CONFIG_PREEMPT=y
6#CHECK#CONFIG_PREEMPT_RCU=y
7CONFIG_HZ_PERIODIC=n
8CONFIG_NO_HZ_IDLE=y
9CONFIG_NO_HZ_FULL=n
10CONFIG_RCU_FAST_NO_HZ=n
11CONFIG_RCU_TRACE=n
12CONFIG_HOTPLUG_CPU=n
13CONFIG_SUSPEND=n
14CONFIG_HIBERNATION=n
15CONFIG_RCU_FANOUT=3
16CONFIG_RCU_FANOUT_LEAF=2
17CONFIG_RCU_NOCB_CPU=n
18CONFIG_DEBUG_LOCK_ALLOC=n
19CONFIG_PROVE_LOCKING=n
20CONFIG_RCU_BOOST=n
21CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
22CONFIG_RCU_EXPERT=y
23CONFIG_RCU_TRACE=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh
new file mode 100644
index 000000000000..34f2a1b35ee5
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh
@@ -0,0 +1,52 @@
1#!/bin/bash
2#
3# Torture-suite-dependent shell functions for the rest of the scripts.
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, you can access it online at
17# http://www.gnu.org/licenses/gpl-2.0.html.
18#
19# Copyright (C) IBM Corporation, 2015
20#
21# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
22
23# rcuperf_param_nreaders bootparam-string
24#
25# Adds nreaders rcuperf module parameter if not already specified.
26rcuperf_param_nreaders () {
27 if ! echo "$1" | grep -q "rcuperf.nreaders"
28 then
29 echo rcuperf.nreaders=-1
30 fi
31}
32
33# rcuperf_param_nwriters bootparam-string
34#
35# Adds nwriters rcuperf module parameter if not already specified.
36rcuperf_param_nwriters () {
37 if ! echo "$1" | grep -q "rcuperf.nwriters"
38 then
39 echo rcuperf.nwriters=-1
40 fi
41}
42
43# per_version_boot_params bootparam-string config-file seconds
44#
45# Adds per-version torture-module parameters to kernels supporting them.
46per_version_boot_params () {
47 echo $1 `rcuperf_param_nreaders "$1"` \
48 `rcuperf_param_nwriters "$1"` \
49 rcuperf.perf_runnable=1 \
50 rcuperf.shutdown=1 \
51 rcuperf.verbose=1
52}
diff --git a/tools/testing/selftests/sigaltstack/Makefile b/tools/testing/selftests/sigaltstack/Makefile
new file mode 100644
index 000000000000..56af56eda6fa
--- /dev/null
+++ b/tools/testing/selftests/sigaltstack/Makefile
@@ -0,0 +1,8 @@
1CFLAGS = -Wall
2BINARIES = sas
3all: $(BINARIES)
4
5include ../lib.mk
6
7clean:
8 rm -rf $(BINARIES)
diff --git a/tools/testing/selftests/sigaltstack/sas.c b/tools/testing/selftests/sigaltstack/sas.c
new file mode 100644
index 000000000000..1bb01258e559
--- /dev/null
+++ b/tools/testing/selftests/sigaltstack/sas.c
@@ -0,0 +1,176 @@
1/*
2 * Stas Sergeev <stsp@users.sourceforge.net>
3 *
4 * test sigaltstack(SS_ONSTACK | SS_AUTODISARM)
5 * If that succeeds, then swapcontext() can be used inside sighandler safely.
6 *
7 */
8
9#define _GNU_SOURCE
10#include <signal.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <sys/mman.h>
14#include <ucontext.h>
15#include <alloca.h>
16#include <string.h>
17#include <assert.h>
18#include <errno.h>
19
20#ifndef SS_AUTODISARM
21#define SS_AUTODISARM (1U << 31)
22#endif
23
24static void *sstack, *ustack;
25static ucontext_t uc, sc;
26static const char *msg = "[OK]\tStack preserved";
27static const char *msg2 = "[FAIL]\tStack corrupted";
28struct stk_data {
29 char msg[128];
30 int flag;
31};
32
33void my_usr1(int sig, siginfo_t *si, void *u)
34{
35 char *aa;
36 int err;
37 stack_t stk;
38 struct stk_data *p;
39
40 register unsigned long sp asm("sp");
41
42 if (sp < (unsigned long)sstack ||
43 sp >= (unsigned long)sstack + SIGSTKSZ) {
44 printf("[FAIL]\tSP is not on sigaltstack\n");
45 exit(EXIT_FAILURE);
46 }
47 /* put some data on stack. other sighandler will try to overwrite it */
48 aa = alloca(1024);
49 assert(aa);
50 p = (struct stk_data *)(aa + 512);
51 strcpy(p->msg, msg);
52 p->flag = 1;
53 printf("[RUN]\tsignal USR1\n");
54 err = sigaltstack(NULL, &stk);
55 if (err) {
56 perror("[FAIL]\tsigaltstack()");
57 exit(EXIT_FAILURE);
58 }
59 if (stk.ss_flags != SS_DISABLE)
60 printf("[FAIL]\tss_flags=%i, should be SS_DISABLE\n",
61 stk.ss_flags);
62 else
63 printf("[OK]\tsigaltstack is disabled in sighandler\n");
64 swapcontext(&sc, &uc);
65 printf("%s\n", p->msg);
66 if (!p->flag) {
67 printf("[RUN]\tAborting\n");
68 exit(EXIT_FAILURE);
69 }
70}
71
72void my_usr2(int sig, siginfo_t *si, void *u)
73{
74 char *aa;
75 struct stk_data *p;
76
77 printf("[RUN]\tsignal USR2\n");
78 aa = alloca(1024);
79 /* dont run valgrind on this */
80 /* try to find the data stored by previous sighandler */
81 p = memmem(aa, 1024, msg, strlen(msg));
82 if (p) {
83 printf("[FAIL]\tsigaltstack re-used\n");
84 /* corrupt the data */
85 strcpy(p->msg, msg2);
86 /* tell other sighandler that his data is corrupted */
87 p->flag = 0;
88 }
89}
90
91static void switch_fn(void)
92{
93 printf("[RUN]\tswitched to user ctx\n");
94 raise(SIGUSR2);
95 setcontext(&sc);
96}
97
98int main(void)
99{
100 struct sigaction act;
101 stack_t stk;
102 int err;
103
104 sigemptyset(&act.sa_mask);
105 act.sa_flags = SA_ONSTACK | SA_SIGINFO;
106 act.sa_sigaction = my_usr1;
107 sigaction(SIGUSR1, &act, NULL);
108 act.sa_sigaction = my_usr2;
109 sigaction(SIGUSR2, &act, NULL);
110 sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
111 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
112 if (sstack == MAP_FAILED) {
113 perror("mmap()");
114 return EXIT_FAILURE;
115 }
116
117 err = sigaltstack(NULL, &stk);
118 if (err) {
119 perror("[FAIL]\tsigaltstack()");
120 exit(EXIT_FAILURE);
121 }
122 if (stk.ss_flags == SS_DISABLE) {
123 printf("[OK]\tInitial sigaltstack state was SS_DISABLE\n");
124 } else {
125 printf("[FAIL]\tInitial sigaltstack state was %i; should have been SS_DISABLE\n", stk.ss_flags);
126 return EXIT_FAILURE;
127 }
128
129 stk.ss_sp = sstack;
130 stk.ss_size = SIGSTKSZ;
131 stk.ss_flags = SS_ONSTACK | SS_AUTODISARM;
132 err = sigaltstack(&stk, NULL);
133 if (err) {
134 if (errno == EINVAL) {
135 printf("[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n");
136 /*
137 * If test cases for the !SS_AUTODISARM variant were
138 * added, we could still run them. We don't have any
139 * test cases like that yet, so just exit and report
140 * success.
141 */
142 return 0;
143 } else {
144 perror("[FAIL]\tsigaltstack(SS_ONSTACK | SS_AUTODISARM)");
145 return EXIT_FAILURE;
146 }
147 }
148
149 ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
150 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
151 if (ustack == MAP_FAILED) {
152 perror("mmap()");
153 return EXIT_FAILURE;
154 }
155 getcontext(&uc);
156 uc.uc_link = NULL;
157 uc.uc_stack.ss_sp = ustack;
158 uc.uc_stack.ss_size = SIGSTKSZ;
159 makecontext(&uc, switch_fn, 0);
160 raise(SIGUSR1);
161
162 err = sigaltstack(NULL, &stk);
163 if (err) {
164 perror("[FAIL]\tsigaltstack()");
165 exit(EXIT_FAILURE);
166 }
167 if (stk.ss_flags != SS_AUTODISARM) {
168 printf("[FAIL]\tss_flags=%i, should be SS_AUTODISARM\n",
169 stk.ss_flags);
170 exit(EXIT_FAILURE);
171 }
172 printf("[OK]\tsigaltstack is still SS_AUTODISARM after signal\n");
173
174 printf("[OK]\tTest passed\n");
175 return 0;
176}
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index b47ebd170690..c73425de3cfe 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -9,6 +9,7 @@ TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_sysc
9TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ 9TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
10 test_FCMOV test_FCOMI test_FISTTP \ 10 test_FCMOV test_FCOMI test_FISTTP \
11 vdso_restorer 11 vdso_restorer
12TARGETS_C_64BIT_ONLY := fsgsbase
12 13
13TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) 14TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
14TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) 15TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY)
diff --git a/tools/testing/selftests/x86/fsgsbase.c b/tools/testing/selftests/x86/fsgsbase.c
new file mode 100644
index 000000000000..5b2b4b3c634c
--- /dev/null
+++ b/tools/testing/selftests/x86/fsgsbase.c
@@ -0,0 +1,398 @@
1/*
2 * fsgsbase.c, an fsgsbase test
3 * Copyright (c) 2014-2016 Andy Lutomirski
4 * GPL v2
5 */
6
7#define _GNU_SOURCE
8#include <stdio.h>
9#include <stdlib.h>
10#include <stdbool.h>
11#include <string.h>
12#include <sys/syscall.h>
13#include <unistd.h>
14#include <err.h>
15#include <sys/user.h>
16#include <asm/prctl.h>
17#include <sys/prctl.h>
18#include <signal.h>
19#include <limits.h>
20#include <sys/ucontext.h>
21#include <sched.h>
22#include <linux/futex.h>
23#include <pthread.h>
24#include <asm/ldt.h>
25#include <sys/mman.h>
26
27#ifndef __x86_64__
28# error This test is 64-bit only
29#endif
30
31static volatile sig_atomic_t want_segv;
32static volatile unsigned long segv_addr;
33
34static int nerrs;
35
36static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
37 int flags)
38{
39 struct sigaction sa;
40 memset(&sa, 0, sizeof(sa));
41 sa.sa_sigaction = handler;
42 sa.sa_flags = SA_SIGINFO | flags;
43 sigemptyset(&sa.sa_mask);
44 if (sigaction(sig, &sa, 0))
45 err(1, "sigaction");
46}
47
48static void clearhandler(int sig)
49{
50 struct sigaction sa;
51 memset(&sa, 0, sizeof(sa));
52 sa.sa_handler = SIG_DFL;
53 sigemptyset(&sa.sa_mask);
54 if (sigaction(sig, &sa, 0))
55 err(1, "sigaction");
56}
57
58static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
59{
60 ucontext_t *ctx = (ucontext_t*)ctx_void;
61
62 if (!want_segv) {
63 clearhandler(SIGSEGV);
64 return; /* Crash cleanly. */
65 }
66
67 want_segv = false;
68 segv_addr = (unsigned long)si->si_addr;
69
70 ctx->uc_mcontext.gregs[REG_RIP] += 4; /* Skip the faulting mov */
71
72}
73
74enum which_base { FS, GS };
75
76static unsigned long read_base(enum which_base which)
77{
78 unsigned long offset;
79 /*
80 * Unless we have FSGSBASE, there's no direct way to do this from
81 * user mode. We can get at it indirectly using signals, though.
82 */
83
84 want_segv = true;
85
86 offset = 0;
87 if (which == FS) {
88 /* Use a constant-length instruction here. */
89 asm volatile ("mov %%fs:(%%rcx), %%rax" : : "c" (offset) : "rax");
90 } else {
91 asm volatile ("mov %%gs:(%%rcx), %%rax" : : "c" (offset) : "rax");
92 }
93 if (!want_segv)
94 return segv_addr + offset;
95
96 /*
97 * If that didn't segfault, try the other end of the address space.
98 * Unless we get really unlucky and run into the vsyscall page, this
99 * is guaranteed to segfault.
100 */
101
102 offset = (ULONG_MAX >> 1) + 1;
103 if (which == FS) {
104 asm volatile ("mov %%fs:(%%rcx), %%rax"
105 : : "c" (offset) : "rax");
106 } else {
107 asm volatile ("mov %%gs:(%%rcx), %%rax"
108 : : "c" (offset) : "rax");
109 }
110 if (!want_segv)
111 return segv_addr + offset;
112
113 abort();
114}
115
116static void check_gs_value(unsigned long value)
117{
118 unsigned long base;
119 unsigned short sel;
120
121 printf("[RUN]\tARCH_SET_GS to 0x%lx\n", value);
122 if (syscall(SYS_arch_prctl, ARCH_SET_GS, value) != 0)
123 err(1, "ARCH_SET_GS");
124
125 asm volatile ("mov %%gs, %0" : "=rm" (sel));
126 base = read_base(GS);
127 if (base == value) {
128 printf("[OK]\tGSBASE was set as expected (selector 0x%hx)\n",
129 sel);
130 } else {
131 nerrs++;
132 printf("[FAIL]\tGSBASE was not as expected: got 0x%lx (selector 0x%hx)\n",
133 base, sel);
134 }
135
136 if (syscall(SYS_arch_prctl, ARCH_GET_GS, &base) != 0)
137 err(1, "ARCH_GET_GS");
138 if (base == value) {
139 printf("[OK]\tARCH_GET_GS worked as expected (selector 0x%hx)\n",
140 sel);
141 } else {
142 nerrs++;
143 printf("[FAIL]\tARCH_GET_GS was not as expected: got 0x%lx (selector 0x%hx)\n",
144 base, sel);
145 }
146}
147
148static void mov_0_gs(unsigned long initial_base, bool schedule)
149{
150 unsigned long base, arch_base;
151
152 printf("[RUN]\tARCH_SET_GS to 0x%lx then mov 0 to %%gs%s\n", initial_base, schedule ? " and schedule " : "");
153 if (syscall(SYS_arch_prctl, ARCH_SET_GS, initial_base) != 0)
154 err(1, "ARCH_SET_GS");
155
156 if (schedule)
157 usleep(10);
158
159 asm volatile ("mov %0, %%gs" : : "rm" (0));
160 base = read_base(GS);
161 if (syscall(SYS_arch_prctl, ARCH_GET_GS, &arch_base) != 0)
162 err(1, "ARCH_GET_GS");
163 if (base == arch_base) {
164 printf("[OK]\tGSBASE is 0x%lx\n", base);
165 } else {
166 nerrs++;
167 printf("[FAIL]\tGSBASE changed to 0x%lx but kernel reports 0x%lx\n", base, arch_base);
168 }
169}
170
171static volatile unsigned long remote_base;
172static volatile bool remote_hard_zero;
173static volatile unsigned int ftx;
174
175/*
176 * ARCH_SET_FS/GS(0) may or may not program a selector of zero. HARD_ZERO
177 * means to force the selector to zero to improve test coverage.
178 */
179#define HARD_ZERO 0xa1fa5f343cb85fa4
180
181static void do_remote_base()
182{
183 unsigned long to_set = remote_base;
184 bool hard_zero = false;
185 if (to_set == HARD_ZERO) {
186 to_set = 0;
187 hard_zero = true;
188 }
189
190 if (syscall(SYS_arch_prctl, ARCH_SET_GS, to_set) != 0)
191 err(1, "ARCH_SET_GS");
192
193 if (hard_zero)
194 asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
195
196 unsigned short sel;
197 asm volatile ("mov %%gs, %0" : "=rm" (sel));
198 printf("\tother thread: ARCH_SET_GS(0x%lx)%s -- sel is 0x%hx\n",
199 to_set, hard_zero ? " and clear gs" : "", sel);
200}
201
202void do_unexpected_base(void)
203{
204 /*
205 * The goal here is to try to arrange for GS == 0, GSBASE !=
206 * 0, and for the the kernel the think that GSBASE == 0.
207 *
208 * To make the test as reliable as possible, this uses
209 * explicit descriptorss. (This is not the only way. This
210 * could use ARCH_SET_GS with a low, nonzero base, but the
211 * relevant side effect of ARCH_SET_GS could change.)
212 */
213
214 /* Step 1: tell the kernel that we have GSBASE == 0. */
215 if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0)
216 err(1, "ARCH_SET_GS");
217
218 /* Step 2: change GSBASE without telling the kernel. */
219 struct user_desc desc = {
220 .entry_number = 0,
221 .base_addr = 0xBAADF00D,
222 .limit = 0xfffff,
223 .seg_32bit = 1,
224 .contents = 0, /* Data, grow-up */
225 .read_exec_only = 0,
226 .limit_in_pages = 1,
227 .seg_not_present = 0,
228 .useable = 0
229 };
230 if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) == 0) {
231 printf("\tother thread: using LDT slot 0\n");
232 asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0x7));
233 } else {
234 /* No modify_ldt for us (configured out, perhaps) */
235
236 struct user_desc *low_desc = mmap(
237 NULL, sizeof(desc),
238 PROT_READ | PROT_WRITE,
239 MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
240 memcpy(low_desc, &desc, sizeof(desc));
241
242 low_desc->entry_number = -1;
243
244 /* 32-bit set_thread_area */
245 long ret;
246 asm volatile ("int $0x80"
247 : "=a" (ret) : "a" (243), "b" (low_desc)
248 : "flags");
249 memcpy(&desc, low_desc, sizeof(desc));
250 munmap(low_desc, sizeof(desc));
251
252 if (ret != 0) {
253 printf("[NOTE]\tcould not create a segment -- test won't do anything\n");
254 return;
255 }
256 printf("\tother thread: using GDT slot %d\n", desc.entry_number);
257 asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)((desc.entry_number << 3) | 0x3)));
258 }
259
260 /*
261 * Step 3: set the selector back to zero. On AMD chips, this will
262 * preserve GSBASE.
263 */
264
265 asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
266}
267
268static void *threadproc(void *ctx)
269{
270 while (1) {
271 while (ftx == 0)
272 syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0);
273 if (ftx == 3)
274 return NULL;
275
276 if (ftx == 1)
277 do_remote_base();
278 else if (ftx == 2)
279 do_unexpected_base();
280 else
281 errx(1, "helper thread got bad command");
282
283 ftx = 0;
284 syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
285 }
286}
287
288static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
289{
290 unsigned long base;
291
292 bool hard_zero = false;
293 if (local == HARD_ZERO) {
294 hard_zero = true;
295 local = 0;
296 }
297
298 printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
299 local, hard_zero ? " and clear gs" : "", remote);
300 if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
301 err(1, "ARCH_SET_GS");
302 if (hard_zero)
303 asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
304
305 if (read_base(GS) != local) {
306 nerrs++;
307 printf("[FAIL]\tGSBASE wasn't set as expected\n");
308 }
309
310 remote_base = remote;
311 ftx = 1;
312 syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
313 while (ftx != 0)
314 syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
315
316 base = read_base(GS);
317 if (base == local) {
318 printf("[OK]\tGSBASE remained 0x%lx\n", local);
319 } else {
320 nerrs++;
321 printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
322 }
323}
324
325static void test_unexpected_base(void)
326{
327 unsigned long base;
328
329 printf("[RUN]\tARCH_SET_GS(0), clear gs, then manipulate GSBASE in a different thread\n");
330 if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0)
331 err(1, "ARCH_SET_GS");
332 asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
333
334 ftx = 2;
335 syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
336 while (ftx != 0)
337 syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
338
339 base = read_base(GS);
340 if (base == 0) {
341 printf("[OK]\tGSBASE remained 0\n");
342 } else {
343 nerrs++;
344 printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
345 }
346}
347
348int main()
349{
350 pthread_t thread;
351
352 sethandler(SIGSEGV, sigsegv, 0);
353
354 check_gs_value(0);
355 check_gs_value(1);
356 check_gs_value(0x200000000);
357 check_gs_value(0);
358 check_gs_value(0x200000000);
359 check_gs_value(1);
360
361 for (int sched = 0; sched < 2; sched++) {
362 mov_0_gs(0, !!sched);
363 mov_0_gs(1, !!sched);
364 mov_0_gs(0x200000000, !!sched);
365 }
366
367 /* Set up for multithreading. */
368
369 cpu_set_t cpuset;
370 CPU_ZERO(&cpuset);
371 CPU_SET(0, &cpuset);
372 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
373 err(1, "sched_setaffinity to CPU 0"); /* should never fail */
374
375 if (pthread_create(&thread, 0, threadproc, 0) != 0)
376 err(1, "pthread_create");
377
378 static unsigned long bases_with_hard_zero[] = {
379 0, HARD_ZERO, 1, 0x200000000,
380 };
381
382 for (int local = 0; local < 4; local++) {
383 for (int remote = 0; remote < 4; remote++) {
384 set_gs_and_switch_to(bases_with_hard_zero[local],
385 bases_with_hard_zero[remote]);
386 }
387 }
388
389 test_unexpected_base();
390
391 ftx = 3; /* Kill the thread. */
392 syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
393
394 if (pthread_join(thread, NULL) != 0)
395 err(1, "pthread_join");
396
397 return nerrs == 0 ? 0 : 1;
398}
diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c
index 31a3035cd4eb..4af47079cf04 100644
--- a/tools/testing/selftests/x86/ldt_gdt.c
+++ b/tools/testing/selftests/x86/ldt_gdt.c
@@ -21,6 +21,9 @@
21#include <pthread.h> 21#include <pthread.h>
22#include <sched.h> 22#include <sched.h>
23#include <linux/futex.h> 23#include <linux/futex.h>
24#include <sys/mman.h>
25#include <asm/prctl.h>
26#include <sys/prctl.h>
24 27
25#define AR_ACCESSED (1<<8) 28#define AR_ACCESSED (1<<8)
26 29
@@ -44,6 +47,12 @@
44 47
45static int nerrs; 48static int nerrs;
46 49
50/* Points to an array of 1024 ints, each holding its own index. */
51static const unsigned int *counter_page;
52static struct user_desc *low_user_desc;
53static struct user_desc *low_user_desc_clear; /* Use to delete GDT entry */
54static int gdt_entry_num;
55
47static void check_invalid_segment(uint16_t index, int ldt) 56static void check_invalid_segment(uint16_t index, int ldt)
48{ 57{
49 uint32_t has_limit = 0, has_ar = 0, limit, ar; 58 uint32_t has_limit = 0, has_ar = 0, limit, ar;
@@ -561,16 +570,257 @@ static void do_exec_test(void)
561 } 570 }
562} 571}
563 572
573static void setup_counter_page(void)
574{
575 unsigned int *page = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
576 MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
577 if (page == MAP_FAILED)
578 err(1, "mmap");
579
580 for (int i = 0; i < 1024; i++)
581 page[i] = i;
582 counter_page = page;
583}
584
585static int invoke_set_thread_area(void)
586{
587 int ret;
588 asm volatile ("int $0x80"
589 : "=a" (ret), "+m" (low_user_desc) :
590 "a" (243), "b" (low_user_desc)
591 : "flags");
592 return ret;
593}
594
595static void setup_low_user_desc(void)
596{
597 low_user_desc = mmap(NULL, 2 * sizeof(struct user_desc),
598 PROT_READ | PROT_WRITE,
599 MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
600 if (low_user_desc == MAP_FAILED)
601 err(1, "mmap");
602
603 low_user_desc->entry_number = -1;
604 low_user_desc->base_addr = (unsigned long)&counter_page[1];
605 low_user_desc->limit = 0xfffff;
606 low_user_desc->seg_32bit = 1;
607 low_user_desc->contents = 0; /* Data, grow-up*/
608 low_user_desc->read_exec_only = 0;
609 low_user_desc->limit_in_pages = 1;
610 low_user_desc->seg_not_present = 0;
611 low_user_desc->useable = 0;
612
613 if (invoke_set_thread_area() == 0) {
614 gdt_entry_num = low_user_desc->entry_number;
615 printf("[NOTE]\tset_thread_area is available; will use GDT index %d\n", gdt_entry_num);
616 } else {
617 printf("[NOTE]\tset_thread_area is unavailable\n");
618 }
619
620 low_user_desc_clear = low_user_desc + 1;
621 low_user_desc_clear->entry_number = gdt_entry_num;
622 low_user_desc_clear->read_exec_only = 1;
623 low_user_desc_clear->seg_not_present = 1;
624}
625
626static void test_gdt_invalidation(void)
627{
628 if (!gdt_entry_num)
629 return; /* 64-bit only system -- we can't use set_thread_area */
630
631 unsigned short prev_sel;
632 unsigned short sel;
633 unsigned int eax;
634 const char *result;
635#ifdef __x86_64__
636 unsigned long saved_base;
637 unsigned long new_base;
638#endif
639
640 /* Test DS */
641 invoke_set_thread_area();
642 eax = 243;
643 sel = (gdt_entry_num << 3) | 3;
644 asm volatile ("movw %%ds, %[prev_sel]\n\t"
645 "movw %[sel], %%ds\n\t"
646#ifdef __i386__
647 "pushl %%ebx\n\t"
648#endif
649 "movl %[arg1], %%ebx\n\t"
650 "int $0x80\n\t" /* Should invalidate ds */
651#ifdef __i386__
652 "popl %%ebx\n\t"
653#endif
654 "movw %%ds, %[sel]\n\t"
655 "movw %[prev_sel], %%ds"
656 : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
657 "+a" (eax)
658 : "m" (low_user_desc_clear),
659 [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
660 : "flags");
661
662 if (sel != 0) {
663 result = "FAIL";
664 nerrs++;
665 } else {
666 result = "OK";
667 }
668 printf("[%s]\tInvalidate DS with set_thread_area: new DS = 0x%hx\n",
669 result, sel);
670
671 /* Test ES */
672 invoke_set_thread_area();
673 eax = 243;
674 sel = (gdt_entry_num << 3) | 3;
675 asm volatile ("movw %%es, %[prev_sel]\n\t"
676 "movw %[sel], %%es\n\t"
677#ifdef __i386__
678 "pushl %%ebx\n\t"
679#endif
680 "movl %[arg1], %%ebx\n\t"
681 "int $0x80\n\t" /* Should invalidate es */
682#ifdef __i386__
683 "popl %%ebx\n\t"
684#endif
685 "movw %%es, %[sel]\n\t"
686 "movw %[prev_sel], %%es"
687 : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
688 "+a" (eax)
689 : "m" (low_user_desc_clear),
690 [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
691 : "flags");
692
693 if (sel != 0) {
694 result = "FAIL";
695 nerrs++;
696 } else {
697 result = "OK";
698 }
699 printf("[%s]\tInvalidate ES with set_thread_area: new ES = 0x%hx\n",
700 result, sel);
701
702 /* Test FS */
703 invoke_set_thread_area();
704 eax = 243;
705 sel = (gdt_entry_num << 3) | 3;
706#ifdef __x86_64__
707 syscall(SYS_arch_prctl, ARCH_GET_FS, &saved_base);
708#endif
709 asm volatile ("movw %%fs, %[prev_sel]\n\t"
710 "movw %[sel], %%fs\n\t"
711#ifdef __i386__
712 "pushl %%ebx\n\t"
713#endif
714 "movl %[arg1], %%ebx\n\t"
715 "int $0x80\n\t" /* Should invalidate fs */
716#ifdef __i386__
717 "popl %%ebx\n\t"
718#endif
719 "movw %%fs, %[sel]\n\t"
720 : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
721 "+a" (eax)
722 : "m" (low_user_desc_clear),
723 [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
724 : "flags");
725
726#ifdef __x86_64__
727 syscall(SYS_arch_prctl, ARCH_GET_FS, &new_base);
728#endif
729
730 /* Restore FS/BASE for glibc */
731 asm volatile ("movw %[prev_sel], %%fs" : : [prev_sel] "rm" (prev_sel));
732#ifdef __x86_64__
733 if (saved_base)
734 syscall(SYS_arch_prctl, ARCH_SET_FS, saved_base);
735#endif
736
737 if (sel != 0) {
738 result = "FAIL";
739 nerrs++;
740 } else {
741 result = "OK";
742 }
743 printf("[%s]\tInvalidate FS with set_thread_area: new FS = 0x%hx\n",
744 result, sel);
745
746#ifdef __x86_64__
747 if (sel == 0 && new_base != 0) {
748 nerrs++;
749 printf("[FAIL]\tNew FSBASE was 0x%lx\n", new_base);
750 } else {
751 printf("[OK]\tNew FSBASE was zero\n");
752 }
753#endif
754
755 /* Test GS */
756 invoke_set_thread_area();
757 eax = 243;
758 sel = (gdt_entry_num << 3) | 3;
759#ifdef __x86_64__
760 syscall(SYS_arch_prctl, ARCH_GET_GS, &saved_base);
761#endif
762 asm volatile ("movw %%gs, %[prev_sel]\n\t"
763 "movw %[sel], %%gs\n\t"
764#ifdef __i386__
765 "pushl %%ebx\n\t"
766#endif
767 "movl %[arg1], %%ebx\n\t"
768 "int $0x80\n\t" /* Should invalidate gs */
769#ifdef __i386__
770 "popl %%ebx\n\t"
771#endif
772 "movw %%gs, %[sel]\n\t"
773 : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),
774 "+a" (eax)
775 : "m" (low_user_desc_clear),
776 [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)
777 : "flags");
778
779#ifdef __x86_64__
780 syscall(SYS_arch_prctl, ARCH_GET_GS, &new_base);
781#endif
782
783 /* Restore GS/BASE for glibc */
784 asm volatile ("movw %[prev_sel], %%gs" : : [prev_sel] "rm" (prev_sel));
785#ifdef __x86_64__
786 if (saved_base)
787 syscall(SYS_arch_prctl, ARCH_SET_GS, saved_base);
788#endif
789
790 if (sel != 0) {
791 result = "FAIL";
792 nerrs++;
793 } else {
794 result = "OK";
795 }
796 printf("[%s]\tInvalidate GS with set_thread_area: new GS = 0x%hx\n",
797 result, sel);
798
799#ifdef __x86_64__
800 if (sel == 0 && new_base != 0) {
801 nerrs++;
802 printf("[FAIL]\tNew GSBASE was 0x%lx\n", new_base);
803 } else {
804 printf("[OK]\tNew GSBASE was zero\n");
805 }
806#endif
807}
808
564int main(int argc, char **argv) 809int main(int argc, char **argv)
565{ 810{
566 if (argc == 1 && !strcmp(argv[0], "ldt_gdt_test_exec")) 811 if (argc == 1 && !strcmp(argv[0], "ldt_gdt_test_exec"))
567 return finish_exec_test(); 812 return finish_exec_test();
568 813
814 setup_counter_page();
815 setup_low_user_desc();
816
569 do_simple_tests(); 817 do_simple_tests();
570 818
571 do_multicpu_tests(); 819 do_multicpu_tests();
572 820
573 do_exec_test(); 821 do_exec_test();
574 822
823 test_gdt_invalidation();
824
575 return nerrs ? 1 : 0; 825 return nerrs ? 1 : 0;
576} 826}