--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tracesrv/tracecore/btrace_handler/src/TraceCoreWriter.cpp Fri Oct 08 14:56:39 2010 +0300
@@ -0,0 +1,449 @@
+// Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Trace Core
+//
+
+#include "TraceCoreWriter.h"
+#include "TraceCore.h"
+#include "TraceCoreDebug.h"
+
+#include "TraceCoreConstants.h"
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "TraceCoreWriterTraces.h"
+#endif
+
+#ifdef WRITE_OST_HEADER
+
+const TUint KDWordShift = 32;
+const TUint KDWordMask = 0xFFFFFFFF;
+const TUint KNanoSeconds = 1000000000;
+
+/**
+ * Musti timestamp mask. First 4 bits are reserved for flags
+ */
+const TUint KTimestampMask = 0x0FFFFFFF;
+
+/**
+ * Musti timestamp flags for XTIv2
+ */
+const TUint KTimestampFlags = 0xD0000000;
+
+const TUint KComponentIdLength(4);
+const TUint KGroupIdLength(4);
+const TUint KTimestampLenght(8);
+
+#endif // WRITE_OST_HEADER
+
+/**
+ * Constructor
+ */
+EXPORT_C DTraceCoreWriter::DTraceCoreWriter( TWriterType aWriterType )
+: iWriterType( aWriterType )
+ {
+ }
+
+
+/**
+ * Destructor
+ */
+EXPORT_C DTraceCoreWriter::~DTraceCoreWriter()
+ {
+ Unregister();
+ }
+
+
+/**
+ * Registers this writer to TraceCore
+ */
+EXPORT_C TInt DTraceCoreWriter::Register()
+ {
+ TInt ret= KErrGeneral;
+ // Get TraceCore
+ DTraceCore* traceCore = DTraceCore::GetInstance();
+ if ( traceCore != NULL )
+ {
+ // Register this writer
+ ret = traceCore->RegisterWriter( *this );
+ }
+ OstTrace1( TRACE_BORDER, DTRACECOREWRITER_REGISTER_EXIT, "< DTraceCoreWriter::Register %d", ret );
+ return ret;
+ }
+
+
+/**
+ * Unregisters this writer from TraceCore
+ */
+void DTraceCoreWriter::Unregister()
+ {
+ // Get TraceCore
+ DTraceCore* traceCore = DTraceCore::GetInstance();
+ if ( traceCore != NULL )
+ {
+ // Unregister this writer
+ traceCore->UnregisterWriter( *this );
+ }
+ }
+
+
+/**
+ * Gets the writer type
+ */
+TWriterType DTraceCoreWriter::GetWriterType()
+ {
+ return iWriterType;
+ }
+
+
+/**
+ * Outputs a TraceCore frame. This calls WriteStart, writes the component and group ID's,
+ * calls WriteBTraceFrame and calls WriteEnd.
+ *
+ * Tracing is not allowed from this method.
+ *
+ * @param aComponentId the component ID
+ * @param aTraceWord The trace word containing the group ID and the trace ID to write
+ * @param aHeader BTrace header
+ * @param aHeader2 Extra header data
+ * @param aContext The thread context in which this function was called
+ * @param a1 The first trace parameter
+ * @param a2 The second trace parameter
+ * @param a3 The third trace parameter
+ * @param aExtra Extra trace data
+ * @param aPc The program counter value
+ * @param aRecordSize The record size
+ */
+EXPORT_C void DTraceCoreWriter::WriteTraceCoreFrame( const TUint32 aComponentId, const TUint32 aTraceWord,
+ TUint32 aHeader, TUint32 aHeader2, const TUint32 aContext, const TUint32 a1,
+ const TUint32 a2, const TUint32 a3, const TUint32 aExtra, const TUint32 aPc, TUint32 aRecordSize )
+ {
+ //TODO: tidy up code from #ifdef's
+
+#ifdef USE_OPTIMIZED_WRITE
+ if ( iWriterType == EWriterTypeXTI )
+#else
+ if ( false )
+#endif
+ {
+ }
+ else
+ {
+ TUint32 entryId = WriteStart( EWriterEntryTrace );
+
+#ifdef WRITE_OST_HEADER
+ if ( iWriterType == EWriterTypeXTI )
+ {
+ // Size is in the beginning of the
+ TUint32 size = aRecordSize + KTimestampLenght + KComponentIdLength + KGroupIdLength; //+(aHeader & 0xff)
+ #ifdef AUTOGEN_ADD_BTRACE_TIMESTAMP
+ size += KTimestampSize;
+ #endif
+
+ // Decrease component, group and trace ID (8 bytes) from the size as they are also included in the BTrace
+ // variables and they won't be written in the BTrace packet anymore
+ size -= ( KA1Size + KA2Size );
+
+ // version(0x05); // OST Base Protocol version "1.0" (v00-80-00_r1-04.pdf)
+ // entityId(0x01); // Entity id TODO: check if this needs to change with CPU
+ // protocolId(0x03); // Simple Application Trace Protocol (Not in MIPI specs 08 yet)
+
+ WriteData( entryId, ( TUint8 )0x05 ); // Version "0.5" because BTrace header included with protocol id 0x03
+ WriteData( entryId, ( TUint8 )0x01 ); // EntityId
+ WriteData( entryId, ( TUint8 )0x03 ); // ProtocolId (not specified in MIPI specs yet)
+
+ // Set length
+ // If write size less than 256
+ if(size < 256 )
+ {
+ // length(size);
+ WriteData( entryId, ( TUint8 )size );
+
+ }
+ else
+ {
+ // extendedLengthBits0_7(0x00);
+ // extendedLengthBits8_15(0x00);
+ // extendedLengthBits16_23(0x00);
+ // extendedLengthBits24_31(0x00);
+ WriteData( entryId, ( TUint8 )0x00 ); // length field 0 if extended length in use
+ //WriteData( entryId, ( TUint32 )size );// No swap, Length in protocol is little endian //SWAP_DATA( size ) );
+ // Swap needed after all to make little endian in XTI trace??
+ WriteData( entryId, ( TUint32 )SWAP_DATA( size ) );
+ }
+
+ // Write timestamp
+ TUint64 timestamp = NKern::FastCounter();
+ timestamp = (timestamp * KNanoSeconds ) / NKern::FastCounterFrequency();
+
+ TUint32 timestampLSB = timestamp & KDWordMask;
+ TUint32 timestampMSB = ( (timestamp >> KDWordShift ) & KTimestampMask ) | KTimestampFlags;
+
+ WriteData( entryId, SWAP_ID( timestampMSB ) );
+ WriteData( entryId, SWAP_ID( timestampLSB ) );
+ }
+
+ // Write Component and groupid (including traceid )
+ WriteData( entryId, SWAP_ID( aComponentId ) );
+ WriteData( entryId, SWAP_ID( aTraceWord ) );
+
+#else // WRITE_OST_HEADER
+ WriteData( entryId, SWAP_ID( aComponentId ) );
+ WriteData( entryId, SWAP_ID( aTraceWord ) );
+#endif
+ WriteBTraceFrame( entryId, aHeader, aHeader2, aContext, a1, a2, a3, aExtra, aPc, aRecordSize );
+
+ WriteEnd( entryId );
+ }
+
+ }
+
+
+/**
+ * Outputs a BTrace frame into this writer.
+ * Tracing is not allowed from this method.
+ *
+ * @param aEntryId the entry ID returned by WriteStart
+ * @param aHeader BTrace header
+ * @param aHeader2 Extra header data
+ * @param aContext The thread context in which this function was called
+ * @param a1 The first trace parameter
+ * @param a2 The second trace parameter
+ * @param a3 The third trace parameter
+ * @param aExtra Extra trace data
+ * @param aPc The program counter value
+ * @param aRecordSize The record size
+ */
+void DTraceCoreWriter::WriteBTraceFrame( const TUint32 aEntryId, TUint32 aHeader, TUint32 aHeader2,
+ const TUint32 aContext, const TUint32 a1, const TUint32 a2, const TUint32 a3,
+ const TUint32 aExtra, const TUint32 aPc, TUint32 aRecordSize )
+ {
+ // BTrace frame header. Don't read size from the header because Multipart trace can bigger than can fit to one byte.
+ TUint32 size = aRecordSize;
+ TUint8 flags = static_cast< TUint8 >( ( aHeader >> ( BTrace::EFlagsIndex * KByteSize ) ) & KByteMask );
+ TUint8 category = static_cast< TUint8 >( ( aHeader >> ( BTrace::ECategoryIndex * KByteSize ) ) & KByteMask );
+ TUint8 subcategory = static_cast< TUint8 >( ( aHeader >> ( BTrace::ESubCategoryIndex * KByteSize ) ) & KByteMask );
+
+ #ifdef __SMP__
+ // Header 2 always present and contains CPU number
+ // If Header2 not originally there, add 4 to size
+ if (!( flags & BTrace::EHeader2Present))
+ {
+ flags |= BTrace::EHeader2Present;
+ aHeader2 = 0;
+ size += KHeader2Size;
+ }
+ aHeader2 = (aHeader2 &~ BTrace::ECpuIdMask) | (NKern::CurrentCpu()<<20);
+ #endif
+
+ // If timestamp is added to frame, the timestamp flag is also set to the header
+ // and the header size is increased by the size of the timestamp
+#ifdef AUTOGEN_ADD_BTRACE_TIMESTAMP
+ if (!( flags & BTrace::ETimestampPresent))
+ {
+ size += KTimestampSize;
+ flags |= BTrace::ETimestampPresent;
+ }
+#endif
+
+ // In case of autogen and OST categories, the BTrace frame size needs to be adjusted
+ // depending on whether the group / trace ID info is replicated into the
+ // frame or not.
+ if ( category == KCategoryNokiaAutogen )
+ {
+ // Group and trace ID's are not written -> Skip a1
+ size -= KA1Size;
+ }
+
+ // Same applies to OST categories
+ else if (category >= KMaxKernelCategory && // category <= KMaxCategory && // Not needed since category is a TUint8
+ category != KCategoryNokiaBranchCoverage)
+ {
+ // Component, group and trace ID's from a1 and a2 are skipped
+ size -= ( KA1Size + KA2Size );
+ }
+ else
+ {
+ // Other categories do not have component / group / trace ID's
+ // -> No flagging is needed here
+ }
+
+ // Insert possibly changed values to BTrace header
+ TUint8 sizeToHeader = size;
+ if (size >= KByteMask )
+ {
+ sizeToHeader = KByteMask;
+ }
+
+ aHeader = ( sizeToHeader << ( BTrace::ESizeIndex * KByteSize ) )
+ | ( flags << ( BTrace::EFlagsIndex * KByteSize ) )
+ | ( category << ( BTrace::ECategoryIndex * KByteSize ) )
+ | ( subcategory << ( BTrace::ESubCategoryIndex * KByteSize ) );
+
+ // Writes the header
+ WriteData( aEntryId, SWAP_DATA( aHeader ) );
+ size -= KHeaderSize; // Subtract header size
+
+ if ( flags & BTrace::EHeader2Present )
+ {
+ WriteData( aEntryId, SWAP_DATA( aHeader2 ) );
+ size -= KHeader2Size;
+ }
+
+#ifdef AUTOGEN_ADD_BTRACE_TIMESTAMP
+ // Timestamp is written after header2
+ TUint32 timestamp = NKern::FastCounter();
+ WriteData( aEntryId, SWAP_DATA( timestamp ) );
+ size -= KTimestampSize;
+#endif
+
+ if ( flags & BTrace::EContextIdPresent )
+ {
+ WriteData( aEntryId, SWAP_DATA( aContext ) );
+ size -= KContextIdSize;
+ }
+ if ( flags & BTrace::EPcPresent )
+ {
+ WriteData( aEntryId, SWAP_DATA( aPc ) );
+ size -= KPcSize;
+ }
+ if ( flags & BTrace::EExtraPresent )
+ {
+ WriteData( aEntryId, SWAP_DATA( aExtra ) );
+ size -= KExtraSize;
+ }
+ // If A1 is present, it is written
+ if ( size >= KA1Size )
+ {
+ if ( category == KCategoryNokiaAutogen )
+ {
+ // Don't write anything
+ }
+ else if (category >= KMaxKernelCategory && // category <= KMaxCategory && // Not needed since category is a TUint8
+ category != KCategoryNokiaBranchCoverage)
+ {
+ // Don't write anything
+ }
+ else
+ {
+ WriteData( aEntryId, SWAP_DATA( a1 ) );
+ size -= KA1Size;
+ }
+
+ // If A2 is present, it is written
+ if ( size >= KA2Size )
+ {
+ if (category >= KMaxKernelCategory && // category <= KMaxCategory && // Not needed since category is a TUint8
+ category != KCategoryNokiaBranchCoverage)
+ {
+ // In OST, group / trace ID is in a2 -> Not written
+ }
+ else
+ {
+ WriteData( aEntryId, SWAP_DATA( a2 ) );
+ size -= KA2Size;
+ }
+
+ // If there is 4 bytes of data left, A3 is written as is
+ // If more, the data is read from buffer pointed by A3
+ if ( size <= KA3Size && size > 0 )
+ {
+ WriteData( aEntryId, SWAP_DATA( a3 ) );
+ }
+ else if ( size > 0 )
+ {
+ WriteRemainingBytes( aEntryId, size, a3 );
+ }
+ }
+ }
+ }
+
+
+/**
+ * Writes the remaining bytes if data is not 32-bit aligned
+ */
+void DTraceCoreWriter::WriteRemainingBytes( TUint32 aEntryId, TUint32 aSize, TUint32 a3 )
+ {
+ TUint8 extra = aSize % 4; // CodForChk_Dis_Magic
+ TUint32* ptr = ( TUint32* )a3;
+ TUint32* end = ( TUint32* )( ( ( TUint8* )a3 ) + ( aSize - extra ) );
+ TUint32 val;
+ while( ptr < end )
+ {
+ val = *ptr++;
+ WriteData( aEntryId, SWAP_DATA( val ) );
+ }
+ // Write remaining bytes and aligns to 32-bit boundary
+ if ( extra > 0 )
+ {
+ TUint8* ptr8 = ( TUint8* )ptr;
+ TUint8* end8 = ptr8 + extra;
+ TUint8* alignEnd = ( TUint8* )( end + 1 );
+ while ( ptr8 < alignEnd )
+ {
+ if ( ptr8 < end8 )
+ {
+ WriteData( aEntryId, *ptr8++ );
+ }
+ else
+ {
+ WriteData( aEntryId, ( TUint8 )0 );
+ ptr8++;
+ }
+ }
+ }
+ }
+
+
+EXPORT_C void DTraceCoreWriter::WriteEnd( const TWriteEndParams& aWriteEndParams )
+ {
+ WriteEnd( aWriteEndParams.iEntryId );
+ }
+
+
+/**
+ * Signal to TraceCore if there has been a dropped trace
+ *
+ * @param aDropped ETrue if the writer dropped the trace - otherwise EFalse
+ *
+ */
+
+EXPORT_C void DTraceCoreWriter::TraceDropped(TBool aDropped)
+ {
+ DTraceCore* tracecore = DTraceCore::GetInstance();
+ tracecore->SetPreviousTraceDropped(aDropped);
+ }
+
+
+/**
+ * Interrogates tracecore if the last trace was dropped
+ *
+ * @return returns ETrue if the trace was dropped otherwise EFalse
+ *
+ */
+EXPORT_C TBool DTraceCoreWriter::WasLastTraceDropped() const
+ {
+ TBool ret = EFalse;
+ DTraceCore* tracecore = DTraceCore::GetInstance();
+ ret = tracecore->PreviousTraceDropped();
+ return ret;
+ }
+
+
+
+EXPORT_C TBool DTraceCoreWriter::AbleToWrite(TUint /*aTraceSize*/)
+ {
+ return ETrue;
+ }
+
+// End of File