CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Loading...
Searching...
No Matches
__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 <__cheri_sealed.h>
6#include <cdefs.h>
7#include <stdbool.h>
8
9/**
10 * \file
11 *
12 * Helper macros used by compartment-macros.h.
13 *
14 * Do not use any of the macros in this file directly.
15 *
16 * These are separated to make the documentation of compartment-macros.h
17 * cleaner.
18 */
19
20/**
21 * \internal
22 *
23 * Helper macro for MMIO and pre-shared object imports, should not be used
24 * directly.
25 */
26#define IMPORT_CAPABILITY_WITH_PERMISSIONS_HELPER(type, \
27 name, \
28 prefix, \
29 mangledName, \
30 permitLoad, \
31 permitStore, \
32 permitLoadStoreCapabilities, \
33 permitLoadMutable, \
34 permitLoadGlobal) \
35 ({ \
36 type *ret; /* NOLINT(bugprone-macro-parentheses) */ \
37 __asm(".ifndef " mangledName "\n" \
38 " .type " mangledName ",@object\n" \
39 " .section .compartment_imports." #name \
40 ",\"awG\",@progbits," mangledName ",comdat\n" \
41 " .globl " mangledName "\n" \
42 " .p2align 3\n" mangledName ":\n" \
43 " .word " #prefix #name "\n" \
44 " .word " #prefix #name "_end - " #prefix #name " + %c1\n" \
45 " .size " mangledName ", 8\n" \
46 " .previous\n" \
47 ".endif\n" \
48 "1:" \
49 " auipcc %0," \
50 " %%cheriot_compartment_hi(" mangledName ")\n" \
51 " clc %0, %%cheriot_compartment_lo_i(1b)(%0)\n" \
52 : "=C"(ret) \
53 : "i"(((permitLoad) ? (1 << 31) : 0) + \
54 ((permitStore) ? (1 << 30) : 0) + \
55 ((permitLoadStoreCapabilities) ? (1 << 29) : 0) + \
56 ((permitLoadMutable) ? (1 << 28) : 0) + \
57 ((permitLoadGlobal) ? (1 << 27) : 0))); \
58 ret; \
59 })
60
61// NOLINTBEGIN
62#define CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG_true(flag) flag
63#define CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG_1(flag) flag
64#define CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG_false(flag) ""
65#define CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG_0(flag) ""
66
67#define CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG(cond, flag) \
68 CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG_##cond(flag)
69// NOLINTEND
70
71#define CHERIOT_COMPARTMENT_MACROS_JOIN_FLAGS(pL, pS, pC, pM, pG) \
72 CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG(pL, "R") \
73 CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG(pS, "W") \
74 CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG(pC, "c") \
75 CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG(pM, "m") \
76 CHERIOT_COMPARTMENT_MACROS_PERMIT_FLAG(pG, "g")
77
78#define CHERIOT_COMPARTMENT_MACROS_TOKEN_PASTE_INNER(x, y) x##y
79#define CHERIOT_COMPARTMENT_MACROS_TOKEN_PASTE(x, y) \
80 CHERIOT_COMPARTMENT_MACROS_TOKEN_PASTE_INNER(x, y)
81
82#if defined(__has_attribute) && __has_attribute(cheriot_mmio)
83/**
84 * \internal
85 *
86 * Helper for `MMIO_CAPABILITY_WITH_PERMISSIONS_` that forces evaluation of the
87 * `__COUNTER__` macro.
88 */
89# define MMIO_CAPABILITY_WITH_PERMISSIONS_INNER( \
90 type, \
91 name, \
92 permitLoad, \
93 permitStore, \
94 permitLoadStoreCapabilities, \
95 permitLoadMutable, \
96 permitLoadGlobal, \
97 cValue) \
98 ({ \
99 /* NOLINTBEGIN(bugprone-macro-parentheses) */ \
100 _Static_assert(permitLoad || permitStore, \
101 "Importing an MMIO capability with no permissions " \
102 "is not allowed."); \
103 _Pragma("GCC diagnostic push") \
104 _Pragma("GCC diagnostic ignored \"-Wundefined-internal\"") \
105 __attribute__((cheri_no_subobject_bounds)) \
106 __attribute__((cheriot_mmio( \
107 #name, \
108 CHERIOT_COMPARTMENT_MACROS_JOIN_FLAGS( \
109 permitLoad, \
110 permitStore, \
111 permitLoadStoreCapabilities, \
112 permitLoadMutable, \
113 permitLoadGlobal)))) volatile extern char cValue; \
114 (type *)&cValue; \
115 _Pragma("GCC diagnostic pop") \
116 /* NOLINTEND(bugprone-macro-parentheses) */ \
117 })
118#else
119/**
120 * \internal
121 *
122 * Helper macro, should not be used directly.
123 */
124# define MMIO_CAPABILITY_WITH_PERMISSIONS_HELPER( \
125 type, \
126 name, \
127 mangledName, \
128 permitLoad, \
129 permitStore, \
130 permitLoadStoreCapabilities, \
131 permitLoadMutable, \
132 permitLoadGlobal) \
133 IMPORT_CAPABILITY_WITH_PERMISSIONS_HELPER(type, \
134 name, \
135 __export_mem_, \
136 mangledName, \
137 permitLoad, \
138 permitStore, \
139 permitLoadStoreCapabilities, \
140 permitLoadMutable, \
141 permitLoadGlobal)
142
143#endif
144
145#if defined(__has_attribute) && __has_attribute(cheriot_shared_object)
146/**
147 * \internal
148 *
149 * Helper for implementing `SHARED_OBJECT_WITH_PERMISSIONS`, expanding the
150 * definition of `__COUNTER__`, passed as the final macro parameter.
151 */
152# define SHARED_OBJECT_WITH_PERMISSIONS_INNER(type, \
153 name, \
154 permitLoad, \
155 permitStore, \
156 permitLoadStoreCapabilities, \
157 permitLoadMutable, \
158 permitLoadGlobal, \
159 cValue) \
160 ({ \
161 /* NOLINTBEGIN(bugprone-macro-parentheses) */ \
162 _Static_assert( \
163 permitLoad || permitStore, \
164 "Importing a shared object capability with no permissions " \
165 "is not allowed."); \
166 _Pragma("GCC diagnostic push") \
167 _Pragma("GCC diagnostic ignored \"-Wundefined-internal\"") \
168 __attribute__((cheri_no_subobject_bounds)) \
169 __attribute__((cheriot_shared_object( \
170 #name, \
171 CHERIOT_COMPARTMENT_MACROS_JOIN_FLAGS( \
172 permitLoad, \
173 permitStore, \
174 permitLoadStoreCapabilities, \
175 permitLoadMutable, \
176 permitLoadGlobal)))) extern char cValue; \
177 (type *)&cValue; \
178 _Pragma("GCC diagnostic pop") \
179 /* NOLINTEND(bugprone-macro-parentheses) */ \
180 })
181#endif
182
183/**
184 * \internal
185 *
186 * Helper macro, used by `STATIC_SEALING_TYPE`. Do not use this
187 * directly, it exists to avoid error-prone copying and pasting
188 * of the mangled name for a static sealing type.
189 */
190#define CHERIOT_EMIT_STATIC_SEALING_TYPE(name) \
191 ({ \
192 TokenKey ret; /* NOLINT(bugprone-macro-parentheses) */ \
193 __asm( \
194 ".ifndef __import." name "\n" \
195 " .type __import." name ",@object\n" \
196 " .section .compartment_imports." name ",\"awG\",@progbits," name \
197 ",comdat\n" \
198 " .globl __import." name "\n" \
199 " .p2align 3\n" \
200 "__import." name ":\n" \
201 " .word __export." name "\n" \
202 " .word 0\n" \
203 " .previous\n" \
204 ".endif\n" \
205 ".ifndef __export." name "\n" \
206 " .type __export." name ",@object\n" \
207 " .section .compartment_exports." name ",\"awG\",@progbits," name \
208 ",comdat\n" \
209 " .globl __export." name "\n" \
210 " .p2align 2\n" \
211 "__export." name ":\n" \
212 " .half 0\n" /* function start and stack size initialised to 0 */ \
213 " .byte 0\n" \
214 " .byte 0b100000\n" /* Set the flag that indicates that this is a \
215 sealing key. */ \
216 " .size __export." name ", 4\n" \
217 " .previous\n" \
218 ".endif\n" \
219 "1:\n" \
220 " auipcc %0, %%cheriot_compartment_hi(__import." name ")\n" \
221 " clc %0, %%cheriot_compartment_lo_i(1b)(%0)\n" \
222 : "=C"(ret)); \
223 ret; \
224 })
225
226/**
227 * \internal
228 *
229 * Helper macro that evaluates to the compartment of the current
230 * compilation unit, as a string.
231 */
232#define COMPARTMENT_NAME_STRING __XSTRING(__CHERI_COMPARTMENT__)