1 //===---- arm_cmse.h - Arm CMSE support -----------------------------------===//
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
7 //===----------------------------------------------------------------------===//
12 #if (__ARM_FEATURE_CMSE & 0x1)
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)
24 #define cmse_check_pointed_object(p, f) \
25 cmse_check_address_range((p), sizeof(*(p)), (f))
27 #if defined(__cplusplus)
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;
39 unsigned nonsecure_readwrite_ok
: 1;
40 unsigned nonsecure_read_ok
: 1;
44 unsigned readwrite_ok
: 1;
46 #if (__ARM_CMSE_SECURE_MODE)
47 unsigned sau_region_valid
: 1;
51 unsigned mpu_region_valid
: 1;
52 #if (__ARM_CMSE_SECURE_MODE)
53 unsigned sau_region
: 8;
57 unsigned mpu_region
: 8;
59 #else /* __ARM_LITTLE_ENDIAN */
60 unsigned mpu_region
: 8;
61 #if (__ARM_CMSE_SECURE_MODE)
62 unsigned sau_region
: 8;
66 unsigned mpu_region_valid
: 1;
67 #if (__ARM_CMSE_SECURE_MODE)
68 unsigned sau_region_valid
: 1;
73 unsigned readwrite_ok
: 1;
74 #if (__ARM_CMSE_SECURE_MODE)
75 unsigned nonsecure_read_ok
: 1;
76 unsigned nonsecure_readwrite_ok
: 1;
78 unsigned idau_region_valid
: 1;
79 unsigned idau_region
: 8;
83 #endif /*__ARM_LITTLE_ENDIAN */
86 } cmse_address_info_t
;
88 static cmse_address_info_t
__attribute__((__always_inline__
, __nodebug__
))
90 cmse_address_info_t __u
;
91 __u
.value
= __builtin_arm_cmse_TT(__p
);
94 static cmse_address_info_t
__attribute__((__always_inline__
, __nodebug__
))
96 cmse_address_info_t __u
;
97 __u
.value
= __builtin_arm_cmse_TTT(__p
);
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
);
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
);
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)))
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)))
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;
130 return NULL
; /* wrap around check */
132 /* Check whether the range crosses a 32-bytes aligned address */
133 const int __single_check
= (__begin
^ __end
) < 0x20u
;
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
)) {
140 __permb
= cmse_TT(__pb
);
141 __perme
= __single_check
? __permb
: cmse_TT(__pe
);
143 case CMSE_MPU_UNPRIV
:
144 __permb
= cmse_TTT(__pb
);
145 __perme
= __single_check
? __permb
: cmse_TTT(__pe
);
147 #if __ARM_CMSE_SECURE_MODE
148 case CMSE_MPU_NONSECURE
:
149 __permb
= cmse_TTA(__pb
);
150 __perme
= __single_check
? __permb
: cmse_TTA(__pe
);
152 case CMSE_MPU_UNPRIV
| CMSE_MPU_NONSECURE
:
153 __permb
= cmse_TTAT(__pb
);
154 __perme
= __single_check
? __permb
: cmse_TTAT(__pe
);
157 /* if CMSE_NONSECURE is specified w/o __ARM_CMSE_SECURE_MODE */
162 /* check that the range does not cross MPU, SAU, or IDAU region boundaries */
163 if (__permb
.value
!= __perme
.value
)
165 #if !(__ARM_CMSE_SECURE_MODE)
166 /* CMSE_AU_NONSECURE is only supported when __ARM_FEATURE_CMSE & 0x2 */
167 if (__flags
& CMSE_AU_NONSECURE
)
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
;
178 case CMSE_MPU_READ
| CMSE_AU_NONSECURE
:
179 return __permb
.flags
.nonsecure_read_ok
? __pb
: NULL
;
181 case CMSE_AU_NONSECURE
:
182 return __permb
.flags
.secure
? NULL
: __pb
;
184 case CMSE_MPU_READ
| CMSE_MPU_READWRITE
:
185 case CMSE_MPU_READWRITE
:
186 return __permb
.flags
.readwrite_ok
? __pb
: NULL
;
189 return __permb
.flags
.read_ok
? __pb
: NULL
;
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);
202 #define cmse_nsfptr_create(p) \
203 __builtin_bit_cast(__typeof__(p), \
204 (__builtin_bit_cast(uintptr_t, p) & ~(uintptr_t)1))
206 #define cmse_is_nsfptr(p) ((__builtin_bit_cast(uintptr_t, p) & 1) == 0)
208 #endif /* __ARM_CMSE_SECURE_MODE */
210 void __attribute__((__noreturn__
)) cmse_abort(void);
211 #if defined(__cplusplus)
215 #endif /* (__ARM_FEATURE_CMSE & 0x1) */
217 #endif /* __ARM_CMSE_H */