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