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