Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// Program that loops for ever doing lots of recursions and system calls,
2// intended to be used as part of a stress test for GCS context switching.
3//
4// Copyright 2015-2023 Arm Ltd
5
6#include <asm/unistd.h>
7
8#define sa_sz 32
9#define sa_flags 8
10#define sa_handler 0
11#define sa_mask_sz 8
12
13#define si_code 8
14
15#define SIGINT 2
16#define SIGABRT 6
17#define SIGUSR1 10
18#define SIGSEGV 11
19#define SIGUSR2 12
20#define SIGTERM 15
21#define SEGV_CPERR 10
22
23#define SA_NODEFER 1073741824
24#define SA_SIGINFO 4
25#define ucontext_regs 184
26
27#define PR_SET_SHADOW_STACK_STATUS 75
28# define PR_SHADOW_STACK_ENABLE (1UL << 0)
29
30#define GCSPR_EL0 S3_3_C2_C5_1
31
32.macro function name
33 .macro endfunction
34 .type \name, @function
35 .purgem endfunction
36 .endm
37\name:
38.endm
39
40// Print a single character x0 to stdout
41// Clobbers x0-x2,x8
42function putc
43 str x0, [sp, #-16]!
44
45 mov x0, #1 // STDOUT_FILENO
46 mov x1, sp
47 mov x2, #1
48 mov x8, #__NR_write
49 svc #0
50
51 add sp, sp, #16
52 ret
53endfunction
54.globl putc
55
56// Print a NUL-terminated string starting at address x0 to stdout
57// Clobbers x0-x3,x8
58function puts
59 mov x1, x0
60
61 mov x2, #0
620: ldrb w3, [x0], #1
63 cbz w3, 1f
64 add x2, x2, #1
65 b 0b
66
671: mov w0, #1 // STDOUT_FILENO
68 mov x8, #__NR_write
69 svc #0
70
71 ret
72endfunction
73.globl puts
74
75// Utility macro to print a literal string
76// Clobbers x0-x4,x8
77.macro puts string
78 .pushsection .rodata.str1.1, "aMS", @progbits, 1
79.L__puts_literal\@: .string "\string"
80 .popsection
81
82 ldr x0, =.L__puts_literal\@
83 bl puts
84.endm
85
86// Print an unsigned decimal number x0 to stdout
87// Clobbers x0-x4,x8
88function putdec
89 mov x1, sp
90 str x30, [sp, #-32]! // Result can't be > 20 digits
91
92 mov x2, #0
93 strb w2, [x1, #-1]! // Write the NUL terminator
94
95 mov x2, #10
960: udiv x3, x0, x2 // div-mod loop to generate the digits
97 msub x0, x3, x2, x0
98 add w0, w0, #'0'
99 strb w0, [x1, #-1]!
100 mov x0, x3
101 cbnz x3, 0b
102
103 ldrb w0, [x1]
104 cbnz w0, 1f
105 mov w0, #'0' // Print "0" for 0, not ""
106 strb w0, [x1, #-1]!
107
1081: mov x0, x1
109 bl puts
110
111 ldr x30, [sp], #32
112 ret
113endfunction
114.globl putdec
115
116// Print an unsigned decimal number x0 to stdout, followed by a newline
117// Clobbers x0-x5,x8
118function putdecn
119 mov x5, x30
120
121 bl putdec
122 mov x0, #'\n'
123 bl putc
124
125 ret x5
126endfunction
127.globl putdecn
128
129// Fill x1 bytes starting at x0 with 0.
130// Clobbers x1, x2.
131function memclr
132 mov w2, #0
133endfunction
134.globl memclr
135 // fall through to memfill
136
137// Trivial memory fill: fill x1 bytes starting at address x0 with byte w2
138// Clobbers x1
139function memfill
140 cmp x1, #0
141 b.eq 1f
142
1430: strb w2, [x0], #1
144 subs x1, x1, #1
145 b.ne 0b
146
1471: ret
148endfunction
149.globl memfill
150
151// w0: signal number
152// x1: sa_action
153// w2: sa_flags
154// Clobbers x0-x6,x8
155function setsignal
156 str x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
157
158 mov w4, w0
159 mov x5, x1
160 mov w6, w2
161
162 add x0, sp, #16
163 mov x1, #sa_sz
164 bl memclr
165
166 mov w0, w4
167 add x1, sp, #16
168 str w6, [x1, #sa_flags]
169 str x5, [x1, #sa_handler]
170 mov x2, #0
171 mov x3, #sa_mask_sz
172 mov x8, #__NR_rt_sigaction
173 svc #0
174
175 cbz w0, 1f
176
177 puts "sigaction failure\n"
178 b abort
179
1801: ldr x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
181 ret
182endfunction
183
184
185function tickle_handler
186 // Perhaps collect GCSPR_EL0 here in future?
187 ret
188endfunction
189
190function terminate_handler
191 mov w21, w0
192 mov x20, x2
193
194 puts "Terminated by signal "
195 mov w0, w21
196 bl putdec
197 puts ", no error\n"
198
199 mov x0, #0
200 mov x8, #__NR_exit
201 svc #0
202endfunction
203
204function segv_handler
205 // stash the siginfo_t *
206 mov x20, x1
207
208 // Disable GCS, we don't want additional faults logging things
209 mov x0, PR_SET_SHADOW_STACK_STATUS
210 mov x1, xzr
211 mov x2, xzr
212 mov x3, xzr
213 mov x4, xzr
214 mov x5, xzr
215 mov x8, #__NR_prctl
216 svc #0
217
218 puts "Got SIGSEGV code "
219
220 ldr x21, [x20, #si_code]
221 mov x0, x21
222 bl putdec
223
224 // GCS faults should have si_code SEGV_CPERR
225 cmp x21, #SEGV_CPERR
226 bne 1f
227
228 puts " (GCS violation)"
2291:
230 mov x0, '\n'
231 bl putc
232 b abort
233endfunction
234
235// Recurse x20 times
236.macro recurse id
237function recurse\id
238 stp x29, x30, [sp, #-16]!
239 mov x29, sp
240
241 cmp x20, 0
242 beq 1f
243 sub x20, x20, 1
244 bl recurse\id
245
2461:
247 ldp x29, x30, [sp], #16
248
249 // Do a syscall immediately prior to returning to try to provoke
250 // scheduling and migration at a point where coherency issues
251 // might trigger.
252 mov x8, #__NR_getpid
253 svc #0
254
255 ret
256endfunction
257.endm
258
259// Generate and use two copies so we're changing the GCS contents
260recurse 1
261recurse 2
262
263.globl _start
264function _start
265 // Run with GCS
266 mov x0, PR_SET_SHADOW_STACK_STATUS
267 mov x1, PR_SHADOW_STACK_ENABLE
268 mov x2, xzr
269 mov x3, xzr
270 mov x4, xzr
271 mov x5, xzr
272 mov x8, #__NR_prctl
273 svc #0
274 cbz x0, 1f
275 puts "Failed to enable GCS\n"
276 b abort
2771:
278
279 mov w0, #SIGTERM
280 adr x1, terminate_handler
281 mov w2, #SA_SIGINFO
282 bl setsignal
283
284 mov w0, #SIGUSR1
285 adr x1, tickle_handler
286 mov w2, #SA_SIGINFO
287 orr w2, w2, #SA_NODEFER
288 bl setsignal
289
290 mov w0, #SIGSEGV
291 adr x1, segv_handler
292 mov w2, #SA_SIGINFO
293 orr w2, w2, #SA_NODEFER
294 bl setsignal
295
296 puts "Running\n"
297
298loop:
299 // Small recursion depth so we're frequently flipping between
300 // the two recursors and changing what's on the stack
301 mov x20, #5
302 bl recurse1
303 mov x20, #5
304 bl recurse2
305 b loop
306endfunction
307
308abort:
309 mov x0, #255
310 mov x8, #__NR_exit
311 svc #0