zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

arm_cmse.h (6357B) - Raw


      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 */