| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| /* | |
| * Copyright (C) 2023 ARM Limited. | |
| */ | |
| #ifndef GCS_UTIL_H | |
| #define GCS_UTIL_H | |
| #include <stdbool.h> | |
| #ifndef __NR_map_shadow_stack | |
| #define __NR_map_shadow_stack 453 | |
| #endif | |
| #ifndef __NR_prctl | |
| #define __NR_prctl 167 | |
| #endif | |
| #ifndef NT_ARM_GCS | |
| #define NT_ARM_GCS 0x410 | |
| #endif | |
| /* Shadow Stack/Guarded Control Stack interface */ | |
| #define PR_GET_SHADOW_STACK_STATUS 74 | |
| #define PR_SET_SHADOW_STACK_STATUS 75 | |
| #define PR_LOCK_SHADOW_STACK_STATUS 76 | |
| # define PR_SHADOW_STACK_ENABLE (1UL << 0) | |
| # define PR_SHADOW_STACK_WRITE (1UL << 1) | |
| # define PR_SHADOW_STACK_PUSH (1UL << 2) | |
| #define PR_SHADOW_STACK_ALL_MODES \ | |
| PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE | PR_SHADOW_STACK_PUSH | |
| #define SHADOW_STACK_SET_TOKEN (1ULL << 0) /* Set up a restore token in the shadow stack */ | |
| #define SHADOW_STACK_SET_MARKER (1ULL << 1) /* Set up a top of stack merker in the shadow stack */ | |
| #define GCS_CAP_ADDR_MASK (0xfffffffffffff000UL) | |
| #define GCS_CAP_TOKEN_MASK (0x0000000000000fffUL) | |
| #define GCS_CAP_VALID_TOKEN 1 | |
| #define GCS_CAP_IN_PROGRESS_TOKEN 5 | |
| #define GCS_CAP(x) (((unsigned long)(x) & GCS_CAP_ADDR_MASK) | \ | |
| GCS_CAP_VALID_TOKEN) | |
| /* | |
| * prctl(..., arg1, arg2) with unused registers forced to zero. The | |
| * kernel rejects non-zero unused args; libc may leave garbage there. | |
| */ | |
| #define my_syscall2(num, arg1, arg2) \ | |
| ({ \ | |
| register long _num __asm__ ("x8") = (num); \ | |
| register long _arg1 __asm__ ("x0") = (long)(arg1); \ | |
| register long _arg2 __asm__ ("x1") = (long)(arg2); \ | |
| register long _arg3 __asm__ ("x2") = 0; \ | |
| register long _arg4 __asm__ ("x3") = 0; \ | |
| register long _arg5 __asm__ ("x4") = 0; \ | |
| \ | |
| __asm__ volatile ( \ | |
| "svc #0\n" \ | |
| : "=r"(_arg1) \ | |
| : "r"(_arg1), "r"(_arg2), \ | |
| "r"(_arg3), "r"(_arg4), \ | |
| "r"(_arg5), "r"(_num) \ | |
| : "memory", "cc" \ | |
| ); \ | |
| _arg1; \ | |
| }) | |
| static inline unsigned long *get_gcspr(void) | |
| { | |
| unsigned long *gcspr; | |
| asm volatile( | |
| "mrs %0, S3_3_C2_C5_1" | |
| : "=r" (gcspr) | |
| : | |
| : "cc"); | |
| return gcspr; | |
| } | |
| static inline void __attribute__((always_inline)) gcsss1(unsigned long *Xt) | |
| { | |
| asm volatile ( | |
| "sys #3, C7, C7, #2, %0\n" | |
| : | |
| : "rZ" (Xt) | |
| : "memory"); | |
| } | |
| static inline unsigned long __attribute__((always_inline)) *gcsss2(void) | |
| { | |
| unsigned long *Xt; | |
| asm volatile( | |
| "SYSL %0, #3, C7, C7, #3\n" | |
| : "=r" (Xt) | |
| : | |
| : "memory"); | |
| return Xt; | |
| } | |
| static inline bool chkfeat_gcs(void) | |
| { | |
| register long val __asm__ ("x16") = 1; | |
| /* CHKFEAT x16 */ | |
| asm volatile( | |
| "hint #0x28\n" | |
| : "=r" (val) | |
| : "r" (val)); | |
| return val != 1; | |
| } | |
| #endif |