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 11#include <config.h> 12#include <object/structures.h> 13#include <object/tcb.h> 14#include <model/statedata.h> 15#include <machine/capdl.h> 16#include <arch/machine/capdl.h> 17#include <machine/io.h> 18 19#ifdef CONFIG_DEBUG_BUILD 20 21#define ARCH 0xe1 22 23#define PD_READ_SIZE BIT(PD_INDEX_BITS) 24#define PT_READ_SIZE BIT(PT_INDEX_BITS) 25#define ASID_POOL_READ_SIZE BIT(ASID_POOL_INDEX_BITS) 26#define IO_PT_READ_SIZE BIT(VTD_PT_INDEX_BITS) 27 28static int getDecodedChar(unsigned char *result) 29{ 30 unsigned char c; 31 c = getDebugChar(); 32 if (c == START) { 33 return 1; 34 } 35 if (c == ESCAPE) { 36 c = getDebugChar(); 37 if (c == START) { 38 return 1; 39 } 40 switch (c) { 41 case ESCAPE_ESCAPE: 42 *result = ESCAPE; 43 break; 44 case START_ESCAPE: 45 *result = START; 46 break; 47 case END_ESCAPE: 48 *result = END; 49 break; 50 default: 51 if (c >= 20 && c < 40) { 52 *result = c - 20; 53 } else { 54 return 1; 55 } 56 } 57 return 0; 58 } else { 59 *result = c; 60 return 0; 61 } 62} 63 64static void putEncodedChar(unsigned char c) 65{ 66 switch (c) { 67 case ESCAPE: 68 putDebugChar(ESCAPE); 69 putDebugChar(ESCAPE_ESCAPE); 70 break; 71 case START: 72 putDebugChar(ESCAPE); 73 putDebugChar(START_ESCAPE); 74 break; 75 case END: 76 putDebugChar(ESCAPE); 77 putDebugChar(END_ESCAPE); 78 break; 79 default: 80 if (c < 20) { 81 putDebugChar(ESCAPE); 82 putDebugChar(c + 20); 83 } else { 84 putDebugChar(c); 85 } 86 } 87} 88 89static int getArg(unsigned long *res) 90{ 91 unsigned long i; 92 unsigned char byte; 93 *res = 0; 94 for (i = 0; i < sizeof(unsigned long); i++) { 95 if (getDecodedChar(&byte)) { 96 return 1; 97 } 98 (*res) = ((*res) << 8) | byte; 99 } 100 return 0; 101} 102 103static void sendWord(unsigned long word) 104{ 105 unsigned long i; 106 for (i = 0; i < sizeof(unsigned long); i++) { 107 putEncodedChar( (word >> (i * 8)) & 0xff); 108 } 109} 110 111static cte_t *getMDBParent(cte_t *slot) 112{ 113 cte_t *oldSlot = CTE_PTR(mdb_node_get_mdbPrev(slot->cteMDBNode)); 114 115 while (oldSlot != 0 && !isMDBParentOf(oldSlot, slot)) { 116 oldSlot = CTE_PTR(mdb_node_get_mdbPrev(oldSlot->cteMDBNode)); 117 } 118 119 return oldSlot; 120} 121 122static void sendPD(unsigned long address) 123{ 124 unsigned long i; 125 unsigned int exists; 126 pde_t *start = (pde_t *)address; 127 for (i = 0; i < PD_READ_SIZE; i++) { 128 pde_t pde = start[i]; 129 exists = 1; 130 if (pde_get_page_size(pde) == pde_pde_pt && (pde_pde_pt_get_pt_base_address(pde) == 0 || 131 !pde_pde_pt_get_present(pde) || !pde_pde_pt_get_super_user(pde))) { 132 exists = 0; 133 } else if (pde_get_page_size(pde) == pde_pde_large && (pde_pde_large_get_page_base_address(pde) == 0 || 134 !pde_pde_large_get_present(pde) || !pde_pde_large_get_super_user(pde))) { 135 exists = 0; 136 } 137 if (exists != 0 && i < PPTR_BASE >> pageBitsForSize(X86_LargePage)) { 138 sendWord(i); 139 sendWord(pde.words[0]); 140 } 141 } 142} 143 144static void sendPT(unsigned long address) 145{ 146 unsigned long i; 147 pte_t *start = (pte_t *)address; 148 for (i = 0; i < PT_READ_SIZE; i++) { 149 pte_t pte = start[i]; 150 if (pte_get_page_base_address(pte) != 0 && pte_get_present(pte) && pte_get_super_user(pte)) { 151 sendWord(i); 152 sendWord(pte.words[0]); 153 } 154 } 155} 156 157static void sendASIDPool(unsigned long address) 158{ 159 unsigned long i; 160 pde_t **start = (pde_t **)address; 161 for (i = 0; i < ASID_POOL_READ_SIZE; i++) { 162 pde_t *pde = start[i]; 163 if (pde != 0) { 164 sendWord(i); 165 sendWord((unsigned long)pde); 166 } 167 } 168} 169 170#ifdef CONFIG_IOMMU 171static void sendIOPT(unsigned long address, unsigned int level) 172{ 173 unsigned long i; 174 vtd_pte_t *start = (vtd_pte_t *)address; 175 for (i = 0; i < IO_PT_READ_SIZE; i++) { 176 vtd_pte_t vtd_pte = start[i]; 177 if (vtd_pte_get_addr(vtd_pte) != 0) { 178 sendWord(i); 179 sendWord(vtd_pte.words[0]); 180#ifdef CONFIG_ARCH_IA32 181 sendWord(vtd_pte.words[1]); 182#endif 183 if (level == x86KSnumIOPTLevels) { 184 sendWord(1); 185 } else { 186 sendWord(0); 187 } 188 } 189 } 190} 191 192static void sendIOSpace(uint32_t pci_request_id) 193{ 194 uint32_t vtd_root_index; 195 uint32_t vtd_context_index; 196 vtd_rte_t* vtd_root_slot; 197 vtd_cte_t* vtd_context; 198 vtd_cte_t* vtd_context_slot; 199 200 vtd_root_index = get_pci_bus(pci_request_id); 201 vtd_root_slot = x86KSvtdRootTable + vtd_root_index; 202 203 vtd_context = (vtd_cte_t*)paddr_to_pptr(vtd_rte_ptr_get_ctp(vtd_root_slot)); 204 vtd_context_index = (get_pci_dev(pci_request_id) << 3) | get_pci_fun(pci_request_id); 205 vtd_context_slot = &vtd_context[vtd_context_index]; 206 207 if (vtd_cte_ptr_get_present(vtd_context_slot)) { 208 sendWord(vtd_cte_ptr_get_asr(vtd_context_slot)); 209 } else { 210 sendWord(0); 211 } 212} 213#endif 214 215static void sendRunqueues(void) 216{ 217 word_t i; 218 sendWord((unsigned long)NODE_STATE(ksCurThread)); 219 for (i = 0; i < NUM_READY_QUEUES; i++) { 220 tcb_t *current = NODE_STATE(ksReadyQueues[i]).head; 221 if (current != 0) { 222 while (current != NODE_STATE(ksReadyQueues[i]).end) { 223 sendWord((unsigned long)current); 224 current = current -> tcbSchedNext; 225 } 226 sendWord((unsigned long)current); 227 } 228 } 229} 230 231static void sendEPQueue(unsigned long epptr) 232{ 233 tcb_t *current = (tcb_t *)endpoint_ptr_get_epQueue_head((endpoint_t *)epptr); 234 tcb_t *tail = (tcb_t *)endpoint_ptr_get_epQueue_tail((endpoint_t *)epptr); 235 if (current == 0) { 236 return; 237 } 238 while (current != tail) { 239 sendWord((unsigned long)current); 240 current = current->tcbEPNext; 241 } 242 sendWord((unsigned long)current); 243} 244 245static void sendCNode(unsigned long address, unsigned int sizebits) 246{ 247 unsigned long i; 248 cte_t *start = (cte_t *)address; 249 for (i = 0; i < (1 << sizebits); i++) { 250 cap_t cap = start[i].cap; 251 if (cap_get_capType(cap) != cap_null_cap) { 252 cte_t *parent = getMDBParent(&start[i]); 253 sendWord(i); 254 sendWord(cap.words[0]); 255 sendWord(cap.words[1]); 256 sendWord((unsigned long)parent); 257 } 258 } 259} 260 261static void sendIRQNode(void) 262{ 263 sendCNode((unsigned long)intStateIRQNode, 8); 264} 265 266static void sendVersion(void) 267{ 268 sendWord(ARCH); 269 sendWord(CAPDL_VERSION); 270} 271 272void capDL(void) 273{ 274 int result; 275 int done = 0; 276 while (done == 0) { 277 unsigned char c; 278 do { 279 c = getDebugChar(); 280 } while (c != START); 281 do { 282 result = getDecodedChar(&c); 283 if (result) { 284 continue; 285 } 286 switch (c) { 287 case PD_COMMAND: { 288 /*pgdir */ 289 unsigned long arg; 290 result = getArg(&arg); 291 if (result) { 292 continue; 293 } 294 sendPD(arg); 295 putDebugChar(END); 296 } 297 break; 298 case PT_COMMAND: { 299 /*pg table */ 300 unsigned long arg; 301 result = getArg(&arg); 302 if (result) { 303 continue; 304 } 305 sendPT(arg); 306 putDebugChar(END); 307 } 308 break; 309 case ASID_POOL_COMMAND: { 310 /*asid pool */ 311 unsigned long arg; 312 result = getArg(&arg); 313 if (result) { 314 continue; 315 } 316 sendASIDPool(arg); 317 putDebugChar(END); 318 } 319 break; 320#ifdef CONFIG_IOMMU 321 case IO_PT_COMMAND: { 322 /*io pt table */ 323 unsigned long address, level; 324 result = getArg(&address); 325 if (result) { 326 continue; 327 } 328 result = getArg(&level); 329 if (result) { 330 continue; 331 } 332 sendIOPT(address, level); 333 putDebugChar(END); 334 } 335 break; 336 case IO_SPACE_COMMAND: { 337 /*io space */ 338 unsigned long arg; 339 result = getArg(&arg); 340 if (result) { 341 continue; 342 } 343 sendIOSpace(arg); 344 putDebugChar(END); 345 } 346#endif 347 break; 348 case RQ_COMMAND: { 349 /*runqueues */ 350 sendRunqueues(); 351 putDebugChar(END); 352 result = 0; 353 } 354 break; 355 case EP_COMMAND: { 356 /*endpoint waiters */ 357 unsigned long arg; 358 result = getArg(&arg); 359 if (result) { 360 continue; 361 } 362 sendEPQueue(arg); 363 putDebugChar(END); 364 } 365 break; 366 case CN_COMMAND: { 367 /*cnode */ 368 unsigned long address, sizebits; 369 result = getArg(&address); 370 if (result) { 371 continue; 372 } 373 result = getArg(&sizebits); 374 if (result) { 375 continue; 376 } 377 378 sendCNode(address, sizebits); 379 putDebugChar(END); 380 } 381 break; 382 case IRQ_COMMAND: { 383 sendIRQNode(); 384 putDebugChar(END); 385 result = 0; 386 } 387 break; 388 case VERSION_COMMAND: { 389 sendVersion(); 390 putDebugChar(END); 391 } 392 break; 393 case DONE: { 394 done = 1; 395 putDebugChar(END); 396 } 397 default: 398 result = 0; 399 break; 400 } 401 } while (result); 402 } 403} 404 405#endif 406