The seL4 microkernel https://sel4.systems/

gdb-macros 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. #
  2. # Copyright 2014, General Dynamics C4 Systems
  3. #
  4. # This software may be distributed and modified according to the terms of
  5. # the GNU General Public License version 2. Note that NO WARRANTY is provided.
  6. # See "LICENSE_GPLv2.txt" for details.
  7. #
  8. # @TAG(GD_GPL)
  9. #
  10. #GDB macros for displaying seL4 data structures. Currently a work in progress.
  11. #TODO: macros for examining an address space
  12. set print pretty on
  13. define sel4
  14. end
  15. document sel4
  16. This is a set of macros to interpret sel4 data structures. Available commands:
  17. runqueues
  18. currthread
  19. sched_action
  20. current_lookup_fault
  21. current_fault
  22. current_syscall_error
  23. resolve_cap
  24. resolve_cap_current
  25. currthread_cnode
  26. disp_cap
  27. disp_ep
  28. disp_ep_queue
  29. dump_cnode
  30. dump_currthread_cnode
  31. get_thread_vspace
  32. get_thread_cspace
  33. get_thread_reply_slot
  34. get_thread_most_recent_ipc_sender
  35. get_thread_ipc_buffer
  36. dump_thread_info
  37. Type help <command> for more information on a specific command
  38. end
  39. define runqueues
  40. set $found=0
  41. while($found<255)
  42. set $queue = ksReadyQueues[$found]
  43. if($queue.head != 0x0)
  44. set $current = $queue.head
  45. while($current != $queue->end)
  46. print *$current
  47. set $current = $current->tcbSchedNext
  48. end
  49. print *$current
  50. end
  51. set $found++
  52. end
  53. end
  54. document runqueues
  55. Print TCBs of all runnable threads
  56. end
  57. define runqueues_c
  58. set $found=0
  59. while($found<255)
  60. set $queue = ksReadyQueues[$found]
  61. if($queue.head != 0x0)
  62. set $current = $queue.head
  63. while($current != $queue->end)
  64. print_condensed_tcb $current
  65. set $current = $current->tcbSchedNext
  66. end
  67. print_condensed_tcb $current
  68. end
  69. set $found++
  70. end
  71. end
  72. define print_condensed_tcb
  73. printf "%d\n", $arg0->tcbPriority
  74. end
  75. define currthread
  76. print *ksCurThread
  77. end
  78. document currthread
  79. Print TCB of current thread
  80. end
  81. define sched_action
  82. if(ksSchedulerAction == 0x0)
  83. printf "ResumeCurrentThread\n"
  84. else
  85. if (ksSchedulerAction == ~0x0)
  86. printf "ChooseNewThread\n"
  87. else
  88. printf "SwitchToThread:\n"
  89. print *ksSchedulerAction
  90. end
  91. end
  92. end
  93. document sched_action
  94. Print the next scheduler action
  95. end
  96. define current_lookup_fault
  97. #print current_lookup_fault
  98. if((current_lookup_fault.words[0] & 0x3)==lookup_fault_invalid_root)
  99. printf "invalid root\n"
  100. else
  101. if((current_lookup_fault.words[0] & 0x3)==lookup_fault_missing_capability)
  102. printf "missing capability\n"
  103. else
  104. if ((current_lookup_fault.words[0] & 0x3)==lookup_fault_depth_mismatch)
  105. printf "depth mismatch\n"
  106. else
  107. if((current_lookup_fault.words[0] & 0x3)==lookup_fault_guard_mismatch)
  108. printf "guard mismatch\n"
  109. else
  110. printf "unknown lookup fault\n"
  111. end
  112. end
  113. end
  114. end
  115. end
  116. document current_lookup_fault
  117. Decodes the current_lookup_fault variable to determine what went wrong with the last lookup
  118. end
  119. define current_fault
  120. print current_fault
  121. end
  122. document current_fault
  123. Prints the last fault
  124. end
  125. define current_syscall_error
  126. print current_syscall_error
  127. end
  128. document current_syscall_error
  129. Prints the last syscall error
  130. end
  131. define cap_type
  132. return ($arg1.words[0]>>28) & 0xf
  133. end
  134. define mask
  135. ((1<< $arg0)-1)
  136. end
  137. define currthread_cnode
  138. set $cnode = ((cte_t *)((unsigned int)ksCurThread&~((1<<9)-1)))
  139. print $cnode->cap
  140. end
  141. document currthread_cnode
  142. Prints the root CNode of the current thread
  143. end
  144. define cnode_for_thread
  145. set $cnode = ((cte_t *)((unsigned int)($arg0)&~((1<<9)-1)))
  146. print $cnode->cap
  147. end
  148. define disp_ep
  149. set $ep = *(endpoint_t *)$arg0
  150. printf "Queue head: %x\n", ($ep.words[1] & 0xfffffff0)
  151. printf "Queue tail: %x\n", ($ep.words[0] & 0xfffffff0)
  152. print ((enum endpoint_state)($ep.words[0] & 0x3))
  153. end
  154. document disp_ep
  155. Display basic information about an endpoint. arg0: pointer to an endpoint data structure in-kernel memory. This can be obtained from resolve_cap.
  156. end
  157. define disp_ep_queue
  158. set $ep = *(endpoint_t *)$arg0
  159. set $current = (tcb_t *)($ep.words[1] & 0xfffffff0)
  160. set $tail = (tcb_t *)($ep.words[0] & 0xfffffff0)
  161. if( $current == 0)
  162. printf "empty\n"
  163. else
  164. while( $current != $tail)
  165. print *$current
  166. set $current = $current->tcbEPNext
  167. end
  168. print *$current
  169. end
  170. end
  171. document disp_ep_queue
  172. Display all TCBs in an endpoint's queue. arg0: pointer to an endpoint data structure in kernel memory. This can be obtained from resolve_cap.
  173. end
  174. define disp_cap
  175. set $cap = $arg0
  176. set $type = (cap_tag_t)(($cap.words[0] >> 28) & 0xf)
  177. if( $type == cap_null_cap )
  178. printf "Type: cap_null_cap\n"
  179. end
  180. if( $type == cap_untyped_cap )
  181. printf "Type: cap_untyped_cap\n"
  182. printf "blocksize: %x\n", $cap.words[1] & 0x1f
  183. printf "capPtr: %x\n", ($cap.words[0]>>28) & 0xf
  184. end
  185. if( $type == cap_endpoint_cap )
  186. printf "Type: cap_endpoint_cap\n"
  187. printf "badge: %x\n", ($cap.words[1] & 0xfffffff8) >> 3
  188. printf "EPPtr: %x\n", ($cap.words[0] & 0xfffffff) << 4
  189. end
  190. if( $type == cap_notification_cap )
  191. printf "Type: cap_notification_cap\n"
  192. printf "badge: %x\n", ($cap.words[1] & 0xfffffff8) >> 3
  193. printf "AEPPtr: %x\n", ($cap.words[0] & 0xfffffff) << 4
  194. end
  195. if( $type == cap_reply_cap )
  196. printf "Type: cap_reply_cap\n"
  197. end
  198. if( $type == cap_cnode_cap)
  199. printf "Type: cap_cnode_cap\n"
  200. printf "Radix: %x\n", ($cap.words[1] & 0xf800000) >> 23
  201. printf "Guard size: %x\n", ($cap.words[1] & 0x7c0000) >> 18
  202. printf "Guard: %x\n", ($cap.words[1] & 0x3ffff) >> 0
  203. printf "CNode ptr: %x\n", ($cap.words[0] & 0x7ffffff) << 5
  204. end
  205. if( $type == cap_thread_cap)
  206. printf "Type: cap_thread_cap\n"
  207. printf "TCBPtr: %x\n", ($cap.words[0] & 0xfffffff) << 4
  208. end
  209. if( $type == cap_irq_handler_cap )
  210. printf "Type: cap_irq_handler_cap\n"
  211. printf "capIRQ: %x\n", ($cap.words[1] & 0xff) >> 0
  212. end
  213. if( $type == cap_irq_control_cap )
  214. printf "Type: cap_irq_control_cap\n"
  215. printf "not implemented\n"
  216. end
  217. if( $type == cap_zombie_cap )
  218. printf "Type: cap_zombie_cap\n"
  219. end
  220. if( $type == cap_subtype_cap )
  221. printf "Type: cap_subtype_cap\n"
  222. set $subtype = (subcap_tag_t)(($cap.words[0] & 0xf000000) >> 24)
  223. if( $subtype == subcap_asid_control_cap )
  224. printf "Subtype: subcap_asid_control_cap\n"
  225. end
  226. if( $subtype == subcap_asid_pool_cap )
  227. printf "Subtype: subcap_asid_pool_cap\n"
  228. printf "capASIDBase: %x\n", $cap.words[1] & 0xffff
  229. printf "capType: %x\n", ($cap.words[0] >> 28) & 0xf
  230. printf "capASIDPool %x\n", ($cap.words[0] << 12)
  231. end
  232. if( $subtype == subcap_io_port_cap )
  233. printf "Subtype: subcap_io_port_cap\n"
  234. printf "capType: %x\n", ($cap.words[0] >> 28) & 0xf
  235. end
  236. if( $subtype == subcap_io_space_cap )
  237. printf "Subtype: subcap_io_space_cap\n"
  238. end
  239. if( $subtype == subcap_io_page_table_cap )
  240. printf "Subtype: subcap_io_page_table_cap\n"
  241. end
  242. end
  243. if( $type == cap_frame_cap )
  244. printf "Type: cap_frame_cap\n"
  245. printf "FMappedAddress: %x\n", ($cap.words[1] & 0xfffff) << 12
  246. printf "FBasePtr: %x\n", ($cap.words[0] & 0xfffff) << 12
  247. printf "FMappedASIDLow: %x\n", ($cap.words[1] & 0x3ff00000) >> 20
  248. printf "FMappedASIDHigh: %x\n", ($cap.words[0] & 0xfc00000) >> 22
  249. printf "Frame size: %x\n", ($cap.words[1] & 0x80000000) >> 31
  250. end
  251. if( $type == cap_page_table_cap )
  252. printf "Type: cap_page_table_cap\n"
  253. printf "not implemented\n"
  254. end
  255. if( $type == cap_page_directory_cap )
  256. printf "Type: cap_page_directory_cap\n"
  257. printf "Is mapped: %x\n", ($cap.words[1] & 0x10000) >> 16
  258. printf "ASID: %x\n", ($cap->words[1] & 0xffff) >> 0
  259. printf "CapPDBasePTR: %x\n", $cap->words[1] << 12
  260. end
  261. print $cap
  262. end
  263. document disp_cap
  264. Determines the type of a cap and prints relevant information. arg0: a kernel capability data structure (not a pointer). This can be obtained from resolve_cap.
  265. end
  266. define get_thread_cap
  267. set $result = ((cte_t *)(((unsigned int) $arg0 )&~((1<<10)-1))) + $arg1
  268. set $result = $result->cap
  269. end
  270. document get_thread_cap
  271. Gets one of the caps associated with a TCB e.g. root CNode, VSpace, ipc_buffer. arg0: pointer to tcb struct, arg1: index of cap
  272. end
  273. define get_thread_cspace
  274. get_thread_cap $arg0 0
  275. end
  276. document get_thread_cspace
  277. Get the CTE for the root CNode of a thread. arg0: the in-kernel data structure representing the thread cap
  278. end
  279. define get_thread_vspace
  280. get_thread_cap $arg0 1
  281. end
  282. document get_thread_vspace
  283. Get the CTE for the vspace of a thread. arg0: the in-kernel data structure representing the thread cap
  284. end
  285. define get_thread_reply_slot
  286. get_thread_cap $arg0 2
  287. end
  288. document get_thread_reply_slot
  289. Get the CTE for the reply slot of a thread. arg0: the in-kernel data structure representing the thread cap
  290. end
  291. define get_thread_most_recent_ipc_sender
  292. get_thread_cap $arg0 3
  293. end
  294. document get_thread_most_recent_ipc_sender
  295. Get the CTE for the most recent IPC sender of a thread. arg0: the in-kernel data structure representing the thread cap
  296. end
  297. define get_thread_ipc_buffer
  298. get_thread_cap $arg0 4
  299. end
  300. document get_thread_ipc_buffer
  301. Get the CTE for the IPC buffer of a thread. arg0: the in-kernel data structure representing the thread cap
  302. end
  303. define dump_thread_info
  304. set $tcbptr = $arg0
  305. printf "\nCSpace:\n"
  306. get_thread_cspace $tcbptr
  307. disp_cap $result
  308. printf "\nVSpace:\n"
  309. get_thread_vspace $tcbptr
  310. disp_cap $result
  311. printf "\nReply slot:\n"
  312. get_thread_reply_slot $tcbptr
  313. disp_cap $result
  314. printf "\nMost recent IPC sender:\n"
  315. get_thread_most_recent_ipc_sender $tcbptr
  316. disp_cap $result
  317. printf "\nIPC buffer:\n"
  318. get_thread_ipc_buffer $tcbptr
  319. disp_cap $result
  320. end
  321. document dump_thread_info
  322. Dump the extra caps associated with a thread (root CNode, VSpace etc). arg0: the in-kernel data structure representing the thread cap
  323. end
  324. define pd_for_asid
  325. set $asid = $arg0
  326. set $poolPtr = ia32KSASIDTable[$asid >> asidLowBits];
  327. set $pd = poolPtr->array[$asid & ((1<<asidLowBits)-1)];
  328. if( !$asid || !$poolPtr )
  329. printf "Something went wrong\n"
  330. else
  331. print $pd
  332. end
  333. end
  334. define resolve_cap
  335. set $nodeCap = $arg0
  336. set $capptr = (int)$arg1
  337. set $n_bits = (int)$arg2
  338. while(1)
  339. #printf "loop: remaining: %d\n", $n_bits
  340. #test cap type
  341. if((( $nodeCap.words[0]>>28)&0xf) != cap_cnode_cap)
  342. printf "Error: not a CNode\n"
  343. loop_break
  344. end
  345. set $radixBits = ($nodeCap.words[1] & 0xf800000) >> 23
  346. set $guardBits = ($nodeCap.words[1] & 0x7c0000) >> 18
  347. set $levelBits = $radixBits + $guardBits
  348. set $capGuard = ($nodeCap.words[1] & 0x3ffff) >> 0
  349. set $guard = ($capptr >> ($n_bits - $guardBits)) & ((1<<$guardBits)-1)
  350. if( ($guardBits > $n_bits) || ($guard != $capGuard))
  351. printf "levelbits: %d, radixbits: %d, guardbits: %d, n_bits: %d\n", $levelBits, $radixBits, $guardBits, $n_bits
  352. printf "guard: %x, capguard: %x", $guard, $capGuard
  353. printf "lookup fault guard mismatch\n"
  354. loop_break
  355. end
  356. if( $levelBits > $n_bits )
  357. printf "lookup fault depth mismatch\n"
  358. loop_break
  359. end
  360. set $offset = ($capptr >> ($n_bits - $levelBits)) & ((1<<$radixBits)-1)
  361. set $slot = ((cte_t *)(($nodeCap.words[0] & 0x7ffffff) << 5)) + $offset
  362. if( $n_bits <= $levelBits)
  363. disp_cap $slot->cap
  364. loop_break
  365. end
  366. set $n_bits -= $levelBits
  367. set $nodeCap = $slot->cap
  368. #test cap type
  369. if((( $nodeCap.words[0]>>28)&0xf) != cap_cnode_cap)
  370. printf "warning: terminating because node is not a CNode, not because all bits were resolved\n"
  371. disp_cap $nodeCap
  372. loop_break
  373. end
  374. end
  375. end
  376. document resolve_cap
  377. Resolve a capPtr and print its contents using disp_cap. arg0: CNode to start resolving at, arg1: the cap to resolve (an integer), arg2: the depth to resolve to (an integer). The currthread_cnode macro may be useful to obtain the first argument.
  378. end
  379. define resolve_cap_current
  380. currthread_cnode
  381. resolve_cap $cnode->cap $arg0 $arg1
  382. end
  383. document resolve_cap_current
  384. Resolve a capPtr and print its contents. Caps are resolved relative to root CNode of current thread. arg1: the cap to resolve, arg2: the depth.
  385. end
  386. define dump_cnode
  387. set $nodeCap = $arg0
  388. if((( $nodeCap.words[0]>>28)&0xf) != cap_cnode_cap)
  389. printf "Error: not a CNode\n"
  390. end
  391. set $radixBits = ($nodeCap.words[1] & 0xf800000) >> 23
  392. set $guardBits = ($nodeCap.words[1] & 0x7c0000) >> 18
  393. set $levelBits = $radixBits + $guardBits
  394. set $count = 0
  395. while( $count < (1<<$radixBits))
  396. set $slot = ((cte_t *)(($nodeCap.words[0] & 0x7ffffff) << 5)) + $count
  397. if((($slot->cap.words[0]>>28)&0xf) != cap_null_cap)
  398. printf "offset: %d\n", $count
  399. disp_cap $slot->cap
  400. printf "\n"
  401. end
  402. set $count = $count+1
  403. end
  404. end
  405. document dump_cnode
  406. Dump the contents of a CNode. arg1: the CNode to dump
  407. end
  408. define dump_currthread_cnode
  409. printf "Top level CNode: \n"
  410. currthread_cnode
  411. printf "\n\n"
  412. dump_cnode $cnode->cap
  413. end
  414. document dump_currthread_cnode
  415. Dump the contents of the root CNode of the current thread. No arguments.
  416. end
  417. define irq_handler
  418. set $slot = intStateIRQNode + $arg0
  419. set $cap = $slot->cap
  420. if((cap_tag_t)(($cap.words[0] >> 28) & 0xf) != cap_notification_cap)
  421. printf "no handler\n"
  422. else
  423. set $cap = (async_endpoint_t *)(($cap.words[0] & 0xfffffff) << 4)
  424. disp_ep *$cap
  425. disp_ep_queue *$cap
  426. end
  427. end
  428. document irq_handler
  429. Print the endpoints and handling threads for an IRQ. arg0: the IRQ number
  430. end
  431. define wombat_current
  432. print ((struct thread_info *)per_cpu___l4_current_tinfo)->task
  433. end
  434. define finish_irq
  435. set $current_sel4_thread = ksCurThread
  436. #set $current = ((struct thread_info *)per_cpu___l4_current_tinfo)->task
  437. tbreak *0xf012102a if (ksCurThread==$current_sel4_thread)
  438. continue
  439. stepi
  440. end
  441. document finish_irq
  442. Run until the end of the IRQ handler. This is useful if you are stepping through userland code and an interrupt occurs and control moves to the kernel. As far as I know there is no way to disable interrupts in qemu to avoid this.
  443. end
  444. define n2
  445. next
  446. if $eip>0xf0000000
  447. printf "IRQ happened\n"
  448. finish_irq
  449. end
  450. end
  451. document n2
  452. Like next but if it detects that an IRQ happens it executes that and returns.
  453. end
  454. define vtd_root
  455. print ia32KSvtdRootTable
  456. end
  457. define decode_vtd_root_entry
  458. set $vtd_root_entry = (vtd_root_entry_t)$arg0
  459. set $vtd_re_ctp = ($vtd_root_entry.words[0] & 0xfffff000)
  460. set $vtd_re_present = ($vtd_root_entry.words[0] & 0x1)
  461. end
  462. document decode_vtd_root_entry
  463. "Decodes the vtd root entry into its component parts"
  464. end
  465. define print_vtd_root_entry
  466. printf "ctp: %x\n", $vtd_re_ctp
  467. printf "present: %x\n", $vtd_re_present
  468. end
  469. document print_vtd_root_entry
  470. "Print the fields of an earlier decoded vtd root entry"
  471. end
  472. define print_vtd_root_table
  473. set $vtd_root_entry_ptr = ia32KSvtdRootTable
  474. set $count = 0
  475. while($count < 256)
  476. decode_vtd_root_entry $vtd_root_entry_ptr[$count]
  477. if($vtd_re_present)
  478. printf "Index: %x\n", $count
  479. print_vtd_root_entry
  480. end
  481. set $count++
  482. end
  483. end
  484. document print_vtd_root_table
  485. "Prints all of the entries in the vtd root table. There is one entry for each PCI bus"
  486. end
  487. define decode_vtd_context_entry
  488. set $vtd_context_entry = (vtd_context_entry_t)$arg0
  489. set $vtd_ce_did = ($vtd_context_entry.words[2] & 0xffff00) >> 8
  490. set $vtd_ce_aw = ($vtd_context_entry.words[2] & 0x7)
  491. set $vtd_ce_asr = ($vtd_context_entry.words[0] & 0xfffff000)
  492. set $vtd_ce_present = ($vtd_context_entry.words[0] & 0x1)
  493. end
  494. document decode_vtd_context_entry
  495. "Decodes a vtd context entry into its component parts. arg0: pointer to the entry"
  496. end
  497. define print_vtd_context_entry
  498. printf "did: %x\n", $vtd_ce_did
  499. printf "aw: %x\n", $vtd_ce_aw
  500. printf "asr: %x\n", $vtd_ce_asr
  501. printf "present: %x\n", $vtd_ce_present
  502. end
  503. document print_vtd_context_entry
  504. "Print the fields of an earlier decoded vtd context entry"
  505. end
  506. define print_vtd_context_table
  507. set $vtd_context_entry_ptr = (vtd_context_entry_t *)$arg0
  508. set $count = 0
  509. while($count < 256)
  510. decode_vtd_context_entry $vtd_context_entry_ptr[$count]
  511. if($vtd_ce_present)
  512. printf "index %x\n", $count
  513. print_vtd_context_entry
  514. end
  515. set $count++
  516. end
  517. end
  518. document print_vtd_context_table
  519. "Prints all of the fields in a vtd context table. There is one entry for each (dev, fn) in the bus. arg0: a pointer to the context table"
  520. end
  521. define decode_vtd_page_table_entry
  522. set $vtd_page_table_entry = (vtd_pte_t)$arg0
  523. set $vtd_pte_addr = ($vtd_page_table_entry.words[0] & 0xfffff000)
  524. set $vtd_pte_write = ($vtd_page_table_entry.words[0] & 0x2) >> 1
  525. set $vtd_pte_read = ($vtd_page_table_entry.words[0] & 0x1)
  526. end
  527. document decode_vtd_page_table_entry
  528. "Decodes a vtd PTE info its component parts. arg0: pointer to the entry"
  529. end
  530. define print_vtd_page_table_entry
  531. printf "addr: %x\n", $vtd_pte_addr
  532. printf "write: %x\n", $vtd_pte_write
  533. printf "read: %x\n", $vtd_pte_read
  534. end
  535. document print_vtd_page_table_entry
  536. "Print the fields of an earlier decoded vtd page table entry"
  537. end
  538. define print_vtd_page_table
  539. set $vtd_pte_ptr = (vtd_pte_t *)$arg0
  540. set $count = 0
  541. while($count < 256)
  542. decode_vtd_page_table_entry $vtd_pte_ptr[$count]
  543. if($vtd_pte_read || $vtd_pte_write)
  544. printf "index: %x\n", $count
  545. print_vtd_page_table_entry
  546. end
  547. set $count++
  548. end
  549. end
  550. document print_vtd_page_table
  551. "Prints all of the fields in a vtd page table. arg0: a pointer to the page table"
  552. end
  553. define paddr_to_vaddr
  554. set $var = (unsigned int)$arg0
  555. set $vaddr = ($var + 0xf0000000)
  556. end
  557. document paddr_to_vaddr
  558. "Convert a physical address to the locaction to which it is mapped in the kernel"
  559. end
  560. define vaddr_to_paddr
  561. set $paddr = ($arg0 - 0xf0000000)
  562. end
  563. document vaddr_to_paddr
  564. "Convert a virtual address in the kernel to a physical address"
  565. end
  566. define lookup_vtd_address
  567. set $bus = $arg0
  568. set $devfn = $arg1
  569. set $address = $arg2
  570. set $vtd_root_entry_ptr = ia32KSvtdRootTable
  571. decode_vtd_root_entry $vtd_root_entry_ptr[$bus]
  572. if($vtd_re_present)
  573. printf "Root entry: \n"
  574. print_vtd_root_entry
  575. paddr_to_vaddr $vtd_re_ctp
  576. set $vtd_context_entry_ptr = (vtd_context_entry_t *)$vaddr
  577. decode_vtd_context_entry $vtd_context_entry_ptr[$devfn]
  578. if($vtd_ce_present)
  579. printf "Context entry: \n"
  580. print_vtd_context_entry
  581. walk_vtd_pgtables $vtd_ce_asr $address
  582. else
  583. printf "Error: context entry not present\n"
  584. end
  585. else
  586. printf "Error: root entry not present\n"
  587. end
  588. end
  589. document lookup_vtd_address
  590. "Looks up an address in the address space of a given PCI device. arg0: PCI bus number, arg1: PCI devfn number, arg2: virtual address to look up"
  591. end
  592. define walk_vtd_pgtables
  593. set $pg_tab = (vtd_pte_t *)$arg0
  594. set $address = (unsigned long long int)$arg1
  595. set $count=0
  596. if(($address & 0xffffff8000000000) == 0x0)
  597. set $address = $address << 25
  598. while(1)
  599. set $index = ($address & 0xff80000000000000) >> (64-9)
  600. printf "index: %x\n", $index
  601. set $address = ($address << 9)
  602. paddr_to_vaddr $pg_tab
  603. set $pg_tab = (vtd_pte_t *)$vaddr
  604. decode_vtd_page_table_entry $pg_tab[$index]
  605. if($vtd_pte_read || $vtd_pte_write)
  606. printf "Page table entry: \n"
  607. print_vtd_page_table_entry
  608. #TODO check for superpages
  609. set $count++
  610. if($count==3)
  611. printf "Translation complete. Physical address: %llx\n", $vtd_pte_addr
  612. loop_break
  613. else
  614. set $pg_tab = (vtd_pte_t *)$vtd_pte_addr
  615. end
  616. else
  617. printf "Error: Page table entry not present\n"
  618. printf "Page table: "
  619. print_vtd_page_table_entry
  620. loop_break
  621. end
  622. end
  623. else
  624. printf "Error: bits 63:39 must be 0\n"
  625. end
  626. end
  627. document walk_vtd_pgtables
  628. "Walks the IOMMU page table to resolve a virtual address starting at the given page table. arg0: pointer to page table (in seL4 virtual memory), arg1: virtual address to resolve"
  629. end
  630. define decode_pte
  631. set $pte_addr = $arg0 & 0xfffff000
  632. set $pte_present = $arg0 & 1
  633. set $pte_rw = ($arg0 >> 1) & 1
  634. set $pte_usr = ($arg0 >> 2) & 1
  635. set $pte_pwt = ($arg0 >> 3) & 1
  636. set $pte_pcd = ($arg0 >> 4) & 1
  637. set $pte_accessed = ($arg0 >> 5) & 1
  638. set $pte_dirty = ($arg0 >> 6) & 1
  639. set $pte_pse = ($arg0 >> 7) & 1
  640. set $pte_pat = ($arg0 >> 12) & 1
  641. set $pte_avl = ($arg0 >> 9) & 7
  642. set $pte_global = ($arg0 >> 8) & 1
  643. end
  644. document decode_pte
  645. Decode an IA32 page table leaf entry into its component parts.
  646. If the PRESENT bit is 0 then the rest of the bits can be anything
  647. (OSs typically reuse them for swap housekeeping)
  648. end
  649. define maybe_print
  650. if $arg0
  651. printf $arg1
  652. else
  653. printf $arg2
  654. end
  655. end
  656. document maybe_print
  657. If arg0 is non-zero print arg1 otherwise print arg2.
  658. end
  659. # Can't use the obvious printf formulation for this because gdb tries
  660. # to call malloc in the target --- which doesn't work in SeL4
  661. define print_pte
  662. printf "Address 0x%x ", $pte_addr
  663. printf " attributes: "
  664. maybe_print $pte_present "P" "-"
  665. maybe_print $pte_rw "w" "r"
  666. maybe_print $pte_usr "U" "S"
  667. maybe_print $pte_pwt " WT " " WB "
  668. maybe_print $pte_pcd "NC " "C "
  669. maybe_print $pte_accessed "A" "-"
  670. maybe_print $pte_dirty "d" "-"
  671. maybe_print $pte_pse "4M" "4k"
  672. maybe_print $pte_pat " PAT " ""
  673. maybe_print $pte_global "g" ""
  674. printf "AVL%x\n", $pte_avl
  675. end
  676. document print_pte
  677. Print the PTE parts split out by decode_pte.
  678. You must invoke decode_pte before invoking this function.
  679. end
  680. define pgd
  681. set $idx = 0
  682. set $pgdptr = $arg0
  683. while ($idx < 1024)
  684. set $pte = *(long *)$pgdptr
  685. #printf "PGD@0x%x is 0x%x\n", $pgdptr, $pte
  686. decode_pte $pte
  687. set $mapped_addr = $idx * (4 * 1024 * 1024)
  688. set $idx = $idx + 1
  689. set $pgdptr = $pgdptr + 4
  690. if (! $pte_present)
  691. loop_continue
  692. end
  693. if $pte_pse
  694. printf "HUGE (4G) V 0x%x ", $mapped_addr
  695. print_pte
  696. else
  697. set $pteptr = (long)$pte_addr + 0xe0000000
  698. set $n = 0
  699. while ($n < 1024)
  700. set $pte = *(long *)$pteptr
  701. decode_pte $pte
  702. if $pte_present
  703. printf "V:%08x ", $mapped_addr
  704. print_pte
  705. end
  706. set $pteptr = $pteptr + 4
  707. set $mapped_addr = $mapped_addr + 4096
  708. set $n = $n + 1
  709. end
  710. end
  711. end
  712. end
  713. document pgd
  714. Print a page table, starting at the page global directory.
  715. Assumes 2-level (non-PAE) page tables,
  716. end