2 * \file trc_pkt_decode_etmv3.cpp
3 * \brief OpenCSD : ETMv3 trace packet decode.
5 * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
9 * Redistribution and use in source and binary forms, with or without modification,
10 * are permitted provided that the following conditions are met:
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * 3. Neither the name of the copyright holder nor the names of its contributors
20 * may be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "opencsd/etmv3/trc_pkt_decode_etmv3.h"
37 #define DCD_NAME "DCD_ETMV3"
39 TrcPktDecodeEtmV3::TrcPktDecodeEtmV3() :
40 TrcPktDecodeBase(DCD_NAME)
45 TrcPktDecodeEtmV3::TrcPktDecodeEtmV3(int instIDNum) :
46 TrcPktDecodeBase(DCD_NAME, instIDNum)
51 TrcPktDecodeEtmV3::~TrcPktDecodeEtmV3()
56 /* implementation packet decoding interface */
57 ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPacket()
59 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
60 bool bPktDone = false;
63 return OCSD_RESP_FATAL_NOT_INIT;
65 // iterate round the state machine, waiting for sync, then decoding packets.
71 // output the initial not synced packet to the sink
72 resp = sendUnsyncPacket();
73 m_curr_state = WAIT_ASYNC; // immediate wait for ASync and actually check out the packet
77 // if async, wait for ISync, but this packet done.
78 if(m_curr_packet_in->getType() == ETM3_PKT_A_SYNC)
79 m_curr_state = WAIT_ISYNC;
84 m_bWaitISync = true; // we are waiting for ISync
85 if((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC) ||
86 (m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE))
88 // process the ISync immediately as the first ISync seen.
89 resp = processISync((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE),true);
90 m_curr_state = SEND_PKTS;
93 // something like TS, CC, PHDR+CC, which after ASYNC may be valid prior to ISync
94 else if(preISyncValid(m_curr_packet_in->getType()))
96 // decode anything that might be valid - send will be set automatically
97 resp = decodePacket(bPktDone);
104 resp = decodePacket(bPktDone);
108 resp = m_outputElemList.sendElements();
109 if(OCSD_DATA_RESP_IS_CONT(resp))
110 m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS;
116 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,"Unknown Decoder State"));
117 resetDecoder(); // mark decoder as unsynced - dump any current state.
118 resp = OCSD_RESP_FATAL_SYS_ERR;
126 ocsd_datapath_resp_t TrcPktDecodeEtmV3::onEOT()
128 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
129 OcsdTraceElement *pElem = 0;
131 pElem = GetNextOpElem(resp);
132 pElem->setType(OCSD_GEN_TRC_ELEM_EO_TRACE);
133 m_outputElemList.commitAllPendElem();
134 m_curr_state = SEND_PKTS;
135 resp = m_outputElemList.sendElements();
136 if(OCSD_DATA_RESP_IS_CONT(resp))
137 m_curr_state = DECODE_PKTS;
139 catch(ocsdError &err)
142 resetDecoder(); // mark decoder as unsynced - dump any current state.
147 ocsd_datapath_resp_t TrcPktDecodeEtmV3::onReset()
149 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
154 ocsd_datapath_resp_t TrcPktDecodeEtmV3::onFlush()
156 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
157 if(m_curr_state == SEND_PKTS)
159 resp = m_outputElemList.sendElements();
160 if(OCSD_DATA_RESP_IS_CONT(resp))
161 m_curr_state = m_bWaitISync ? WAIT_ISYNC : DECODE_PKTS;
166 ocsd_err_t TrcPktDecodeEtmV3::onProtocolConfig()
168 ocsd_err_t err = OCSD_OK;
171 // set some static config elements
172 m_CSID = m_config->getTraceID();
174 // check config compatible with current decoder support level.
175 // at present no data trace;
176 if(m_config->GetTraceMode() != EtmV3Config::TM_INSTR_ONLY)
178 err = OCSD_ERR_HW_CFG_UNSUPP;
179 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,"ETMv3 trace decoder : data trace decode not yet supported"));
182 // need to set up core profile info in follower
183 ocsd_arch_profile_t arch_profile;
184 arch_profile.arch = m_config->getArchVersion();
185 arch_profile.profile = m_config->getCoreProfile();
186 m_code_follower.setArchProfile(arch_profile);
187 m_code_follower.setMemSpaceCSID(m_CSID);
188 m_outputElemList.initCSID(m_CSID);
191 err = OCSD_ERR_NOT_INIT;
195 /* local decode methods */
197 // initialise on creation
198 void TrcPktDecodeEtmV3::initDecoder()
202 m_code_follower.initInterfaces(getMemoryAccessAttachPt(),getInstrDecodeAttachPt());
203 m_outputElemList.initSendIf(getTraceElemOutAttachPt());
206 // reset for first use / re-use.
207 void TrcPktDecodeEtmV3::resetDecoder()
209 m_curr_state = NO_SYNC; // mark as not synced
211 m_bSentUnknown = false;
212 m_bWaitISync = false;
213 m_outputElemList.reset();
216 OcsdTraceElement *TrcPktDecodeEtmV3::GetNextOpElem(ocsd_datapath_resp_t &resp)
218 OcsdTraceElement *pElem = m_outputElemList.getNextElem(m_index_curr_pkt);
221 resp = OCSD_RESP_FATAL_NOT_INIT;
222 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_MEM,m_index_curr_pkt,m_CSID,"Memory Allocation Error - fatal");
227 bool TrcPktDecodeEtmV3::preISyncValid(ocsd_etmv3_pkt_type pkt_type)
231 if((pkt_type == ETM3_PKT_TIMESTAMP) ||
232 // or we are cycleacc and its a packet that can have CC in it
233 (m_config->isCycleAcc() && ((pkt_type == ETM3_PKT_CYCLE_COUNT) || (pkt_type == ETM3_PKT_P_HDR)))
239 // simple packet transforms handled here, more complex processing passed on to specific routines.
240 ocsd_datapath_resp_t TrcPktDecodeEtmV3::decodePacket(bool &pktDone)
242 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
243 bool bISyncHasCC = false;
244 OcsdTraceElement *pElem = 0;
247 // there may be pended packets that can now be committed.
248 // only the branch address with exception and cancel element can cancel
249 // if not one of those, commit immediately, otherwise defer to branch address handler.
250 if(m_curr_packet_in->getType() != ETM3_PKT_BRANCH_ADDRESS)
251 m_outputElemList.commitAllPendElem();
255 switch(m_curr_packet_in->getType())
258 case ETM3_PKT_NOTSYNC:
259 // mark as not synced - must have lost sync in the packet processor somehow
260 throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Trace Packet Synchronisation Lost");
263 // no action for these packets - ignore and continue
264 case ETM3_PKT_INCOMPLETE_EOT:
265 case ETM3_PKT_A_SYNC:
266 case ETM3_PKT_IGNORE:
269 // markers for valid packets
270 case ETM3_PKT_CYCLE_COUNT:
271 pElem = GetNextOpElem(resp);
272 pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
273 pElem->setCycleCount(m_curr_packet_in->getCycleCount());
276 case ETM3_PKT_TRIGGER:
277 pElem = GetNextOpElem(resp);
278 pElem->setType(OCSD_GEN_TRC_ELEM_EVENT);
279 pElem->setEvent(EVENT_TRIGGER,0);
282 case ETM3_PKT_BRANCH_ADDRESS:
283 resp = processBranchAddr();
286 case ETM3_PKT_I_SYNC_CYCLE:
288 case ETM3_PKT_I_SYNC:
289 resp = processISync(bISyncHasCC);
293 resp = processPHdr();
296 case ETM3_PKT_CONTEXT_ID:
297 pElem = GetNextOpElem(resp);
298 pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
299 m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID());
300 pElem->setContext(m_PeContext);
304 pElem = GetNextOpElem(resp);
305 pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
306 m_PeContext.setVMID(m_curr_packet_in->getVMID());
307 pElem->setContext(m_PeContext);
310 case ETM3_PKT_EXCEPTION_ENTRY:
311 pElem = GetNextOpElem(resp);
312 pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
313 pElem->setExcepMarker(); // exception entries are always v7M data markers in ETMv3 trace.
316 case ETM3_PKT_EXCEPTION_EXIT:
317 pElem = GetNextOpElem(resp);
318 pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET);
319 pendExceptionReturn();
322 case ETM3_PKT_TIMESTAMP:
323 pElem = GetNextOpElem(resp);
324 pElem->setType(OCSD_GEN_TRC_ELEM_TIMESTAMP);
325 pElem->setTS(m_curr_packet_in->getTS());
328 // data packets - data trace not supported at present
329 case ETM3_PKT_STORE_FAIL:
330 case ETM3_PKT_OOO_DATA:
331 case ETM3_PKT_OOO_ADDR_PLC:
332 case ETM3_PKT_NORM_DATA:
333 case ETM3_PKT_DATA_SUPPRESSED:
334 case ETM3_PKT_VAL_NOT_TRACED:
335 case ETM3_PKT_BAD_TRACEMODE:
336 resp = OCSD_RESP_FATAL_INVALID_DATA;
337 throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_index_curr_pkt,m_CSID,"Invalid packet type : Data Tracing decode not supported.");
341 case ETM3_PKT_BAD_SEQUENCE:
342 resp = OCSD_RESP_FATAL_INVALID_DATA;
343 throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Bad Packet sequence.");
347 case ETM3_PKT_RESERVED:
348 resp = OCSD_RESP_FATAL_INVALID_DATA;
349 throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Reserved or unknown packet ID.");
352 m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
353 pktDone = !m_outputElemList.elemToSend();
355 catch(ocsdError &err)
358 resetDecoder(); // mark decoder as unsynced - dump any current state.
363 LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_FAIL,m_index_curr_pkt,m_CSID,"Bad Packet sequence."));
364 resp = OCSD_RESP_FATAL_SYS_ERR;
365 resetDecoder(); // mark decoder as unsynced - dump any current state.
371 ocsd_datapath_resp_t TrcPktDecodeEtmV3::sendUnsyncPacket()
373 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
374 OcsdTraceElement *pElem = 0;
376 pElem = GetNextOpElem(resp);
377 pElem->setType(OCSD_GEN_TRC_ELEM_NO_SYNC);
378 resp = m_outputElemList.sendElements();
380 catch(ocsdError &err)
383 resetDecoder(); // mark decoder as unsynced - dump any current state.
388 void TrcPktDecodeEtmV3::setNeedAddr(bool bNeedAddr)
390 m_bNeedAddr = bNeedAddr;
391 m_bSentUnknown = false;
394 ocsd_datapath_resp_t TrcPktDecodeEtmV3::processISync(const bool withCC, const bool firstSync /* = false */)
396 // map ISync reason to generic reason codes.
397 static trace_on_reason_t on_map[] = { TRACE_ON_NORMAL, TRACE_ON_NORMAL,
398 TRACE_ON_OVERFLOW, TRACE_ON_EX_DEBUG };
400 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
401 bool ctxtUpdate = m_curr_packet_in->isCtxtUpdated();
402 OcsdTraceElement *pElem = 0;
406 pElem = GetNextOpElem(resp);
408 if(firstSync || (m_curr_packet_in->getISyncReason() != iSync_Periodic))
410 pElem->setType(OCSD_GEN_TRC_ELEM_TRACE_ON);
411 pElem->setTraceOnReason(on_map[(int)m_curr_packet_in->getISyncReason()]);
412 pElem = GetNextOpElem(resp);
415 // look for context changes....
416 if(ctxtUpdate || firstSync)
418 // if not first time out, read existing context in output element,
419 // otherwise we are setting it new.
421 m_PeContext.resetCtxt();
423 if(m_curr_packet_in->isCtxtIDUpdated())
424 m_PeContext.setCtxtID(m_curr_packet_in->getCtxtID());
425 if(m_curr_packet_in->isVMIDUpdated())
426 m_PeContext.setVMID(m_curr_packet_in->getVMID());
427 if(m_curr_packet_in->isCtxtFlagsUpdated())
429 m_PeContext.setEL(m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown);
430 m_PeContext.setSecLevel(m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure);
433 // prepare the context packet
434 pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
435 pElem->setContext(m_PeContext);
436 pElem->setISA(m_curr_packet_in->ISA());
438 // with cycle count...
439 if(m_curr_packet_in->getISyncHasCC())
440 pElem->setCycleCount(m_curr_packet_in->getCycleCount());
444 // set ISync address - if it is a valid I address
445 if(!m_curr_packet_in->getISyncNoAddr())
447 if(m_curr_packet_in->getISyncIsLSiPAddr())
449 // TBD: handle extra data processing instruction for data trace
450 // need to output E atom relating to the data instruction
451 // rare - on start-up case.
453 // main instruction address saved in data address for this packet type.
454 m_IAddr = m_curr_packet_in->getDataAddr();
458 m_IAddr = m_curr_packet_in->getAddr();
460 setNeedAddr(false); // ready to process atoms.
462 m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
464 catch(ocsdError &err)
467 resetDecoder(); // mark decoder as unsynced - dump any current state.
472 ocsd_datapath_resp_t TrcPktDecodeEtmV3::processBranchAddr()
474 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
475 OcsdTraceElement *pElem = 0;
476 bool bUpdatePEContext = false;
478 // might need to cancel something ... if the last output was an instruction range or excep return
479 if(m_curr_packet_in->isExcepCancel())
480 m_outputElemList.cancelPendElem();
482 m_outputElemList.commitAllPendElem(); // otherwise commit any pending elements.
484 // record the address
485 m_IAddr = m_curr_packet_in->getAddr();
486 setNeedAddr(false); // no longer need an address.
488 // exception packet - may need additional output
489 if(m_curr_packet_in->isExcepPkt())
491 // exeception packet may have exception, context change, or both.
492 // check for context change
493 if(m_curr_packet_in->isCtxtUpdated())
496 ocsd_sec_level sec = m_curr_packet_in->isNS() ? ocsd_sec_nonsecure : ocsd_sec_secure;
497 if(sec != m_PeContext.getSecLevel())
499 m_PeContext.setSecLevel(sec);
500 bUpdatePEContext = true;
502 ocsd_ex_level pkt_el = m_curr_packet_in->isHyp() ? ocsd_EL2 : ocsd_EL_unknown;
503 if(pkt_el != m_PeContext.getEL())
505 m_PeContext.setEL(pkt_el);
506 bUpdatePEContext = true;
510 // now decide if we need to send any packets out.
515 pElem = GetNextOpElem(resp);
516 pElem->setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT);
517 pElem->setContext(m_PeContext);
520 // check for exception
521 if(m_curr_packet_in->excepNum() != 0)
523 pElem = GetNextOpElem(resp);
524 pElem->setType(OCSD_GEN_TRC_ELEM_EXCEPTION);
525 pElem->setExceptionNum(m_curr_packet_in->excepNum());
528 // finally - do we have anything to send yet?
529 m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
531 catch(ocsdError &err)
534 resetDecoder(); // mark decoder as unsynced - dump any current state.
541 ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPHdr()
543 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
544 OcsdTraceElement *pElem = 0;
546 Etmv3Atoms atoms(m_config->isCycleAcc());
548 atoms.initAtomPkt(m_curr_packet_in,m_index_curr_pkt);
549 isa = m_curr_packet_in->ISA();
550 m_code_follower.setMemSpaceAccess((m_PeContext.getSecLevel() == ocsd_sec_secure) ? OCSD_MEM_SPACE_S : OCSD_MEM_SPACE_N);
556 // if we do not have a valid address then send any cycle count elements
557 // and stop processing
560 // output unknown address packet or a cycle count packet
561 if(!m_bSentUnknown || m_config->isCycleAcc())
563 pElem = GetNextOpElem(resp);
564 if(m_bSentUnknown || !atoms.numAtoms())
565 pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
567 pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN);
568 if(m_config->isCycleAcc())
569 pElem->setCycleCount(atoms.getRemainCC());
570 m_bSentUnknown = true;
572 atoms.clearAll(); // skip remaining atoms
574 else // have an address, can process atoms
576 pElem = GetNextOpElem(resp);
577 pElem->setType(OCSD_GEN_TRC_ELEM_INSTR_RANGE);
579 // cycle accurate may have a cycle count to use
580 if(m_config->isCycleAcc())
582 // note: it is possible to have a CC only atom packet.
583 if(!atoms.numAtoms()) // override type if CC only
584 pElem->setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT);
586 pElem->setCycleCount(atoms.getAtomCC());
589 // now process the atom
592 m_code_follower.setISA(isa);
593 m_code_follower.followSingleAtom(m_IAddr,atoms.getCurrAtomVal());
596 if(m_code_follower.hasRange())
598 pElem->setAddrRange(m_IAddr,m_code_follower.getRangeEn());
599 pElem->setLastInstrInfo(atoms.getCurrAtomVal() == ATOM_E,
600 m_code_follower.getInstrType(),
601 m_code_follower.getInstrSubType(),m_code_follower.getInstrSize());
602 pElem->setLastInstrCond(m_code_follower.isCondInstr());
604 if(m_code_follower.hasNextAddr())
605 m_IAddr = m_code_follower.getNextAddr();
610 // next address has new ISA?
611 if(m_code_follower.ISAChanged())
612 isa = m_code_follower.nextISA();
615 if(m_code_follower.isNacc())
617 if(m_code_follower.hasRange())
619 pElem = GetNextOpElem(resp);
620 pElem->setType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
623 pElem->updateType(OCSD_GEN_TRC_ELEM_ADDR_NACC);
624 pElem->setAddrStart(m_code_follower.getNaccAddr());
626 m_code_follower.clearNacc(); // we have generated some code for the nacc.
630 atoms.clearAtom(); // next atom
633 while(atoms.numAtoms());
635 // is tha last element an atom?
636 int numElem = m_outputElemList.getNumElem();
639 // if the last thing is an instruction range, pend it - could be cancelled later.
640 if(m_outputElemList.getElemType(numElem-1) == OCSD_GEN_TRC_ELEM_INSTR_RANGE)
641 m_outputElemList.pendLastNElem(1);
644 // finally - do we have anything to send yet?
645 m_curr_state = m_outputElemList.elemToSend() ? SEND_PKTS : DECODE_PKTS;
647 catch(ocsdError &err)
650 resetDecoder(); // mark decoder as unsynced - dump any current state.
655 // if v7M -> pend only ERET, if V7A/R pend ERET and prev instr.
656 void TrcPktDecodeEtmV3::pendExceptionReturn()
659 if(m_config->getCoreProfile() != profile_CortexM)
661 int nElem = m_outputElemList.getNumElem();
664 if(m_outputElemList.getElemType(nElem - 2) == OCSD_GEN_TRC_ELEM_INSTR_RANGE)
665 pendElem = 2; // need to pend instr+eret for A/R
668 m_outputElemList.pendLastNElem(pendElem);
671 /* End of File trc_pkt_decode_etmv3.cpp */