1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <config.h>
8#include <arch/machine/capdl.h>
9#include <string.h>
10#include <kernel/cspace.h>
11
12#ifdef CONFIG_DEBUG_BUILD
13
14static void obj_frame_print_attrs(lookupFrame_ret_t ret);
15static void cap_frame_print_attrs_pud(pude_t *pudSlot);
16static void cap_frame_print_attrs_pd(pde_t *pdSlot);
17static void cap_frame_print_attrs_pt(pte_t *ptSlot);
18static void cap_frame_print_attrs_impl(word_t SH, word_t AP, word_t NXN);
19static void cap_frame_print_attrs_vptr(word_t vptr, cap_t vspace);
20
21static void _cap_frame_print_attrs_vptr(word_t vptr, vspace_root_t *vspaceRoot);
22
23static void arm64_obj_pt_print_slots(pde_t *pdSlot);
24static void arm64_obj_pd_print_slots(pude_t *pudSlot);
25static void arm64_obj_pud_print_slots(void *pgdSlot_or_vspace);
26
27static void arm64_cap_pt_print_slots(pde_t *pdSlot, vptr_t vptr);
28static void arm64_cap_pd_print_slots(pude_t *pudSlot, vptr_t vptr);
29static void arm64_cap_pud_print_slots(void *pgdSlot_or_vspace, vptr_t vptr);
30
31word_t get_tcb_sp(tcb_t *tcb)
32{
33    return tcb->tcbArch.tcbContext.registers[SP_EL0];
34}
35
36/* Stage-1 access permissions:
37 * AP[2:1]  higer EL        EL0
38 *   00       rw            None
39 *   01       rw            rw
40 *   10       r             None
41 *   11       r             r
42 *
43 * Stage-2 access permissions:
44 * S2AP    Access from Nonsecure EL1 or Non-secure EL0
45 *  00                      None
46 *  01                      r
47 *  10                      w
48 *  11                      rw
49 *
50 *  For VMs or native seL4 applications, if hypervisor support
51 *  is enabled, we use the S2AP. The kernel itself running in
52 *  EL2 still uses the Stage-1 AP format.
53 */
54/* use when only have access to pte of frames */
55static void cap_frame_print_attrs_pud(pude_t *pudSlot)
56{
57    cap_frame_print_attrs_impl(pude_pude_1g_ptr_get_SH(pudSlot),
58                               pude_pude_1g_ptr_get_AP(pudSlot),
59                               pude_pude_1g_ptr_get_UXN(pudSlot));
60}
61
62static void cap_frame_print_attrs_pd(pde_t *pdSlot)
63{
64    cap_frame_print_attrs_impl(pde_pde_large_ptr_get_SH(pdSlot),
65                               pde_pde_large_ptr_get_AP(pdSlot),
66                               pde_pde_large_ptr_get_UXN(pdSlot));
67}
68
69static void cap_frame_print_attrs_pt(pte_t *ptSlot)
70{
71    cap_frame_print_attrs_impl(pte_ptr_get_SH(ptSlot),
72                               pte_ptr_get_AP(ptSlot),
73                               pte_ptr_get_UXN(ptSlot));
74}
75
76static void cap_frame_print_attrs_impl(word_t SH, word_t AP, word_t NXN)
77{
78    printf("(");
79
80    /* rights */
81    switch (AP) {
82#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
83    case 0b00:
84        break;
85    case 0b01:
86        printf("R");
87        break;
88    case 0b10:
89        printf("W");
90        break;
91    case 0b11:
92        printf("RW");
93        break;
94#else
95    case 0b00:
96        break;
97    case 0b01:
98        printf("RW");
99    case 0b10:
100        break;
101    case 0b11:
102        printf("R");
103#endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */
104    default:
105        break;
106    }
107
108    if (!NXN) {
109        printf("X");
110    }
111
112    /* Only has effect if SMP enabled */
113    if (SH != SMP_TERNARY(SMP_SHARE, 0)) {
114        printf(", uncached");
115    }
116
117    printf(")\n");
118}
119
120/* use when only have access to vptr of frames */
121static void _cap_frame_print_attrs_vptr(word_t vptr, vspace_root_t *vspace)
122{
123    lookupPUDSlot_ret_t pudSlot = lookupPUDSlot(vspace, vptr);
124    if (pudSlot.status != EXCEPTION_NONE) {
125        return;
126    }
127
128    switch (pude_ptr_get_pude_type(pudSlot.pudSlot)) {
129    case pude_pude_1g:
130        printf("frame_%p_%04lu ", pudSlot.pudSlot, GET_PUD_INDEX(vptr));
131        cap_frame_print_attrs_pud(pudSlot.pudSlot);
132        break;
133
134    case pude_pude_pd: {
135        pde_t *pd = paddr_to_pptr(pude_pude_pd_ptr_get_pd_base_address(pudSlot.pudSlot));
136        pde_t *pdSlot = pd + GET_PD_INDEX(vptr);
137
138        switch (pde_ptr_get_pde_type(pdSlot)) {
139        case pde_pde_large:
140            printf("frame_%p_%04lu ", pdSlot, GET_PD_INDEX(vptr));
141            cap_frame_print_attrs_pd(pdSlot);
142            break;
143
144        case pde_pde_small: {
145            pte_t *pt = paddr_to_pptr(pde_pde_small_ptr_get_pt_base_address(pdSlot));
146            pte_t *ptSlot = pt + GET_PT_INDEX(vptr);
147
148            if (pte_ptr_get_present(ptSlot)) {
149                printf("frame_%p_%04lu ", ptSlot, GET_PT_INDEX(vptr));
150                cap_frame_print_attrs_pt(ptSlot);
151                break;
152            } else {
153                return;
154            }
155        }
156        default:
157            assert(0);
158        }
159        break;
160    }
161    default:
162        assert(0);
163    }
164}
165
166void cap_frame_print_attrs_vptr(word_t vptr, cap_t vspace)
167{
168    _cap_frame_print_attrs_vptr(vptr, VSPACE_PTR(pptr_of_cap(vspace)));
169}
170
171/*
172 * print object slots
173 */
174static void arm64_cap_pt_print_slots(pde_t *pdSlot, vptr_t vptr)
175{
176    pte_t *pt = paddr_to_pptr(pde_pde_small_ptr_get_pt_base_address(pdSlot));
177    printf("pt_%p_%04lu {\n", pdSlot, GET_PD_INDEX(vptr));
178
179    for (word_t i = 0; i < BIT(PT_INDEX_OFFSET + PT_INDEX_BITS); i += (1 << PT_INDEX_OFFSET)) {
180        pte_t *ptSlot = pt + GET_PT_INDEX(i);
181
182        if (pte_ptr_get_present(ptSlot)) {
183            // print pte entries
184            printf("0x%lx: frame_%p_%04lu", GET_PT_INDEX(i), ptSlot, GET_PT_INDEX(i));
185            cap_frame_print_attrs_pt(ptSlot);
186        }
187    }
188    printf("}\n"); /* pt */
189}
190
191static void arm64_cap_pd_print_slots(pude_t *pudSlot, vptr_t vptr)
192{
193    printf("pd_%p_%04lu {\n", pudSlot, GET_PUD_INDEX(vptr));
194    pde_t *pd = paddr_to_pptr(pude_pude_pd_ptr_get_pd_base_address(pudSlot));
195
196    for (word_t i = 0; i < BIT(PD_INDEX_OFFSET + PD_INDEX_BITS); i += (1 << PD_INDEX_OFFSET)) {
197        pde_t *pdSlot = pd + GET_PD_INDEX(i);
198
199        switch (pde_ptr_get_pde_type(pdSlot)) {
200
201        case pde_pde_large:
202            printf("0x%lx: frame_%p_%04lu", GET_PD_INDEX(i), pdSlot, GET_PD_INDEX(i));
203            cap_frame_print_attrs_pd(pdSlot);
204            break;
205
206        case pde_pde_small:
207            printf("0x%lx: pt_%p_%04lu\n", GET_PD_INDEX(i), pdSlot, GET_PD_INDEX(i));
208            break;
209        }
210    }
211
212    printf("}\n"); /* pd */
213
214    for (word_t i = 0; i < BIT(PD_INDEX_OFFSET + PD_INDEX_BITS); i += (1 << PD_INDEX_OFFSET)) {
215        pde_t *pdSlot = pd + GET_PD_INDEX(i);
216        if (pde_ptr_get_pde_type(pdSlot) == pde_pde_small) {
217            arm64_cap_pt_print_slots(pdSlot, i);
218        }
219    }
220}
221
222static void arm64_cap_pud_print_slots(void *pgdSlot_or_vspace, vptr_t vptr)
223{
224#ifdef AARCH64_VSPACE_S2_START_L1
225    pude_t *pud = pgdSlot_or_vspace;
226    printf("%p_pd {\n", pgdSlot_or_vspace);
227#else
228    pude_t *pud = paddr_to_pptr(pgde_pgde_pud_ptr_get_pud_base_address(pgdSlot_or_vspace));
229    printf("pud_%p_%04lu {\n", pgdSlot_or_vspace, GET_PGD_INDEX(vptr));
230#endif
231
232    for (word_t i = 0; i < BIT(PUD_INDEX_OFFSET + UPUD_INDEX_BITS); i += (1 << PUD_INDEX_OFFSET)) {
233        pude_t *pudSlot = pud + GET_PUD_INDEX(i);
234        if (pude_ptr_get_pude_type(pudSlot) == pude_pude_pd) {
235            printf("0x%lx: pd_%p_%04lu\n", GET_PUD_INDEX(i), pudSlot, GET_PUD_INDEX(i));
236        }
237    }
238
239    printf("}\n"); /* pgd/pud */
240
241    for (word_t i = 0; i < BIT(PUD_INDEX_OFFSET + UPUD_INDEX_BITS); i += (1 << PUD_INDEX_OFFSET)) {
242        pude_t *pudSlot = pud + GET_PUD_INDEX(i);
243        if (pude_ptr_get_pude_type(pudSlot) == pude_pude_pd) {
244            arm64_cap_pd_print_slots(pudSlot, i);
245        }
246    }
247}
248
249void obj_vtable_print_slots(tcb_t *tcb)
250{
251    if (isVTableRoot(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap) && !seen(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap)) {
252        add_to_seen(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
253        vspace_root_t *vspace = cap_vtable_root_get_basePtr(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
254
255        /*
256        * ARM hyp uses 3 level translation rather than the usual 4 level.
257        * levels: PGD -> UPD -> PD -> PT
258        */
259#ifdef AARCH64_VSPACE_S2_START_L1
260        arm64_cap_pud_print_slots(vspace, 0);
261#else
262        printf("%p_pd {\n", vspace);
263        for (word_t i = 0; i < BIT(PGD_INDEX_OFFSET + PGD_INDEX_BITS); i += (1UL << PGD_INDEX_OFFSET)) {
264            lookupPGDSlot_ret_t pgdSlot = lookupPGDSlot(vspace, i);
265            if (pgde_pgde_pud_ptr_get_present(pgdSlot.pgdSlot)) {
266                printf("0x%lx: pud_%p_%04lu\n", GET_PGD_INDEX(i), pgdSlot.pgdSlot, GET_PGD_INDEX(i));
267            }
268        }
269        printf("}\n"); /* pd */
270
271        for (word_t i = 0; i < BIT(PGD_INDEX_OFFSET + PGD_INDEX_BITS); i += (1UL << PGD_INDEX_OFFSET)) {
272            lookupPGDSlot_ret_t pgdSlot = lookupPGDSlot(vspace, i);
273            if (pgde_pgde_pud_ptr_get_present(pgdSlot.pgdSlot)) {
274                arm64_cap_pud_print_slots(pgdSlot.pgdSlot, i);
275            }
276        }
277#endif
278    }
279}
280
281void print_ipc_buffer_slot(tcb_t *tcb)
282{
283    word_t vptr = tcb->tcbIPCBuffer;
284    printf("ipc_buffer_slot: ");
285    cap_frame_print_attrs_vptr(vptr, TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
286}
287
288void print_cap_arch(cap_t cap)
289{
290
291    switch (cap_get_capType(cap)) {
292    case cap_page_table_cap: {
293        asid_t asid = cap_page_table_cap_get_capPTMappedASID(cap);
294        findVSpaceForASID_ret_t find_ret = findVSpaceForASID(asid);
295        vptr_t vptr = cap_page_table_cap_get_capPTMappedAddress(cap);
296        if (asid) {
297            printf("pt_%p_%04lu (asid: %lu)\n",
298                   lookupPDSlot(find_ret.vspace_root, vptr).pdSlot, GET_PD_INDEX(vptr), (long unsigned int)asid);
299        } else {
300            printf("pt_%p_%04lu\n", lookupPDSlot(find_ret.vspace_root, vptr).pdSlot, GET_PD_INDEX(vptr));
301        }
302        break;
303    }
304    case cap_page_directory_cap: {
305        asid_t asid = cap_page_directory_cap_get_capPDMappedASID(cap);
306        findVSpaceForASID_ret_t find_ret = findVSpaceForASID(asid);
307        vptr_t vptr = cap_page_directory_cap_get_capPDMappedAddress(cap);
308        if (asid) {
309            printf("pd_%p_%04lu (asid: %lu)\n",
310                   lookupPUDSlot(find_ret.vspace_root, vptr).pudSlot, GET_PUD_INDEX(vptr), (long unsigned int)asid);
311        } else {
312            printf("pd_%p_%04lu\n",
313                   lookupPUDSlot(find_ret.vspace_root, vptr).pudSlot, GET_PUD_INDEX(vptr));
314        }
315        break;
316    }
317    case cap_page_upper_directory_cap: {
318        asid_t asid = cap_page_upper_directory_cap_get_capPUDMappedASID(cap);
319        findVSpaceForASID_ret_t find_ret = findVSpaceForASID(asid);
320        vptr_t vptr = cap_page_upper_directory_cap_get_capPUDMappedAddress(cap);
321
322#ifdef AARCH64_VSPACE_S2_START_L1
323        if (asid) {
324            printf("pud_%p_%04lu (asid: %lu)\n",
325                   find_ret.vspace_root, GET_PGD_INDEX(vptr), (long unsigned int)asid);
326        } else {
327            printf("pud_%p_%04lu\n", find_ret.vspace_root, GET_PGD_INDEX(vptr));
328        }
329#else
330        if (asid) {
331            printf("pud_%p_%04lu (asid: %lu)\n",
332                   lookupPGDSlot(find_ret.vspace_root, vptr).pgdSlot, GET_PGD_INDEX(vptr), (long unsigned int)asid);
333        } else {
334            printf("pud_%p_%04lu\n", lookupPGDSlot(find_ret.vspace_root, vptr).pgdSlot, GET_PGD_INDEX(vptr));
335        }
336#endif
337        break;
338    }
339    case cap_page_global_directory_cap: {
340        asid_t asid = cap_page_global_directory_cap_get_capPGDMappedASID(cap);
341        findVSpaceForASID_ret_t find_ret = findVSpaceForASID(asid);
342        if (asid) {
343            printf("%p_pd (asid: %lu)\n",
344                   find_ret.vspace_root, (long unsigned int)asid);
345        } else {
346            printf("%p_pd\n", find_ret.vspace_root);
347        }
348        break;
349    }
350    case cap_asid_control_cap: {
351        /* only one in the system */
352        printf("asid_control\n");
353        break;
354    }
355    case cap_frame_cap: {
356        vptr_t vptr = cap_frame_cap_get_capFMappedAddress(cap);
357        findVSpaceForASID_ret_t find_ret = findVSpaceForASID(cap_frame_cap_get_capFMappedASID(cap));
358        assert(find_ret.status == EXCEPTION_NONE);
359        _cap_frame_print_attrs_vptr(vptr, find_ret.vspace_root);
360        break;
361    }
362    case cap_asid_pool_cap: {
363        printf("%p_asid_pool\n", (void *)cap_asid_pool_cap_get_capASIDPool(cap));
364        break;
365    }
366#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
367    case cap_vcpu_cap: {
368        printf("%p_vcpu\n", (void *)cap_vcpu_cap_get_capVCPUPtr(cap));
369        break;
370    }
371#endif
372
373        /* ARM specific caps */
374#ifdef CONFIG_TK1_SMMU
375    case cap_io_space_cap: {
376        printf("%p_io_space\n", (void *)cap_io_space_cap_get_capModuleID(cap));
377        break;
378    }
379#endif
380    default: {
381        printf("[unknown cap %lu]\n", (long unsigned int)cap_get_capType(cap));
382        break;
383    }
384    }
385}
386
387void print_object_arch(cap_t cap)
388{
389    switch (cap_get_capType(cap)) {
390    case cap_frame_cap:
391    case cap_page_table_cap:
392    case cap_page_directory_cap:
393    case cap_page_upper_directory_cap:
394    case cap_page_global_directory_cap:
395        /* don't need to deal with these objects since they get handled from vtable */
396        break;
397
398    case cap_asid_pool_cap: {
399        printf("%p_asid_pool = asid_pool ",
400               (void *)cap_asid_pool_cap_get_capASIDPool(cap));
401        obj_asidpool_print_attrs(cap);
402        break;
403    }
404#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
405    case cap_vcpu_cap: {
406        printf("%p_vcpu = vcpu\n", (void *)cap_vcpu_cap_get_capVCPUPtr(cap));
407        break;
408    }
409#endif
410        /* ARM specific objects */
411#ifdef CONFIG_TK1_SMMU
412    case cap_io_space_cap: {
413        printf("%p_io_space = io_space ", (void *)cap_io_space_cap_get_capModuleID(cap));
414        arm_obj_iospace_print_attrs(cap);
415        break;
416    }
417#endif
418    default: {
419        printf("[unknown object %lu]\n", (long unsigned int)cap_get_capType(cap));
420        break;
421    }
422    }
423}
424
425void obj_frame_print_attrs(lookupFrame_ret_t ret)
426{
427    printf("(");
428
429    /* VM size */
430    switch (ret.frameSize) {
431    case ARMHugePage:
432        printf("1G");
433        break;
434    case ARMLargePage:
435        printf("2M");
436        break;
437    case ARMSmallPage:
438        printf("4k");
439        break;
440    }
441
442    printf(", paddr: 0x%p)\n", (void *)ret.frameBase);
443}
444
445void arm64_obj_pt_print_slots(pde_t *pdSlot)
446{
447    lookupFrame_ret_t ret;
448    pte_t *pt = paddr_to_pptr(pde_pde_small_ptr_get_pt_base_address(pdSlot));
449
450    for (word_t i = 0; i < BIT(PT_INDEX_OFFSET + PT_INDEX_BITS); i += (1 << PT_INDEX_OFFSET)) {
451        pte_t *ptSlot = pt + GET_PT_INDEX(i);
452
453        if (pte_ptr_get_present(ptSlot)) {
454            ret.frameBase = pte_ptr_get_page_base_address(ptSlot);
455            ret.frameSize = ARMSmallPage;
456            printf("frame_%p_%04lu = frame ", ptSlot, GET_PT_INDEX(i));
457            obj_frame_print_attrs(ret);
458        }
459    }
460}
461
462void arm64_obj_pd_print_slots(pude_t *pudSlot)
463{
464    lookupFrame_ret_t ret;
465    pde_t *pd = paddr_to_pptr(pude_pude_pd_ptr_get_pd_base_address(pudSlot));
466
467    for (word_t i = 0; i < BIT(PD_INDEX_OFFSET + PD_INDEX_BITS); i += (1 << PD_INDEX_OFFSET)) {
468        pde_t *pdSlot = pd + GET_PD_INDEX(i);
469
470        if (pde_ptr_get_pde_type(pdSlot) == pde_pde_large) {
471            ret.frameBase = pde_pde_large_ptr_get_page_base_address(pdSlot);
472            ret.frameSize = ARMLargePage;
473
474            printf("frame_%p_%04lu = frame ", pdSlot, GET_PD_INDEX(i));
475            obj_frame_print_attrs(ret);
476        }
477
478        if (pde_ptr_get_pde_type(pdSlot) == pde_pde_small) {
479            printf("pt_%p_%04lu = pt\n", pdSlot, GET_PD_INDEX(i));
480            arm64_obj_pt_print_slots(pdSlot);
481        }
482    }
483}
484
485void arm64_obj_pud_print_slots(void *pgdSlot_or_vspace)
486{
487    lookupFrame_ret_t ret;
488    pude_t *pud = paddr_to_pptr(pgde_pgde_pud_ptr_get_pud_base_address(pgdSlot_or_vspace));
489
490    for (word_t i = 0; i < BIT(PUD_INDEX_OFFSET + UPUD_INDEX_BITS); i += (1 << PUD_INDEX_OFFSET)) {
491        pude_t *pudSlot = pud + GET_PUD_INDEX(i);
492
493        switch (pude_ptr_get_pude_type(pudSlot)) {
494        case pude_pude_1g:
495            ret.frameBase = pude_pude_1g_ptr_get_page_base_address(pudSlot);
496            ret.frameSize = ARMHugePage;
497
498            printf("frame_%p_%04lu = frame ", pudSlot, GET_PUD_INDEX(i));
499            obj_frame_print_attrs(ret);
500            break;
501
502        case pude_pude_pd: {
503            printf("pd_%p_%04lu = pd\n", pudSlot, GET_PUD_INDEX(i));
504            arm64_obj_pd_print_slots(pudSlot);
505
506        }
507        }
508    }
509}
510
511void obj_tcb_print_vtable(tcb_t *tcb)
512{
513    if (isVTableRoot(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap) && !seen(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap)) {
514        add_to_seen(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
515        vspace_root_t *vspace = cap_vtable_root_get_basePtr(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
516
517        /*
518         * ARM hyp uses 3 level translation rather than the usual 4 level.
519         * levels: PGD -> PUD -> PD -> PT
520         */
521#ifdef AARCH64_VSPACE_S2_START_L1
522        printf("%p_pd = pud\n", vspace);
523        arm64_obj_pud_print_slots(vspace);
524#else
525        printf("%p_pd = pgd\n", vspace);
526        for (word_t i = 0; i < BIT(PGD_INDEX_OFFSET + PGD_INDEX_BITS); i += (1UL << PGD_INDEX_OFFSET)) {
527            lookupPGDSlot_ret_t pgdSlot = lookupPGDSlot(vspace, i);
528            if (pgde_pgde_pud_ptr_get_present(pgdSlot.pgdSlot)) {
529                printf("pud_%p_%04lu = pud\n", pgdSlot.pgdSlot, GET_PGD_INDEX(i));
530                arm64_obj_pud_print_slots(pgdSlot.pgdSlot);
531            }
532        }
533#endif
534    }
535}
536
537void capDL(void)
538{
539    printf("arch aarch64\n");
540    printf("objects {\n");
541    print_objects();
542    printf("}\n");
543
544    printf("caps {\n");
545
546    /* reset the seen list */
547    reset_seen_list();
548
549    print_caps();
550    printf("}\n");
551
552    obj_irq_print_maps();
553}
554
555#endif /* CONFIG_DEBUG_BUILD */
556