Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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 */