1 /*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #pragma once
8
9 #include <config.h>
10 #include <assert.h>
11 #include <util.h>
12 #include <sel4/macros.h>
13 #include <api/types.h>
14 #include <arch/types.h>
15 #include <arch/object/structures_gen.h>
16 #include <arch/machine/hardware.h>
17 #include <arch/machine/registerset.h>
18
19 typedef struct arch_tcb {
20 /* saved user-level context of thread (72 bytes) */
21 user_context_t tcbContext;
22 #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
23 /* Pointer to associated VCPU. NULL if not associated.
24 * tcb->tcbVCPU->vcpuTCB == tcb. */
25 struct vcpu *tcbVCPU;
26 #endif
27 } arch_tcb_t;
28
29 enum vm_rights {
30 VMNoAccess = 0,
31 VMKernelOnly = 1,
32 VMReadOnly = 2,
33 VMReadWrite = 3
34 };
35 typedef word_t vm_rights_t;
36
37 typedef pde_t vspace_root_t;
38
39 #define seL4_PGDEntryBits 3
40 #define seL4_PGDIndexBits 2
41 #define seL4_PGDBits 5
42
43 #define PGDE_SIZE_BITS seL4_PGDEntryBits
44 #define PDE_SIZE_BITS seL4_PageDirEntryBits
45 #define PTE_SIZE_BITS seL4_PageTableEntryBits
46 #define PGD_INDEX_BITS seL4_PGDIndexBits
47 #define PD_INDEX_BITS seL4_PageDirIndexBits
48 #define PT_INDEX_BITS seL4_PageTableIndexBits
49 #define VCPU_SIZE_BITS seL4_VCPUBits
50
51 /* Generate a vcpu_t pointer from a vcpu block reference */
52 #define VCPU_PTR(r) ((struct vcpu *)(r))
53 #define VCPU_REF(p) ((unsigned int)(p))
54
55 #define PDE_PTR(r) ((pde_t *)(r))
56 #define PDE_REF(p) ((unsigned int)p)
57
58 #define PDE_PTR_PTR(r) ((pde_t **)r)
59
60 #define PD_PTR(r) ((pde_t *)(r))
61 #define PD_REF(p) ((unsigned int)p)
62
63 /* Page directory entries (PDEs) */
64 enum pde_type {
65 PDEInvalid = 0,
66 PDECoarse = 1,
67 PDEMapping = 2
68 };
69 typedef word_t pde_type_t;
70
71 #define PTE_PTR(r) ((pte_t *)r)
72 #define PTE_REF(p) ((unsigned int)p)
73
74 #define PT_PTR(r) ((pte_t *)r)
75 #define PT_REF(p) ((unsigned int)p)
76
77 /* LPAE */
78 #define PGD_SIZE_BITS seL4_PGDBits
79 #define LPAE_PGDE_PTR(r) ((lpae_pde_t *)(r))
80 #define LPAE_PGDE_REF(p) ((unsigned int)p)
81 #define LPAE_PGDE_PTR_PTR(r) ((lpae_pde_t **)r)
82 #define LPAE_PGD_PTR(r) ((lpae_pde_t *)(r))
83 #define LPAE_PGD_REF(p) ((unsigned int)p)
84
85 #define LPAE_PTE_PTR(r) ((lpae_pte_t *)r)
86 #define LPAE_PTE_REF(p) ((unsigned int)p)
87
88 #define LPAE_PT_PTR(r) ((lpae_pte_t *)r)
89 #define LPAE_PT_REF(p) ((unsigned int)p)
90
91 struct asid_pool {
92 pde_t *array[BIT(asidLowBits)];
93 };
94
95 typedef struct asid_pool asid_pool_t;
96
97 #define ASID_POOL_PTR(r) ((asid_pool_t *)r)
98 #define ASID_POOL_REF(p) ((unsigned int)p)
99
100 #define HW_ASID_SIZE_BITS 1
101
102 #define ASID_POOL_INDEX_BITS seL4_ASIDPoolIndexBits
103 #define ASID_BITS (asidHighBits+asidLowBits)
104
105 #define nASIDPools BIT(asidHighBits)
106
107 #define ASID_LOW(a) (a & MASK(asidLowBits))
108 #define ASID_HIGH(a) ((a >> asidLowBits) & MASK(asidHighBits))
109
cap_small_frame_cap_set_capFMappedASID(cap_t cap,word_t asid)110 static inline cap_t CONST cap_small_frame_cap_set_capFMappedASID(cap_t cap, word_t asid)
111 {
112 cap = cap_small_frame_cap_set_capFMappedASIDLow(cap,
113 asid & MASK(asidLowBits));
114 return cap_small_frame_cap_set_capFMappedASIDHigh(cap,
115 (asid >> asidLowBits) & MASK(asidHighBits));
116 }
117
cap_small_frame_cap_get_capFMappedASID(cap_t cap)118 static inline word_t CONST cap_small_frame_cap_get_capFMappedASID(cap_t cap)
119 {
120 return (cap_small_frame_cap_get_capFMappedASIDHigh(cap) << asidLowBits) +
121 cap_small_frame_cap_get_capFMappedASIDLow(cap);
122 }
123
cap_frame_cap_set_capFMappedASID(cap_t cap,word_t asid)124 static inline cap_t CONST cap_frame_cap_set_capFMappedASID(cap_t cap, word_t asid)
125 {
126 cap = cap_frame_cap_set_capFMappedASIDLow(cap,
127 asid & MASK(asidLowBits));
128 return cap_frame_cap_set_capFMappedASIDHigh(cap,
129 (asid >> asidLowBits) & MASK(asidHighBits));
130 }
131
cap_frame_cap_get_capFMappedASID(cap_t cap)132 static inline word_t CONST cap_frame_cap_get_capFMappedASID(cap_t cap)
133 {
134 return (cap_frame_cap_get_capFMappedASIDHigh(cap) << asidLowBits) +
135 cap_frame_cap_get_capFMappedASIDLow(cap);
136 }
137
generic_frame_cap_get_capFMappedASID(cap_t cap)138 static inline word_t CONST generic_frame_cap_get_capFMappedASID(cap_t cap)
139 {
140 cap_tag_t ctag;
141
142 ctag = cap_get_capType(cap);
143
144 assert(ctag == cap_small_frame_cap ||
145 ctag == cap_frame_cap);
146
147 if (ctag == cap_small_frame_cap) {
148 return cap_small_frame_cap_get_capFMappedASID(cap);
149 } else {
150 return cap_frame_cap_get_capFMappedASID(cap);
151 }
152 }
153
generic_frame_cap_set_capFMappedAddress(cap_t cap,word_t asid,word_t addr)154 static inline cap_t CONST generic_frame_cap_set_capFMappedAddress(cap_t cap, word_t asid, word_t addr)
155 {
156 cap_tag_t ctag;
157
158 ctag = cap_get_capType(cap);
159 assert(ctag == cap_small_frame_cap ||
160 ctag == cap_frame_cap);
161
162 if (ctag == cap_small_frame_cap) {
163 cap = cap_small_frame_cap_set_capFMappedASID(cap, asid);
164 cap = cap_small_frame_cap_set_capFMappedAddress(cap, addr);
165 return cap;
166 } else {
167 cap = cap_frame_cap_set_capFMappedASID(cap, asid);
168 cap = cap_frame_cap_set_capFMappedAddress(cap, addr);
169 return cap;
170 }
171 }
172
generic_frame_cap_ptr_set_capFMappedAddress(cap_t * cap_ptr,word_t asid,word_t addr)173 static inline void generic_frame_cap_ptr_set_capFMappedAddress(cap_t *cap_ptr, word_t asid,
174 word_t addr)
175 {
176 *cap_ptr = generic_frame_cap_set_capFMappedAddress(*cap_ptr, asid, addr);
177 }
178
generic_frame_cap_get_capFVMRights(cap_t cap)179 static inline vm_rights_t CONST generic_frame_cap_get_capFVMRights(cap_t cap)
180 {
181 cap_tag_t ctag;
182
183 ctag = cap_get_capType(cap);
184 assert(ctag == cap_small_frame_cap ||
185 ctag == cap_frame_cap);
186
187 switch (ctag) {
188 case cap_small_frame_cap:
189 return cap_small_frame_cap_get_capFVMRights(cap);
190
191 case cap_frame_cap:
192 return cap_frame_cap_get_capFVMRights(cap);
193
194 default:
195 return VMNoAccess;
196 }
197 }
198
generic_frame_cap_get_capFBasePtr(cap_t cap)199 static inline word_t CONST generic_frame_cap_get_capFBasePtr(cap_t cap)
200 {
201 cap_tag_t ctag;
202
203 ctag = cap_get_capType(cap);
204 assert(ctag == cap_small_frame_cap ||
205 ctag == cap_frame_cap);
206
207 switch (ctag) {
208 case cap_small_frame_cap:
209 return cap_small_frame_cap_get_capFBasePtr(cap);
210
211 case cap_frame_cap:
212 return cap_frame_cap_get_capFBasePtr(cap);
213
214 default:
215 return 0;
216 }
217 }
218
generic_frame_cap_get_capFSize(cap_t cap)219 static inline word_t CONST generic_frame_cap_get_capFSize(cap_t cap)
220 {
221 cap_tag_t ctag;
222
223 ctag = cap_get_capType(cap);
224 assert(ctag == cap_small_frame_cap ||
225 ctag == cap_frame_cap);
226
227 switch (ctag) {
228 case cap_small_frame_cap:
229 return ARMSmallPage;
230
231 case cap_frame_cap:
232 return cap_frame_cap_get_capFSize(cap);
233
234 default:
235 return 0;
236 }
237 }
238
generic_frame_cap_get_capFIsMapped(cap_t cap)239 static inline word_t CONST generic_frame_cap_get_capFIsMapped(cap_t cap)
240 {
241 return generic_frame_cap_get_capFMappedASID(cap) != 0;
242 }
243
generic_frame_cap_get_capFMappedAddress(cap_t cap)244 static inline word_t CONST generic_frame_cap_get_capFMappedAddress(cap_t cap)
245 {
246 cap_tag_t ctag;
247
248 ctag = cap_get_capType(cap);
249 assert(ctag == cap_small_frame_cap ||
250 ctag == cap_frame_cap);
251
252 if (ctag == cap_small_frame_cap) {
253 return cap_small_frame_cap_get_capFMappedAddress(cap);
254 } else {
255 return cap_frame_cap_get_capFMappedAddress(cap);
256 }
257 }
258
generic_frame_cap_get_capFIsDevice(cap_t cap)259 static inline word_t CONST generic_frame_cap_get_capFIsDevice(cap_t cap)
260 {
261 cap_tag_t ctag;
262
263 ctag = cap_get_capType(cap);
264 assert(ctag == cap_small_frame_cap ||
265 ctag == cap_frame_cap);
266
267 if (ctag == cap_small_frame_cap) {
268 return cap_small_frame_cap_get_capFIsDevice(cap);
269 } else {
270 return cap_frame_cap_get_capFIsDevice(cap);
271 }
272 }
273
cap_get_archCapSizeBits(cap_t cap)274 static inline word_t CONST cap_get_archCapSizeBits(cap_t cap)
275 {
276 cap_tag_t ctag;
277
278 ctag = cap_get_capType(cap);
279
280 switch (ctag) {
281 case cap_small_frame_cap:
282 case cap_frame_cap:
283 return pageBitsForSize(generic_frame_cap_get_capFSize(cap));
284
285 case cap_page_table_cap:
286 return seL4_PageTableBits;
287
288 case cap_page_directory_cap:
289 return seL4_PageDirBits;
290
291 case cap_asid_pool_cap:
292 return seL4_ASIDPoolBits;
293
294 case cap_asid_control_cap:
295 return 0;
296
297 #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
298 case cap_vcpu_cap:
299 return VCPU_SIZE_BITS;
300 #endif
301 #ifdef CONFIG_TK1_SMMU
302 case cap_io_page_table_cap:
303 return seL4_IOPageTableBits;
304 #endif
305
306 default:
307 /* Unreachable, but GCC can't figure that out */
308 return 0;
309 }
310 }
311
cap_get_archCapIsPhysical(cap_t cap)312 static inline bool_t CONST cap_get_archCapIsPhysical(cap_t cap)
313 {
314 cap_tag_t ctag;
315
316 ctag = cap_get_capType(cap);
317
318 switch (ctag) {
319
320 case cap_small_frame_cap:
321 return true;
322
323 case cap_frame_cap:
324 return true;
325
326 case cap_page_table_cap:
327 return true;
328
329 case cap_page_directory_cap:
330 return true;
331
332 case cap_asid_pool_cap:
333 return true;
334
335 case cap_asid_control_cap:
336 return false;
337
338 #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
339 case cap_vcpu_cap:
340 return true;
341 #endif
342
343 #ifdef CONFIG_TK1_SMMU
344 case cap_io_page_table_cap:
345 return true;
346 #endif
347
348 default:
349 /* Unreachable, but GCC can't figure that out */
350 return false;
351 }
352 }
353
cap_get_archCapPtr(cap_t cap)354 static inline void *CONST cap_get_archCapPtr(cap_t cap)
355 {
356 cap_tag_t ctag;
357
358 ctag = cap_get_capType(cap);
359
360 switch (ctag) {
361
362 case cap_small_frame_cap:
363 case cap_frame_cap:
364 return (void *)(generic_frame_cap_get_capFBasePtr(cap));
365
366 case cap_page_table_cap:
367 return PT_PTR(cap_page_table_cap_get_capPTBasePtr(cap));
368
369 case cap_page_directory_cap:
370 return PD_PTR(cap_page_directory_cap_get_capPDBasePtr(cap));
371
372 case cap_asid_pool_cap:
373 return ASID_POOL_PTR(cap_asid_pool_cap_get_capASIDPool(cap));
374
375 case cap_asid_control_cap:
376 return NULL;
377
378 #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
379 case cap_vcpu_cap:
380 return VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap));
381 #endif
382
383 #ifdef CONFIG_TK1_SMMU
384 case cap_io_page_table_cap:
385 return (void *)(cap_io_page_table_cap_get_capIOPTBasePtr(cap));
386 #endif
387
388 default:
389 /* Unreachable, but GCC can't figure that out */
390 return NULL;
391 }
392 }
393
394 #ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
395 /* We need to supply different type getters for the bitfield generated PTE type
396 * because there is an implicit third type that PTEs can be. If the type bit is
397 * set but the reserved bit is not set, the type of the PTE is invalid, not a
398 * large PTE.
399 */
400 enum { pte_pte_invalid = 2 };
401
pte_get_pteType(pte_t pte)402 static inline word_t CONST pte_get_pteType(pte_t pte)
403 {
404 if (pte_get_pteSize(pte) == pte_pte_small) {
405 return pte_pte_small;
406 } else if (pte_pte_large_get_reserved(pte) == 1) {
407 return pte_pte_large;
408 } else {
409 return pte_pte_invalid;
410 }
411 }
412
pte_ptr_get_pteType(pte_t * pte_ptr)413 static inline word_t PURE pte_ptr_get_pteType(pte_t *pte_ptr)
414 {
415 if (pte_ptr_get_pteSize(pte_ptr) == pte_pte_small) {
416 return pte_pte_small;
417 } else if (pte_pte_large_ptr_get_reserved(pte_ptr) == 1) {
418 return pte_pte_large;
419 } else {
420 return pte_pte_invalid;
421 }
422 }
423 #endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */
424
425