1 //===---- arm_cmse.h - Arm CMSE support -----------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef __ARM_CMSE_H 10 #define __ARM_CMSE_H 11 12 #if (__ARM_FEATURE_CMSE & 0x1) 13 #include <stddef.h> 14 #include <stdint.h> 15 16 #define __ARM_CMSE_SECURE_MODE (__ARM_FEATURE_CMSE & 0x2) 17 #define CMSE_MPU_READWRITE 1 /* checks if readwrite_ok field is set */ 18 #define CMSE_AU_NONSECURE 2 /* checks if permissions have secure field unset */ 19 #define CMSE_MPU_UNPRIV 4 /* sets T flag on TT insrtuction */ 20 #define CMSE_MPU_READ 8 /* checks if read_ok field is set */ 21 #define CMSE_MPU_NONSECURE 16 /* sets A flag, checks if secure field unset */ 22 #define CMSE_NONSECURE (CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE) 23 24 #define cmse_check_pointed_object(p, f) \ 25 cmse_check_address_range((p), sizeof(*(p)), (f)) 26 27 #if defined(__cplusplus) 28 extern "C" { 29 #endif 30 31 typedef union { 32 struct cmse_address_info { 33 #ifdef __ARM_BIG_ENDIAN 34 /* __ARM_BIG_ENDIAN */ 35 #if (__ARM_CMSE_SECURE_MODE) 36 unsigned idau_region : 8; 37 unsigned idau_region_valid : 1; 38 unsigned secure : 1; 39 unsigned nonsecure_readwrite_ok : 1; 40 unsigned nonsecure_read_ok : 1; 41 #else 42 unsigned : 12; 43 #endif 44 unsigned readwrite_ok : 1; 45 unsigned read_ok : 1; 46 #if (__ARM_CMSE_SECURE_MODE) 47 unsigned sau_region_valid : 1; 48 #else 49 unsigned : 1; 50 #endif 51 unsigned mpu_region_valid : 1; 52 #if (__ARM_CMSE_SECURE_MODE) 53 unsigned sau_region : 8; 54 #else 55 unsigned : 8; 56 #endif 57 unsigned mpu_region : 8; 58 59 #else /* __ARM_LITTLE_ENDIAN */ 60 unsigned mpu_region : 8; 61 #if (__ARM_CMSE_SECURE_MODE) 62 unsigned sau_region : 8; 63 #else 64 unsigned : 8; 65 #endif 66 unsigned mpu_region_valid : 1; 67 #if (__ARM_CMSE_SECURE_MODE) 68 unsigned sau_region_valid : 1; 69 #else 70 unsigned : 1; 71 #endif 72 unsigned read_ok : 1; 73 unsigned readwrite_ok : 1; 74 #if (__ARM_CMSE_SECURE_MODE) 75 unsigned nonsecure_read_ok : 1; 76 unsigned nonsecure_readwrite_ok : 1; 77 unsigned secure : 1; 78 unsigned idau_region_valid : 1; 79 unsigned idau_region : 8; 80 #else 81 unsigned : 12; 82 #endif 83 #endif /*__ARM_LITTLE_ENDIAN */ 84 } flags; 85 unsigned value; 86 } cmse_address_info_t; 87 88 static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 89 cmse_TT(void *__p) { 90 cmse_address_info_t __u; 91 __u.value = __builtin_arm_cmse_TT(__p); 92 return __u; 93 } 94 static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 95 cmse_TTT(void *__p) { 96 cmse_address_info_t __u; 97 __u.value = __builtin_arm_cmse_TTT(__p); 98 return __u; 99 } 100 101 #if __ARM_CMSE_SECURE_MODE 102 static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 103 cmse_TTA(void *__p) { 104 cmse_address_info_t __u; 105 __u.value = __builtin_arm_cmse_TTA(__p); 106 return __u; 107 } 108 static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 109 cmse_TTAT(void *__p) { 110 cmse_address_info_t __u; 111 __u.value = __builtin_arm_cmse_TTAT(__p); 112 return __u; 113 } 114 #endif 115 116 #define cmse_TT_fptr(p) cmse_TT(__builtin_bit_cast(void *, (p))) 117 #define cmse_TTT_fptr(p) cmse_TTT(__builtin_bit_cast(void *, (p))) 118 119 #if __ARM_CMSE_SECURE_MODE 120 #define cmse_TTA_fptr(p) cmse_TTA(__builtin_bit_cast(void *, (p))) 121 #define cmse_TTAT_fptr(p) cmse_TTAT(__builtin_bit_cast(void *, (p))) 122 #endif 123 124 static void *__attribute__((__always_inline__)) 125 cmse_check_address_range(void *__pb, size_t __s, int __flags) { 126 uintptr_t __begin = (uintptr_t)__pb; 127 uintptr_t __end = __begin + __s - 1; 128 129 if (__end < __begin) 130 return NULL; /* wrap around check */ 131 132 /* Check whether the range crosses a 32-bytes aligned address */ 133 const int __single_check = (__begin ^ __end) < 0x20u; 134 135 /* execute the right variant of the TT instructions */ 136 void *__pe = (void *)__end; 137 cmse_address_info_t __permb, __perme; 138 switch (__flags & (CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) { 139 case 0: 140 __permb = cmse_TT(__pb); 141 __perme = __single_check ? __permb : cmse_TT(__pe); 142 break; 143 case CMSE_MPU_UNPRIV: 144 __permb = cmse_TTT(__pb); 145 __perme = __single_check ? __permb : cmse_TTT(__pe); 146 break; 147 #if __ARM_CMSE_SECURE_MODE 148 case CMSE_MPU_NONSECURE: 149 __permb = cmse_TTA(__pb); 150 __perme = __single_check ? __permb : cmse_TTA(__pe); 151 break; 152 case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE: 153 __permb = cmse_TTAT(__pb); 154 __perme = __single_check ? __permb : cmse_TTAT(__pe); 155 break; 156 #endif 157 /* if CMSE_NONSECURE is specified w/o __ARM_CMSE_SECURE_MODE */ 158 default: 159 return NULL; 160 } 161 162 /* check that the range does not cross MPU, SAU, or IDAU region boundaries */ 163 if (__permb.value != __perme.value) 164 return NULL; 165 #if !(__ARM_CMSE_SECURE_MODE) 166 /* CMSE_AU_NONSECURE is only supported when __ARM_FEATURE_CMSE & 0x2 */ 167 if (__flags & CMSE_AU_NONSECURE) 168 return NULL; 169 #endif 170 171 /* check the permission on the range */ 172 switch (__flags & ~(CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) { 173 #if (__ARM_CMSE_SECURE_MODE) 174 case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE: 175 case CMSE_MPU_READWRITE | CMSE_AU_NONSECURE: 176 return __permb.flags.nonsecure_readwrite_ok ? __pb : NULL; 177 178 case CMSE_MPU_READ | CMSE_AU_NONSECURE: 179 return __permb.flags.nonsecure_read_ok ? __pb : NULL; 180 181 case CMSE_AU_NONSECURE: 182 return __permb.flags.secure ? NULL : __pb; 183 #endif 184 case CMSE_MPU_READ | CMSE_MPU_READWRITE: 185 case CMSE_MPU_READWRITE: 186 return __permb.flags.readwrite_ok ? __pb : NULL; 187 188 case CMSE_MPU_READ: 189 return __permb.flags.read_ok ? __pb : NULL; 190 191 default: 192 return NULL; 193 } 194 } 195 196 #if __ARM_CMSE_SECURE_MODE 197 static int __attribute__((__always_inline__, __nodebug__)) 198 cmse_nonsecure_caller(void) { 199 return !((uintptr_t)__builtin_return_address(0) & 1); 200 } 201 202 #define cmse_nsfptr_create(p) \ 203 __builtin_bit_cast(__typeof__(p), \ 204 (__builtin_bit_cast(uintptr_t, p) & ~(uintptr_t)1)) 205 206 #define cmse_is_nsfptr(p) ((__builtin_bit_cast(uintptr_t, p) & 1) == 0) 207 208 #endif /* __ARM_CMSE_SECURE_MODE */ 209 210 void __attribute__((__noreturn__)) cmse_abort(void); 211 #if defined(__cplusplus) 212 } 213 #endif 214 215 #endif /* (__ARM_FEATURE_CMSE & 0x1) */ 216 217 #endif /* __ARM_CMSE_H */ 218