clang 20.0.0git
arm_cmse.h
Go to the documentation of this file.
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)
28extern "C" {
29#endif
30
31typedef 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
88static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
89cmse_TT(void *__p) {
90 cmse_address_info_t __u;
91 __u.value = __builtin_arm_cmse_TT(__p);
92 return __u;
93}
94static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
95cmse_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
102static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
103cmse_TTA(void *__p) {
104 cmse_address_info_t __u;
105 __u.value = __builtin_arm_cmse_TTA(__p);
106 return __u;
107}
108static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
109cmse_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
124static void *__attribute__((__always_inline__))
125cmse_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
197static int __attribute__((__always_inline__, __nodebug__))
198cmse_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
210void __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 */
_Float16 __2f16 __attribute__((ext_vector_type(2)))
Zeroes the upper 128 bits (bits 255:128) of all YMM registers.
#define NULL
Definition: __stddef_null.h:26
static __inline__ uint32_t volatile uint32_t * __p
Definition: arm_acle.h:88
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...