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  */
64 class TrcPktProcI : public TraceComponent, public ITrcDataIn
65 {
66 public:
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 
79 protected:
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 
96 inline TrcPktProcI::TrcPktProcI(const char *component_name) :
97     TraceComponent(component_name)
98 {
99 }
100 
101 inline 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  */
122 template <class P, class Pt, class Pc>
123 class TrcPktProcBase : public TrcPktProcI
124 {
125 public:
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 
158 protected:
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 
186 private:
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 
200 template<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 
207 template<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 
214 template<class P,class Pt, class Pc> TrcPktProcBase<P, Pt, Pc>::~TrcPktProcBase()
215 {
216     ClearConfigObj();
217 }
218 
219 template<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 
262 template<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 
281 template<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 
297 template<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 
312 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)
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 
326 template<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 
345 template<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 
350 template<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 
357 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)
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 
365 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)
366 {
367     indexPacket(index_sop,pkt_type);
368     outputRawPacketToMonitor(index_sop,pkt,pktlen,pktdata);
369     return outputDecodedPacket(index_sop,pkt);
370 }
371 
372 template<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 
387 template<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 
396 template<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