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