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