xref: /linux/tools/testing/selftests/arm64/gcs/gcspushm.S (revision c771600c6af14749609b49565ffb4cac2959710d)
1*48f8d9ceSMark Brown// SPDX-License-Identifier: GPL-2.0-only
2*48f8d9ceSMark Brown//
3*48f8d9ceSMark Brown// Copyright 2024 Arm Limited
4*48f8d9ceSMark Brown//
5*48f8d9ceSMark Brown// Give ourselves GCS push permissions then use them
6*48f8d9ceSMark Brown
7*48f8d9ceSMark Brown#include <asm/unistd.h>
8*48f8d9ceSMark Brown
9*48f8d9ceSMark Brown/* Shadow Stack/Guarded Control Stack interface */
10*48f8d9ceSMark Brown#define PR_GET_SHADOW_STACK_STATUS	74
11*48f8d9ceSMark Brown#define PR_SET_SHADOW_STACK_STATUS      75
12*48f8d9ceSMark Brown#define PR_LOCK_SHADOW_STACK_STATUS     76
13*48f8d9ceSMark Brown
14*48f8d9ceSMark Brown# define PR_SHADOW_STACK_ENABLE         (1UL << 0)
15*48f8d9ceSMark Brown# define PR_SHADOW_STACK_WRITE		(1UL << 1)
16*48f8d9ceSMark Brown# define PR_SHADOW_STACK_PUSH		(1UL << 2)
17*48f8d9ceSMark Brown
18*48f8d9ceSMark Brown#define KSFT_SKIP 4
19*48f8d9ceSMark Brown
20*48f8d9ceSMark Brown.macro function name
21*48f8d9ceSMark Brown	.macro endfunction
22*48f8d9ceSMark Brown		.type \name, @function
23*48f8d9ceSMark Brown		.purgem endfunction
24*48f8d9ceSMark Brown	.endm
25*48f8d9ceSMark Brown\name:
26*48f8d9ceSMark Brown.endm
27*48f8d9ceSMark Brown
28*48f8d9ceSMark Brown// Print a single character x0 to stdout
29*48f8d9ceSMark Brown// Clobbers x0-x2,x8
30*48f8d9ceSMark Brownfunction putc
31*48f8d9ceSMark Brown	str	x0, [sp, #-16]!
32*48f8d9ceSMark Brown
33*48f8d9ceSMark Brown	mov	x0, #1			// STDOUT_FILENO
34*48f8d9ceSMark Brown	mov	x1, sp
35*48f8d9ceSMark Brown	mov	x2, #1
36*48f8d9ceSMark Brown	mov	x8, #__NR_write
37*48f8d9ceSMark Brown	svc	#0
38*48f8d9ceSMark Brown
39*48f8d9ceSMark Brown	add	sp, sp, #16
40*48f8d9ceSMark Brown	ret
41*48f8d9ceSMark Brownendfunction
42*48f8d9ceSMark Brown.globl	putc
43*48f8d9ceSMark Brown
44*48f8d9ceSMark Brown// Print a NUL-terminated string starting at address x0 to stdout
45*48f8d9ceSMark Brown// Clobbers x0-x3,x8
46*48f8d9ceSMark Brownfunction puts
47*48f8d9ceSMark Brown	mov	x1, x0
48*48f8d9ceSMark Brown
49*48f8d9ceSMark Brown	mov	x2, #0
50*48f8d9ceSMark Brown0:	ldrb	w3, [x0], #1
51*48f8d9ceSMark Brown	cbz	w3, 1f
52*48f8d9ceSMark Brown	add	x2, x2, #1
53*48f8d9ceSMark Brown	b	0b
54*48f8d9ceSMark Brown
55*48f8d9ceSMark Brown1:	mov	w0, #1			// STDOUT_FILENO
56*48f8d9ceSMark Brown	mov	x8, #__NR_write
57*48f8d9ceSMark Brown	svc	#0
58*48f8d9ceSMark Brown
59*48f8d9ceSMark Brown	ret
60*48f8d9ceSMark Brownendfunction
61*48f8d9ceSMark Brown.globl	puts
62*48f8d9ceSMark Brown
63*48f8d9ceSMark Brown// Utility macro to print a literal string
64*48f8d9ceSMark Brown// Clobbers x0-x4,x8
65*48f8d9ceSMark Brown.macro puts string
66*48f8d9ceSMark Brown	.pushsection .rodata.str1.1, "aMS", @progbits, 1
67*48f8d9ceSMark Brown.L__puts_literal\@: .string "\string"
68*48f8d9ceSMark Brown	.popsection
69*48f8d9ceSMark Brown
70*48f8d9ceSMark Brown	ldr	x0, =.L__puts_literal\@
71*48f8d9ceSMark Brown	bl	puts
72*48f8d9ceSMark Brown.endm
73*48f8d9ceSMark Brown
74*48f8d9ceSMark Brown.globl _start
75*48f8d9ceSMark Brownfunction _start
76*48f8d9ceSMark Brown	// Run with GCS
77*48f8d9ceSMark Brown	mov	x0, PR_SET_SHADOW_STACK_STATUS
78*48f8d9ceSMark Brown	mov	x1, PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH
79*48f8d9ceSMark Brown	mov	x2, xzr
80*48f8d9ceSMark Brown	mov	x3, xzr
81*48f8d9ceSMark Brown	mov	x4, xzr
82*48f8d9ceSMark Brown	mov	x5, xzr
83*48f8d9ceSMark Brown	mov	x8, #__NR_prctl
84*48f8d9ceSMark Brown	svc	#0
85*48f8d9ceSMark Brown	cbz	x0, 1f
86*48f8d9ceSMark Brown	puts	"Failed to enable GCS with push permission\n"
87*48f8d9ceSMark Brown	mov	x0, #KSFT_SKIP
88*48f8d9ceSMark Brown	b	2f
89*48f8d9ceSMark Brown1:
90*48f8d9ceSMark Brown	sys	#3, c7, c7, #0, x0	// GCSPUSHM
91*48f8d9ceSMark Brown	sysl	x0, #3, c7, c7, #1	// GCSPOPM
92*48f8d9ceSMark Brown
93*48f8d9ceSMark Brown	mov	x0, #0
94*48f8d9ceSMark Brown2:
95*48f8d9ceSMark Brown	mov	x8, #__NR_exit
96*48f8d9ceSMark Brown	svc	#0
97