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) 28extern "C" { 29#endif 30 31typedef 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 88static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 89cmse_TT(void *__p) { 90 cmse_address_info_t __u; 91 __u.value = __builtin_arm_cmse_TT(__p); 92 return __u; 93} 94static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 95cmse_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 102static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 103cmse_TTA(void *__p) { 104 cmse_address_info_t __u; 105 __u.value = __builtin_arm_cmse_TTA(__p); 106 return __u; 107} 108static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 109cmse_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 124static void *__attribute__((__always_inline__)) 125cmse_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 197static int __attribute__((__always_inline__, __nodebug__)) 198cmse_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 210void __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