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