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