tracesrv/tracecore/btrace_handler/src/TraceCorePrintfTraceHandler.cpp
changeset 56 aa2539c91954
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tracesrv/tracecore/btrace_handler/src/TraceCorePrintfTraceHandler.cpp	Fri Oct 08 14:56:39 2010 +0300
@@ -0,0 +1,414 @@
+// 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 <e32def.h>
+#include <e32btrace.h>
+
+#include "TraceCore.h"
+#include "TraceCorePrintfTraceHandler.h"
+#include "TraceCoreDebug.h"
+#include "TraceCoreConstants.h"
+#include "TraceCoreActivation.h"
+
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "TraceCorePrintfTraceHandlerTraces.h"
+#endif
+#include "TraceCoreTComArgMacro.h"
+
+
+#ifdef __SMP__
+#include <nkernsmp/nkern.h>
+static TInt gIrqState = 0;
+TSpinLock gSpinLock(TSpinLock::TSpinLock::EOrderBTrace);
+#define __LOCK() gIrqState=__SPIN_LOCK_IRQSAVE( gSpinLock );
+#define __UNLOCK() __SPIN_UNLOCK_IRQRESTORE(gSpinLock, gIrqState);
+#else 
+#define __LOCK()
+#define __UNLOCK()
+#endif
+
+// Constants
+#define GRP_SHIFT 16
+
+#ifdef ADD_OST_HEADER_TO_PRINTF
+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 KTimestampLenght(8);
+#endif
+
+/**
+ * String that is send to indicate a trace has been dropped
+ */
+_LIT8(KDroppedTrace,"* Dropped Trace");
+
+/**
+ * Static instance is needed when calling traces from handler function
+ */
+DTraceCorePrintfTraceHandler* DTraceCorePrintfTraceHandler::iInstance = NULL;
+
+/**
+ * State of the Printf activations
+ */
+TBool DTraceCorePrintfTraceHandler::iKernPrintfActive = ETrue;
+TBool DTraceCorePrintfTraceHandler::iRDebugPrintfActive = ETrue;
+TBool DTraceCorePrintfTraceHandler::iPlatSecPrintfActive = ETrue;
+
+/**
+ * Constructor
+ */
+DTraceCorePrintfTraceHandler::DTraceCorePrintfTraceHandler()
+: iPrintfHandler( NULL )
+    {
+    }
+
+
+/**
+ * Destructor
+ */
+DTraceCorePrintfTraceHandler::~DTraceCorePrintfTraceHandler()
+    {
+    DTraceCorePrintfTraceHandler::iInstance = NULL;
+    }
+	
+
+/**
+ * Initializes Printf handler
+ */
+TInt DTraceCorePrintfTraceHandler::Init()
+    {    
+    TC_TRACE( ETraceLevelFlow, Kern::Printf( ">DTraceCorePrintfTraceHandler::Init()" ) );
+    // Register to TraceCore
+    TInt ret = Register();
+    if ( ret == KErrNone )
+        {
+        DTraceCorePrintfTraceHandler::iInstance = this;      
+        RegisterNotificationReceiver( KKernelHooksOSTComponentUID, BTrace::ERDebugPrintf );
+    	RegisterNotificationReceiver( KKernelHooksOSTComponentUID, BTrace::EKernPrintf );
+    	RegisterNotificationReceiver( KKernelHooksOSTComponentUID, BTrace::EPlatsecPrintf );
+        }
+    
+    //activate printf group IDs by default
+    DTraceCore* traceCore = DTraceCore::GetInstance();
+    if (traceCore)
+        {
+        MTraceCoreActivation* activation = traceCore->GetActivation( KKernelHooksOSTComponentUID );
+        if ( activation )
+            {
+             activation->ActivateTrace( KKernelHooksOSTComponentUID, BTrace::ERDebugPrintf );
+             activation->ActivateTrace( KKernelHooksOSTComponentUID, BTrace::EKernPrintf  );
+             activation->ActivateTrace( KKernelHooksOSTComponentUID, BTrace::EPlatsecPrintf  );
+            }
+        }
+    
+    TC_TRACE( ETraceLevelFlow, Kern::Printf( "<DTraceCorePrintfTraceHandler::Init() - %d", ret ) );
+    return ret;
+    }
+
+    
+/**
+ * Prepares for writer change
+ * 
+ * @param aWriter Pointer to writer
+ */       
+void DTraceCorePrintfTraceHandler::PrepareSetWriter( DTraceCoreWriter* aWriter )
+    {
+    OstTrace1( TRACE_FLOW, DTRACECOREPRINTFTRACEHANDLER_PREPARESETWRITER_ENTRY, "> DTraceCorePrintfTraceHandler::PrepareSetWriter 0x%x", ( TUint )( aWriter ) );
+
+    TBool validMedia = aWriter != NULL;
+    
+    if ( validMedia )
+        {
+        DTraceCoreHandler::PrepareSetWriter( aWriter );
+        // SetTraceHandler is not called if it has already been called before
+        if ( iPrintfHandler == NULL )
+            {
+#ifndef TRACECORE_HANDLE_PRINTF_EXCLUDED  // define TRACECORE_HANDLE_PRINTF_EXCLUDED when debugging using printfs
+            iPrintfHandler = Kern::SetTraceHandler( DTraceCorePrintfTraceHandler::PrintfHandler );
+#endif
+            OstTraceExt2( TRACE_NORMAL, DTRACECOREPRINTFTRACEHANDLER_SETWRITER_HANDLER_STARTED,"DTraceCorePrintfTraceHandler::PrepareSetWriter - Printf trace routing started. Addr:0x%x WriterType:%d",(TInt)aWriter, (TInt) aWriter->GetWriterType() );
+            }
+        }
+    else
+        {
+        if ( aWriter == NULL )
+            {
+            OstTrace0( TRACE_NORMAL, DTRACECOREPRINTFTRACEHANDLER_PREPARESETWRITER_HANDLER_RESET,"DTraceCorePrintfTraceHandler::PrepareSetWriter - Printf trace routing stopped");
+            DTraceCoreHandler::PrepareSetWriter( aWriter );
+            
+#ifndef TRACECORE_HANDLE_PRINTF_EXCLUDED // define TRACECORE_HANDLE_PRINTF_EXCLUDED when debugging using printfs
+            Kern::SetTraceHandler( iPrintfHandler );
+#endif
+            iPrintfHandler = NULL;
+            }
+        else
+            {
+            OstTraceExt2( TRACE_NORMAL, DTRACECOREPRINTFTRACEHANDLER_PREPARESETWRITER_HANDLER_NOT_CHANGED,"DTraceCorePrintfTraceHandler::PrepareSetWriter - Printf trace routing was not changed Addr:0x%x WriterType:%d",(TUint)iWriter, (TInt) iWriter->GetWriterType() );
+            }
+        }
+    }
+
+
+/*
+	Trace handler hook.
+	Should be able to run in any content (including ISR).
+	@param aText      Debug log. The content of the descriptor resides in kernel memory.
+	@param aTraceType Identifies the origin of the debug log.
+	@return Specifies whether the log is processed or not.
+		If ETrue,  the log is processed. Kernel will drop the log (it won't be passed to trace port - UART)
+        If EFalse, the log is not processed. Kernel will pass the log to the trace port, as well.
+*/
+TBool DTraceCorePrintfTraceHandler::PrintfHandler( const TDesC8& aText, TTraceSource aTraceSource )
+    {
+    __LOCK();
+    
+    // Print
+    switch( aTraceSource )
+        {
+        case EKernelTrace:
+            // Check if Kernel traces are on
+            if ( DTraceCorePrintfTraceHandler::iKernPrintfActive )
+                {
+                HandleTrace( aText );
+                }
+            break;  
+        case EPlatSecTrace:
+            // Check if PlatSec traces are on
+            if ( DTraceCorePrintfTraceHandler::iPlatSecPrintfActive )
+                {
+                HandleTrace( aText );
+                }
+            break;           
+        case EUserTrace:
+            // Check if User traces are on
+            if ( DTraceCorePrintfTraceHandler::iRDebugPrintfActive )
+                {
+                HandleTrace( aText );
+                }
+
+            break;
+        default:
+            break;            
+        }
+    
+    __UNLOCK();
+       
+    return ETrue;
+    }
+
+
+/**
+	Send the string to the active writer
+ 	@param aDes String to be printed out
+ 	
+ 	@note CR, LF and other special characters are not checked
+ 	@note, Tracing is not allowed from this method (esspecially on SMP system)
+*/
+void DTraceCorePrintfTraceHandler::DebugPrint( const TDesC8& aDes )
+    {
+    // When a writer registers, Kern::SetTraceHandler is called to start printf routing
+    // However, the iWriter member will be NULL for a brief period after Kern::SetTraceHandler
+    //  -> Printf from an interrupt could crash this if NULL-check is not made
+    if ( iWriter != NULL )
+        {
+        const TText8* pS = aDes.Ptr();
+#ifdef ADD_OST_HEADER_TO_PRINTF		
+        TUint length = aDes.Length();
+        const TText8* pE = pS + length;
+#else
+        const TText8* pE = pS + aDes.Length();
+#endif
+        const TUint32* chS_ptr = reinterpret_cast< const TUint32* >( pS );
+        const TUint32* chE_ptr = reinterpret_cast< const TUint32* >( pE );
+        
+        if ( chS_ptr != chE_ptr )
+            {
+            // First send the printf start character
+            TUint32 entryId = iWriter->WriteStart( EWriterEntryAscii );
+            
+#ifdef ADD_OST_HEADER_TO_PRINTF    
+            // DEBUG make sure we use this printfhandler:
+            //iWriter->WriteData( entryId, (TUint8)0x39 );
+            //  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(0x02); // Ascii Trace Protocol (Not in MIPI specs 08 yet)
+            
+            iWriter->WriteData( entryId, ( TUint8 )0x05 ); // Version "0.5" because BTrace header included with protocol id 0x03
+            iWriter->WriteData( entryId, ( TUint8 )0x01 ); // EntityId
+            iWriter->WriteData( entryId, ( TUint8 )0x02 ); // Ascii trace ProtocolId (not specified in MIPI specs yet)
+            
+            length += KTimestampLenght;
+            // Set length
+            // If write size less than 256
+            if(length < 256 )
+            {
+                //  length(size);
+                iWriter->WriteData( entryId, ( TUint8 )length );
+            
+            }
+            else
+            {
+                //  extendedLengthBits0_7(0x00);
+                //  extendedLengthBits8_15(0x00);
+                //  extendedLengthBits16_23(0x00);
+                //  extendedLengthBits24_31(0x00);
+                iWriter->WriteData( entryId, ( TUint8 )0x00 ); // length field 0 if extended length in use
+                iWriter->WriteData( entryId, ( TUint32 )length ); // No swap, Length in protocol is little endian //SWAP_DATA( length ) );
+            }
+            
+            // Write timestamp
+        
+            TUint64 timestamp = NKern::FastCounter();
+            timestamp = (timestamp * KNanoSeconds ) / NKern::FastCounterFrequency();
+            
+            TUint32 timestampLSB = timestamp & KDWordMask;
+            TUint32 timestampMSB = ( (timestamp >> KDWordShift ) & KTimestampMask ) | KTimestampFlags;
+            
+            iWriter->WriteData( entryId, SWAP_ID( timestampMSB ) );
+        	iWriter->WriteData( entryId, SWAP_ID( timestampLSB ) );
+            
+            // DEBUG - END
+
+#endif
+        	
+            while ( chS_ptr + 1 <= chE_ptr )
+                {
+                // Print using 32bit write
+                TUint32 val = *( chS_ptr++ );
+                iWriter->WriteData( entryId, SWAP_DATA( val ) );
+                }    
+            
+            // Print the rest
+            pS = ( TText8* )chS_ptr;
+            if ( pS != pE )
+                {
+                while ( pS < pE )
+                    {
+                    iWriter->WriteData( entryId, *( pS++ ) );
+                    }
+                }
+            
+            // End trace
+            iWriter->WriteData( entryId, static_cast< TUint8 >( 0x00 ) );
+            
+            TWriteEndParams params(entryId, ETrue);
+            iWriter->WriteEnd( params );
+            }
+        }
+    }
+
+/**
+ * Callback function for Trace Activation
+ * 
+ * @param aComponentId
+ * @param aGroupId         
+ */   
+void DTraceCorePrintfTraceHandler::TraceActivated( TUint32 TCOM_ARG(aComponentId), TUint16 aGroupId  )
+    {
+    OstTraceExt2( TRACE_FLOW, DTRACECOREPRINTFTRACEHANDLER_TRACEACTIVATED,"> DTraceCorePrintfTraceHandler::TraceActivated;aComponentId=0x%x;aGroupId=0x%x", (TUint) aComponentId, (TUint) aGroupId );
+    
+    switch( aGroupId )
+    	{
+    	case BTrace::EKernPrintf:
+    		DTraceCorePrintfTraceHandler::iKernPrintfActive = ETrue;
+    		break;
+    	case BTrace::ERDebugPrintf:
+    		DTraceCorePrintfTraceHandler::iRDebugPrintfActive = ETrue;
+    		break;
+    	case BTrace::EPlatsecPrintf:
+    		DTraceCorePrintfTraceHandler::iPlatSecPrintfActive = ETrue;
+    		break;
+    	default:
+    		break;	
+    	}
+    }
+		
+/**
+ * Callback function for Trace Deactivation
+ * 
+ * @param aComponentId
+ * @param aGroupId     
+ */  
+void DTraceCorePrintfTraceHandler::TraceDeactivated( TUint32 TCOM_ARG(aComponentId), TUint16 aGroupId  )
+    {
+    OstTraceExt2( TRACE_FLOW, DTRACECOREPRINTFTRACEHANDLER_TRACEDEACTIVATED,"> DTraceCorePrintfTraceHandler::TraceDeactivated;aComponentId=0x%x;aGroupId=0x%x", (TUint) aComponentId, (TUint) aGroupId );
+    
+    switch( aGroupId )
+    	{
+    	case BTrace::EKernPrintf:
+    		DTraceCorePrintfTraceHandler::iKernPrintfActive = EFalse;
+    		break;
+    	case BTrace::ERDebugPrintf:
+    		DTraceCorePrintfTraceHandler::iRDebugPrintfActive = EFalse;
+    		break;
+    	case BTrace::EPlatsecPrintf:
+    		DTraceCorePrintfTraceHandler::iPlatSecPrintfActive = EFalse;
+    		break;
+    	default:
+    		break;	
+    	}
+    }
+
+/**
+ * This method check if "dropped trace" notification must be sent and if so it
+ * verify whether writer is able to send "dropped trace" and "new incomming trace".
+ * If no the incomming trace is dropped and "dropped traces" flag is kept as set.
+ *
+ * @param aText Text-trace to send.
+ */
+inline void DTraceCorePrintfTraceHandler::HandleTrace( const TDesC8& aText )
+    {    
+    if(!DTraceCorePrintfTraceHandler::iInstance || !DTraceCorePrintfTraceHandler::iInstance->iWriter)
+        return; //no writer or no handler instance - don't even try to send data
+    
+    DTraceCore* tracecore = DTraceCore::GetInstance();
+    DTraceCorePrintfTraceHandler* handler = DTraceCorePrintfTraceHandler::iInstance;
+    DTraceCoreWriter* writer = handler->iWriter;
+    
+    if (tracecore->PreviousTraceDropped() )
+        {
+        if( writer->AbleToWrite(KDroppedTrace().Length()+aText.Length()))
+            { 
+            //send a "dropped trace" text trace and then the actual trace
+            handler->DebugPrint(KDroppedTrace);
+            handler->DebugPrint(aText);
+            tracecore->SetPreviousTraceDropped(EFalse); //rested "dropped trace" flag
+            }
+		else
+			{
+			//don't send anything to the buffer
+			}
+        }
+    else
+        {
+        // send the actual trace
+        handler->DebugPrint(aText);    
+        }
+    }
+
+// End of File