diff -r a151135b0cf9 -r aa2539c91954 tracesrv/tracecore/btrace_handler/src/TraceCoreWriter.cpp --- /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