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