1 /* 2 * \file trc_pkt_decode_etmv4i.cpp 3 * \brief OpenCSD : ETMv4 decoder 4 * 5 * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. 6 */ 7 8 9 /* 10 * Redistribution and use in source and binary forms, with or without modification, 11 * are permitted provided that the following conditions are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright notice, 17 * this list of conditions and the following disclaimer in the documentation 18 * and/or other materials provided with the distribution. 19 * 20 * 3. Neither the name of the copyright holder nor the names of its contributors 21 * may be used to endorse or promote products derived from this software without 22 * specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include "opencsd/etmv4/trc_pkt_decode_etmv4i.h" 37 38 #include "common/trc_gen_elem.h" 39 40 41 #define DCD_NAME "DCD_ETMV4" 42 43 static const uint32_t ETMV4_SUPPORTED_DECODE_OP_FLAGS = OCSD_OPFLG_PKTDEC_COMMON; 44 45 TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I() 46 : TrcPktDecodeBase(DCD_NAME) 47 { 48 initDecoder(); 49 } 50 51 TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I(int instIDNum) 52 : TrcPktDecodeBase(DCD_NAME,instIDNum) 53 { 54 initDecoder(); 55 } 56 57 TrcPktDecodeEtmV4I::~TrcPktDecodeEtmV4I() 58 { 59 } 60 61 /*********************** implementation packet decoding interface */ 62 63 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processPacket() 64 { 65 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 66 bool bPktDone = false; 67 68 while(!bPktDone) 69 { 70 switch (m_curr_state) 71 { 72 case NO_SYNC: 73 // output the initial not synced packet to the sink 74 m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); 75 resp = outputTraceElement(m_output_elem); 76 m_curr_state = WAIT_SYNC; 77 // fall through to check if the current packet is the async we are waiting for. 78 break; 79 80 case WAIT_SYNC: 81 if(m_curr_packet_in->getType() == ETM4_PKT_I_ASYNC) 82 m_curr_state = WAIT_TINFO; 83 bPktDone = true; 84 break; 85 86 case WAIT_TINFO: 87 m_need_ctxt = true; 88 m_need_addr = true; 89 if(m_curr_packet_in->getType() == ETM4_PKT_I_TRACE_INFO) 90 { 91 doTraceInfoPacket(); 92 m_curr_state = DECODE_PKTS; 93 m_return_stack.flush(); 94 } 95 bPktDone = true; 96 break; 97 98 case DECODE_PKTS: 99 resp = decodePacket(bPktDone); // this may change the state to commit elem; 100 break; 101 102 case COMMIT_ELEM: 103 resp = commitElements(bPktDone); // this will change the state to DECODE_PKTS once all elem committed. 104 break; 105 106 } 107 } 108 return resp; 109 } 110 111 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onEOT() 112 { 113 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 114 m_flush_EOT = true; 115 resp = flushEOT(); 116 return resp; 117 } 118 119 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onReset() 120 { 121 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 122 resetDecoder(); 123 return resp; 124 } 125 126 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onFlush() 127 { 128 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 129 130 // continue exception processing (can't go through processPacket as elements no longer on stack) 131 if(m_excep_proc != EXCEP_POP) 132 resp = processException(); 133 // continue ongoing output operations on comitted elements. 134 else if(m_curr_state == COMMIT_ELEM) 135 resp = processPacket(); 136 // continue flushing at end of trace 137 else if(m_flush_EOT) 138 resp = flushEOT(); 139 return resp; 140 } 141 142 ocsd_err_t TrcPktDecodeEtmV4I::onProtocolConfig() 143 { 144 ocsd_err_t err = OCSD_OK; 145 146 // set some static config elements 147 m_CSID = m_config->getTraceID(); 148 m_max_spec_depth = m_config->MaxSpecDepth(); 149 m_p0_key_max = m_config->P0_Key_Max(); 150 m_cond_key_max_incr = m_config->CondKeyMaxIncr(); 151 152 // set up static trace instruction decode elements 153 m_instr_info.dsb_dmb_waypoints = 0; 154 m_instr_info.pe_type.arch = m_config->archVersion(); 155 m_instr_info.pe_type.profile = m_config->coreProfile(); 156 157 m_IASize64 = (m_config->iaSizeMax() == 64); 158 159 if (m_config->enabledRetStack()) 160 { 161 m_return_stack.set_active(true); 162 #ifdef TRC_RET_STACK_DEBUG 163 m_return_stack.set_dbg_logger(this); 164 #endif 165 } 166 167 // check config compatible with current decoder support level. 168 // at present no data trace, no spec depth, no return stack, no QE 169 // Remove these checks as support is added. 170 if(m_max_spec_depth != 0) 171 { 172 err = OCSD_ERR_HW_CFG_UNSUPP; 173 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : None-zero speculation depth not supported")); 174 } 175 else if(m_config->enabledDataTrace()) 176 { 177 err = OCSD_ERR_HW_CFG_UNSUPP; 178 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Data trace elements not supported")); 179 } 180 else if(m_config->enabledLSP0Trace()) 181 { 182 err = OCSD_ERR_HW_CFG_UNSUPP; 183 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : LSP0 elements not supported.")); 184 } 185 else if(m_config->enabledCondITrace() != EtmV4Config::COND_TR_DIS) 186 { 187 err = OCSD_ERR_HW_CFG_UNSUPP; 188 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace on conditional non-branch elements not supported.")); 189 } 190 else if(m_config->enabledQE()) 191 { 192 err = OCSD_ERR_HW_CFG_UNSUPP; 193 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv4 instruction decode : Trace using Q elements not supported.")); 194 } 195 return err; 196 } 197 198 199 /************* local decode methods */ 200 void TrcPktDecodeEtmV4I::initDecoder() 201 { 202 // set the operational modes supported. 203 m_supported_op_flags = ETMV4_SUPPORTED_DECODE_OP_FLAGS; 204 205 /* init elements that get set by config */ 206 m_max_spec_depth = 0; 207 m_p0_key_max = 0; 208 m_CSID = 0; 209 m_cond_key_max_incr = 0; 210 m_IASize64 = false; 211 212 // reset decoder state to unsynced 213 resetDecoder(); 214 } 215 216 void TrcPktDecodeEtmV4I::resetDecoder() 217 { 218 m_curr_state = NO_SYNC; 219 m_timestamp = 0; 220 m_context_id = 0; 221 m_vmid_id = 0; 222 m_is_secure = true; 223 m_is_64bit = false; 224 m_cc_threshold = 0; 225 m_curr_spec_depth = 0; 226 m_p0_key = 0; 227 m_cond_c_key = 0; 228 m_cond_r_key = 0; 229 m_need_ctxt = true; 230 m_need_addr = true; 231 m_except_pending_addr = false; 232 m_mem_nacc_pending = false; 233 m_prev_overflow = false; 234 m_P0_stack.delete_all(); 235 m_output_elem.init(); 236 m_excep_proc = EXCEP_POP; 237 m_flush_EOT = false; 238 } 239 240 // this function can output an immediate generic element if this covers the complete packet decode, 241 // or stack P0 and other elements for later processing on commit or cancel. 242 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::decodePacket(bool &Complete) 243 { 244 bool bAllocErr = false; 245 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 246 Complete = true; 247 bool is_addr = false; 248 bool is_except = false; 249 250 switch(m_curr_packet_in->getType()) 251 { 252 case ETM4_PKT_I_ASYNC: // nothing to do with this packet. 253 break; 254 255 case ETM4_PKT_I_TRACE_INFO: 256 // skip subsequent TInfo packets. 257 m_return_stack.flush(); 258 break; 259 260 case ETM4_PKT_I_TRACE_ON: 261 { 262 if (m_P0_stack.createParamElemNoParam(P0_TRC_ON, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) 263 bAllocErr = true; 264 } 265 break; 266 267 case ETM4_PKT_I_OVERFLOW: 268 { 269 if (m_P0_stack.createParamElemNoParam(P0_OVERFLOW, false, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) 270 bAllocErr = true; 271 } 272 break; 273 274 case ETM4_PKT_I_ATOM_F1: 275 case ETM4_PKT_I_ATOM_F2: 276 case ETM4_PKT_I_ATOM_F3: 277 case ETM4_PKT_I_ATOM_F4: 278 case ETM4_PKT_I_ATOM_F5: 279 case ETM4_PKT_I_ATOM_F6: 280 { 281 if (m_P0_stack.createAtomElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getAtom()) == 0) 282 bAllocErr = true; 283 else 284 m_curr_spec_depth += m_curr_packet_in->getAtom().num; 285 } 286 break; 287 288 case ETM4_PKT_I_CTXT: 289 { 290 if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext()) == 0) 291 bAllocErr = true; 292 } 293 break; 294 295 case ETM4_PKT_I_ADDR_MATCH: 296 { 297 etmv4_addr_val_t addr; 298 299 addr.val = m_curr_packet_in->getAddrVal(); 300 addr.isa = m_curr_packet_in->getAddrIS(); 301 if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) 302 bAllocErr = true; 303 is_addr = true; 304 } 305 break; 306 307 case ETM4_PKT_I_ADDR_CTXT_L_64IS0: 308 case ETM4_PKT_I_ADDR_CTXT_L_64IS1: 309 case ETM4_PKT_I_ADDR_CTXT_L_32IS0: 310 case ETM4_PKT_I_ADDR_CTXT_L_32IS1: 311 { 312 if (m_P0_stack.createContextElem(m_curr_packet_in->getType(), m_index_curr_pkt, m_curr_packet_in->getContext()) == 0) 313 bAllocErr = true; 314 } 315 case ETM4_PKT_I_ADDR_L_32IS0: 316 case ETM4_PKT_I_ADDR_L_32IS1: 317 case ETM4_PKT_I_ADDR_L_64IS0: 318 case ETM4_PKT_I_ADDR_L_64IS1: 319 case ETM4_PKT_I_ADDR_S_IS0: 320 case ETM4_PKT_I_ADDR_S_IS1: 321 { 322 etmv4_addr_val_t addr; 323 324 addr.val = m_curr_packet_in->getAddrVal(); 325 addr.isa = m_curr_packet_in->getAddrIS(); 326 if (m_P0_stack.createAddrElem(m_curr_packet_in->getType(), m_index_curr_pkt, addr) == 0) 327 bAllocErr = true; 328 is_addr = true; 329 } 330 break; 331 332 // Exceptions 333 case ETM4_PKT_I_EXCEPT: 334 { 335 if (m_P0_stack.createExceptElem(m_curr_packet_in->getType(), m_index_curr_pkt, 336 (m_curr_packet_in->exception_info.addr_interp == 0x2), 337 m_curr_packet_in->exception_info.exceptionType) == 0) 338 bAllocErr = true; 339 else 340 { 341 m_except_pending_addr = true; // wait for following packets before marking for commit. 342 is_except = true; 343 } 344 } 345 break; 346 347 case ETM4_PKT_I_EXCEPT_RTN: 348 { 349 // P0 element if V7M profile. 350 bool bV7MProfile = (m_config->archVersion() == ARCH_V7) && (m_config->coreProfile() == profile_CortexM); 351 if (m_P0_stack.createParamElemNoParam(P0_EXCEP_RET, bV7MProfile, m_curr_packet_in->getType(), m_index_curr_pkt) == 0) 352 bAllocErr = true; 353 } 354 break; 355 356 // event trace 357 case ETM4_PKT_I_EVENT: 358 { 359 std::vector<uint32_t> params = { 0 }; 360 params[0] = (uint32_t)m_curr_packet_in->event_val; 361 if (m_P0_stack.createParamElem(P0_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) 362 bAllocErr = true; 363 364 } 365 break; 366 367 /* cycle count packets */ 368 case ETM4_PKT_I_CCNT_F1: 369 case ETM4_PKT_I_CCNT_F2: 370 case ETM4_PKT_I_CCNT_F3: 371 { 372 std::vector<uint32_t> params = { 0 }; 373 params[0] = m_curr_packet_in->getCC(); 374 if (m_P0_stack.createParamElem(P0_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) 375 bAllocErr = true; 376 377 } 378 break; 379 380 // timestamp 381 case ETM4_PKT_I_TIMESTAMP: 382 { 383 bool bTSwithCC = m_config->enabledCCI(); 384 uint64_t ts = m_curr_packet_in->getTS(); 385 std::vector<uint32_t> params = { 0, 0, 0 }; 386 params[0] = (uint32_t)(ts & 0xFFFFFFFF); 387 params[1] = (uint32_t)((ts >> 32) & 0xFFFFFFFF); 388 if (bTSwithCC) 389 params[2] = m_curr_packet_in->getCC(); 390 if (m_P0_stack.createParamElem(P0_EVENT, false, m_curr_packet_in->getType(), m_index_curr_pkt, params) == 0) 391 bAllocErr = true; 392 393 } 394 break; 395 396 case ETM4_PKT_I_BAD_SEQUENCE: 397 resp = handleBadPacket("Bad byte sequence in packet."); 398 break; 399 400 case ETM4_PKT_I_BAD_TRACEMODE: 401 resp = handleBadPacket("Invalid packet type for trace mode."); 402 break; 403 404 case ETM4_PKT_I_RESERVED: 405 resp = handleBadPacket("Reserved packet header"); 406 break; 407 408 /*** presently unsupported packets ***/ 409 /* conditional instruction tracing */ 410 case ETM4_PKT_I_COND_FLUSH: 411 case ETM4_PKT_I_COND_I_F1: 412 case ETM4_PKT_I_COND_I_F2: 413 case ETM4_PKT_I_COND_I_F3: 414 case ETM4_PKT_I_COND_RES_F1: 415 case ETM4_PKT_I_COND_RES_F2: 416 case ETM4_PKT_I_COND_RES_F3: 417 case ETM4_PKT_I_COND_RES_F4: 418 // speculation 419 case ETM4_PKT_I_CANCEL_F1: 420 case ETM4_PKT_I_CANCEL_F2: 421 case ETM4_PKT_I_CANCEL_F3: 422 case ETM4_PKT_I_COMMIT: 423 case ETM4_PKT_I_MISPREDICT: 424 case ETM4_PKT_I_DISCARD: 425 // data synchronisation markers 426 case ETM4_PKT_I_NUM_DS_MKR: 427 case ETM4_PKT_I_UNNUM_DS_MKR: 428 /* Q packets */ 429 case ETM4_PKT_I_Q: 430 resp = OCSD_RESP_FATAL_INVALID_DATA; 431 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Unsupported packet type.")); 432 break; 433 434 default: 435 // any other packet - bad packet error 436 resp = OCSD_RESP_FATAL_INVALID_DATA; 437 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Unknown packet type.")); 438 break; 439 440 } 441 442 // we need to wait for following address after exception 443 // - work out if we have seen enough here... 444 if(m_except_pending_addr && !is_except) 445 { 446 m_except_pending_addr = false; //next packet has to be an address 447 // exception packet sequence complete 448 if(is_addr) 449 { 450 m_curr_spec_depth++; // exceptions are P0 elements so up the spec depth to commit if needed. 451 } 452 else 453 { 454 resp = OCSD_RESP_FATAL_INVALID_DATA; 455 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,"Expected Address packet to follow exception packet.")); 456 } 457 } 458 459 if(bAllocErr) 460 { 461 resp = OCSD_RESP_FATAL_SYS_ERR; 462 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_MEM,"Memory allocation error.")); 463 } 464 else if(m_curr_spec_depth > m_max_spec_depth) 465 { 466 // auto commit anything above max spec depth 467 // (this will auto commit anything if spec depth not supported!) 468 m_P0_commit = m_curr_spec_depth - m_max_spec_depth; 469 m_curr_state = COMMIT_ELEM; 470 Complete = false; // force the processing of the commit elements. 471 } 472 return resp; 473 } 474 475 void TrcPktDecodeEtmV4I::doTraceInfoPacket() 476 { 477 m_trace_info = m_curr_packet_in->getTraceInfo(); 478 m_cc_threshold = m_curr_packet_in->getCCThreshold(); 479 m_p0_key = m_curr_packet_in->getP0Key(); 480 m_curr_spec_depth = m_curr_packet_in->getCurrSpecDepth(); 481 } 482 483 /* 484 * Walks through the element stack, processing from oldest element to the newest, 485 according to the number of P0 elements that need committing. 486 */ 487 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::commitElements(bool &Complete) 488 { 489 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 490 bool bPause = false; // pause commit operation 491 bool bPopElem = true; // do we remove the element from the stack (multi atom elements may need to stay!) 492 int num_commit_req = m_P0_commit; 493 494 Complete = true; // assume we exit due to completion of commit operation 495 496 TrcStackElem *pElem = 0; // stacked element pointer 497 498 while(m_P0_commit && !bPause) 499 { 500 if(m_P0_stack.size() > 0) 501 { 502 pElem = m_P0_stack.back(); // get oldest element 503 504 switch(pElem->getP0Type()) 505 { 506 // indicates a trace restart - beginning of trace or discontinuiuty 507 case P0_TRC_ON: 508 m_output_elem.setType(OCSD_GEN_TRC_ELEM_TRACE_ON); 509 m_output_elem.trace_on_reason = m_prev_overflow ? TRACE_ON_OVERFLOW : TRACE_ON_NORMAL; 510 m_prev_overflow = false; 511 resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); 512 m_return_stack.flush(); 513 break; 514 515 case P0_ADDR: 516 { 517 TrcStackElemAddr *pAddrElem = dynamic_cast<TrcStackElemAddr *>(pElem); 518 m_return_stack.clear_pop_pending(); // address removes the need to pop the indirect address target from the stack 519 if(pAddrElem) 520 { 521 SetInstrInfoInAddrISA(pAddrElem->getAddr().val, pAddrElem->getAddr().isa); 522 m_need_addr = false; 523 } 524 } 525 break; 526 527 case P0_CTXT: 528 { 529 TrcStackElemCtxt *pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem); 530 if(pCtxtElem) 531 { 532 etmv4_context_t ctxt = pCtxtElem->getContext(); 533 // check this is an updated context 534 if(ctxt.updated) 535 { 536 updateContext(pCtxtElem); 537 538 m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); 539 resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); 540 } 541 } 542 } 543 break; 544 545 case P0_EVENT: 546 { 547 TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); 548 if(pParamElem) 549 resp = this->outputEvent(pParamElem); 550 } 551 break; 552 553 case P0_TS: 554 { 555 TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); 556 if(pParamElem) 557 resp = outputTS(pParamElem,false); 558 } 559 break; 560 561 case P0_CC: 562 { 563 TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); 564 if(pParamElem) 565 resp = outputCC(pParamElem); 566 } 567 break; 568 569 case P0_TS_CC: 570 { 571 TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); 572 if(pParamElem) 573 resp = outputTS(pParamElem,true); 574 } 575 break; 576 577 case P0_OVERFLOW: 578 m_prev_overflow = true; 579 break; 580 581 case P0_ATOM: 582 { 583 TrcStackElemAtom *pAtomElem = dynamic_cast<TrcStackElemAtom *>(pElem); 584 585 if(pAtomElem) 586 { 587 bool bContProcess = true; 588 while(!pAtomElem->isEmpty() && m_P0_commit && bContProcess) 589 { 590 ocsd_atm_val atom = pAtomElem->commitOldest(); 591 592 // check if prev atom left us an indirect address target on the return stack 593 if ((resp = returnStackPop()) != OCSD_RESP_CONT) 594 break; 595 596 // if address and context do instruction trace follower. 597 // otherwise skip atom and reduce committed elements 598 if(!m_need_ctxt && !m_need_addr) 599 { 600 resp = processAtom(atom,bContProcess); 601 } 602 m_P0_commit--; // mark committed 603 } 604 if(!pAtomElem->isEmpty()) 605 bPopElem = false; // don't remove if still atoms to process. 606 } 607 } 608 break; 609 610 case P0_EXCEP: 611 // check if prev atom left us an indirect address target on the return stack 612 if ((resp = returnStackPop()) != OCSD_RESP_CONT) 613 break; 614 615 m_excep_proc = EXCEP_POP; // set state in case we need to stop part way through 616 resp = processException(); // output trace + exception elements. 617 m_P0_commit--; 618 break; 619 620 case P0_EXCEP_RET: 621 m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); 622 resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); 623 if(pElem->isP0()) // are we on a core that counts ERET as P0? 624 m_P0_commit--; 625 break; 626 } 627 628 if(bPopElem) 629 m_P0_stack.delete_back(); // remove element from stack; 630 631 // if response not continue, then break out of the loop. 632 if(!OCSD_DATA_RESP_IS_CONT(resp)) 633 { 634 bPause = true; 635 } 636 } 637 else 638 { 639 // too few elements for commit operation - decode error. 640 ocsd_trc_index_t err_idx = 0; 641 if(pElem) 642 err_idx = pElem->getRootIndex(); 643 644 resp = OCSD_RESP_FATAL_INVALID_DATA; 645 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_COMMIT_PKT_OVERRUN,err_idx,m_CSID,"Not enough elements to commit")); 646 bPause = true; 647 } 648 } 649 650 // done all elements - need more packets. 651 if(m_P0_commit == 0) 652 m_curr_state = DECODE_PKTS; 653 654 // reduce the spec depth by number of comitted elements 655 m_curr_spec_depth -= (num_commit_req-m_P0_commit); 656 return resp; 657 } 658 659 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::returnStackPop() 660 { 661 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 662 ocsd_isa nextISA; 663 664 if (m_return_stack.pop_pending()) 665 { 666 ocsd_vaddr_t popAddr = m_return_stack.pop(nextISA); 667 if (m_return_stack.overflow()) 668 { 669 resp = OCSD_RESP_FATAL_INVALID_DATA; 670 LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_RET_STACK_OVERFLOW, "Trace Return Stack Overflow.")); 671 } 672 else 673 { 674 m_instr_info.instr_addr = popAddr; 675 m_instr_info.isa = nextISA; 676 m_need_addr = false; 677 } 678 } 679 return resp; 680 } 681 682 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::flushEOT() 683 { 684 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 685 if(m_flush_EOT) 686 { 687 TrcStackElem *pElem = 0; 688 while(OCSD_DATA_RESP_IS_CONT(resp) && (m_P0_stack.size() > 0)) 689 { 690 // scan for outstanding events, TS and CC, before any outstanding 691 // P0 commit elements. 692 pElem = m_P0_stack.back(); 693 694 switch(pElem->getP0Type()) 695 { 696 // clear stack and stop 697 case P0_UNKNOWN: 698 case P0_ATOM: 699 case P0_TRC_ON: 700 case P0_EXCEP: 701 case P0_EXCEP_RET: 702 case P0_OVERFLOW: 703 m_P0_stack.delete_all(); 704 break; 705 706 //skip 707 case P0_ADDR: 708 case P0_CTXT: 709 break; 710 711 // output 712 case P0_EVENT: 713 { 714 TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); 715 if(pParamElem) 716 resp = this->outputEvent(pParamElem); 717 } 718 break; 719 720 case P0_TS: 721 { 722 TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); 723 if(pParamElem) 724 resp = outputTS(pParamElem,false); 725 } 726 break; 727 728 case P0_CC: 729 { 730 TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); 731 if(pParamElem) 732 resp = outputCC(pParamElem); 733 } 734 break; 735 736 case P0_TS_CC: 737 { 738 TrcStackElemParam *pParamElem = dynamic_cast<TrcStackElemParam *>(pElem); 739 if(pParamElem) 740 resp = outputTS(pParamElem,true); 741 } 742 break; 743 } 744 m_P0_stack.delete_back(); 745 } 746 747 if(OCSD_DATA_RESP_IS_CONT(resp) && (m_P0_stack.size() == 0)) 748 { 749 m_output_elem.setType(OCSD_GEN_TRC_ELEM_EO_TRACE); 750 resp = outputTraceElement(m_output_elem); 751 m_flush_EOT = false; 752 } 753 } 754 return resp; 755 } 756 757 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputCC(TrcStackElemParam *pParamElem) 758 { 759 m_output_elem.setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); 760 m_output_elem.cycle_count = pParamElem->getParam(0); 761 return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); 762 } 763 764 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputTS(TrcStackElemParam *pParamElem, bool withCC) 765 { 766 m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); 767 m_output_elem.timestamp = (uint64_t)(pParamElem->getParam(0)) | (((uint64_t)pParamElem->getParam(1)) << 32); 768 if(withCC) 769 m_output_elem.setCycleCount(pParamElem->getParam(2)); 770 return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); 771 } 772 773 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::outputEvent(TrcStackElemParam *pParamElem) 774 { 775 m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT); 776 m_output_elem.trace_event.ev_type = EVENT_NUMBERED; 777 m_output_elem.trace_event.ev_number = pParamElem->getParam(0); 778 return outputTraceElementIdx(pParamElem->getRootIndex(),m_output_elem); 779 } 780 781 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processAtom(const ocsd_atm_val atom, bool &bCont) 782 { 783 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 784 TrcStackElem *pElem = m_P0_stack.back(); // get the atom element 785 bool bWPFound = false; 786 ocsd_err_t err; 787 bCont = true; 788 789 err = traceInstrToWP(bWPFound); 790 if(err != OCSD_OK) 791 { 792 if(err == OCSD_ERR_UNSUPPORTED_ISA) 793 { 794 m_need_addr = true; 795 m_need_ctxt = true; 796 LogError(ocsdError(OCSD_ERR_SEV_WARN,err,pElem->getRootIndex(),m_CSID,"Warning: unsupported instruction set processing atom packet.")); 797 // wait for next context 798 return resp; 799 } 800 else 801 { 802 bCont = false; 803 resp = OCSD_RESP_FATAL_INVALID_DATA; 804 LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,pElem->getRootIndex(),m_CSID,"Error processing atom packet.")); 805 return resp; 806 } 807 } 808 809 if(bWPFound) 810 { 811 // save recorded next instuction address 812 ocsd_vaddr_t nextAddr = m_instr_info.instr_addr; 813 814 // action according to waypoint type and atom value 815 switch(m_instr_info.type) 816 { 817 case OCSD_INSTR_BR: 818 if (atom == ATOM_E) 819 { 820 m_instr_info.instr_addr = m_instr_info.branch_addr; 821 if (m_instr_info.is_link) 822 m_return_stack.push(nextAddr, m_instr_info.isa); 823 824 } 825 break; 826 827 case OCSD_INSTR_BR_INDIRECT: 828 if (atom == ATOM_E) 829 { 830 m_need_addr = true; // indirect branch taken - need new address. 831 if (m_instr_info.is_link) 832 m_return_stack.push(nextAddr,m_instr_info.isa); 833 m_return_stack.set_pop_pending(); // need to know next packet before we know what is to happen 834 } 835 break; 836 } 837 m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); 838 m_output_elem.setLastInstrInfo((atom == ATOM_E),m_instr_info.type, m_instr_info.sub_type); 839 m_output_elem.setISA(m_instr_info.isa); 840 resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); 841 842 } 843 else 844 { 845 // no waypoint - likely inaccessible memory range. 846 m_need_addr = true; // need an address update 847 848 if(m_output_elem.st_addr != m_output_elem.en_addr) 849 { 850 // some trace before we were out of memory access range 851 m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); 852 m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); 853 m_output_elem.setISA(m_instr_info.isa); 854 resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); 855 } 856 857 if(m_mem_nacc_pending && OCSD_DATA_RESP_IS_CONT(resp)) 858 { 859 m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); 860 m_output_elem.st_addr = m_nacc_addr; 861 resp = outputTraceElementIdx(pElem->getRootIndex(),m_output_elem); 862 m_mem_nacc_pending = false; 863 } 864 } 865 866 if(!OCSD_DATA_RESP_IS_CONT(resp)) 867 bCont = false; 868 869 return resp; 870 } 871 872 // Exception processor 873 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::processException() 874 { 875 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 876 bool excep_implied_P0 = false; //!< exception implies P0 877 878 if(m_excep_proc == EXCEP_POP) 879 { 880 TrcStackElemExcept *pExceptElem = dynamic_cast<TrcStackElemExcept *>(m_P0_stack.back()); // get the exception element 881 TrcStackElemAddr *pAddressElem = 0; 882 TrcStackElemCtxt *pCtxtElem = 0; 883 TrcStackElem *pElem = 0; 884 885 m_P0_stack.pop_back(); // remove the exception element 886 pElem = m_P0_stack.back(); // look at next element. 887 if(pElem->getP0Type() == P0_CTXT) 888 { 889 pCtxtElem = dynamic_cast<TrcStackElemCtxt *>(pElem); 890 m_P0_stack.pop_back(); // remove the context element 891 pElem = m_P0_stack.back(); // next one should be an address element 892 } 893 894 if(pElem->getP0Type() != P0_ADDR) 895 { 896 // no following address element - indicate processing error. 897 resp = OCSD_RESP_FATAL_INVALID_DATA; 898 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,pExceptElem->getRootIndex(),m_CSID,"Address missing in exception packet.")); 899 } 900 else 901 { 902 // extract address 903 pAddressElem = static_cast<TrcStackElemAddr *>(pElem); 904 905 m_excep_addr = pAddressElem->getAddr(); 906 907 // if we have context, get that. 908 if(pCtxtElem) 909 updateContext(pCtxtElem); 910 911 // record the exception number 912 m_output_elem.exception_number = pExceptElem->getExcepNum(); 913 914 // see if there is an implied P0 element on the exception. 915 excep_implied_P0 = pExceptElem->getPrevSame(); 916 917 // save the trace index. 918 m_excep_index = pExceptElem->getRootIndex(); 919 920 // figure out next move 921 if(m_excep_addr.val == m_instr_info.instr_addr) 922 m_excep_proc = EXCEP_EXCEP; 923 else 924 m_excep_proc = EXCEP_RANGE; 925 } 926 m_P0_stack.delete_popped(); 927 } 928 929 // output a range element 930 if(m_excep_proc == EXCEP_RANGE) 931 { 932 bool bWPFound = false; 933 ocsd_err_t err; 934 935 // last instr_info address is the start address 936 m_output_elem.st_addr = m_instr_info.instr_addr; 937 938 // look for either a WP or match to return address. 939 err = traceInstrToWP(bWPFound,!excep_implied_P0,m_excep_addr.val); 940 941 if(err != OCSD_OK) 942 { 943 if(err == OCSD_ERR_UNSUPPORTED_ISA) 944 { 945 m_need_addr = true; 946 m_need_ctxt = true; 947 LogError(ocsdError(OCSD_ERR_SEV_WARN,err,m_excep_index,m_CSID,"Warning: unsupported instruction set processing exception packet.")); 948 } 949 else 950 { 951 resp = OCSD_RESP_FATAL_INVALID_DATA; 952 LogError(ocsdError(OCSD_ERR_SEV_ERROR,err,m_excep_index,m_CSID,"Error processing exception packet.")); 953 m_excep_proc = EXCEP_POP; // nothing more to do, reset to start of exception handling 954 } 955 } 956 957 if(bWPFound) 958 { 959 // action according to waypoint type and atom value 960 if(excep_implied_P0) 961 { 962 switch(m_instr_info.type) 963 { 964 case OCSD_INSTR_BR: 965 m_instr_info.instr_addr = m_instr_info.branch_addr; 966 break; 967 968 case OCSD_INSTR_BR_INDIRECT: 969 m_instr_info.instr_addr = m_excep_addr.val; 970 break; 971 } 972 } 973 m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); 974 m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); 975 m_output_elem.setISA(m_instr_info.isa); 976 resp = outputTraceElementIdx(m_excep_index, m_output_elem); 977 m_excep_proc = EXCEP_EXCEP; 978 } 979 else 980 { 981 // no waypoint - likely inaccessible memory range. 982 m_need_addr = true; // need an address update 983 984 if(m_output_elem.st_addr != m_output_elem.en_addr) 985 { 986 // some trace before we were out of memory access range 987 m_output_elem.setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE); 988 m_output_elem.setLastInstrInfo(true,m_instr_info.type, m_instr_info.sub_type); 989 m_output_elem.setISA(m_instr_info.isa); 990 resp = outputTraceElementIdx(m_excep_index,m_output_elem); 991 } 992 993 m_excep_proc = m_mem_nacc_pending ? EXCEP_NACC : EXCEP_EXCEP; 994 } 995 } 996 997 if((m_excep_proc == EXCEP_NACC) && OCSD_DATA_RESP_IS_CONT(resp)) 998 { 999 m_output_elem.setType(OCSD_GEN_TRC_ELEM_ADDR_NACC); 1000 m_output_elem.st_addr = m_nacc_addr; 1001 resp = outputTraceElementIdx(m_excep_index,m_output_elem); 1002 m_excep_proc = EXCEP_EXCEP; 1003 m_mem_nacc_pending = false; 1004 } 1005 1006 if((m_excep_proc == EXCEP_EXCEP) && OCSD_DATA_RESP_IS_CONT(resp)) 1007 { 1008 // output element. 1009 m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION); 1010 // add end address as preferred return address to end addr in element 1011 m_output_elem.en_addr = m_excep_addr.val; 1012 m_output_elem.excep_ret_addr = 1; 1013 resp = outputTraceElementIdx(m_excep_index,m_output_elem); 1014 m_excep_proc = EXCEP_POP; 1015 } 1016 return resp; 1017 } 1018 1019 void TrcPktDecodeEtmV4I::SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val, const uint8_t isa) 1020 { 1021 m_instr_info.instr_addr = addr_val; 1022 if(m_is_64bit) 1023 m_instr_info.isa = ocsd_isa_aarch64; 1024 else 1025 m_instr_info.isa = (isa == 0) ? ocsd_isa_arm : ocsd_isa_thumb2; 1026 } 1027 1028 // trace an instruction range to a waypoint - and set next address to restart from. 1029 ocsd_err_t TrcPktDecodeEtmV4I::traceInstrToWP(bool &bWPFound, const bool traceToAddrNext /*= false*/, const ocsd_vaddr_t nextAddrMatch /*= 0*/) 1030 { 1031 uint32_t opcode; 1032 uint32_t bytesReq; 1033 ocsd_err_t err = OCSD_OK; 1034 1035 // TBD?: update mem space to allow for EL as well. 1036 ocsd_mem_space_acc_t mem_space = m_is_secure ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N; 1037 1038 m_output_elem.st_addr = m_output_elem.en_addr = m_instr_info.instr_addr; 1039 1040 bWPFound = false; 1041 1042 while(!bWPFound && !m_mem_nacc_pending) 1043 { 1044 // start off by reading next opcode; 1045 bytesReq = 4; 1046 err = accessMemory(m_instr_info.instr_addr,mem_space,&bytesReq,(uint8_t *)&opcode); 1047 if(err != OCSD_OK) break; 1048 1049 if(bytesReq == 4) // got data back 1050 { 1051 m_instr_info.opcode = opcode; 1052 err = instrDecode(&m_instr_info); 1053 if(err != OCSD_OK) break; 1054 1055 // increment address - may be adjusted by direct branch value later 1056 m_instr_info.instr_addr += m_instr_info.instr_size; 1057 1058 // update the range decoded address in the output packet. 1059 m_output_elem.en_addr = m_instr_info.instr_addr; 1060 1061 // either walking to match the next instruction address or a real watchpoint 1062 if(traceToAddrNext) 1063 bWPFound = (m_output_elem.en_addr == nextAddrMatch); 1064 else 1065 bWPFound = (m_instr_info.type != OCSD_INSTR_OTHER); 1066 } 1067 else 1068 { 1069 // not enough memory accessible. 1070 m_mem_nacc_pending = true; 1071 m_nacc_addr = m_instr_info.instr_addr; 1072 } 1073 } 1074 return err; 1075 } 1076 1077 void TrcPktDecodeEtmV4I::updateContext(TrcStackElemCtxt *pCtxtElem) 1078 { 1079 etmv4_context_t ctxt = pCtxtElem->getContext(); 1080 // map to output element and local saved state. 1081 m_is_64bit = (ctxt.SF != 0); 1082 m_output_elem.context.bits64 = ctxt.SF; 1083 m_is_secure = (ctxt.NS == 0); 1084 m_output_elem.context.security_level = ctxt.NS ? ocsd_sec_nonsecure : ocsd_sec_secure; 1085 m_output_elem.context.exception_level = (ocsd_ex_level)ctxt.EL; 1086 m_output_elem.context.el_valid = 1; 1087 if(ctxt.updated_c) 1088 { 1089 m_output_elem.context.ctxt_id_valid = 1; 1090 m_context_id = m_output_elem.context.context_id = ctxt.ctxtID; 1091 } 1092 if(ctxt.updated_v) 1093 { 1094 m_output_elem.context.vmid_valid = 1; 1095 m_vmid_id = m_output_elem.context.vmid = ctxt.VMID; 1096 } 1097 m_need_ctxt = false; 1098 } 1099 1100 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::handleBadPacket(const char *reason) 1101 { 1102 ocsd_datapath_resp_t resp = OCSD_RESP_CONT; 1103 1104 if(getComponentOpMode() && OCSD_OPFLG_PKTDEC_ERROR_BAD_PKTS) 1105 { 1106 // error out - stop decoding 1107 resp = OCSD_RESP_FATAL_INVALID_DATA; 1108 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_DECODE_PKT,reason)); 1109 } 1110 else 1111 { 1112 // switch to unsync - clear decode state 1113 m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); 1114 resp = outputTraceElement(m_output_elem); 1115 resetDecoder(); 1116 m_curr_state = WAIT_SYNC; 1117 } 1118 return resp; 1119 } 1120 1121 /* End of File trc_pkt_decode_etmv4i.cpp */ 1122