aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>2018-06-02 08:44:04 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-06-06 05:58:34 -0400
commit2e155fb7d605d37c423ad0076f82feca572efdce (patch)
treeb12f4dbd2bb1aae258b865008f150e24102ff282
parent4e49ed2f9ac32b0ba22c113dc405a49d3133eb57 (diff)
rseq/selftests: Provide rseq library
This rseq helper library provides a user-space API to the rseq() system call. The rseq fast-path exposes the instruction pointer addresses where the rseq assembly blocks begin and end, as well as the associated abort instruction pointer, in the __rseq_table section. This section allows debuggers may know where to place breakpoints when single-stepping through assembly blocks which may be aborted at any point by the kernel. Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Joel Fernandes <joelaf@google.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Dave Watson <davejwatson@fb.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Shuah Khan <shuahkh@osg.samsung.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: linux-kselftest@vger.kernel.org Cc: "H . Peter Anvin" <hpa@zytor.com> Cc: Chris Lameter <cl@linux.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Andrew Hunter <ahh@google.com> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: "Paul E . McKenney" <paulmck@linux.vnet.ibm.com> Cc: Paul Turner <pjt@google.com> Cc: Boqun Feng <boqun.feng@gmail.com> Cc: Josh Triplett <josh@joshtriplett.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Ben Maurer <bmaurer@fb.com> Cc: linux-api@vger.kernel.org Cc: Andy Lutomirski <luto@amacapital.net> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: https://lkml.kernel.org/r/20180602124408.8430-13-mathieu.desnoyers@efficios.com
-rw-r--r--tools/testing/selftests/rseq/rseq-arm.h715
-rw-r--r--tools/testing/selftests/rseq/rseq-ppc.h671
-rw-r--r--tools/testing/selftests/rseq/rseq-skip.h65
-rw-r--r--tools/testing/selftests/rseq/rseq-x86.h1132
-rw-r--r--tools/testing/selftests/rseq/rseq.c117
-rw-r--r--tools/testing/selftests/rseq/rseq.h147
6 files changed, 2847 insertions, 0 deletions
diff --git a/tools/testing/selftests/rseq/rseq-arm.h b/tools/testing/selftests/rseq/rseq-arm.h
new file mode 100644
index 000000000000..3b055f9aeaab
--- /dev/null
+++ b/tools/testing/selftests/rseq/rseq-arm.h
@@ -0,0 +1,715 @@
1/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2/*
3 * rseq-arm.h
4 *
5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 */
7
8#define RSEQ_SIG 0x53053053
9
10#define rseq_smp_mb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
11#define rseq_smp_rmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
12#define rseq_smp_wmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
13
14#define rseq_smp_load_acquire(p) \
15__extension__ ({ \
16 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
17 rseq_smp_mb(); \
18 ____p1; \
19})
20
21#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
22
23#define rseq_smp_store_release(p, v) \
24do { \
25 rseq_smp_mb(); \
26 RSEQ_WRITE_ONCE(*p, v); \
27} while (0)
28
29#ifdef RSEQ_SKIP_FASTPATH
30#include "rseq-skip.h"
31#else /* !RSEQ_SKIP_FASTPATH */
32
33#define __RSEQ_ASM_DEFINE_TABLE(version, flags, start_ip, \
34 post_commit_offset, abort_ip) \
35 ".pushsection __rseq_table, \"aw\"\n\t" \
36 ".balign 32\n\t" \
37 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
38 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
39 ".popsection\n\t"
40
41#define RSEQ_ASM_DEFINE_TABLE(start_ip, post_commit_ip, abort_ip) \
42 __RSEQ_ASM_DEFINE_TABLE(0x0, 0x0, start_ip, \
43 (post_commit_ip - start_ip), abort_ip)
44
45#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
46 RSEQ_INJECT_ASM(1) \
47 "adr r0, " __rseq_str(cs_label) "\n\t" \
48 "str r0, %[" __rseq_str(rseq_cs) "]\n\t" \
49 __rseq_str(label) ":\n\t"
50
51#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
52 RSEQ_INJECT_ASM(2) \
53 "ldr r0, %[" __rseq_str(current_cpu_id) "]\n\t" \
54 "cmp %[" __rseq_str(cpu_id) "], r0\n\t" \
55 "bne " __rseq_str(label) "\n\t"
56
57#define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
58 abort_label, version, flags, \
59 start_ip, post_commit_offset, abort_ip) \
60 __rseq_str(table_label) ":\n\t" \
61 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
62 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
63 ".word " __rseq_str(RSEQ_SIG) "\n\t" \
64 __rseq_str(label) ":\n\t" \
65 teardown \
66 "b %l[" __rseq_str(abort_label) "]\n\t"
67
68#define RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, abort_label, \
69 start_ip, post_commit_ip, abort_ip) \
70 __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
71 abort_label, 0x0, 0x0, start_ip, \
72 (post_commit_ip - start_ip), abort_ip)
73
74#define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
75 __rseq_str(label) ":\n\t" \
76 teardown \
77 "b %l[" __rseq_str(cmpfail_label) "]\n\t"
78
79#define rseq_workaround_gcc_asm_size_guess() __asm__ __volatile__("")
80
81static inline __attribute__((always_inline))
82int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
83{
84 RSEQ_INJECT_C(9)
85
86 rseq_workaround_gcc_asm_size_guess();
87 __asm__ __volatile__ goto (
88 RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
89 /* Start rseq by storing table entry pointer into rseq_cs. */
90 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
91 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
92 RSEQ_INJECT_ASM(3)
93 "ldr r0, %[v]\n\t"
94 "cmp %[expect], r0\n\t"
95 "bne %l[cmpfail]\n\t"
96 RSEQ_INJECT_ASM(4)
97#ifdef RSEQ_COMPARE_TWICE
98 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
99 "ldr r0, %[v]\n\t"
100 "cmp %[expect], r0\n\t"
101 "bne %l[error2]\n\t"
102#endif
103 /* final store */
104 "str %[newv], %[v]\n\t"
105 "2:\n\t"
106 RSEQ_INJECT_ASM(5)
107 "b 5f\n\t"
108 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
109 "5:\n\t"
110 : /* gcc asm goto does not allow outputs */
111 : [cpu_id] "r" (cpu),
112 [current_cpu_id] "m" (__rseq_abi.cpu_id),
113 [rseq_cs] "m" (__rseq_abi.rseq_cs),
114 [v] "m" (*v),
115 [expect] "r" (expect),
116 [newv] "r" (newv)
117 RSEQ_INJECT_INPUT
118 : "r0", "memory", "cc"
119 RSEQ_INJECT_CLOBBER
120 : abort, cmpfail
121#ifdef RSEQ_COMPARE_TWICE
122 , error1, error2
123#endif
124 );
125 rseq_workaround_gcc_asm_size_guess();
126 return 0;
127abort:
128 rseq_workaround_gcc_asm_size_guess();
129 RSEQ_INJECT_FAILED
130 return -1;
131cmpfail:
132 rseq_workaround_gcc_asm_size_guess();
133 return 1;
134#ifdef RSEQ_COMPARE_TWICE
135error1:
136 rseq_bug("cpu_id comparison failed");
137error2:
138 rseq_bug("expected value comparison failed");
139#endif
140}
141
142static inline __attribute__((always_inline))
143int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
144 off_t voffp, intptr_t *load, int cpu)
145{
146 RSEQ_INJECT_C(9)
147
148 rseq_workaround_gcc_asm_size_guess();
149 __asm__ __volatile__ goto (
150 RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */
151 /* Start rseq by storing table entry pointer into rseq_cs. */
152 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
153 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
154 RSEQ_INJECT_ASM(3)
155 "ldr r0, %[v]\n\t"
156 "cmp %[expectnot], r0\n\t"
157 "beq %l[cmpfail]\n\t"
158 RSEQ_INJECT_ASM(4)
159#ifdef RSEQ_COMPARE_TWICE
160 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
161 "ldr r0, %[v]\n\t"
162 "cmp %[expectnot], r0\n\t"
163 "beq %l[error2]\n\t"
164#endif
165 "str r0, %[load]\n\t"
166 "add r0, %[voffp]\n\t"
167 "ldr r0, [r0]\n\t"
168 /* final store */
169 "str r0, %[v]\n\t"
170 "2:\n\t"
171 RSEQ_INJECT_ASM(5)
172 "b 5f\n\t"
173 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
174 "5:\n\t"
175 : /* gcc asm goto does not allow outputs */
176 : [cpu_id] "r" (cpu),
177 [current_cpu_id] "m" (__rseq_abi.cpu_id),
178 [rseq_cs] "m" (__rseq_abi.rseq_cs),
179 /* final store input */
180 [v] "m" (*v),
181 [expectnot] "r" (expectnot),
182 [voffp] "Ir" (voffp),
183 [loa