1223486Shselasky/*
2223486Shselasky * Copyright 2014, General Dynamics C4 Systems
3223486Shselasky *
4223486Shselasky * SPDX-License-Identifier: GPL-2.0-only
5223486Shselasky */
6223486Shselasky
7223486Shselasky#pragma once
8223486Shselasky
9223486Shselasky#include <config.h>
10223486Shselasky#include <assert.h>
11223486Shselasky#include <util.h>
12223486Shselasky#include <sel4/macros.h>
13223486Shselasky#include <api/types.h>
14223486Shselasky#include <arch/types.h>
15223486Shselasky#include <arch/object/structures_gen.h>
16223486Shselasky#include <arch/machine/hardware.h>
17223486Shselasky#include <arch/machine/registerset.h>
18223486Shselasky
19223486Shselaskytypedef struct arch_tcb {
20223486Shselasky    /* saved user-level context of thread (72 bytes) */
21223486Shselasky    user_context_t tcbContext;
22223486Shselasky#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
23223486Shselasky    /* Pointer to associated VCPU. NULL if not associated.
24223486Shselasky     * tcb->tcbVCPU->vcpuTCB == tcb. */
25223486Shselasky    struct vcpu *tcbVCPU;
26223486Shselasky#endif
27223486Shselasky} arch_tcb_t;
28223486Shselasky
29223486Shselaskyenum vm_rights {
30228975Suqs    VMNoAccess = 0,
31223486Shselasky    VMKernelOnly = 1,
32223486Shselasky    VMReadOnly = 2,
33223486Shselasky    VMReadWrite = 3
34223486Shselasky};
35223486Shselaskytypedef word_t vm_rights_t;
36223534Shselasky
37223534Shselaskytypedef pde_t vspace_root_t;
38223534Shselasky
39223486Shselasky#define seL4_PGDEntryBits 3
40223486Shselasky#define seL4_PGDIndexBits 2
41223486Shselasky#define seL4_PGDBits 5
42223534Shselasky
43223534Shselasky#define PGDE_SIZE_BITS seL4_PGDEntryBits
44223534Shselasky#define PDE_SIZE_BITS  seL4_PageDirEntryBits
45223486Shselasky#define PTE_SIZE_BITS  seL4_PageTableEntryBits
46223486Shselasky#define PGD_INDEX_BITS seL4_PGDIndexBits
47223486Shselasky#define PD_INDEX_BITS seL4_PageDirIndexBits
48223486Shselasky#define PT_INDEX_BITS seL4_PageTableIndexBits
49223486Shselasky#define VCPU_SIZE_BITS seL4_VCPUBits
50223486Shselasky
51223534Shselasky/* Generate a vcpu_t pointer from a vcpu block reference */
52223534Shselasky#define VCPU_PTR(r)       ((struct vcpu *)(r))
53223486Shselasky#define VCPU_REF(p)       ((unsigned int)(p))
54223486Shselasky
55223486Shselasky#define PDE_PTR(r) ((pde_t *)(r))
56223486Shselasky#define PDE_REF(p) ((unsigned int)p)
57223486Shselasky
58223486Shselasky#define PDE_PTR_PTR(r) ((pde_t **)r)
59223486Shselasky
60223486Shselasky#define PD_PTR(r) ((pde_t *)(r))
61223534Shselasky#define PD_REF(p) ((unsigned int)p)
62223534Shselasky
63223534Shselasky/* Page directory entries (PDEs) */
64223534Shselaskyenum pde_type {
65223534Shselasky    PDEInvalid = 0,
66223534Shselasky    PDECoarse  = 1,
67223534Shselasky    PDEMapping = 2
68223486Shselasky};
69223534Shselaskytypedef word_t pde_type_t;
70223486Shselasky
71223486Shselasky#define PTE_PTR(r) ((pte_t *)r)
72223486Shselasky#define PTE_REF(p) ((unsigned int)p)
73223486Shselasky
74223534Shselasky#define PT_PTR(r) ((pte_t *)r)
75223534Shselasky#define PT_REF(p) ((unsigned int)p)
76223534Shselasky
77223534Shselasky/* LPAE */
78223534Shselasky#define PGD_SIZE_BITS seL4_PGDBits
79223534Shselasky#define LPAE_PGDE_PTR(r) ((lpae_pde_t *)(r))
80223534Shselasky#define LPAE_PGDE_REF(p) ((unsigned int)p)
81223534Shselasky#define LPAE_PGDE_PTR_PTR(r) ((lpae_pde_t **)r)
82223534Shselasky#define LPAE_PGD_PTR(r) ((lpae_pde_t *)(r))
83223534Shselasky#define LPAE_PGD_REF(p) ((unsigned int)p)
84223534Shselasky
85223534Shselasky#define LPAE_PTE_PTR(r) ((lpae_pte_t *)r)
86223534Shselasky#define LPAE_PTE_REF(p) ((unsigned int)p)
87223534Shselasky
88223534Shselasky#define LPAE_PT_PTR(r) ((lpae_pte_t *)r)
89223534Shselasky#define LPAE_PT_REF(p) ((unsigned int)p)
90223534Shselasky
91223534Shselaskystruct asid_pool {
92223534Shselasky    pde_t *array[BIT(asidLowBits)];
93223534Shselasky};
94223534Shselasky
95223534Shselaskytypedef struct asid_pool asid_pool_t;
96223534Shselasky
97223534Shselasky#define ASID_POOL_PTR(r) ((asid_pool_t *)r)
98223534Shselasky#define ASID_POOL_REF(p) ((unsigned int)p)
99223534Shselasky
100223534Shselasky#define HW_ASID_SIZE_BITS 1
101223534Shselasky
102223486Shselasky#define ASID_POOL_INDEX_BITS seL4_ASIDPoolIndexBits
103223534Shselasky#define ASID_BITS (asidHighBits+asidLowBits)
104223534Shselasky
105223534Shselasky#define nASIDPools BIT(asidHighBits)
106223534Shselasky
107223534Shselasky#define ASID_LOW(a) (a & MASK(asidLowBits))
108223534Shselasky#define ASID_HIGH(a) ((a >> asidLowBits) & MASK(asidHighBits))
109223534Shselasky
110223534Shselaskystatic inline cap_t CONST cap_small_frame_cap_set_capFMappedASID(cap_t cap, word_t asid)
111223486Shselasky{
112223534Shselasky    cap = cap_small_frame_cap_set_capFMappedASIDLow(cap,
113223486Shselasky                                                    asid & MASK(asidLowBits));
114223486Shselasky    return cap_small_frame_cap_set_capFMappedASIDHigh(cap,
115223486Shselasky                                                      (asid >> asidLowBits) & MASK(asidHighBits));
116223486Shselasky}
117223486Shselasky
118223486Shselaskystatic inline word_t CONST cap_small_frame_cap_get_capFMappedASID(cap_t cap)
119223534Shselasky{
120223486Shselasky    return (cap_small_frame_cap_get_capFMappedASIDHigh(cap) << asidLowBits) +
121223486Shselasky           cap_small_frame_cap_get_capFMappedASIDLow(cap);
122223534Shselasky}
123223486Shselasky
124223486Shselaskystatic inline cap_t CONST cap_frame_cap_set_capFMappedASID(cap_t cap, word_t asid)
125223486Shselasky{
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