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