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