1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
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 <api/types.h>
13#include <sel4/macros.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    user_context_t tcbContext;
21#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
22    struct vcpu *tcbVCPU;
23#endif
24} arch_tcb_t;
25
26enum vm_rights {
27    VMKernelOnly = 0,
28    VMReadWrite = 1,
29    VMKernelReadOnly = 2,
30    VMReadOnly = 3
31};
32typedef word_t vm_rights_t;
33
34/* If hypervisor support for aarch64 is enabled and we run on processors with
35 * 40-bit PA, the stage-2 translation for EL1/EL0 uses a 3-level translation, skipping the PGD level.
36 * Yet the kernel will still use a stage-1 translation with 48 bit input addresses and a 4-level
37 * translation.  Therefore, PUD and PGD size for the kernel can be different from EL1/EL0
38 * so we do not use the libsel4 definitions */
39#define PGD_SIZE_BITS       12
40#define PGD_INDEX_BITS      9
41#define PUD_SIZE_BITS       12
42#define PUD_INDEX_BITS      9
43#define UPUD_SIZE_BITS      seL4_PUDBits
44#define UPUD_INDEX_BITS     seL4_PUDIndexBits
45
46#define PDE_SIZE_BITS       seL4_PageDirEntryBits
47#define PD_INDEX_BITS       seL4_PageDirIndexBits
48#define PTE_SIZE_BITS       seL4_PageTableEntryBits
49#define PT_INDEX_BITS       seL4_PageTableIndexBits
50
51#define PT_INDEX_OFFSET     (seL4_PageBits)
52#define PD_INDEX_OFFSET     (PT_INDEX_OFFSET + PT_INDEX_BITS)
53#define PUD_INDEX_OFFSET    (PD_INDEX_OFFSET + PD_INDEX_BITS)
54#define PGD_INDEX_OFFSET    (PUD_INDEX_OFFSET + PUD_INDEX_BITS)
55
56#define VCPU_SIZE_BITS      seL4_VCPUBits
57
58#ifdef AARCH64_VSPACE_S2_START_L1
59/* For hyp with 40 bit PA, EL1 and EL0 use a 3 level translation and skips the PGD */
60typedef pude_t vspace_root_t;
61#else
62/* Otherwise we use a 4-level translation */
63typedef pgde_t vspace_root_t;
64#endif
65
66#define VSPACE_PTR(r)       ((vspace_root_t *)(r))
67
68#define GET_PGD_INDEX(x)    (((x) >> (PGD_INDEX_OFFSET)) & MASK(PGD_INDEX_BITS))
69#define GET_PUD_INDEX(x)    (((x) >> (PUD_INDEX_OFFSET)) & MASK(PUD_INDEX_BITS))
70#define GET_UPUD_INDEX(x)   (((x) >> (PUD_INDEX_OFFSET)) & MASK(UPUD_INDEX_BITS))
71#define GET_PD_INDEX(x)     (((x) >> (PD_INDEX_OFFSET)) & MASK(PD_INDEX_BITS))
72#define GET_PT_INDEX(x)     (((x) >> (PT_INDEX_OFFSET)) & MASK(PT_INDEX_BITS))
73
74#define PGDE_PTR(r)         ((pgde_t *)(r))
75#define PGDE_PTR_PTR(r)     ((pgde_t **)(r))
76#define PGDE_REF(p)         ((word_t)(p))
77
78#define PGD_PTR(r)          ((pgde_t *)(r))
79#define PGD_REF(p)          ((word_t)(r))
80
81#define PUDE_PTR(r)         ((pude_t *)(r))
82#define PUDE_PTR_PTR(r)     ((pude_t **)(r))
83#define PUDE_REF(p)         ((word_t)(p))
84
85#define PUD_PTR(r)          ((pude_t *)(r))
86#define PUD_PREF(p)         ((word_t)(p))
87
88#define PDE_PTR(r)          ((pde_t *)(r))
89#define PDE_PTR_PTR(r)      ((pde_t **)(r))
90#define PDE_REF(p)          ((word_t)(p))
91
92#define PD_PTR(r)           ((pde_t *)(r))
93#define PD_REF(p)           ((word_t)(p))
94
95#define PTE_PTR(r)          ((pte_t *)(r))
96#define PTE_REF(p)          ((word_t)(p))
97
98#define PT_PTR(r)           ((pte_t *)(r))
99#define PT_REF(p)           ((word_t)(p))
100
101/* Generate a vcpu_t pointer from a vcpu block reference */
102#define VCPU_PTR(r)       ((struct vcpu *)(r))
103#define VCPU_REF(p)       ((word_t)(p))
104
105struct asid_pool {
106    vspace_root_t *array[BIT(asidLowBits)];
107};
108typedef struct asid_pool asid_pool_t;
109
110#define ASID_POOL_PTR(r)    ((asid_pool_t*)r)
111#define ASID_POOL_REF(p)    ((word_t)p)
112
113
114#define ASID_POOL_INDEX_BITS seL4_ASIDPoolIndexBits
115#define ASID_BITS (asidHighBits+asidLowBits)
116#define nASIDs     BIT(ASID_BITS)
117#define nASIDPools BIT(asidHighBits)
118
119#define ASID_LOW(a) (a & MASK(asidLowBits))
120#define ASID_HIGH(a) ((a >> asidLowBits) & MASK(asidHighBits))
121
122static inline word_t CONST cap_get_archCapSizeBits(cap_t cap)
123{
124    cap_tag_t ctag;
125
126    ctag = cap_get_capType(cap);
127
128    switch (ctag) {
129    case cap_frame_cap:
130        return pageBitsForSize(cap_frame_cap_get_capFSize(cap));
131
132    case cap_page_table_cap:
133        return seL4_PageTableBits;
134
135    case cap_page_directory_cap:
136        return seL4_PageDirBits;
137
138    case cap_page_upper_directory_cap:
139        return seL4_PUDBits;
140
141    case cap_page_global_directory_cap:
142        return seL4_PGDBits;
143
144    case cap_asid_pool_cap:
145        return seL4_ASIDPoolBits;
146
147    case cap_asid_control_cap:
148        return 0;
149
150#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
151    case cap_vcpu_cap:
152        return seL4_VCPUBits;
153#endif
154
155    default:
156        /* Unreachable, but GCC can't figure that out */
157        return 0;
158    }
159}
160
161static inline bool_t CONST cap_get_archCapIsPhysical(cap_t cap)
162{
163    cap_tag_t ctag;
164
165    ctag = cap_get_capType(cap);
166
167    switch (ctag) {
168
169    case cap_frame_cap:
170        return true;
171
172    case cap_page_table_cap:
173        return true;
174
175    case cap_page_directory_cap:
176        return true;
177
178    case cap_page_upper_directory_cap:
179        return true;
180
181    case cap_page_global_directory_cap:
182        return true;
183
184    case cap_asid_pool_cap:
185        return true;
186
187    case cap_asid_control_cap:
188        return false;
189
190#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
191    case cap_vcpu_cap:
192        return true;
193#endif
194
195    default:
196        /* Unreachable, but GCC can't figure that out */
197        return false;
198    }
199}
200
201static inline void *CONST cap_get_archCapPtr(cap_t cap)
202{
203    cap_tag_t ctag;
204
205    ctag = cap_get_capType(cap);
206
207    switch (ctag) {
208    case cap_frame_cap:
209        return (void *)(cap_frame_cap_get_capFBasePtr(cap));
210
211    case cap_page_table_cap:
212        return PD_PTR(cap_page_table_cap_get_capPTBasePtr(cap));
213
214    case cap_page_directory_cap:
215        return PT_PTR(cap_page_directory_cap_get_capPDBasePtr(cap));
216
217    case cap_page_upper_directory_cap:
218        return PUD_PTR(cap_page_upper_directory_cap_get_capPUDBasePtr(cap));
219
220    case cap_page_global_directory_cap:
221        return PGD_PTR(cap_page_global_directory_cap_get_capPGDBasePtr(cap));
222
223    case cap_asid_control_cap:
224        return NULL;
225
226    case cap_asid_pool_cap:
227        return ASID_POOL_PTR(cap_asid_pool_cap_get_capASIDPool(cap));
228
229#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
230    case cap_vcpu_cap:
231        return VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap));
232#endif
233
234    default:
235        /* Unreachable, but GCC can't figure that out */
236        return NULL;
237    }
238}
239
240static inline bool_t pgde_pgde_pud_ptr_get_present(pgde_t *pgd)
241{
242    return (pgde_ptr_get_pgde_type(pgd) == pgde_pgde_pud);
243}
244
245static inline bool_t pude_pude_pd_ptr_get_present(pude_t *pud)
246{
247    return (pude_ptr_get_pude_type(pud) == pude_pude_pd);
248}
249
250static inline bool_t pude_pude_1g_ptr_get_present(pude_t *pud)
251{
252    return (pude_ptr_get_pude_type(pud) == pude_pude_1g);
253}
254
255static inline pude_t pude_invalid_new(void)
256{
257    return (pude_t) {
258        {
259            0
260        }
261    };
262}
263
264static inline bool_t pde_pde_small_ptr_get_present(pde_t *pd)
265{
266    return (pde_ptr_get_pde_type(pd) == pde_pde_small);
267}
268
269static inline bool_t pde_pde_large_ptr_get_present(pde_t *pd)
270{
271    return (pde_ptr_get_pde_type(pd) == pde_pde_large);
272}
273
274static inline pde_t pde_invalid_new(void)
275{
276    return (pde_t) {
277        {
278            0
279        }
280    };
281}
282
283static inline bool_t pte_ptr_get_present(pte_t *pt)
284{
285    return (pte_ptr_get_reserved(pt) == 0x3);
286}
287
288static inline pte_t pte_invalid_new(void)
289{
290    return (pte_t) {
291        {
292            0
293        }
294    };
295}
296
297