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 312