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) && \
232
__CHERIOT__ >= 20260806
233
# define DECLARE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
234
type, valueType, compartment, keyName, name) \
235
extern valueType __sealed_type_placeholder_##name; \
236
typedef type __##name##_type; \
237
extern __##name##_type \
238
__attribute__((cheriot_sealed(#compartment, #keyName))) (name);
239
#else
240
# define DECLARE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
241
type, valueType, compartment, keyName, name) \
242
/* Implementation detail: This declaration in the reserved namespace \
243
* exists only so that __typeof__ can be used later to determine the \
244
* original type. This will be removed once the compiler understands \
245
* static sealed objects natively. */
\
246
extern valueType __sealed_type_placeholder_##name; \
247
_Alignas(_Alignof(type) < 8 ? 8 : _Alignof(type)) extern __if_cxx( \
248
"C") struct __##name##_type \
249
{ \
250
uint32_t key; \
251
uint32_t padding; \
252
type body; \
253
}(name); \
254
/* Make sure the type that we're casting this to is not bigger than \
255
* the value that we've emitted. */
\
256
_Static_assert(sizeof(__sealed_type_placeholder_##name) <= \
257
sizeof((name).body))
258
#endif
259
260
/**
261
* Forward-declare a static sealed object. This declares an
262
* object of type `type` that can be referenced with the
263
* `STATIC_SEALED_VALUE` macro using `name`. The pointer
264
* returned by the latter macro will be sealed with the sealing
265
* key exported from `compartment` as `keyName` with the
266
* `STATIC_SEALING_TYPE` macro.
267
*
268
* The object created with this macro can be accessed only by
269
* code that has access to the sealing key.
270
*
271
* \hideinitializer
272
*/
273
#define DECLARE_STATIC_SEALED_VALUE(type, compartment, keyName, name) \
274
DECLARE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
275
type, type, compartment, keyName, name)
276
277
/**
278
* Define a static sealed object. This creates an object of
279
* type `type`, initialised with `initialiser`, that can be
280
* referenced with the `STATIC_SEALED_VALUE` macro using `name`.
281
* The pointer returned by the latter macro will be sealed with
282
* the sealing key exported from `compartment` as `keyName` with
283
* the `STATIC_SEALING_TYPE` macro.
284
*
285
* The object created with this macro can be accessed only by
286
* code that has access to the sealing key.
287
*
288
* If you do not need a separate forward definition, use
289
* `DECLARE_AND_DEFINE_STATIC_SEALED_VALUE` instead.
290
*
291
* \hideinitializer
292
*/
293
#if defined(__has_attribute) && __has_attribute(cheriot_sealed) && \
294
__CHERIOT__ >= 20260806
295
# define DEFINE_STATIC_SEALED_VALUE( \
296
type, compartment, keyName, name, initialiser, ...) \
297
__if_cxx(inline) _Alignas(_Alignof(type) < 8 ? 8 : _Alignof(type)) \
298
__##name##_type name = {initialiser, ##__VA_ARGS__}
299
#else
300
# define DEFINE_STATIC_SEALED_VALUE( \
301
type, compartment, keyName, name, initialiser, ...) \
302
extern __if_cxx("C") int \
303
__sealing_key_##compartment##_##keyName __asm( \
304
"__export.sealing_type." #compartment "." #keyName); \
305
__attribute__((section(".sealed_objects"), used)) __if_cxx( \
306
inline) _Alignas(_Alignof(type) < 8 \
307
? 8 \
308
: _Alignof(type)) struct __##name##_type \
309
name =
/* NOLINT(bugprone-macro-parentheses) */
\
310
{(uint32_t)&__sealing_key_##compartment##_##keyName, \
311
0, \
312
{initialiser, ##__VA_ARGS__}}
313
#endif
314
315
/**
316
* Helper macro that declares and defines a sealed value.
317
*
318
* Unlike `DECLARE_AND_DEFINE_STATIC_SEALED_VALUE`, this allows
319
* the type that value should be read as to be different to the
320
* type used to initialise it. The type of the value in
321
* `STATIC_SEALED_VALUE` will be `CHERI_SEALED(valueType*)`.
322
* This is useful for variable length arrays at the end of the
323
* structure.
324
*
325
* \hideinitializer
326
*/
327
#define DECLARE_AND_DEFINE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
328
type, valueType, compartment, keyName, name, initialiser, ...) \
329
/* NOLINTBEGIN(bugprone-macro-parentheses) */
\
330
DECLARE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
331
type, valueType, compartment, keyName, name); \
332
DEFINE_STATIC_SEALED_VALUE( \
333
type, compartment, keyName, name, initialiser, ##__VA_ARGS__); \
334
/* NOLINTEND(bugprone-macro-parentheses) */
335
336
/**
337
* Helper macro that declares and defines a sealed value.
338
*
339
* The arguments for this are the same as `DEFINE_STATIC_SEALED_VALUE`. Use
340
* this version when you do not need a separate forward declaration.
341
*
342
* \hideinitializer
343
*/
344
#define DECLARE_AND_DEFINE_STATIC_SEALED_VALUE( \
345
type, compartment, keyName, name, initialiser, ...) \
346
DECLARE_AND_DEFINE_STATIC_SEALED_VALUE_EXPLICIT_TYPE( \
347
type, type, compartment, keyName, name, initialiser, ##__VA_ARGS__)
348
349
/**
350
* Returns a sealed capability to the named object created with
351
* `DECLARE_STATIC_SEALED_VALUE`.
352
*
353
* \hideinitializer
354
*/
355
#if defined(__has_attribute) && __has_attribute(cheriot_sealed) && \
356
__CHERIOT__ >= 20260806
357
# define STATIC_SEALED_VALUE(name, ...) \
358
(CHERI_SEALED(__typeof__(__sealed_type_placeholder_##name) *))(&name)
359
#else
360
# define STATIC_SEALED_VALUE(name) \
361
({ \
362
CHERI_SEALED(__typeof__(__sealed_type_placeholder_##name) *) \
363
ret;
/* NOLINT(bugprone-macro-parentheses) */
\
364
__asm(".ifndef __import.sealed_object." #name "\n" \
365
" .type __import.sealed_object." #name ",@object\n" \
366
" .section .compartment_imports." #name \
367
",\"awG\",@progbits," #name "\n" \
368
" .weak __import.sealed_object." #name "\n" \
369
" .p2align 3\n" \
370
"__import.sealed_object." #name ":\n" \
371
" .word " #name "\n" \
372
" .word %c1\n" \
373
" .size __import.sealed_object." #name ", 8\n" \
374
" .previous\n" \
375
".endif\n" \
376
"1:" \
377
" auipcc %0," \
378
" " \
379
"%%cheriot_compartment_hi(__import.sealed_object." #name \
380
")\n" \
381
" clc %0, %%cheriot_compartment_lo_i(1b)(%0)\n" \
382
: "=C"(ret) \
383
: "i"(sizeof(__typeof__(name)))); \
384
ret; \
385
})
386
#endif
387
388
/**
389
* Declare a CHERIoT initialiser function. This macro can be
390
* used in place of a prototype for a function called
391
* `function`. Initialiser functions are called in ascending
392
* priority order.
393
*
394
* Initialiser functions take no arguments and return `void`.
395
*
396
* \hideinitializer
397
*/
398
#define CHERIOT_INITIALISER(function, priority) \
399
__asm(" .section .cheriot_initialiser." #priority ",\"aR\",@progbits\n" \
400
" .p2align 3\n" \
401
" .word __export_" COMPARTMENT_NAME_STRING "_" #function "\n" \
402
" .word 0\n" \
403
" .previous\n"); \
404
__if_cxx(extern "C") __cheriot_callback \
405
[[cheriot::interrupt_state(disabled)]] void \
406
function(__if_c(void))
__compartment-macros.h
Helper macros used by compartment-macros.h.
Generated by
1.18.0