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