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 */
65class TrcPktProcI : public TraceComponent, public ITrcDataIn
66{
67public:
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;
82protected:
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
99inline TrcPktProcI::TrcPktProcI(const char *component_name) :
100    TraceComponent(component_name)
101{
102}
103
104inline 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 */
125template <class P, class Pt, class Pc>
126class TrcPktProcBase : public TrcPktProcI
127{
128public:
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
165protected:
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
201private:
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
220template<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
229template<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
238template<class P,class Pt, class Pc> TrcPktProcBase<P, Pt, Pc>::~TrcPktProcBase()
239{
240    ClearConfigObj();
241}
242
243template<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
286template<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
305template<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
321template<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
336template<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
350template<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
369template<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
374template<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
381template<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
389template<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
396template<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
411template<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
420template<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
432template<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
439template<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