1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <machine/capdl.h>
8#include <machine/registerset.h>
9#include <machine/timer.h>
10#include <config.h>
11#include <string.h>
12#include <kernel/cspace.h>
13#ifdef CONFIG_KERNEL_MCS
14#include <kernel/sporadic.h>
15#endif
16
17#ifdef CONFIG_DEBUG_BUILD
18
19#define SEEN_SZ 256
20
21/* seen list - check this array before we print cnode and vspace */
22/* TBD: This is to avoid traversing the same cnode. It should be applied to object
23 * as well since the extractor might comes across multiple caps to the same object.
24 */
25cap_t seen_list[SEEN_SZ];
26int watermark = 0;
27
28void add_to_seen(cap_t c)
29{
30    /* Won't work well if there're more than SEEN_SZ cnode */
31    if (watermark <= SEEN_SZ) {
32        seen_list[watermark] = c;
33        watermark++;
34    }
35}
36
37void reset_seen_list(void)
38{
39    memset(seen_list, 0, SEEN_SZ * sizeof(seen_list[0]));
40    watermark = 0;
41}
42
43bool_t seen(cap_t c)
44{
45    for (int i = 0; i < watermark; i++) {
46        if (same_cap(seen_list[i], c)) {
47            return true;
48        }
49    }
50    return false;
51}
52
53bool_t same_cap(cap_t a, cap_t b)
54{
55    return (a.words[0] == b.words[0] && a.words[1] == b.words[1]);
56}
57
58/* Return true if strings are the same */
59static inline bool_t strings_equal(const char *str1, const char *str2)
60{
61    while (*str1 && *str2 && (*str1 == *str2)) {
62        str1++;
63        str2++;
64    }
65    return !(*(const unsigned char *)str1 - * (const unsigned char *)str2);
66}
67
68/* Return true if the tcb is for rootserver or idle thread */
69bool_t root_or_idle_tcb(tcb_t *tcb)
70{
71    return (strings_equal(TCB_PTR_DEBUG_PTR(tcb)->tcbName, "rootserver")
72            || strings_equal(TCB_PTR_DEBUG_PTR(tcb)->tcbName, "idle_thread"));
73}
74
75/*
76 * Print objects
77 */
78
79void obj_tcb_print_attrs(tcb_t *tcb)
80{
81    printf("(addr: 0x%lx, ip: 0x%lx, sp: 0x%lx, prio: %lu, max_prio: %lu",
82           (long unsigned int)tcb->tcbIPCBuffer,
83           (long unsigned int)getRestartPC(tcb),
84           (long unsigned int)get_tcb_sp(tcb),
85           (long unsigned int)tcb->tcbPriority,
86           (long unsigned int)tcb->tcbMCP);
87
88#ifdef ENABLE_SMP_SUPPORT
89    printf(", affinity: %lu", (long unsigned int)tcb->tcbAffinity);
90#endif /* ENABLE_SMP_SUPPORT */
91
92    /* init */
93
94#ifdef CONFIG_KERNEL_MCS
95    cap_t ep_cap = TCB_PTR_CTE_PTR(tcb, tcbFaultHandler)->cap;
96    if (cap_get_capType(ep_cap) != cap_null_cap) {
97        printf(", fault_ep: %p", EP_PTR(cap_endpoint_cap_get_capEPPtr(ep_cap)));
98    }
99#endif
100
101    printf(", dom: %ld)\n", tcb->tcbDomain);
102}
103
104#ifdef CONFIG_KERNEL_MCS
105
106/* to make compilers happy */
107#define REFILL_INDEX(sc, index) (((refill_t *) (SC_REF(sc) + sizeof(sched_context_t)))[index])
108#define REFILL_HEAD(sc) REFILL_INDEX((sc), (sc)->scRefillHead)
109
110static inline ticks_t sc_get_budget(sched_context_t *sc)
111{
112    ticks_t sum = REFILL_HEAD(sc).rAmount;
113    word_t current = sc->scRefillHead;
114
115    while (current != sc->scRefillTail) {
116        current = ((current == sc->scRefillMax - 1u) ? (0) : current + 1u);
117        sum += REFILL_INDEX(sc, current).rAmount;
118    }
119
120    return sum;
121}
122
123void obj_sc_print_attrs(cap_t sc_cap)
124{
125    sched_context_t *sc = SC_PTR(cap_sched_context_cap_get_capSCPtr(sc_cap));
126    printf("(period: %lu, budget: %lu, %lu bits)\n",
127           (long unsigned int)ticksToUs(sc->scPeriod),
128           (long unsigned int)ticksToUs(sc_get_budget(sc)),
129           (word_t)cap_sched_context_cap_get_capSCSizeBits(sc_cap)
130          );
131}
132#endif /* CONFIG_KERNEL_MCS */
133
134void obj_ut_print_attrs(cte_t *slot, tcb_t *tcb)
135{
136    /* might have two untypeds with the same address but different size */
137    printf("%p_%lu_untyped = ut (%lu bits, paddr: %p) {",
138           (void *)cap_untyped_cap_get_capPtr(slot->cap),
139           (long unsigned int)cap_untyped_cap_get_capBlockSize(slot->cap),
140           (long unsigned int)cap_untyped_cap_get_capBlockSize(slot->cap),
141           WORD_PTR(cap_untyped_cap_get_capPtr(slot->cap)));
142
143    /* there is no need to check for a NullCap as NullCaps are
144    always accompanied by null mdb pointers */
145    for (cte_t *nextPtr = CTE_PTR(mdb_node_get_mdbNext(slot->cteMDBNode));
146         nextPtr && isMDBParentOf(slot, nextPtr);
147         nextPtr = CTE_PTR(mdb_node_get_mdbNext(slot->cteMDBNode))) {
148        if (!sameRegionAs(slot->cap, nextPtr->cap)) {
149            /* TBD:
150             * - this will print out the attributes of the cap, which it shouldn't
151             *
152             * - might be a pathological case where an untyped has a child cap that
153             *   isn't reachable from any of the non root threads. This would result
154             *   in an object being mentioned but never properly defined
155             */
156            print_cap(nextPtr->cap);
157        }
158    }
159    printf("}\n");
160}
161
162void obj_cnode_print_attrs(cap_t cnode)
163{
164    printf("(%lu bits)\n", (long unsigned int)cap_cnode_cap_get_capCNodeRadix(cnode));
165}
166
167void obj_tcb_print_cnodes(cap_t cnode, tcb_t *tcb)
168{
169    if (seen(cnode)) {
170        return;
171    }
172    add_to_seen(cnode);
173    printf("%p_cnode = cnode ", (void *)cap_cnode_cap_get_capCNodePtr(cnode));
174    obj_cnode_print_attrs(cnode);
175    word_t radix = cap_cnode_cap_get_capCNodeRadix(cnode);
176
177    for (uint32_t i = 0; i < (1 << radix); i++) {
178        lookupCapAndSlot_ret_t c = lookupCapAndSlot(tcb, i);
179        if (cap_get_capType(c.cap) == cap_untyped_cap) {
180            /* we need `cte_t *` to print out the slots of an untyped object */
181            obj_ut_print_attrs(c.slot, tcb);
182
183        } else if (cap_get_capType(c.cap) == cap_cnode_cap) {
184            /* TBD: deal with nested cnodes */
185
186        } else if (cap_get_capType(c.cap) != cap_null_cap) {
187            print_object(c.cap);
188        }
189    }
190}
191
192/*
193 * Caps
194 */
195
196void cap_cnode_print_attrs(cap_t cnode)
197{
198    printf("(guard: %lu, guard_size: %lu)\n",
199           (long unsigned int)cap_cnode_cap_get_capCNodeGuard(cnode),
200           (long unsigned int)cap_cnode_cap_get_capCNodeGuardSize(cnode));
201}
202
203void cap_ep_print_attrs(cap_t ep)
204{
205    printf("(");
206    cap_endpoint_cap_get_capCanReceive(ep) ? putchar('R') : 0;
207    cap_endpoint_cap_get_capCanSend(ep) ? putchar('W') : 0;
208    cap_endpoint_cap_get_capCanGrant(ep) ? putchar('G') : 0;
209    cap_endpoint_cap_get_capCanGrantReply(ep) ? putchar('P') : 0;
210    long unsigned int badge = cap_endpoint_cap_get_capEPBadge(ep);
211    badge ? printf(", badge: %lu)\n", badge) : printf(")\n");
212}
213
214void cap_ntfn_print_attrs(cap_t ntfn)
215{
216    printf("(");
217    cap_notification_cap_get_capNtfnCanReceive(ntfn) ? putchar('R') : 0;
218    cap_notification_cap_get_capNtfnCanSend(ntfn) ? putchar('W') : 0;
219    long unsigned int badge = cap_notification_cap_get_capNtfnBadge(ntfn);
220    badge ? printf(", badge: %lu)\n", badge) : printf(")\n");
221}
222
223/*
224 * print object slots
225 */
226
227void obj_tcb_print_slots(tcb_t *tcb)
228{
229    printf("%p_tcb {\n", tcb);
230
231    /* CSpace root */
232    if (cap_get_capType(TCB_PTR_CTE_PTR(tcb, tcbCTable)->cap) != cap_null_cap) {
233        printf("cspace: %p_cnode ",
234               (void *)cap_cnode_cap_get_capCNodePtr(TCB_PTR_CTE_PTR(tcb, tcbCTable)->cap));
235        cap_cnode_print_attrs(TCB_PTR_CTE_PTR(tcb, tcbCTable)->cap);
236    }
237
238    /* VSpace root */
239    if (cap_get_capType(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap) != cap_null_cap) {
240        printf("vspace: %p_pd\n",
241               cap_vtable_cap_get_vspace_root_fp(TCB_PTR_CTE_PTR(tcb, tcbVTable)->cap));
242
243    }
244
245    /* IPC buffer cap slot */
246    if (cap_get_capType(TCB_PTR_CTE_PTR(tcb, tcbBuffer)->cap) != cap_null_cap) {
247        /* TBD: print out the bound vcpu */
248        print_ipc_buffer_slot(tcb);
249    }
250
251#ifdef CONFIG_KERNEL_MCS
252
253    /* Fault endpoint slot */
254    if (cap_get_capType(TCB_PTR_CTE_PTR(tcb, tcbFaultHandler)->cap) != cap_null_cap) {
255        printf("fault_ep_slot: %p_ep ",
256               (void *)cap_endpoint_cap_get_capEPPtr(TCB_PTR_CTE_PTR(tcb, tcbFaultHandler)->cap));
257        cap_ep_print_attrs(TCB_PTR_CTE_PTR(tcb, tcbFaultHandler)->cap);
258    }
259
260    /* sc */
261    if (tcb->tcbSchedContext) {
262        printf("sc_slot: %p_sc\n", tcb->tcbSchedContext);
263    }
264
265    /* Timeout endpoint slot */
266    if (cap_get_capType(TCB_PTR_CTE_PTR(tcb, tcbTimeoutHandler)->cap) != cap_null_cap) {
267        printf("temp_fault_ep_slot: %p_ep ",
268               (void *)cap_endpoint_cap_get_capEPPtr(TCB_PTR_CTE_PTR(tcb, tcbTimeoutHandler)->cap));
269        cap_ep_print_attrs(TCB_PTR_CTE_PTR(tcb, tcbTimeoutHandler)->cap);
270    }
271
272# else
273    /* Reply cap slot */
274    if (cap_get_capType(TCB_PTR_CTE_PTR(tcb, tcbReply)->cap) != cap_null_cap) {
275        printf("reply_slot: %p_reply\n",
276               (void *)cap_reply_cap_get_capTCBPtr(TCB_PTR_CTE_PTR(tcb, tcbReply)->cap));
277    }
278
279    /* TCB of most recent IPC sender */
280    if (cap_get_capType(TCB_PTR_CTE_PTR(tcb, tcbCaller)->cap) != cap_null_cap) {
281        tcb_t *caller = TCB_PTR(cap_thread_cap_get_capTCBPtr(TCB_PTR_CTE_PTR(tcb, tcbCaller)->cap));
282        printf("caller_slot: %p_tcb\n", caller);
283    }
284#endif /* CONFIG_KERNEL_MCS */
285    printf("}\n");
286}
287
288/* TBD: deal with nested cnodes */
289void obj_cnode_print_slots(tcb_t *tcb)
290{
291    cap_t root = TCB_PTR_CTE_PTR(tcb, tcbCTable)->cap;
292    if (cap_get_capType(root) != cap_cnode_cap) {
293        return;
294    }
295
296    word_t radix = cap_cnode_cap_get_capCNodeRadix(root);
297    if (seen(root)) {
298        return;
299    }
300    add_to_seen(root);
301
302    printf("%p_cnode {\n", (void *)cap_cnode_cap_get_capCNodePtr(root));
303
304    for (uint32_t i = 0; i < (1 << radix); i++) {
305        lookupCapAndSlot_ret_t c = lookupCapAndSlot(tcb, i);
306        if (cap_get_capType(c.cap) != cap_null_cap) {
307            printf("0x%x: ", i);
308            print_cap(c.cap);
309        }
310    }
311    printf("}\n");
312
313    for (uint32_t i = 0; i < (1 << radix); i++) {
314        lookupCapAndSlot_ret_t c = lookupCapAndSlot(tcb, i);
315        if (cap_get_capType(c.cap) == cap_irq_handler_cap) {
316            /* TBD: should instead print it from IRQNode */
317            obj_irq_print_slots(c.cap);
318        }
319    }
320}
321
322void obj_irq_print_maps(void)
323{
324    printf("irq maps {\n");
325
326    for (seL4_Word target = 0; target < CONFIG_MAX_NUM_NODES; target++) {
327        for (unsigned i = 0; i <= maxIRQ; i++) {
328            irq_t irq = CORE_IRQ_TO_IRQT(target, i);
329            if (isIRQActive(irq)) {
330                cap_t cap = intStateIRQNode[IRQT_TO_IDX(irq)].cap;
331                if (cap_get_capType(cap) != cap_null_cap) {
332                    printf("%d: 0x%lx_%lu_irq\n",
333                           i,
334#if defined(ENABLE_SMP_SUPPORT) && defined(CONFIG_ARCH_ARM)
335                           (long unsigned int)irq.irq,
336#else
337                           (long unsigned int)irq,
338#endif
339                           (long unsigned int)target);
340                }
341            }
342        }
343    }
344    printf("}\n");
345}
346
347void obj_irq_print_slots(cap_t irq_cap)
348{
349    irq_t irq = IDX_TO_IRQT(cap_irq_handler_cap_get_capIRQ(irq_cap));
350    if (isIRQActive(irq)) {
351        printf("0x%lx_%lu_irq {\n",
352#if defined(ENABLE_SMP_SUPPORT) && defined(CONFIG_ARCH_ARM)
353               (long unsigned int)irq.irq,
354#else
355               (long unsigned int)irq,
356#endif
357               (long unsigned int)IRQT_TO_CORE(irq));
358        cap_t ntfn_cap = intStateIRQNode[IRQT_TO_IDX(irq)].cap;
359        if (cap_get_capType(ntfn_cap) != cap_null_cap) {
360            printf("0x0: ");
361            print_cap(ntfn_cap);
362        }
363        printf("}\n");
364    }
365}
366
367void print_objects(void)
368{
369    for (tcb_t *curr = NODE_STATE(ksDebugTCBs); curr != NULL; curr = TCB_PTR_DEBUG_PTR(curr)->tcbDebugNext) {
370        if (root_or_idle_tcb(curr)) {
371            continue;
372        }
373        /* print the contains of the tcb's vtable as objects */
374        obj_tcb_print_vtable(curr);
375    }
376
377    for (tcb_t *curr = NODE_STATE(ksDebugTCBs); curr != NULL; curr = TCB_PTR_DEBUG_PTR(curr)->tcbDebugNext) {
378        if (root_or_idle_tcb(curr)) {
379            continue;
380        }
381
382        /* print the tcb as objects */
383        printf("%p_tcb = tcb ", curr);
384        obj_tcb_print_attrs(curr);
385
386        /* print the contains of the tcb's ctable as objects */
387        if (cap_get_capType(TCB_PTR_CTE_PTR(curr, tcbCTable)->cap) == cap_cnode_cap) {
388            obj_tcb_print_cnodes(TCB_PTR_CTE_PTR(curr, tcbCTable)->cap, curr);
389        }
390    }
391}
392
393void print_caps(void)
394{
395    for (tcb_t *curr = NODE_STATE(ksDebugTCBs); curr != NULL; curr = TCB_PTR_DEBUG_PTR(curr)->tcbDebugNext) {
396        if (root_or_idle_tcb(curr)) {
397            continue;
398        }
399        obj_cnode_print_slots(curr);
400        obj_vtable_print_slots(curr);
401        obj_tcb_print_slots(curr);
402    }
403}
404
405void print_cap(cap_t cap)
406{
407    switch (cap_get_capType(cap)) {
408    case cap_endpoint_cap: {
409        printf("%p_ep ",
410               (void *)cap_endpoint_cap_get_capEPPtr(cap));
411        cap_ep_print_attrs(cap);
412        break;
413    }
414    case cap_notification_cap: {
415        printf("%p_notification ",
416               (void *)cap_notification_cap_get_capNtfnPtr(cap));
417        cap_ntfn_print_attrs(cap);
418        break;
419    }
420    case cap_untyped_cap: {
421        printf("%p_untyped\n",
422               (void *)cap_untyped_cap_get_capPtr(cap));
423        break;
424    }
425    case cap_thread_cap: {
426        printf("%p_tcb\n",
427               (void *)cap_thread_cap_get_capTCBPtr(cap));
428        break;
429    }
430    case cap_cnode_cap: {
431        printf("%p_cnode ",
432               (void *)cap_cnode_cap_get_capCNodePtr(cap));
433        cap_cnode_print_attrs(cap);
434        break;
435    }
436#ifdef CONFIG_KERNEL_MCS
437    case cap_reply_cap: {
438        printf("%p_reply\n",
439               (void *)cap_reply_cap_get_capReplyPtr(cap));
440        break;
441    }
442    case cap_sched_context_cap: {
443        printf("%p_sc\n",
444               (void *)cap_sched_context_cap_get_capSCPtr(cap));
445        break;
446    }
447    case cap_sched_control_cap: {
448        printf("%lu_sched_control\n",
449               (long unsigned int)cap_sched_control_cap_get_core(cap));
450        break;
451    }
452#endif
453    case cap_irq_control_cap: {
454        printf("irq_control\n"); /* only one in the system */
455        break;
456    }
457    case cap_irq_handler_cap: {
458        printf("%p_%lu_irq\n",
459               (void *)cap_irq_handler_cap_get_capIRQ(cap),
460               (long unsigned int)IRQT_TO_CORE(IDX_TO_IRQT(cap_irq_handler_cap_get_capIRQ(cap))));
461        break;
462    }
463    default: {
464        print_cap_arch(cap);
465        break;
466    }
467    }
468}
469
470void print_object(cap_t cap)
471{
472    switch (cap_get_capType(cap)) {
473    case cap_endpoint_cap: {
474        printf("%p_ep = ep\n",
475               (void *)cap_endpoint_cap_get_capEPPtr(cap));
476        break;
477    }
478    case cap_notification_cap: {
479        printf("%p_notification = notification\n",
480               (void *)cap_notification_cap_get_capNtfnPtr(cap));
481        break;
482    }
483    case cap_thread_cap: {
484        /* this object has already got handle by `print_objects` */
485        break;
486    }
487    case cap_cnode_cap: {
488        assert(!"should not happend");
489    }
490#ifdef CONFIG_KERNEL_MCS
491    case cap_reply_cap: {
492        printf("%p_reply = rtreply\n",
493               (void *)cap_reply_cap_get_capReplyPtr(cap));
494        break;
495    }
496    case cap_sched_context_cap: {
497        printf("%p_sc = sc ",
498               (void *)cap_sched_context_cap_get_capSCPtr(cap));
499        obj_sc_print_attrs(cap);
500        break;
501    }
502#endif
503    case cap_irq_handler_cap: {
504        printf("%p_%lu_irq = irq\n",
505               (void *)cap_irq_handler_cap_get_capIRQ(cap),
506               (long unsigned int)IRQT_TO_CORE(IDX_TO_IRQT(cap_irq_handler_cap_get_capIRQ(cap))));
507        break;
508    }
509    default:
510        print_object_arch(cap);
511        break;
512    }
513}
514
515#endif
516