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
19typedef 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
29enum vm_rights {
30    VMNoAccess = 0,
31    VMKernelOnly = 1,
32    VMReadOnly = 2,
33    VMReadWrite = 3
34};
35typedef word_t vm_rights_t;
36
37typedef 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) */
64enum pde_type {
65    PDEInvalid = 0,
66    PDECoarse  = 1,
67    PDEMapping = 2
68};
69typedef 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
91struct asid_pool {
92    pde_t *array[BIT(asidLowBits)];
93};
94
95typedef 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
110static 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
118static 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
124static 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
132static 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
138static 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
154static 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
173static 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
179static 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
199static 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
219static 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
239static inline word_t CONST generic_frame_cap_get_capFIsMapped(cap_t cap)
240{
241    return generic_frame_cap_get_capFMappedASID(cap) != 0;
242}
243
244static 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
259static 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
274static 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
312static 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
354static 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 */
400enum { pte_pte_invalid = 2 };
401
402static 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
413static 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