1/*
2 * Copyright 2014, General Dynamics C4 Systems
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
14#define MAX_UL          0xffffffff
15#define PT_INDEX(vptr)  ((vptr >> PAGE_BITS) & MASK(PT_INDEX_BITS))
16#define PD_INDEX(vptr)  (vptr >> (PAGE_BITS + PT_INDEX_BITS))
17
18static void obj_frame_print_attrs(resolve_ret_t ret);
19static void cap_frame_print_attrs_pt(pte_t *pte);
20static void cap_frame_print_attrs_pd(pde_t *pde);
21static void cap_frame_print_attrs_impl(word_t AP, word_t XN, word_t TEX);
22static void arm32_obj_pt_print_slots(pte_t *pt);
23static void arm32_cap_pt_print_slots(pte_t *pt);
24
25/*
26 * Caps
27 */
28word_t get_tcb_sp(tcb_t *tcb)
29{
30    return tcb->tcbArch.tcbContext.registers[SP];
31}
32
33/*
34 * AP   S   R   Privileged permissions  User permissions
35 * 00   0   0   No access               No access
36 * 00   1   0   Read-only               No access
37 * 00   0   1   Read-only               Read-only
38 * 00   1   1   Unpredictable           Unpredictable
39 * 01   x   x   Read/write              No access
40 * 10   x   x   Read/write              Read-only
41 * 11   x   x   Read/write              Read/write
42 */
43/* use when only have access to pte of frames */
44static void cap_frame_print_attrs_pt(pte_t *pte)
45{
46    word_t AP, XN, TEX;
47    switch (pte_ptr_get_pteType(pte)) {
48    case pte_pte_small:
49#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
50        AP = pte_pte_small_ptr_get_HAP(pte);
51        TEX = pte_pte_small_ptr_get_MemAttr(pte);
52#else
53        AP = pte_pte_small_ptr_get_AP(pte);
54        TEX = pte_pte_small_ptr_get_TEX(pte);
55#endif
56        XN = pte_pte_small_ptr_get_XN(pte);
57        break;
58
59#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
60    case pte_pte_large:
61        AP = pte_pte_large_ptr_get_AP(pte);
62        TEX = pte_pte_large_ptr_get_TEX(pte);
63        XN = pte_pte_large_ptr_get_XN(pte);
64        break;
65#endif
66    default:
67        assert(!"should not happend");
68    }
69    cap_frame_print_attrs_impl(AP, XN, TEX);
70}
71
72static void cap_frame_print_attrs_pd(pde_t *pde)
73{
74#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
75    cap_frame_print_attrs_impl(pde_pde_section_ptr_get_HAP(pde),
76                               pde_pde_section_ptr_get_XN(pde),
77                               pde_pde_section_ptr_get_MemAttr(pde));
78#else
79    cap_frame_print_attrs_impl(pde_pde_section_ptr_get_AP(pde),
80                               pde_pde_section_ptr_get_XN(pde),
81                               pde_pde_section_ptr_get_TEX(pde));
82#endif
83}
84
85static void cap_frame_print_attrs_impl(word_t AP, word_t XN, word_t TEX)
86{
87    printf("(");
88
89    /* rights */
90    switch (AP) {
91    case 0b00:
92    case 0b01:
93        break;
94    case 0b10:
95        printf("R");
96        break;
97    case 0b11:
98        printf("RW");
99    default:
100        break;
101    }
102
103    if (!XN) {
104        printf("X");
105    }
106
107    if (!TEX) {
108        printf(", uncached");
109    }
110
111    printf(")\n");
112}
113
114static void arm32_cap_pt_print_slots(pte_t *pt)
115{
116    vm_page_size_t page_size;
117    word_t i = 0;
118    while (i < BIT(PT_INDEX_BITS + PAGE_BITS)) {
119        pte_t *pte = lookupPTSlot_nofail(pt, i);
120        switch (pte_ptr_get_pteType(pte)) {
121        case pte_pte_small: {
122#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
123            if (pte_pte_small_ptr_get_contiguous_hint(pte)) {
124                page_size = ARMLargePage;
125            } else {
126                page_size = ARMSmallPage;
127            }
128#else
129            page_size = ARMSmallPage;
130#endif
131            printf("0x%lx: frame_%p_%04lu ", PT_INDEX(i), pte, PT_INDEX(i));
132            cap_frame_print_attrs_pt(pte);
133            break;
134        }
135#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
136        case pte_pte_large: {
137            page_size = ARMLargePage;
138            printf("0x%lx: frame_%p_%04lu ", PT_INDEX(i), pte, PT_INDEX(i));
139            cap_frame_print_attrs_pt(pte);
140            break;
141        }
142#endif
143        default:
144            page_size = ARMSmallPage;
145        }
146        i += (1 << pageBitsForSize(page_size));
147    }
148}
149
150void obj_vtable_print_slots(tcb_t *tcb)
151{
152    if (isValidVTableRoot(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap) && !seen(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap)) {
153        add_to_seen(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
154        pde_t *pd = (pde_t *)pptr_of_cap(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
155        vm_page_size_t page_size;
156        printf("%p_pd {\n", pd);
157
158        /* PD_INDEX_BITS + ARMSectionBits = 32, can't use left shift here */
159        word_t i = 0;
160        while (i < MAX_UL) {
161            pde_t *pde = lookupPDSlot(pd, i);
162            switch (pde_ptr_get_pdeType(pde)) {
163            case pde_pde_section: {
164#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
165                if (pde_pde_section_ptr_get_size(pde)) {
166                    page_size = ARMSuperSection;
167                } else {
168                    page_size = ARMSection;
169                }
170#else
171                if (pde_pde_section_ptr_get_contiguous_hint(pde)) {
172                    page_size = ARMSuperSection;
173                } else {
174                    page_size = ARMSection;
175                }
176#endif
177                printf("0x%lx: frame_%p_%04lu ", PD_INDEX(i), pde, PD_INDEX(i));
178                cap_frame_print_attrs_pd(pde);
179                break;
180            }
181
182            case pde_pde_coarse: {
183                printf("0x%lx: pt_%p_%04lu\n", PD_INDEX(i), pde, PD_INDEX(i));
184                page_size = ARMSection;
185                break;
186            }
187            default:
188                page_size = ARMSection;
189                break;
190            }
191            i += (1 << pageBitsForSize(page_size));
192            if (i < (1 << pageBitsForSize(page_size))) {
193                break; /* overflowed */
194            }
195        }
196        printf("}\n"); /* pd */
197
198        i = 0;
199        /* PD_INDEX_BITS + ARMSectionBits = 32, can't use left shift here */
200        while (i < MAX_UL) {
201            pde_t *pde = lookupPDSlot(pd, i);
202            if (pde_ptr_get_pdeType(pde) == pde_pde_coarse) {
203                pte_t *pt = ptrFromPAddr(pde_pde_coarse_ptr_get_address(pde));
204                printf("pt_%p_%04lu {\n", pde, PD_INDEX(i));
205                arm32_cap_pt_print_slots(pt);
206                printf("}\n"); /* pt */
207            }
208            i += (1 << pageBitsForSize(ARMSection));
209            if (i < (1 << pageBitsForSize(ARMSection))) {
210                break; /* overflowed */
211            }
212        }
213    }
214}
215
216/* use when only have access to vptr of frames */
217static void cap_frame_print_attrs_vptr(word_t vptr, pde_t *pd)
218{
219    pde_t *pde = lookupPDSlot(pd, vptr);
220
221    switch (pde_ptr_get_pdeType(pde)) {
222    case pde_pde_section: {
223        printf("frame_%p_%04lu ", pde, PD_INDEX(vptr));
224        cap_frame_print_attrs_pd(pde);
225        break;
226    }
227    case pde_pde_coarse: {
228        pte_t *pt = ptrFromPAddr(pde_pde_coarse_ptr_get_address(pde));
229        pte_t *pte = lookupPTSlot_nofail(pt, vptr);
230        switch (pte_ptr_get_pteType(pte)) {
231        case pte_pte_small: {
232            printf("frame_%p_%04lu ", pte, PT_INDEX(vptr));
233            cap_frame_print_attrs_pt(pte);
234            break;
235        }
236
237#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
238        case pte_pte_large: {
239            printf("frame_%p_%04lu ", pte, PT_INDEX(vptr));
240            cap_frame_print_attrs_pt(pte);
241            break;
242        }
243#endif
244        default:
245            assert(0);
246        }
247        break;
248    }
249    default:
250        assert(0);
251    }
252}
253
254void print_ipc_buffer_slot(tcb_t *tcb)
255{
256    word_t vptr = tcb->tcbIPCBuffer;
257    asid_t asid = cap_page_directory_cap_get_capPDMappedASID(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
258    findPDForASID_ret_t find_ret = findPDForASID(asid);
259    printf("ipc_buffer_slot: ");
260    cap_frame_print_attrs_vptr(vptr, find_ret.pd);
261}
262
263void print_cap_arch(cap_t cap)
264{
265    switch (cap_get_capType(cap)) {
266    case cap_page_table_cap: {
267        asid_t asid = cap_page_table_cap_get_capPTMappedASID(cap);
268        findPDForASID_ret_t find_ret = findPDForASID(asid);
269        vptr_t vptr = cap_page_table_cap_get_capPTMappedAddress(cap);
270        if (asid) {
271            printf("pt_%p_%04lu (asid: %lu)\n",
272                   lookupPDSlot(find_ret.pd, vptr), PD_INDEX(vptr), (long unsigned int)asid);
273        } else {
274            printf("pt_%p_%04lu\n", lookupPDSlot(find_ret.pd, vptr), PD_INDEX(vptr));
275        }
276        break;
277    }
278    case cap_page_directory_cap: {
279        asid_t asid = cap_page_directory_cap_get_capPDMappedASID(cap);
280        findPDForASID_ret_t find_ret = findPDForASID(asid);
281        if (asid) {
282            printf("%p_pd (asid: %lu)\n",
283                   find_ret.pd, (long unsigned int)asid);
284        } else {
285            printf("%p_pd\n", find_ret.pd);
286        }
287        break;
288    }
289    case cap_asid_control_cap: {
290        /* only one in the system */
291        printf("asid_control\n");
292        break;
293    }
294    case cap_small_frame_cap: {
295        vptr_t vptr = cap_small_frame_cap_get_capFMappedAddress(cap);
296        findPDForASID_ret_t find_ret = findPDForASID(cap_small_frame_cap_get_capFMappedASID(cap));
297        assert(find_ret.status == EXCEPTION_NONE);
298        cap_frame_print_attrs_vptr(vptr, find_ret.pd);
299        break;
300    }
301    case cap_frame_cap: {
302        vptr_t vptr = cap_frame_cap_get_capFMappedAddress(cap);
303        findPDForASID_ret_t find_ret = findPDForASID(cap_frame_cap_get_capFMappedASID(cap));
304        assert(find_ret.status == EXCEPTION_NONE);
305        cap_frame_print_attrs_vptr(vptr, find_ret.pd);
306        break;
307    }
308    case cap_asid_pool_cap: {
309        printf("%p_asid_pool\n", (void *)cap_asid_pool_cap_get_capASIDPool(cap));
310        break;
311    }
312#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
313    case cap_vcpu_cap: {
314        printf("%p_vcpu\n", (void *)cap_vcpu_cap_get_capVCPUPtr(cap));
315        break;
316    }
317#endif
318
319        /* ARM specific caps */
320#ifdef CONFIG_TK1_SMMU
321    case cap_io_space_cap: {
322        printf("%p_io_space\n", (void *)cap_io_space_cap_get_capModuleID(cap));
323        break;
324    }
325#endif
326    default: {
327        printf("[unknown cap %u]\n", cap_get_capType(cap));
328        break;
329    }
330    }
331}
332
333void print_object_arch(cap_t cap)
334{
335
336    switch (cap_get_capType(cap)) {
337    case cap_frame_cap:
338    case cap_small_frame_cap:
339    case cap_page_table_cap:
340    case cap_page_directory_cap:
341        /* don't need to deal with these objects since they get handled from vtable */
342        break;
343
344    case cap_asid_pool_cap: {
345        printf("%p_asid_pool = asid_pool ",
346               (void *)cap_asid_pool_cap_get_capASIDPool(cap));
347        obj_asidpool_print_attrs(cap);
348        break;
349    }
350#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
351    case cap_vcpu_cap: {
352        printf("%p_vcpu = vcpu\n", (void *)cap_vcpu_cap_get_capVCPUPtr(cap));
353        break;
354    }
355#endif
356        /* ARM specific objects */
357#ifdef CONFIG_TK1_SMMU
358    case cap_io_space_cap: {
359        printf("%p_io_space = io_space ", (void *)cap_io_space_cap_get_capModuleID(cap));
360        arm_obj_iospace_print_attrs(cap);
361        break;
362    }
363#endif
364    default: {
365        printf("[unknown object %u]\n", cap_get_capType(cap));
366        break;
367    }
368    }
369}
370
371static void obj_frame_print_attrs(resolve_ret_t ret)
372{
373    printf("(");
374
375    /* VM size */
376    switch (ret.frameSize) {
377#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
378    case ARMSection:
379        printf("2M");
380        break;
381    case ARMSuperSection:
382        printf("32M");
383        break;
384#else
385    case ARMSection:
386        printf("1M");
387        break;
388    case ARMSuperSection:
389        printf("16M");
390        break;
391#endif
392    case ARMLargePage:
393        printf("64k");
394        break;
395    case ARMSmallPage:
396        printf("4k");
397        break;
398    }
399
400    printf(", paddr: %p)\n", (void *)ret.frameBase);
401}
402
403static void arm32_obj_pt_print_slots(pte_t *pt)
404{
405    resolve_ret_t ret;
406    word_t i = 0;
407    while (i < BIT(PT_INDEX_BITS + PAGE_BITS)) {
408        pte_t *pte = lookupPTSlot_nofail(pt, i);
409        switch (pte_ptr_get_pteType(pte)) {
410        case pte_pte_small: {
411            ret.frameBase = pte_pte_small_ptr_get_address(pte);
412#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
413            if (pte_pte_small_ptr_get_contiguous_hint(pte)) {
414                /* Entries are represented as 16 contiguous small frames. We need to mask
415                   to get the large frame base */
416                ret.frameBase &= ~MASK(pageBitsForSize(ARMLargePage));
417                ret.frameSize = ARMLargePage;
418            } else {
419                ret.frameSize = ARMSmallPage;
420            }
421#else
422            ret.frameSize = ARMSmallPage;
423#endif
424            printf("frame_%p_%04lu = frame ", pte, PT_INDEX(i));
425            obj_frame_print_attrs(ret);
426            break;
427        }
428#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
429        case pte_pte_large: {
430            ret.frameBase = pte_pte_large_ptr_get_address(pte);
431            ret.frameSize = ARMLargePage;
432            printf("frame_%p_%04lu = frame ", pte, PT_INDEX(i));
433            obj_frame_print_attrs(ret);
434            break;
435        }
436#endif
437        default:
438            ret.frameSize = ARMSmallPage;
439        }
440        i += (1 << pageBitsForSize(ret.frameSize));
441    }
442}
443
444void obj_tcb_print_vtable(tcb_t *tcb)
445{
446    if (isValidVTableRoot(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap) && !seen(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap)) {
447        add_to_seen(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
448        pde_t *pd = (pde_t *)pptr_of_cap(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap);
449        resolve_ret_t ret = {};
450        printf("%p_pd = pd\n", pd);
451
452        /* PD_INDEX_BITS + ARMSectionBits = 32, can't use left shift here */
453        word_t i = 0;
454        while (i < MAX_UL) {
455            pde_t *pde = lookupPDSlot(pd, i);
456            switch (pde_ptr_get_pdeType(pde)) {
457            case pde_pde_section: {
458                ret.frameBase = pde_pde_section_ptr_get_address(pde);
459#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
460                if (pde_pde_section_ptr_get_size(pde)) {
461                    ret.frameSize = ARMSuperSection;
462                } else {
463                    ret.frameSize = ARMSection;
464                }
465#else
466                if (pde_pde_section_ptr_get_contiguous_hint(pde)) {
467                    /* Entires are represented as 16 contiguous sections. We need to mask
468                    to get the super section frame base */
469                    ret.frameBase &= ~MASK(pageBitsForSize(ARMSuperSection));
470                    ret.frameSize = ARMSuperSection;
471                } else {
472                    ret.frameSize = ARMSection;
473                }
474#endif
475                printf("frame_%p_%04lu = frame ", pde, PD_INDEX(i));
476                obj_frame_print_attrs(ret);
477                break;
478            }
479
480            case pde_pde_coarse: {
481                pte_t *pt = ptrFromPAddr(pde_pde_coarse_ptr_get_address(pde));
482                printf("pt_%p_%04lu = pt\n", pde, PD_INDEX(i));
483                arm32_obj_pt_print_slots(pt);
484                ret.frameSize = ARMSection;
485                break;
486            }
487            default:
488                ret.frameSize = ARMSection;
489                break;
490            }
491            i += (1 << pageBitsForSize(ret.frameSize));
492            if (i < (1 << pageBitsForSize(ret.frameSize))) {
493                break; /* overflowed */
494            }
495        }
496    }
497}
498
499void capDL(void)
500{
501    printf("arch aarch32\n");
502    printf("objects {\n");
503    print_objects();
504    printf("}\n");
505
506    printf("caps {\n");
507
508    /* reset the seen list */
509    reset_seen_list();
510
511    print_caps();
512    printf("}\n");
513
514    obj_irq_print_maps();
515}
516
517#endif /* CONFIG_DEBUG_BUILD */
518