1 /*
2  * \file       trc_pkt_elem_ptm.cpp
3  * \brief      OpenCSD :
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 <sstream>
37 #include <iomanip>
38 
39 #include "opencsd/ptm/trc_pkt_elem_ptm.h"
40 
41 PtmTrcPacket::PtmTrcPacket()
42 {
43 }
44 
45 PtmTrcPacket::~PtmTrcPacket()
46 {
47 }
48 
49 PtmTrcPacket &PtmTrcPacket::operator =(const ocsd_ptm_pkt* p_pkt)
50 {
51     *dynamic_cast<ocsd_ptm_pkt *>(this) = *p_pkt;
52     return *this;
53 }
54 
55 void PtmTrcPacket::Clear()
56 {
57     err_type = PTM_PKT_NOERROR;
58     cycle_count = 0;
59     cc_valid = 0;
60     context.updated = 0;
61     context.updated_c = 0;
62     context.updated_v = 0;
63     ts_update_bits = 0;
64     atom.En_bits = 0;
65     exception.bits.present = 0;
66     prev_isa = curr_isa;    // mark ISA as not changed
67 }
68 
69 void PtmTrcPacket::ResetState()
70 {
71     type = PTM_PKT_NOTSYNC;
72 
73     context.ctxtID = 0;
74     context.VMID = 0;
75     context.curr_alt_isa = 0;
76     context.curr_Hyp = 0;
77     context.curr_NS = 0;
78 
79     addr.valid_bits = 0;
80     addr.size = VA_32BIT;
81     addr.val = 0;
82 
83     prev_isa = curr_isa = ocsd_isa_unknown;
84 
85     timestamp = 0;
86 
87     Clear();
88 }
89 
90 void PtmTrcPacket::UpdateAddress(const ocsd_vaddr_t partAddrVal, const int updateBits)
91 {
92     ocsd_vaddr_t validMask = OCSD_VA_MASK;
93     validMask >>= OCSD_MAX_VA_BITSIZE-updateBits;
94     addr.pkt_bits = updateBits;
95     addr.val &= ~validMask;
96     addr.val |= (partAddrVal & validMask);
97     if(updateBits > addr.valid_bits)
98         addr.valid_bits = updateBits;
99 }
100 
101 void PtmTrcPacket::UpdateTimestamp(const uint64_t tsVal, const uint8_t updateBits)
102 {
103     uint64_t validMask = ~0ULL;
104     validMask >>= 64-updateBits;
105     timestamp &= ~validMask;
106     timestamp |= (tsVal & validMask);
107     ts_update_bits = updateBits;
108 }
109 
110 void PtmTrcPacket::SetCycleAccAtomFromPHdr(const uint8_t pHdr)
111 {
112     atom.num = 1;
113     atom.En_bits = (pHdr & 0x2) ? 0x0 : 0x1;
114 }
115 
116 void PtmTrcPacket::SetAtomFromPHdr(const uint8_t pHdr)
117 {
118     // how many atoms
119     uint8_t atom_fmt_id = pHdr & 0xF0;
120     if(atom_fmt_id == 0x80)
121     {
122         // format 1 or 2
123         if((pHdr & 0x08) == 0x08)
124             atom.num = 2;
125         else
126             atom.num = 1;
127     }
128     else if(atom_fmt_id == 0x90)
129     {
130         atom.num = 3;
131     }
132     else
133     {
134         if((pHdr & 0xE0) == 0xA0)
135             atom.num = 4;
136         else
137             atom.num = 5;
138     }
139 
140     // extract the E/N bits
141     uint8_t atom_mask = 0x2;    // start @ bit 1 - newest instruction
142     atom.En_bits = 0;
143     for(int i = 0; i < atom.num; i++)
144     {
145         atom.En_bits <<= 1;
146         if(!(atom_mask & pHdr)) // 0 bit is an E in PTM -> a one in the standard atom bit type
147             atom.En_bits |= 0x1;
148         atom_mask <<= 1;
149     }
150 }
151 
152     // printing
153 void PtmTrcPacket::toString(std::string &str) const
154 {
155     std::string temp1, temp2;
156     std::ostringstream oss;
157 
158     packetTypeName(type, temp1,temp2);
159     oss << temp1 << " : " << temp2 << "; ";
160 
161     // some packets require additional data.
162     switch(type)
163     {
164     case PTM_PKT_BAD_SEQUENCE:
165         packetTypeName(err_type, temp1,temp2);
166         oss << "[" << temp1 << "]; ";
167         break;
168 
169     case PTM_PKT_ATOM:
170         getAtomStr(temp1);
171         oss << temp1;
172         break;
173 
174     case PTM_PKT_CONTEXT_ID:
175         oss << "CtxtID=0x" << std::hex << std::setw(8) << std::setfill('0') << context.ctxtID << "; ";
176         break;
177 
178     case PTM_PKT_VMID:
179         oss << "VMID=0x" << std::hex << std::setw(2) << std::setfill('0') << context.VMID << "; ";
180         break;
181 
182     case PTM_PKT_WPOINT_UPDATE:
183     case PTM_PKT_BRANCH_ADDRESS:
184         getBranchAddressStr(temp1);
185         oss << temp1;
186         break;
187 
188     case PTM_PKT_I_SYNC:
189         getISyncStr(temp1);
190         oss << temp1;
191         break;
192 
193     case PTM_PKT_TIMESTAMP:
194         getTSStr(temp1);
195         oss << temp1;
196         break;
197     }
198 
199     str = oss.str();
200 }
201 
202 void PtmTrcPacket::toStringFmt(const uint32_t fmtFlags, std::string &str) const
203 {
204     toString(str);
205 }
206 
207 void PtmTrcPacket::getAtomStr(std::string &valStr) const
208 {
209     std::ostringstream oss;
210     uint32_t bitpattern = atom.En_bits; // arranged LSBit oldest, MSbit newest
211 
212     if(cc_valid)    // cycle accurate trace - single atom
213     {
214         std::string subStr;
215         oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
216         oss << "; ";
217         getCycleCountStr(subStr);
218         oss << subStr;
219     }
220     else
221     {
222         // none cycle count
223         for(int i = 0; i < atom.num; i++)
224         {
225             oss << ((bitpattern & 0x1) ? "E" : "N"); // in spec read L->R, oldest->newest
226             bitpattern >>= 1;
227         }
228         oss << "; ";
229     }
230     valStr = oss.str();
231 }
232 
233 void PtmTrcPacket::getBranchAddressStr(std::string &valStr) const
234 {
235     std::ostringstream oss;
236     std::string subStr;
237 
238     // print address.
239     trcPrintableElem::getValStr(subStr,32,addr.valid_bits,addr.val,true,addr.pkt_bits);
240     oss << "Addr=" << subStr << "; ";
241 
242     // current ISA if changed.
243     if(curr_isa != prev_isa)
244     {
245         getISAStr(subStr);
246         oss << subStr;
247     }
248 
249     // S / NS etc if changed.
250     if(context.updated)
251     {
252         oss << (context.curr_NS ? "NS; " : "S; ");
253         oss << (context.curr_Hyp ? "Hyp; " : "");
254     }
255 
256     // exception?
257     if(exception.bits.present)
258     {
259         getExcepStr(subStr);
260         oss << subStr;
261     }
262 
263     if(cc_valid)
264     {
265         getCycleCountStr(subStr);
266         oss << subStr;
267     }
268     valStr = oss.str();
269 }
270 
271 void PtmTrcPacket::getISAStr(std::string &isaStr) const
272 {
273     std::ostringstream oss;
274     oss << "ISA=";
275     switch(curr_isa)
276     {
277     case ocsd_isa_arm:
278         oss << "ARM(32); ";
279         break;
280 
281     case ocsd_isa_thumb2:
282         oss << "Thumb2; ";
283         break;
284 
285     case ocsd_isa_aarch64:
286         oss << "AArch64; ";
287         break;
288 
289     case ocsd_isa_tee:
290         oss << "ThumbEE; ";
291         break;
292 
293     case ocsd_isa_jazelle:
294         oss << "Jazelle; ";
295         break;
296 
297     default:
298     case ocsd_isa_unknown:
299         oss << "Unknown; ";
300         break;
301     }
302     isaStr = oss.str();
303 }
304 
305 void PtmTrcPacket::getExcepStr(std::string &excepStr) const
306 {
307     static const char *ARv7Excep[] = {
308         "No Exception", "Debug Halt", "SMC", "Hyp",
309         "Async Data Abort", "Jazelle", "Reserved", "Reserved",
310         "PE Reset", "Undefined Instr", "SVC", "Prefetch Abort",
311         "Data Fault", "Generic", "IRQ", "FIQ"
312     };
313 
314     std::ostringstream oss;
315     oss << "Excep=";
316     if(exception.number < 16)
317         oss << ARv7Excep[exception.number];
318     else
319         oss << "Unknown";
320     oss << " [" << std::hex << std::setw(2) << std::setfill('0') << exception.number << "]; ";
321     excepStr = oss.str();
322 }
323 
324 void PtmTrcPacket::getISyncStr(std::string &valStr) const
325 {
326     std::ostringstream oss;
327     std::string tmpStr;
328     static const char *reason[] = { "Periodic", "Trace Enable", "Restart Overflow", "Debug Exit" };
329 
330     // reason.
331     oss << "(" << reason[(int)i_sync_reason] << "); ";
332 
333     // full address.
334     oss << "Addr=0x" << std::hex << std::setfill('0') << std::setw(8) << (uint32_t)addr.val << "; ";
335 
336     oss << (context.curr_NS ? "NS; " : "S; ");
337     oss << (context.curr_Hyp ? "Hyp; " : " ");
338 
339     if(context.updated_c)
340     {
341         oss << "CtxtID=" << std::hex  << std::setw(8) << std::setfill('0') << context.ctxtID << "; ";
342     }
343 
344     getISAStr(tmpStr);
345     oss << tmpStr;
346 
347     if(cc_valid)
348     {
349         getCycleCountStr(tmpStr);
350         oss << tmpStr;
351     }
352     valStr = oss.str();
353 }
354 
355 void PtmTrcPacket::getTSStr(std::string &valStr) const
356 {
357     std::string tmpStr;
358     std::ostringstream oss;
359 
360     trcPrintableElem::getValStr(tmpStr,64,64,timestamp,true,ts_update_bits);
361     oss << "TS=" << tmpStr + "(" << std::dec << timestamp << "); ";
362     if(cc_valid)
363     {
364         getCycleCountStr(tmpStr);
365         oss << tmpStr;
366     }
367     valStr = oss.str();
368 }
369 
370 
371 void PtmTrcPacket::getCycleCountStr(std::string &subStr) const
372 {
373     std::ostringstream oss;
374     oss << "Cycles=" << std::dec << cycle_count << "; ";
375     subStr = oss.str();
376 }
377 
378 
379 void PtmTrcPacket::packetTypeName(const ocsd_ptm_pkt_type pkt_type, std::string &name, std::string &desc) const
380 {
381     switch(pkt_type)
382     {
383     case PTM_PKT_NOTSYNC:        //!< no sync found yet
384         name = "NOTSYNC";
385         desc = "PTM Not Synchronised";
386         break;
387 
388     case PTM_PKT_INCOMPLETE_EOT:
389         name = "INCOMPLETE_EOT";
390         desc = "Incomplete packet flushed at end of trace";
391         break;
392 
393     case PTM_PKT_NOERROR:
394         name = "NO_ERROR";
395         desc = "Error type not set";
396         break;
397 
398     case PTM_PKT_BAD_SEQUENCE:
399         name = "BAD_SEQUENCE";
400         desc = "Invalid sequence in packet";
401         break;
402 
403     case PTM_PKT_RESERVED:
404         name = "RESERVED";
405         desc = "Reserved Packet Header";
406         break;
407 
408     case PTM_PKT_BRANCH_ADDRESS:
409         name = "BRANCH_ADDRESS";
410         desc = "Branch address packet";
411         break;
412 
413     case PTM_PKT_A_SYNC:
414         name = "ASYNC";
415         desc = "Alignment Synchronisation Packet";
416         break;
417 
418 	case PTM_PKT_I_SYNC:
419         name = "ISYNC";
420         desc = "Instruction Synchronisation packet";
421         break;
422 
423     case PTM_PKT_TRIGGER:
424         name = "TRIGGER";
425         desc = "Trigger Event packet";
426         break;
427 
428 	case PTM_PKT_WPOINT_UPDATE:
429         name = "WP_UPDATE";
430         desc = "Waypoint update packet";
431         break;
432 
433 	case PTM_PKT_IGNORE:
434         name = "IGNORE";
435         desc = "Ignore packet";
436         break;
437 
438 	case PTM_PKT_CONTEXT_ID:
439         name = "CTXTID";
440         desc = "Context ID packet";
441         break;
442 
443     case PTM_PKT_VMID:
444         name = "VMID";
445         desc = "VM ID packet";
446         break;
447 
448 	case PTM_PKT_ATOM:
449         name = "ATOM";
450         desc = "Atom packet";
451         break;
452 
453 	case PTM_PKT_TIMESTAMP:
454         name = "TIMESTAMP";
455         desc = "Timestamp packet";
456         break;
457 
458 	case PTM_PKT_EXCEPTION_RET:
459         name = "ERET";
460         desc = "Exception return packet";
461         break;
462 
463     default:
464         name = "UNKNOWN";
465         desc = "Unknown packet type";
466         break;
467 
468 	//PTM_PKT_BRANCH_OR_BYPASS_EOT,
469     //PTM_PKT_TPIU_PAD_EOB,
470     }
471 }
472 
473 /* End of File trc_pkt_elem_ptm.cpp */
474