CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Toggle main menu visibility
Loading...
Searching...
No Matches
sdk
include
compartment-macros.h
Go to the documentation of this file.
1
// Copyright Microsoft and CHERIoT Contributors.
2
// SPDX-License-Identifier: MIT
3
4
#pragma once
5
#include <
__compartment-macros.h
>
6
7
/**
8
* \file
9
*
10
* Macros for interacting with the compartmentalisation model in CHERIoT.
11
*/
12
13
/**
14
* Provide a capability of the type `volatile type *` referring to the MMIO
15
* region exported in the linker script with `name` as its name. This macro
16
* can be used only in code (it cannot be used to initialise a global).
17
*
18
* The last arguments specify the set of permissions that this capability holds:
19
*
20
* - `permitLoad` if this should have load / read (R) permission.
21
* - `permitStore` if this should have store / write (W) permission.
22
* - `permitLoadStoreCapabilities` if this should have load/store capability
23
* permission (C).
24
* - `permitLoadMutable` if this should have load-mutable (m) permission. This
25
* permission requires R and C.
26
* - `permitLoadGlobal` if this should have load-global (g) permission. This
27
* permission requires R and C.
28
*
29
* At least one out of `permitLoad` and `permitStore` should be provided.
30
*
31
* MMIO capabilities are always global (G) and without store-local (l)
32
* permission.
33
*
34
* \hideinitializer
35
*/
36
#if defined(__has_attribute) && __has_attribute(cheriot_mmio)
37
# define MMIO_CAPABILITY_WITH_PERMISSIONS(type, \
38
name, \
39
permitLoad, \
40
permitStore, \
41
permitLoadStoreCapabilities, \
42
permitLoadMutable, \
43
permitLoadGlobal) \
44
MMIO_CAPABILITY_WITH_PERMISSIONS_INNER( \
45
volatile type, \
46
name, \
47
permitLoad, \
48
permitStore, \
49
permitLoadStoreCapabilities, \
50
permitLoadMutable, \
51
permitLoadGlobal, \
52
CHERIOT_COMPARTMENT_MACROS_TOKEN_PASTE( \
53
__cheriot_mmio__, \
54
CHERIOT_COMPARTMENT_MACROS_TOKEN_PASTE(name, __COUNTER__)))
55
56
#else
57
# define MMIO_CAPABILITY_WITH_PERMISSIONS(type, \
58
name, \
59
permitLoad, \
60
permitStore, \
61
permitLoadStoreCapabilities, \
62
permitLoadMutable, \
63
permitLoadGlobal) \
64
MMIO_CAPABILITY_WITH_PERMISSIONS_HELPER( \
65
volatile type,
/* NOLINT(bugprone-macro-parentheses) */
\
66
name, \
67
"__import_mem_" #name "_" #permitLoad "_" #permitStore \
68
"_" #permitLoadStoreCapabilities "_" #permitLoadMutable \
69
"_" #permitLoadGlobal, \
70
permitLoad, \
71
permitStore, \
72
permitLoadStoreCapabilities, \
73
permitLoadMutable, \
74
permitLoadGlobal)
75
76
#endif
77
78
/**
79
* Provide a capability of the type `volatile type *` referring
80
* to the MMIO region exported in the linker script with `name`
81
* as its name. This macro can be used only in code (it cannot
82
* be used to initialise a global).
83
*
84
* MMIO capabilities produced by this macro have load and store
85
* permissions but cannot hold capabilities. For richer
86
* permissions use MMIO_CAPABILITY_WITH_PERMISSIONS.
87
*
88
* \hideinitializer
89
*/
90
#define MMIO_CAPABILITY(type, name) \
91
MMIO_CAPABILITY_WITH_PERMISSIONS( \
92
type, name, true, true, false, false, false)
93
94
/**
95
* Provide a capability of the type `type *` referring to the
96
* pre-shared object with `name` as its name. This macro can be
97
* used only in code (it cannot be used to initialise a global).
98
*
99
* The last arguments specify the set of permissions that this
100
* capability holds: Load Data (LD), Store Data (SD), Memory
101
* Capabilities (MC), Load Mutable (LM), and Load Global (LG).
102
*
103
* Capabilities to pre-shared objects are always global (G) and without
104
* store-local (l) permission.
105
*
106
* \hideinitializer
107
*/
108
#if defined(__has_attribute) && __has_attribute(cheriot_shared_object)
109
# define SHARED_OBJECT_WITH_PERMISSIONS(type, \
110
name, \
111
permitLoad, \
112
permitStore, \
113
permitLoadStoreCapabilities, \
114
permitLoadMutable, \
115
permitLoadGlobal) \
116
SHARED_OBJECT_WITH_PERMISSIONS_INNER( \
117
type, \
118
name, \
119
permitLoad, \
120
permitStore, \
121
permitLoadStoreCapabilities, \
122
permitLoadMutable, \
123
permitLoadGlobal, \
124
CHERIOT_COMPARTMENT_MACROS_TOKEN_PASTE( \
125
__cheriot_so__, \
126
CHERIOT_COMPARTMENT_MACROS_TOKEN_PASTE(name, __COUNTER__)))
127
#else
128
# define SHARED_OBJECT_WITH_PERMISSIONS(type, \
129
name, \
130
permitLoad, \
131
permitStore, \
132
permitLoadStoreCapabilities, \
133
permitLoadMutable, \
134
permitLoadGlobal) \
135
IMPORT_CAPABILITY_WITH_PERMISSIONS_HELPER( \
136
type,
/* NOLINT(bugprone-macro-parentheses) */
\
137
name, \
138
__cheriot_shared_object_, \
139
"__import_cheriot_shared_object_" #name "_" #permitLoad \
140
"_" #permitStore "_" #permitLoadStoreCapabilities \
141
"_" #permitLoadMutable "_" #permitLoadGlobal, \
142
permitLoad, \
143
permitStore, \
144
permitLoadStoreCapabilities, \
145
permitLoadMutable, \
146
permitLoadGlobal)
147
#endif
148
149
/**
150
* Provide a capability of the type `type *` referring to the
151
* pre-shared object with `name` as its name. This macro can be
152
* used only in code (it cannot be used to initialise a global).
153
*
154
* Pre-shared object capabilities produced by this macro have
155
* load, store, load-mutable, and load/store-capability
156
* permissions. To define a reduced set of permissions use
157
* `SHARED_OBJECT_WITH_PERMISSIONS`.
158
*
159
* \hideinitializer
160
*/
161
#define SHARED_OBJECT(type, name) \
162
SHARED_OBJECT_WITH_PERMISSIONS(type, name, true, true, true, true, true)
163
164
/**
165
* Provide a capability of the type `type *` referring to the
166
* pre-shared object with `name` as its name. This macro can be
167
* used only in code (it cannot be used to initialise a global).
168
*
169
* Pre-shared object capabilities produced by this macro have
170
* the indicated load and store permission, but no
171
* load/store-capability permissions (and, therefore, no
172
* load-mutable or load-global permissions).
173
*
174
* \hideinitializer
175
*/
176
#define SHARED_OBJECT_WITH_DATA_PERMISSIONS( \
177
type, name, permitLoad, permitStore) \
178
SHARED_OBJECT_WITH_PERMISSIONS( \
179
type, name, permitLoad, permitStore, false, false, false)
180
181
/**
182
* Macro to test whether a device with a specific name exists in
183
* the board definition for the current target.
184
*
185
* \hideinitializer
186
*/
187
#define DEVICE_EXISTS(x) defined(DEVICE_EXISTS_##x)
188
189
/**
190
* Macro that evaluates to a static sealing type that is local
191
* to this compartment.
192
*
193
* The `name` is a unique identifier. This matches the `keyName` passed to
194
* `DECLARE_STATIC_SEALED_VALUE` and related macros and will appear in the
195
* audit log when linking the firmware image. Names within a compartment may
196
* be unique but two compartments may expose sealing types of the same name
197
* without conflicts.
198
*
199
* \hideinitializer
200
*/
201
#if defined(__has_builtin) && __has_builtin(__builtin_cheriot_sealing_type)
202
# define STATIC_SEALING_TYPE(name) \
203
static_cast<TokenKey>( \
204
__builtin_cheriot_sealing_type(#name))
/* NOLINT */
205
#else
206
# define STATIC_SEALING_TYPE(name) \
207
CHERIOT_EMIT_STATIC_SEALING_TYPE( \
208
"sealing_type." COMPARTMENT_NAME_STRING "." #name)
209
#endif
210
211
/**
212
* Forward-declare a static sealed object. This declares an
213
* object of type `type` that can be referenced with the
214
* `STATIC_SEALED_VALUE` macro using `name`. The pointer
215
* returned by the latter macro will be sealed with the sealing
216
* key exported from `compartment` as `keyName` with the
217
* `STATIC_SEALING_TYPE` macro.
218
*
219
* The object created with this macro can be accessed only by
220
* code that has access to the sealing key.
221
*
222
* Unlike `DECLARE_STATIC_SEALED_VALUE`, this allows the type
223
* that value should be read as to be different to the type used
224
* to initialise it. The type of the value in
225
* `STATIC_SEALED_VALUE` will be `CHERI_SEALED(valueType*)`.
226
* This is useful for variable length arrays at the end of the
227
* structure.
228
*
229
* \hideinitializer
230
*/
231
#if defined(__has_attribute) && __has_attribute(cheriot_sealed) && 0
232
# define DECLARE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
233
type, valueType, compartment, keyName, name) \
234
extern valueType __sealed_type_placeholder_##name; \
235
typedef type __##name##_type \
236
__attribute__((cheriot_sealed(#compartment, #keyName))); \
237
extern __##name##_type name;
238
#else
239
# define DECLARE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
240
type, valueType, compartment, keyName, name) \
241
/* Implementation detail: This declaration in the reserved namespace \
242
* exists only so that __typeof__ can be used later to determine the \
243
* original type. This will be removed once the compiler understands \
244
* static sealed objects natively. */
\
245
extern valueType __sealed_type_placeholder_##name; \
246
_Alignas(_Alignof(type) < 8 ? 8 : _Alignof(type)) extern __if_cxx( \
247
"C") struct __##name##_type \
248
{ \
249
uint32_t key; \
250
uint32_t padding; \
251
type body; \
252
}(name); \
253
/* Make sure the type that we're casting this to is not bigger than \
254
* the value that we've emitted. */
\
255
_Static_assert(sizeof(__sealed_type_placeholder_##name) <= \
256
sizeof((name).body))
257
#endif
258
259
/**
260
* Forward-declare a static sealed object. This declares an
261
* object of type `type` that can be referenced with the
262
* `STATIC_SEALED_VALUE` macro using `name`. The pointer
263
* returned by the latter macro will be sealed with the sealing
264
* key exported from `compartment` as `keyName` with the
265
* `STATIC_SEALING_TYPE` macro.
266
*
267
* The object created with this macro can be accessed only by
268
* code that has access to the sealing key.
269
*
270
* \hideinitializer
271
*/
272
#define DECLARE_STATIC_SEALED_VALUE(type, compartment, keyName, name) \
273
DECLARE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
274
type, type, compartment, keyName, name)
275
276
/**
277
* Define a static sealed object. This creates an object of
278
* type `type`, initialised with `initialiser`, that can be
279
* referenced with the `STATIC_SEALED_VALUE` macro using `name`.
280
* The pointer returned by the latter macro will be sealed with
281
* the sealing key exported from `compartment` as `keyName` with
282
* the `STATIC_SEALING_TYPE` macro.
283
*
284
* The object created with this macro can be accessed only by
285
* code that has access to the sealing key.
286
*
287
* If you do not need a separate forward definition, use
288
* `DECLARE_AND_DEFINE_STATIC_SEALED_VALUE` instead.
289
*
290
* \hideinitializer
291
*/
292
#if defined(__has_attribute) && __has_attribute(cheriot_sealed) && 0
293
# define DEFINE_STATIC_SEALED_VALUE( \
294
type, compartment, keyName, name, initialiser, ...) \
295
__if_cxx(inline) _Alignas(_Alignof(type) < 8 ? 8 : _Alignof(type)) \
296
__##name##_type name = {initialiser, ##__VA_ARGS__}
297
#else
298
# define DEFINE_STATIC_SEALED_VALUE( \
299
type, compartment, keyName, name, initialiser, ...) \
300
extern __if_cxx("C") int \
301
__sealing_key_##compartment##_##keyName __asm( \
302
"__export.sealing_type." #compartment "." #keyName); \
303
__attribute__((section(".sealed_objects"), used)) __if_cxx( \
304
inline) _Alignas(_Alignof(type) < 8 \
305
? 8 \
306
: _Alignof(type)) struct __##name##_type \
307
name =
/* NOLINT(bugprone-macro-parentheses) */
\
308
{(uint32_t)&__sealing_key_##compartment##_##keyName, \
309
0, \
310
{initialiser, ##__VA_ARGS__}}
311
#endif
312
313
/**
314
* Helper macro that declares and defines a sealed value.
315
*
316
* Unlike `DECLARE_AND_DEFINE_STATIC_SEALED_VALUE`, this allows
317
* the type that value should be read as to be different to the
318
* type used to initialise it. The type of the value in
319
* `STATIC_SEALED_VALUE` will be `CHERI_SEALED(valueType*)`.
320
* This is useful for variable length arrays at the end of the
321
* structure.
322
*
323
* \hideinitializer
324
*/
325
#define DECLARE_AND_DEFINE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
326
type, valueType, compartment, keyName, name, initialiser, ...) \
327
DECLARE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
328
type, \
329
valueType, \
330
compartment, \
331
keyName, \
332
name);
/* NOLINT(bugprone-macro-parentheses) */
\
333
DEFINE_STATIC_SEALED_VALUE( \
334
type, \
335
compartment, \
336
keyName, \
337
name, \
338
initialiser, \
339
##__VA_ARGS__);
/* NOLINT(bugprone-macro-parentheses) */
340
341
/**
342
* Helper macro that declares and defines a sealed value.
343
*
344
* The arguments for this are the same as `DEFINE_STATIC_SEALED_VALUE`. Use
345
* this version when you do not need a separate forward declaration.
346
*
347
* \hideinitializer
348
*/
349
#define DECLARE_AND_DEFINE_STATIC_SEALED_VALUE( \
350
type, compartment, keyName, name, initialiser, ...) \
351
DECLARE_AND_DEFINE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
352
type, type, compartment, keyName, name, initialiser, ##__VA_ARGS__)
353
354
/**
355
* Returns a sealed capability to the named object created with
356
* `DECLARE_STATIC_SEALED_VALUE`.
357
*
358
* \hideinitializer
359
*/
360
#if defined(__has_attribute) && __has_attribute(cheriot_sealed) && 0
361
# define STATIC_SEALED_VALUE(name, ...) \
362
(CHERI_SEALED(__typeof__(__sealed_type_placeholder_##name) *))(&name)
363
#else
364
# define STATIC_SEALED_VALUE(name) \
365
({ \
366
CHERI_SEALED(__typeof__(__sealed_type_placeholder_##name) *) \
367
ret;
/* NOLINT(bugprone-macro-parentheses) */
\
368
__asm(".ifndef __import.sealed_object." #name "\n" \
369
" .type __import.sealed_object." #name ",@object\n" \
370
" .section .compartment_imports." #name \
371
",\"awG\",@progbits," #name "\n" \
372
" .weak __import.sealed_object." #name "\n" \
373
" .p2align 3\n" \
374
"__import.sealed_object." #name ":\n" \
375
" .word " #name "\n" \
376
" .word %c1\n" \
377
" .size __import.sealed_object." #name ", 8\n" \
378
" .previous\n" \
379
".endif\n" \
380
"1:" \
381
" auipcc %0," \
382
" " \
383
"%%cheriot_compartment_hi(__import.sealed_object." #name \
384
")\n" \
385
" clc %0, %%cheriot_compartment_lo_i(1b)(%0)\n" \
386
: "=C"(ret) \
387
: "i"(sizeof(__typeof__(name)))); \
388
ret; \
389
})
390
#endif
391
392
/**
393
* Declare a CHERIoT initialiser function. This macro can be
394
* used in place of a prototype for a function called
395
* `function`. Initialiser functions are called in ascending
396
* priority order.
397
*
398
* Initialiser functions take no arguments and return `void`.
399
*
400
* \hideinitializer
401
*/
402
#define CHERIOT_INITIALISER(function, priority) \
403
__asm(" .section .cheriot_initialiser." #priority ",\"aR\",@progbits\n" \
404
" .p2align 3\n" \
405
" .word __export_" COMPARTMENT_NAME_STRING "_" #function "\n" \
406
" .word 0\n" \
407
" .previous\n"); \
408
__if_cxx(extern "C") __cheriot_callback \
409
[[cheriot::interrupt_state(disabled)]] void \
410
function(__if_c(void))
__compartment-macros.h
Helper macros used by compartment-macros.h.
Generated by
1.18.0