1 /*!
2  * \file       trc_pkt_proc_base.h
3  * \brief      OpenCSD : Trace packet processor base class.
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 #ifndef ARM_TRC_PKT_PROC_BASE_H_INCLUDED
37 #define ARM_TRC_PKT_PROC_BASE_H_INCLUDED
38 
39 #include "interfaces/trc_data_raw_in_i.h"
40 #include "interfaces/trc_pkt_in_i.h"
41 #include "interfaces/trc_pkt_raw_in_i.h"
42 #include "interfaces/trc_indexer_pkt_i.h"
43 
44 #include "trc_component.h"
45 #include "comp_attach_pt_t.h"
46 #include "opencsd/ocsd_if_version.h"
47 
48 /** @defgroup ocsd_pkt_proc  OpenCSD Library : Packet Processors.
49     @brief Classes providing Protocol Packet Processing capability.
50 
51     Packet processors take an incoming byte stream and convert into discrete packets for the
52     required trace protocol.
53 @{*/
54 
55 
56 
57 /*!
58  * @class TrcPktProcI
59  * @brief Base Packet processing interface
60  *
61  * Defines the packet processing methods that protocol specific processors must
62  * implement.
63  *
64  */
65 class TrcPktProcI : public TraceComponent, public ITrcDataIn
66 {
67 public:
68     TrcPktProcI(const char *component_name);
69     TrcPktProcI(const char *component_name, int instIDNum);
70     virtual ~TrcPktProcI() {};
71 
72     /** Trace byte data input interface - from ITrcDataIn.
73      */
74     virtual ocsd_datapath_resp_t TraceDataIn(  const ocsd_datapath_op_t op,
75                                                 const ocsd_trc_index_t index,
76                                                 const uint32_t dataBlockSize,
77                                                 const uint8_t *pDataBlock,
78                                                 uint32_t *numBytesProcessed) = 0;
79 
80     virtual ocsd_err_t getStatsBlock(ocsd_decode_stats_t **pp_stats) = 0;
81     virtual void resetStats() = 0;
82 protected:
83 
84     /* implementation packet processing interface */
85 
86     /*! @brief Implementation function for the OCSD_OP_DATA operation */
87     virtual ocsd_datapath_resp_t processData(  const ocsd_trc_index_t index,
88                                                 const uint32_t dataBlockSize,
89                                                 const uint8_t *pDataBlock,
90                                                 uint32_t *numBytesProcessed) = 0;
91 
92     virtual ocsd_datapath_resp_t onEOT() = 0;       //!< Implementation function for the OCSD_OP_EOT operation
93     virtual ocsd_datapath_resp_t onReset() = 0;     //!< Implementation function for the OCSD_OP_RESET operation
94     virtual ocsd_datapath_resp_t onFlush() = 0;     //!< Implementation function for the OCSD_OP_FLUSH operation
95     virtual ocsd_err_t onProtocolConfig() = 0;      //!< Called when the configuration object is passed to the decoder.
96     virtual const bool isBadPacket() const = 0;     //!< check if the current packet is an error / bad packet
97 };
98 
99 inline TrcPktProcI::TrcPktProcI(const char *component_name) :
100     TraceComponent(component_name)
101 {
102 }
103 
104 inline TrcPktProcI::TrcPktProcI(const char *component_name, int instIDNum) :
105     TraceComponent(component_name,instIDNum)
106 {
107 }
108 
109 /*!
110  * @class TrcPktProcBase
111  * @brief Packet Processor base class. Provides common infrastructure and interconnections for packet processors.
112  *
113  *  The class is a templated base class.
114  *  - P  - this is the packet object class.
115  *  - Pt - this is the packet type class.
116  *  - Pc - this is the packet configuration class.
117  *
118  *  implementations will provide concrete classes for each of these to operate under the common infrastructures.
119  *  The base provides the trace data in (ITrcDataIn) interface and operates on the incoming operation type.
120  *
121  *  Implementions override the 'onFn()' and data process functions defined in TrcPktProcI,
122  *  with the base class ensuring consistent ordering of operations.
123  *
124  */
125 template <class P, class Pt, class Pc>
126 class TrcPktProcBase : public TrcPktProcI
127 {
128 public:
129     TrcPktProcBase(const char *component_name);
130     TrcPktProcBase(const char *component_name, int instIDNum);
131     virtual ~TrcPktProcBase();
132 
133     /** Byte trace data input interface defined in ITrcDataIn
134 
135         The base class implementation processes the operation to call the
136         interface functions on TrcPktProcI.
137      */
138     virtual ocsd_datapath_resp_t TraceDataIn(  const ocsd_datapath_op_t op,
139                                                 const ocsd_trc_index_t index,
140                                                 const uint32_t dataBlockSize,
141                                                 const uint8_t *pDataBlock,
142                                                 uint32_t *numBytesProcessed);
143 
144 
145 /* component attachment points */
146 
147     //! Attachement point for the protocol packet output
148     componentAttachPt<IPktDataIn<P>> *getPacketOutAttachPt()  { return &m_pkt_out_i; };
149     //! Attachment point for the protocol packet monitor
150     componentAttachPt<IPktRawDataMon<P>> *getRawPacketMonAttachPt() { return &m_pkt_raw_mon_i; };
151 
152     //! Attachment point for a packet indexer
153     componentAttachPt<ITrcPktIndexer<Pt>> *getTraceIDIndexerAttachPt() { return &m_pkt_indexer_i; };
154 
155 /* protocol configuration */
156     //!< Set the protocol specific configuration for the decoder.
157     virtual ocsd_err_t setProtocolConfig(const Pc *config);
158     //!< Get the configuration for the decoder.
159     virtual const Pc *getProtocolConfig() const { return m_config; };
160 
161 /*  stats block access - derived class must init stats for the block to be returned. */
162     virtual ocsd_err_t getStatsBlock(ocsd_decode_stats_t **pp_stats);
163     virtual void resetStats();  /* reset the counts - operates separately from decoder reset. */
164 
165 protected:
166 
167     /* data output functions */
168     ocsd_datapath_resp_t outputDecodedPacket(const ocsd_trc_index_t index_sop, const P *pkt);
169 
170     void outputRawPacketToMonitor( const ocsd_trc_index_t index_sop,
171                                    const P *pkt,
172                                    const uint32_t size,
173                                    const uint8_t *p_data);
174 
175     void indexPacket(const ocsd_trc_index_t index_sop, const Pt *packet_type);
176 
177     ocsd_datapath_resp_t outputOnAllInterfaces(const ocsd_trc_index_t index_sop, const P *pkt, const Pt *pkt_type, std::vector<uint8_t> &pktdata);
178 
179     ocsd_datapath_resp_t outputOnAllInterfaces(const ocsd_trc_index_t index_sop, const P *pkt, const Pt *pkt_type, const uint8_t *pktdata, uint32_t pktlen);
180 
181     /*! Let the derived class figure out if it needs to collate and send raw data.
182         can improve wait for sync performance if we do not need to save and send unsynced data.
183     */
184     const bool hasRawMon() const;
185 
186     /* the protocol configuration */
187     const Pc *m_config;
188 
189     void ClearConfigObj();  // remove our copy of the config
190 
191     const bool checkInit(); // return true if init (configured and at least one output sink attached), false otherwise.
192 
193     /* stats block updates - called by derived protocol specific decoder */
194     void statsAddTotalCount(const uint64_t count) { m_stats.channel_total += count; };
195     void statsAddUnsyncCount(const uint64_t count) { m_stats.channel_unsynced += count; };
196     void statsAddBadSeqCount(const uint32_t count) { m_stats.bad_sequence_errs += count; };
197     void statsAddBadHdrCount(const uint32_t count) { m_stats.bad_header_errs += count; };
198     void statsInit() { m_stats_init = true; };  /* mark stats as in use */
199 
200 
201 private:
202     /* decode control */
203     ocsd_datapath_resp_t Reset(const ocsd_trc_index_t index);
204     ocsd_datapath_resp_t Flush();
205     ocsd_datapath_resp_t EOT();
206 
207     componentAttachPt<IPktDataIn<P>> m_pkt_out_i;
208     componentAttachPt<IPktRawDataMon<P>> m_pkt_raw_mon_i;
209 
210     componentAttachPt<ITrcPktIndexer<Pt>> m_pkt_indexer_i;
211 
212     bool m_b_is_init;
213 
214     /* decode statistics block */
215     ocsd_decode_stats_t m_stats;
216     bool m_stats_init; /*< true if the specific decoder is using the stats */
217 
218 };
219 
220 template<class P,class Pt, class Pc> TrcPktProcBase<P, Pt, Pc>::TrcPktProcBase(const char *component_name) :
221     TrcPktProcI(component_name),
222     m_config(0),
223     m_b_is_init(false),
224     m_stats_init(false)
225 {
226     resetStats();
227 }
228 
229 template<class P,class Pt, class Pc> TrcPktProcBase<P, Pt, Pc>::TrcPktProcBase(const char *component_name, int instIDNum) :
230     TrcPktProcI(component_name, instIDNum),
231     m_config(0),
232     m_b_is_init(false),
233     m_stats_init(false)
234 {
235     resetStats();
236 }
237 
238 template<class P,class Pt, class Pc> TrcPktProcBase<P, Pt, Pc>::~TrcPktProcBase()
239 {
240     ClearConfigObj();
241 }
242 
243 template<class P,class Pt, class Pc> ocsd_datapath_resp_t TrcPktProcBase<P, Pt, Pc>::TraceDataIn(  const ocsd_datapath_op_t op,
244                                                 const ocsd_trc_index_t index,
245                                                 const uint32_t dataBlockSize,
246                                                 const uint8_t *pDataBlock,
247                                                 uint32_t *numBytesProcessed)
248 {
249     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
250 
251     switch(op)
252     {
253     case OCSD_OP_DATA:
254         if((dataBlockSize == 0) || (pDataBlock == 0) || (numBytesProcessed == 0))
255         {
256             if(numBytesProcessed)
257                 *numBytesProcessed = 0; // ensure processed bytes value set to 0.
258             LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL,"Packet Processor: Zero length data block or NULL pointer error\n"));
259             resp = OCSD_RESP_FATAL_INVALID_PARAM;
260         }
261         else
262             resp = processData(index,dataBlockSize,pDataBlock,numBytesProcessed);
263         break;
264 
265     case OCSD_OP_EOT:
266         resp = EOT();
267         break;
268 
269     case OCSD_OP_FLUSH:
270         resp = Flush();
271         break;
272 
273     case OCSD_OP_RESET:
274         resp = Reset(index);
275         break;
276 
277     default:
278         LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL,"Packet Processor : Unknown Datapath operation\n"));
279         resp = OCSD_RESP_FATAL_INVALID_OP;
280         break;
281     }
282     return resp;
283 }
284 
285 
286 template<class P,class Pt, class Pc> ocsd_datapath_resp_t TrcPktProcBase<P, Pt, Pc>::Reset(const ocsd_trc_index_t index)
287 {
288     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
289 
290     // reset the trace decoder attachment on main data path.
291     if(m_pkt_out_i.hasAttachedAndEnabled())
292         resp = m_pkt_out_i.first()->PacketDataIn(OCSD_OP_RESET,index,0);
293 
294     // reset the packet processor implmentation
295     if(!OCSD_DATA_RESP_IS_FATAL(resp))
296         resp = onReset();
297 
298     // packet monitor
299     if(m_pkt_raw_mon_i.hasAttachedAndEnabled())
300         m_pkt_raw_mon_i.first()->RawPacketDataMon(OCSD_OP_RESET,index,0,0,0);
301 
302     return resp;
303 }
304 
305 template<class P,class Pt, class Pc> ocsd_datapath_resp_t TrcPktProcBase<P, Pt, Pc>::Flush()
306 {
307     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
308     ocsd_datapath_resp_t resplocal = OCSD_RESP_CONT;
309 
310     // the trace decoder attachment on main data path.
311     if(m_pkt_out_i.hasAttachedAndEnabled())
312         resp = m_pkt_out_i.first()->PacketDataIn(OCSD_OP_FLUSH,0,0); // flush up the data path first.
313 
314     // if the connected components are flushed, not flush this one.
315     if(OCSD_DATA_RESP_IS_CONT(resp))
316         resplocal = onFlush();      // local flush
317 
318     return (resplocal > resp) ?  resplocal : resp;
319 }
320 
321 template<class P,class Pt, class Pc> ocsd_datapath_resp_t TrcPktProcBase<P, Pt, Pc>::EOT()
322 {
323     ocsd_datapath_resp_t resp = onEOT();   // local EOT - mark any part packet as incomplete type and prepare to send
324 
325     // the trace decoder attachment on main data path.
326     if(m_pkt_out_i.hasAttachedAndEnabled() && !OCSD_DATA_RESP_IS_FATAL(resp))
327         resp = m_pkt_out_i.first()->PacketDataIn(OCSD_OP_EOT,0,0);
328 
329     // packet monitor
330     if(m_pkt_raw_mon_i.hasAttachedAndEnabled())
331         m_pkt_raw_mon_i.first()->RawPacketDataMon(OCSD_OP_EOT,0,0,0,0);
332 
333     return resp;
334 }
335 
336 template<class P,class Pt, class Pc> ocsd_datapath_resp_t TrcPktProcBase<P, Pt, Pc>::outputDecodedPacket(const ocsd_trc_index_t index, const P *pkt)
337 {
338      ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
339 
340     // bad packet filter.
341     if((getComponentOpMode() & OCSD_OPFLG_PKTPROC_NOFWD_BAD_PKTS) && isBadPacket())
342         return resp;
343 
344     // send a complete packet over the primary data path
345     if(m_pkt_out_i.hasAttachedAndEnabled())
346         resp = m_pkt_out_i.first()->PacketDataIn(OCSD_OP_DATA,index,pkt);
347     return resp;
348 }
349 
350 template<class P,class Pt, class Pc> void TrcPktProcBase<P, Pt, Pc>::outputRawPacketToMonitor(
351                                     const ocsd_trc_index_t index_sop,
352                                     const P *pkt,
353                                     const uint32_t size,
354                                     const uint8_t *p_data)
355 {
356     // never output 0 sized packets.
357     if(size == 0)
358         return;
359 
360     // bad packet filter.
361     if((getComponentOpMode() & OCSD_OPFLG_PKTPROC_NOMON_BAD_PKTS) && isBadPacket())
362         return;
363 
364     // packet monitor - this cannot return CONT / WAIT, but does get the raw packet data.
365     if(m_pkt_raw_mon_i.hasAttachedAndEnabled())
366         m_pkt_raw_mon_i.first()->RawPacketDataMon(OCSD_OP_DATA,index_sop,pkt,size,p_data);
367 }
368 
369 template<class P,class Pt, class Pc> const bool TrcPktProcBase<P, Pt, Pc>::hasRawMon() const
370 {
371     return m_pkt_raw_mon_i.hasAttachedAndEnabled();
372 }
373 
374 template<class P,class Pt, class Pc> void TrcPktProcBase<P, Pt, Pc>::indexPacket(const ocsd_trc_index_t index_sop, const Pt *packet_type)
375 {
376     // packet indexer - cannot return CONT / WAIT, just gets the current index and type.
377     if(m_pkt_indexer_i.hasAttachedAndEnabled())
378         m_pkt_indexer_i.first()->TracePktIndex(index_sop,packet_type);
379 }
380 
381 template<class P,class Pt, class Pc> ocsd_datapath_resp_t TrcPktProcBase<P, Pt, Pc>::outputOnAllInterfaces(const ocsd_trc_index_t index_sop, const P *pkt, const Pt *pkt_type, std::vector<uint8_t> &pktdata)
382 {
383     indexPacket(index_sop,pkt_type);
384     if(pktdata.size() > 0)  // prevent out of range errors for 0 length vector.
385         outputRawPacketToMonitor(index_sop,pkt,(uint32_t)pktdata.size(),&pktdata[0]);
386     return outputDecodedPacket(index_sop,pkt);
387 }
388 
389 template<class P,class Pt, class Pc> ocsd_datapath_resp_t TrcPktProcBase<P, Pt, Pc>::outputOnAllInterfaces(const ocsd_trc_index_t index_sop, const P *pkt, const Pt *pkt_type, const uint8_t *pktdata, uint32_t pktlen)
390 {
391     indexPacket(index_sop,pkt_type);
392     outputRawPacketToMonitor(index_sop,pkt,pktlen,pktdata);
393     return outputDecodedPacket(index_sop,pkt);
394 }
395 
396 template<class P,class Pt, class Pc> ocsd_err_t TrcPktProcBase<P, Pt, Pc>::setProtocolConfig(const Pc *config)
397 {
398     ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL;
399     if(config != 0)
400     {
401         ClearConfigObj();
402         m_config = new (std::nothrow) Pc(*config);
403         if(m_config != 0)
404             err = onProtocolConfig();
405         else
406             err = OCSD_ERR_MEM;
407     }
408     return err;
409 }
410 
411 template<class P,class Pt, class Pc> void TrcPktProcBase<P, Pt, Pc>::ClearConfigObj()
412 {
413     if(m_config)
414     {
415         delete m_config;
416         m_config = 0;
417     }
418 }
419 
420 template<class P,class Pt, class Pc> const bool TrcPktProcBase<P, Pt, Pc>::checkInit()
421 {
422     if(!m_b_is_init)
423     {
424         if( (m_config != 0) &&
425             (m_pkt_out_i.hasAttached() || m_pkt_raw_mon_i.hasAttached())
426           )
427             m_b_is_init = true;
428     }
429     return m_b_is_init;
430 }
431 
432 template<class P,class Pt, class Pc> ocsd_err_t TrcPktProcBase<P, Pt, Pc>::getStatsBlock(ocsd_decode_stats_t **pp_stats)
433 {
434 
435     *pp_stats = &m_stats;
436     return m_stats_init ? OCSD_OK : OCSD_ERR_NOT_INIT;
437 }
438 
439 template<class P,class Pt, class Pc> void TrcPktProcBase<P, Pt, Pc>::resetStats()
440 {
441     m_stats.version = OCSD_VER_NUM;
442     m_stats.revision = OCSD_STATS_REVISION;
443     m_stats.channel_total = 0;
444     m_stats.channel_unsynced = 0;
445     m_stats.bad_header_errs = 0;
446     m_stats.bad_sequence_errs = 0;
447     m_stats.demux.frame_bytes = 0;
448     m_stats.demux.no_id_bytes = 0;
449     m_stats.demux.valid_id_bytes = 0;
450 }
451 
452 /** @}*/
453 
454 #endif // ARM_TRC_PKT_PROC_BASE_H_INCLUDED
455 
456 /* End of File trc_pkt_proc_base.h */
457