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
TrcPktDecodeEtmV4I()45 TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I()
46 : TrcPktDecodeBase(DCD_NAME)
47 {
48 initDecoder();
49 }
50
TrcPktDecodeEtmV4I(int instIDNum)51 TrcPktDecodeEtmV4I::TrcPktDecodeEtmV4I(int instIDNum)
52 : TrcPktDecodeBase(DCD_NAME,instIDNum)
53 {
54 initDecoder();
55 }
56
~TrcPktDecodeEtmV4I()57 TrcPktDecodeEtmV4I::~TrcPktDecodeEtmV4I()
58 {
59 }
60
61 /*********************** implementation packet decoding interface */
62
processPacket()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
onEOT()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
onReset()119 ocsd_datapath_resp_t TrcPktDecodeEtmV4I::onReset()
120 {
121 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
122 resetDecoder();
123 return resp;
124 }
125
onFlush()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
onProtocolConfig()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 */
initDecoder()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
resetDecoder()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.
decodePacket(bool & Complete)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
doTraceInfoPacket()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 */
commitElements(bool & Complete)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
returnStackPop()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
flushEOT()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
outputCC(TrcStackElemParam * pParamElem)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
outputTS(TrcStackElemParam * pParamElem,bool withCC)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
outputEvent(TrcStackElemParam * pParamElem)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
processAtom(const ocsd_atm_val atom,bool & bCont)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
processException()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
SetInstrInfoInAddrISA(const ocsd_vaddr_t addr_val,const uint8_t isa)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.
traceInstrToWP(bool & bWPFound,const bool traceToAddrNext,const ocsd_vaddr_t nextAddrMatch)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
updateContext(TrcStackElemCtxt * pCtxtElem)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
handleBadPacket(const char * reason)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