Added wrapper for PE context object. Creating decoder routines
Signed-off-by: Mike Leach mike.leach@linaro.org --- .../ref_trace_decode_lib.vcxproj | 2 +- .../ref_trace_decode_lib.vcxproj.filters | 6 +- decoder/include/common/ocsd_pe_context.h | 90 ++++++++++ decoder/include/common/trc_gen_elem.h | 4 + decoder/include/etmv3/trc_pkt_decode_etmv3.h | 18 +- decoder/include/etmv3/trc_pkt_elem_etmv3.h | 15 +- decoder/include/trc_gen_elem_types.h | 1 + decoder/source/etmv3/trc_pkt_decode_etmv3.cpp | 200 ++++++++++++++++++++- 8 files changed, 323 insertions(+), 13 deletions(-) create mode 100644 decoder/include/common/ocsd_pe_context.h
diff --git a/decoder/build/win/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj b/decoder/build/win/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj index acfafb9..07aad23 100644 --- a/decoder/build/win/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj +++ b/decoder/build/win/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj @@ -294,7 +294,6 @@ </Link> </ItemDefinitionGroup> <ItemGroup> - <None Include="..\..\..\..\HOWTO" /> <None Include="..\..\..\..\HOWTO.md" /> <None Include="..\..\..\..\LICENSE" /> <None Include="..\..\..\..\README.md" /> @@ -310,6 +309,7 @@ <ClInclude Include="..\..\..\include\common\ocsd_error.h" /> <ClInclude Include="..\..\..\include\common\ocsd_error_logger.h" /> <ClInclude Include="..\..\..\include\common\ocsd_msg_logger.h" /> + <ClInclude Include="..\..\..\include\common\ocsd_pe_context.h" /> <ClInclude Include="..\..\..\include\common\ocsd_version.h" /> <ClInclude Include="..\..\..\include\common\trc_component.h" /> <ClInclude Include="..\..\..\include\common\trc_core_arch_map.h" /> diff --git a/decoder/build/win/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj.filters b/decoder/build/win/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj.filters index 51b328a..34a7737 100644 --- a/decoder/build/win/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj.filters +++ b/decoder/build/win/ref_trace_decode_lib/ref_trace_decode_lib.vcxproj.filters @@ -60,9 +60,6 @@ </Filter> </ItemGroup> <ItemGroup> - <None Include="..\..\..\..\HOWTO"> - <Filter>docs-files</Filter> - </None> <None Include="..\..\..\..\LICENSE"> <Filter>docs-files</Filter> </None> @@ -284,6 +281,9 @@ <ClInclude Include="..\..\..\include\trc_pkt_types.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\..\include\common\ocsd_pe_context.h"> + <Filter>Header Files\common</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\..\..\source\trc_component.cpp"> diff --git a/decoder/include/common/ocsd_pe_context.h b/decoder/include/common/ocsd_pe_context.h new file mode 100644 index 0000000..5ec17e2 --- /dev/null +++ b/decoder/include/common/ocsd_pe_context.h @@ -0,0 +1,90 @@ +/* + * \file ocsd_pe_context.h + * \brief OpenCSD : Wrapper class for PE context + * + * \copyright Copyright (c) 2016, ARM Limited. All Rights Reserved. + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef ARM_OCSD_PE_CONTEXT_H_INCLUDED +#define ARM_OCSD_PE_CONTEXT_H_INCLUDED + +#include "ocsd_if_types.h" + +/*! Handler for the ocsd_pe_context structure + */ +class OcsdPeContext +{ +public: + OcsdPeContext(); + ~OcsdPeContext() {}; + + void resetCtxt(); + + void setSecLevel(const ocsd_sec_level sl) { m_context.security_level = sl; }; + void setEL(const ocsd_ex_level el) { m_context.exception_level = el; m_context.el_valid = 1; }; + void setCtxtID(const uint32_t id) { m_context.context_id = id; m_context.ctxt_id_valid = 1; }; + void setVMID(const uint32_t id) { m_context.vmid = id; m_context.vmid_valid = 1; }; + void set64bit(const bool is64bit) { m_context.bits64 = is64bit ? 1 : 0; }; + + const ocsd_sec_level getSecLevel() const { return m_context.security_level; }; + const ocsd_ex_level getEL() const { return m_context.exception_level; }; + const bool ELvalid() const { return (m_context.el_valid == 1); }; + const uint32_t getCtxtID() const { return (m_context.ctxt_id_valid == 1) ? m_context.context_id : 0; }; + const bool ctxtIDvalid() const { return (m_context.ctxt_id_valid == 1); }; + const uint32_t getVMID() const { return (m_context.vmid_valid == 1) ? m_context.vmid : 0; }; + const bool VMIDvalid() const { return (m_context.vmid_valid == 1); }; + + // only allow an immutable copy of the structure out to C-API land. + operator const ocsd_pe_context &() const { return m_context; }; + +private: + ocsd_pe_context m_context; +}; + +OcsdPeContext::OcsdPeContext() +{ + resetCtxt(); +} + +void OcsdPeContext::resetCtxt() +{ + // initialise the context + m_context.bits64 = 0; + m_context.context_id = 0; + m_context.ctxt_id_valid = 0; + m_context.el_valid = 0; + m_context.exception_level = ocsd_EL0; + m_context.security_level = ocsd_sec_secure; + m_context.vmid = 0; + m_context.vmid_valid = 0; +} + +#endif // ARM_OCSD_PE_CONTEXT_H_INCLUDED + +/* End of File ocsd_pe_context.h */ diff --git a/decoder/include/common/trc_gen_elem.h b/decoder/include/common/trc_gen_elem.h index 4b9a302..d5fbe41 100644 --- a/decoder/include/common/trc_gen_elem.h +++ b/decoder/include/common/trc_gen_elem.h @@ -58,6 +58,8 @@ public: void setContext(const ocsd_pe_context &new_context) { context = new_context; }; void setCycleCount(const uint32_t cycleCount); void setEvent(const event_t ev_type, const uint16_t number); + void setTS(const uint64_t ts, const bool freqChange = false) { timestamp = ts; cpu_freq_change = freqChange ? 1 : 0; }; + void setExcepMarker() { excep_data_marker = 1; };
virtual void toString(std::string &str) const;
@@ -96,6 +98,7 @@ inline void OcsdTraceElement::setType(const ocsd_gen_trc_elem_t type) last_i_type = OCSD_INSTR_OTHER; excep_ret_addr = 0; exception_number = 0; + excep_data_marker = 0; }
inline void OcsdTraceElement::init() @@ -108,6 +111,7 @@ inline void OcsdTraceElement::init() has_cc = 0; last_instr_exec = 0; excep_ret_addr = 0; + excep_data_marker = 0; }
/** @}*/ diff --git a/decoder/include/etmv3/trc_pkt_decode_etmv3.h b/decoder/include/etmv3/trc_pkt_decode_etmv3.h index 870d9c7..3987f29 100644 --- a/decoder/include/etmv3/trc_pkt_decode_etmv3.h +++ b/decoder/include/etmv3/trc_pkt_decode_etmv3.h @@ -39,6 +39,7 @@ #include "etmv3/trc_pkt_elem_etmv3.h" #include "etmv3/trc_cmp_cfg_etmv3.h" #include "common/trc_gen_elem.h" +#include "common/ocsd_pe_context.h"
@@ -62,7 +63,13 @@ protected: void initDecoder(); //!< initial state on creation (zeros all config) void resetDecoder(); //!< reset state to start of decode. (moves state, retains config)
+ ocsd_datapath_resp_t decodePacket(); //!< decode a packet
+ ocsd_datapath_resp_t processISync(const bool withCC); + ocsd_datapath_resp_t processBranchAddr(); + ocsd_datapath_resp_t processPHdr(); + + void pendPacket(); //!< save current packet for re-assess next pass
private:
@@ -75,14 +82,21 @@ private: // trace decode FSM typedef enum { NO_SYNC, //!< pre start trace - init state or after reset or overflow, loss of sync. - WAIT_SYNC, //!< waiting for sync packet. - DECODE_PKTS, //!< processing packets - creating decode elements on stack + WAIT_ASYNC, //!< waiting for a-sync packet. + WAIT_ISYNC, //!< waiting for i-sync packet. + DECODE_PKTS, //!< processing a packet + PEND_INSTR, //!< instruction output pended - need to check next packet for cancel - data in output element + PEND_PACKET, //!< packet decode pended - save previous none decoded packet data - prev pended instr had wait response. } processor_state_t;
processor_state_t m_curr_state;
uint8_t m_CSID; //!< Coresight trace ID for this decoder.
+ OcsdPeContext m_pe_context; //!< context for the PE + + EtmV3TrcPacket m_pended_packet; //! Saved packet when processing pended. + //** output element OcsdTraceElement m_output_elem; }; diff --git a/decoder/include/etmv3/trc_pkt_elem_etmv3.h b/decoder/include/etmv3/trc_pkt_elem_etmv3.h index 9b352e7..5d04719 100644 --- a/decoder/include/etmv3/trc_pkt_elem_etmv3.h +++ b/decoder/include/etmv3/trc_pkt_elem_etmv3.h @@ -92,16 +92,23 @@ public: void SetISyncNoAddr();
// packet status interface - get packet info. - + const ocsd_etmv3_pkt_type getType() const { return type; }; + const int AltISA() const { return context.curr_alt_isa; }; const ocsd_isa ISA() const { return curr_isa; }; const bool isBadPacket() const;
-// printing + const uint32_t getCycleCount() const { return cycle_count; }; + const uint32_t getCtxtID() const { return context.ctxtID; }; + const uint32_t getVMID() const { return context.VMID; }; + const uint64_t getTS() const { return timestamp; }; + + const bool isExcepCancel() const { return (exception.bits.present == 1) && (exception.bits.cancel == 1); }; + + // printing virtual void toString(std::string &str) const; virtual void toStringFmt(const uint32_t fmtFlags, std::string &str) const; - - + private: const char *packetTypeName(const ocsd_etmv3_pkt_type type, const char **ppDesc) const; void getBranchAddressStr(std::string &valStr) const; diff --git a/decoder/include/trc_gen_elem_types.h b/decoder/include/trc_gen_elem_types.h index 7f217b33..e0714c0 100644 --- a/decoder/include/trc_gen_elem_types.h +++ b/decoder/include/trc_gen_elem_types.h @@ -97,6 +97,7 @@ typedef struct _ocsd_generic_trace_elem { uint32_t has_cc:1; /**< 1 if this packet has a valid cycle count included (e.g. cycle count included as part of instruction range packet, always 1 for pure cycle count packet.*/ uint32_t cpu_freq_change:1; /**< 1 if this packet indicates a change in CPU frequency */ uint32_t excep_ret_addr:1; /**< 1 if en_addr is the preferred exception return address on exception packet type */ + uint32_t excep_data_marker:1; /**< 1 if the exception entry packet is a data push marker only, with no address information (used typically in v7M trace for marking data pushed onto stack) */ };
// packet specific payloads diff --git a/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp b/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp index 4bf40a0..14cea8b 100644 --- a/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp +++ b/decoder/source/etmv3/trc_pkt_decode_etmv3.cpp @@ -57,6 +57,75 @@ TrcPktDecodeEtmV3::~TrcPktDecodeEtmV3() ocsd_datapath_resp_t TrcPktDecodeEtmV3::processPacket() { ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bPktDone = false; + + if(!m_config) + return OCSD_RESP_FATAL_NOT_INIT; + + // iterate round the state machine, waiting for sync, then decoding packets. + while(!bPktDone) + { + switch(m_curr_state) + { + case NO_SYNC: + // output the initial not synced packet to the sink + m_output_elem.setType(OCSD_GEN_TRC_ELEM_NO_SYNC); + resp = outputTraceElement(m_output_elem); + m_curr_state = WAIT_ASYNC; + break; + + case WAIT_ASYNC: + if(m_curr_packet_in->getType() == ETM3_PKT_A_SYNC) + m_curr_state = WAIT_ISYNC; + bPktDone = true; + break; + + case WAIT_ISYNC: + if((m_curr_packet_in->getType() == ETM3_PKT_I_SYNC) || + (m_curr_packet_in->getType() == ETM3_PKT_I_SYNC_CYCLE)) + m_curr_state = DECODE_PKTS; + else + bPktDone = true; // not I-sync - done. + break; + + case DECODE_PKTS: + resp = decodePacket(); + bPktDone = true; + break; + + case PEND_INSTR: + // check the current packet for cancel + if(!m_curr_packet_in->isExcepCancel()) + // if not output the last instruction + resp = outputTraceElement(m_output_elem); + + if( OCSD_DATA_RESP_IS_CONT(resp)) + m_curr_state = DECODE_PKTS; + else + { + pendPacket(); + bPktDone = true; + } + break; + + case PEND_PACKET: + { + const EtmV3TrcPacket *p_temp_pkt = m_curr_packet_in; + m_curr_packet_in = &m_pended_packet; + m_curr_state = DECODE_PKTS; + resp = decodePacket(); + m_curr_packet_in = p_temp_pkt; + if(!OCSD_DATA_RESP_IS_CONT(resp)) + { + // previous packet pended returned a wait, so pend current + pendPacket(); + bPktDone = true; + } + } + break; + + } + }
return resp; } @@ -104,17 +173,142 @@ ocsd_err_t TrcPktDecodeEtmV3::onProtocolConfig() }
/* local decode methods */ + +// initialise on creation void TrcPktDecodeEtmV3::initDecoder() { - - + m_CSID = 0; resetDecoder(); }
+// reset for first use / re-use. void TrcPktDecodeEtmV3::resetDecoder() { - m_curr_state = NO_SYNC; + m_curr_state = NO_SYNC; // mark as not synced + m_pe_context.resetCtxt(); + m_output_elem.init(); + +} + +// simple packet transforms handled here, more complex processing passed on to specific routines. +ocsd_datapath_resp_t TrcPktDecodeEtmV3::decodePacket() +{ + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + bool bOutputElem = false; + bool bISyncHasCC = false; + + switch(m_curr_packet_in->getType()) + { + + case ETM3_PKT_NOTSYNC: + // mark as not synced - must have lost sync in the packet processor somehow + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Trace Packet Synchronisation Lost")); + resetDecoder(); // mark decoder as unsynced - dump any current state. + break; + + // no action for these packets - ignore and continue + case ETM3_PKT_INCOMPLETE_EOT: + case ETM3_PKT_A_SYNC: + case ETM3_PKT_IGNORE: + break; + +// markers for valid packets + case ETM3_PKT_CYCLE_COUNT: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_CYCLE_COUNT); + m_output_elem.setCycleCount(m_curr_packet_in->getCycleCount()); + bOutputElem = true; + break; + + case ETM3_PKT_TRIGGER: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EVENT); + m_output_elem.setEvent(EVENT_TRIGGER,0); + bOutputElem = true; + break; + + case ETM3_PKT_BRANCH_ADDRESS: + resp = processBranchAddr(); + break; + + case ETM3_PKT_I_SYNC_CYCLE: + bISyncHasCC = true; + case ETM3_PKT_I_SYNC: + resp = processISync(bISyncHasCC); + break; + + case ETM3_PKT_P_HDR: + resp = processPHdr(); + break; + + case ETM3_PKT_CONTEXT_ID: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_pe_context.setCtxtID(m_curr_packet_in->getCtxtID()); + m_output_elem.setContext(m_pe_context); + bOutputElem = true; + break; + + case ETM3_PKT_VMID: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_PE_CONTEXT); + m_pe_context.setVMID(m_curr_packet_in->getVMID()); + m_output_elem.setContext(m_pe_context); + bOutputElem = true; + break; + + case ETM3_PKT_EXCEPTION_ENTRY: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION); + m_output_elem.setExcepMarker(); // exception entries are always v7M data markers in ETMv3 trace. + bOutputElem = true; + break;
+ case ETM3_PKT_EXCEPTION_EXIT: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_EXCEPTION_RET); + bOutputElem = true; + break; + + case ETM3_PKT_TIMESTAMP: + m_output_elem.setType(OCSD_GEN_TRC_ELEM_TIMESTAMP); + m_output_elem.setTS(m_curr_packet_in->getTS()); + bOutputElem = true; + break; + + // data packets - data trace not supported at present + case ETM3_PKT_STORE_FAIL: + case ETM3_PKT_OOO_DATA: + case ETM3_PKT_OOO_ADDR_PLC: + case ETM3_PKT_NORM_DATA: + case ETM3_PKT_DATA_SUPPRESSED: + case ETM3_PKT_VAL_NOT_TRACED: + case ETM3_PKT_BAD_TRACEMODE: + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_HW_CFG_UNSUPP,m_index_curr_pkt,m_CSID,"Invalid packet type : Data Tracing decode not supported.")); + resp = OCSD_RESP_FATAL_INVALID_DATA; + resetDecoder(); // mark decoder as unsynced - dump any current state. + break; + + +// packet errors + case ETM3_PKT_BAD_SEQUENCE: + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Bad Packet sequence.")); + resp = OCSD_RESP_FATAL_INVALID_DATA; + resetDecoder(); // mark decoder as unsynced - dump any current state. + break; + + default: + case ETM3_PKT_RESERVED: + LogError(ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_BAD_PACKET_SEQ,m_index_curr_pkt,m_CSID,"Reserved or unknown packet ID.")); + resp = OCSD_RESP_FATAL_INVALID_DATA; + resetDecoder(); // mark decoder as unsynced - dump any current state. + break; + } + + if(bOutputElem) + resp = outputTraceElementIdx(m_index_curr_pkt,m_output_elem); + + return resp; +} + +void TrcPktDecodeEtmV3::pendPacket() +{ + m_pended_packet = *m_curr_packet_in; + m_curr_state = PEND_PACKET; }