|
1 // Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Trace Core |
|
15 // |
|
16 |
|
17 #include <e32def.h> |
|
18 #include <e32btrace.h> |
|
19 |
|
20 #include "TraceCore.h" |
|
21 #include "TraceCorePrintfTraceHandler.h" |
|
22 #include "TraceCoreDebug.h" |
|
23 #include "TraceCoreConstants.h" |
|
24 #include "TraceCoreActivation.h" |
|
25 |
|
26 #include "OstTraceDefinitions.h" |
|
27 #ifdef OST_TRACE_COMPILER_IN_USE |
|
28 #include "TraceCorePrintfTraceHandlerTraces.h" |
|
29 #endif |
|
30 #include "TraceCoreTComArgMacro.h" |
|
31 |
|
32 |
|
33 #ifdef __SMP__ |
|
34 #include <nkernsmp/nkern.h> |
|
35 static TInt gIrqState = 0; |
|
36 TSpinLock gSpinLock(TSpinLock::TSpinLock::EOrderBTrace); |
|
37 #define __LOCK() gIrqState=__SPIN_LOCK_IRQSAVE( gSpinLock ); |
|
38 #define __UNLOCK() __SPIN_UNLOCK_IRQRESTORE(gSpinLock, gIrqState); |
|
39 #else |
|
40 #define __LOCK() |
|
41 #define __UNLOCK() |
|
42 #endif |
|
43 |
|
44 // Constants |
|
45 #define GRP_SHIFT 16 |
|
46 |
|
47 #ifdef ADD_OST_HEADER_TO_PRINTF |
|
48 const TUint KDWordShift = 32; |
|
49 const TUint KDWordMask = 0xFFFFFFFF; |
|
50 const TUint KNanoSeconds = 1000000000; |
|
51 |
|
52 /** |
|
53 * Musti timestamp mask. First 4 bits are reserved for flags |
|
54 */ |
|
55 const TUint KTimestampMask = 0x0FFFFFFF; |
|
56 |
|
57 /** |
|
58 * Musti timestamp flags for XTIv2 |
|
59 */ |
|
60 const TUint KTimestampFlags = 0xD0000000; |
|
61 |
|
62 const TUint KTimestampLenght(8); |
|
63 #endif |
|
64 |
|
65 /** |
|
66 * String that is send to indicate a trace has been dropped |
|
67 */ |
|
68 _LIT8(KDroppedTrace,"* Dropped Trace"); |
|
69 |
|
70 /** |
|
71 * Static instance is needed when calling traces from handler function |
|
72 */ |
|
73 DTraceCorePrintfTraceHandler* DTraceCorePrintfTraceHandler::iInstance = NULL; |
|
74 |
|
75 /** |
|
76 * State of the Printf activations |
|
77 */ |
|
78 TBool DTraceCorePrintfTraceHandler::iKernPrintfActive = ETrue; |
|
79 TBool DTraceCorePrintfTraceHandler::iRDebugPrintfActive = ETrue; |
|
80 TBool DTraceCorePrintfTraceHandler::iPlatSecPrintfActive = ETrue; |
|
81 |
|
82 /** |
|
83 * Constructor |
|
84 */ |
|
85 DTraceCorePrintfTraceHandler::DTraceCorePrintfTraceHandler() |
|
86 : iPrintfHandler( NULL ) |
|
87 { |
|
88 } |
|
89 |
|
90 |
|
91 /** |
|
92 * Destructor |
|
93 */ |
|
94 DTraceCorePrintfTraceHandler::~DTraceCorePrintfTraceHandler() |
|
95 { |
|
96 DTraceCorePrintfTraceHandler::iInstance = NULL; |
|
97 } |
|
98 |
|
99 |
|
100 /** |
|
101 * Initializes Printf handler |
|
102 */ |
|
103 TInt DTraceCorePrintfTraceHandler::Init() |
|
104 { |
|
105 TC_TRACE( ETraceLevelFlow, Kern::Printf( ">DTraceCorePrintfTraceHandler::Init()" ) ); |
|
106 // Register to TraceCore |
|
107 TInt ret = Register(); |
|
108 if ( ret == KErrNone ) |
|
109 { |
|
110 DTraceCorePrintfTraceHandler::iInstance = this; |
|
111 RegisterNotificationReceiver( KKernelHooksOSTComponentUID, BTrace::ERDebugPrintf ); |
|
112 RegisterNotificationReceiver( KKernelHooksOSTComponentUID, BTrace::EKernPrintf ); |
|
113 RegisterNotificationReceiver( KKernelHooksOSTComponentUID, BTrace::EPlatsecPrintf ); |
|
114 } |
|
115 |
|
116 //activate printf group IDs by default |
|
117 DTraceCore* traceCore = DTraceCore::GetInstance(); |
|
118 if (traceCore) |
|
119 { |
|
120 MTraceCoreActivation* activation = traceCore->GetActivation( KKernelHooksOSTComponentUID ); |
|
121 if ( activation ) |
|
122 { |
|
123 activation->ActivateTrace( KKernelHooksOSTComponentUID, BTrace::ERDebugPrintf ); |
|
124 activation->ActivateTrace( KKernelHooksOSTComponentUID, BTrace::EKernPrintf ); |
|
125 activation->ActivateTrace( KKernelHooksOSTComponentUID, BTrace::EPlatsecPrintf ); |
|
126 } |
|
127 } |
|
128 |
|
129 TC_TRACE( ETraceLevelFlow, Kern::Printf( "<DTraceCorePrintfTraceHandler::Init() - %d", ret ) ); |
|
130 return ret; |
|
131 } |
|
132 |
|
133 |
|
134 /** |
|
135 * Prepares for writer change |
|
136 * |
|
137 * @param aWriter Pointer to writer |
|
138 */ |
|
139 void DTraceCorePrintfTraceHandler::PrepareSetWriter( DTraceCoreWriter* aWriter ) |
|
140 { |
|
141 OstTrace1( TRACE_FLOW, DTRACECOREPRINTFTRACEHANDLER_PREPARESETWRITER_ENTRY, "> DTraceCorePrintfTraceHandler::PrepareSetWriter 0x%x", ( TUint )( aWriter ) ); |
|
142 |
|
143 TBool validMedia = aWriter != NULL; |
|
144 |
|
145 if ( validMedia ) |
|
146 { |
|
147 DTraceCoreHandler::PrepareSetWriter( aWriter ); |
|
148 // SetTraceHandler is not called if it has already been called before |
|
149 if ( iPrintfHandler == NULL ) |
|
150 { |
|
151 #ifndef TRACECORE_HANDLE_PRINTF_EXCLUDED // define TRACECORE_HANDLE_PRINTF_EXCLUDED when debugging using printfs |
|
152 iPrintfHandler = Kern::SetTraceHandler( DTraceCorePrintfTraceHandler::PrintfHandler ); |
|
153 #endif |
|
154 OstTraceExt2( TRACE_NORMAL, DTRACECOREPRINTFTRACEHANDLER_SETWRITER_HANDLER_STARTED,"DTraceCorePrintfTraceHandler::PrepareSetWriter - Printf trace routing started. Addr:0x%x WriterType:%d",(TInt)aWriter, (TInt) aWriter->GetWriterType() ); |
|
155 } |
|
156 } |
|
157 else |
|
158 { |
|
159 if ( aWriter == NULL ) |
|
160 { |
|
161 OstTrace0( TRACE_NORMAL, DTRACECOREPRINTFTRACEHANDLER_PREPARESETWRITER_HANDLER_RESET,"DTraceCorePrintfTraceHandler::PrepareSetWriter - Printf trace routing stopped"); |
|
162 DTraceCoreHandler::PrepareSetWriter( aWriter ); |
|
163 |
|
164 #ifndef TRACECORE_HANDLE_PRINTF_EXCLUDED // define TRACECORE_HANDLE_PRINTF_EXCLUDED when debugging using printfs |
|
165 Kern::SetTraceHandler( iPrintfHandler ); |
|
166 #endif |
|
167 iPrintfHandler = NULL; |
|
168 } |
|
169 else |
|
170 { |
|
171 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() ); |
|
172 } |
|
173 } |
|
174 } |
|
175 |
|
176 |
|
177 /* |
|
178 Trace handler hook. |
|
179 Should be able to run in any content (including ISR). |
|
180 @param aText Debug log. The content of the descriptor resides in kernel memory. |
|
181 @param aTraceType Identifies the origin of the debug log. |
|
182 @return Specifies whether the log is processed or not. |
|
183 If ETrue, the log is processed. Kernel will drop the log (it won't be passed to trace port - UART) |
|
184 If EFalse, the log is not processed. Kernel will pass the log to the trace port, as well. |
|
185 */ |
|
186 TBool DTraceCorePrintfTraceHandler::PrintfHandler( const TDesC8& aText, TTraceSource aTraceSource ) |
|
187 { |
|
188 __LOCK(); |
|
189 |
|
190 // Print |
|
191 switch( aTraceSource ) |
|
192 { |
|
193 case EKernelTrace: |
|
194 // Check if Kernel traces are on |
|
195 if ( DTraceCorePrintfTraceHandler::iKernPrintfActive ) |
|
196 { |
|
197 HandleTrace( aText ); |
|
198 } |
|
199 break; |
|
200 case EPlatSecTrace: |
|
201 // Check if PlatSec traces are on |
|
202 if ( DTraceCorePrintfTraceHandler::iPlatSecPrintfActive ) |
|
203 { |
|
204 HandleTrace( aText ); |
|
205 } |
|
206 break; |
|
207 case EUserTrace: |
|
208 // Check if User traces are on |
|
209 if ( DTraceCorePrintfTraceHandler::iRDebugPrintfActive ) |
|
210 { |
|
211 HandleTrace( aText ); |
|
212 } |
|
213 |
|
214 break; |
|
215 default: |
|
216 break; |
|
217 } |
|
218 |
|
219 __UNLOCK(); |
|
220 |
|
221 return ETrue; |
|
222 } |
|
223 |
|
224 |
|
225 /** |
|
226 Send the string to the active writer |
|
227 @param aDes String to be printed out |
|
228 |
|
229 @note CR, LF and other special characters are not checked |
|
230 @note, Tracing is not allowed from this method (esspecially on SMP system) |
|
231 */ |
|
232 void DTraceCorePrintfTraceHandler::DebugPrint( const TDesC8& aDes ) |
|
233 { |
|
234 // When a writer registers, Kern::SetTraceHandler is called to start printf routing |
|
235 // However, the iWriter member will be NULL for a brief period after Kern::SetTraceHandler |
|
236 // -> Printf from an interrupt could crash this if NULL-check is not made |
|
237 if ( iWriter != NULL ) |
|
238 { |
|
239 const TText8* pS = aDes.Ptr(); |
|
240 #ifdef ADD_OST_HEADER_TO_PRINTF |
|
241 TUint length = aDes.Length(); |
|
242 const TText8* pE = pS + length; |
|
243 #else |
|
244 const TText8* pE = pS + aDes.Length(); |
|
245 #endif |
|
246 const TUint32* chS_ptr = reinterpret_cast< const TUint32* >( pS ); |
|
247 const TUint32* chE_ptr = reinterpret_cast< const TUint32* >( pE ); |
|
248 |
|
249 if ( chS_ptr != chE_ptr ) |
|
250 { |
|
251 // First send the printf start character |
|
252 TUint32 entryId = iWriter->WriteStart( EWriterEntryAscii ); |
|
253 |
|
254 #ifdef ADD_OST_HEADER_TO_PRINTF |
|
255 // DEBUG make sure we use this printfhandler: |
|
256 //iWriter->WriteData( entryId, (TUint8)0x39 ); |
|
257 // version(0x05); // OST Base Protocol version "1.0" (v00-80-00_r1-04.pdf) |
|
258 // entityId(0x01); // Entity id TODO: check if this needs to change with CPU |
|
259 // protocolId(0x02); // Ascii Trace Protocol (Not in MIPI specs 08 yet) |
|
260 |
|
261 iWriter->WriteData( entryId, ( TUint8 )0x05 ); // Version "0.5" because BTrace header included with protocol id 0x03 |
|
262 iWriter->WriteData( entryId, ( TUint8 )0x01 ); // EntityId |
|
263 iWriter->WriteData( entryId, ( TUint8 )0x02 ); // Ascii trace ProtocolId (not specified in MIPI specs yet) |
|
264 |
|
265 length += KTimestampLenght; |
|
266 // Set length |
|
267 // If write size less than 256 |
|
268 if(length < 256 ) |
|
269 { |
|
270 // length(size); |
|
271 iWriter->WriteData( entryId, ( TUint8 )length ); |
|
272 |
|
273 } |
|
274 else |
|
275 { |
|
276 // extendedLengthBits0_7(0x00); |
|
277 // extendedLengthBits8_15(0x00); |
|
278 // extendedLengthBits16_23(0x00); |
|
279 // extendedLengthBits24_31(0x00); |
|
280 iWriter->WriteData( entryId, ( TUint8 )0x00 ); // length field 0 if extended length in use |
|
281 iWriter->WriteData( entryId, ( TUint32 )length ); // No swap, Length in protocol is little endian //SWAP_DATA( length ) ); |
|
282 } |
|
283 |
|
284 // Write timestamp |
|
285 |
|
286 TUint64 timestamp = NKern::FastCounter(); |
|
287 timestamp = (timestamp * KNanoSeconds ) / NKern::FastCounterFrequency(); |
|
288 |
|
289 TUint32 timestampLSB = timestamp & KDWordMask; |
|
290 TUint32 timestampMSB = ( (timestamp >> KDWordShift ) & KTimestampMask ) | KTimestampFlags; |
|
291 |
|
292 iWriter->WriteData( entryId, SWAP_ID( timestampMSB ) ); |
|
293 iWriter->WriteData( entryId, SWAP_ID( timestampLSB ) ); |
|
294 |
|
295 // DEBUG - END |
|
296 |
|
297 #endif |
|
298 |
|
299 while ( chS_ptr + 1 <= chE_ptr ) |
|
300 { |
|
301 // Print using 32bit write |
|
302 TUint32 val = *( chS_ptr++ ); |
|
303 iWriter->WriteData( entryId, SWAP_DATA( val ) ); |
|
304 } |
|
305 |
|
306 // Print the rest |
|
307 pS = ( TText8* )chS_ptr; |
|
308 if ( pS != pE ) |
|
309 { |
|
310 while ( pS < pE ) |
|
311 { |
|
312 iWriter->WriteData( entryId, *( pS++ ) ); |
|
313 } |
|
314 } |
|
315 |
|
316 // End trace |
|
317 iWriter->WriteData( entryId, static_cast< TUint8 >( 0x00 ) ); |
|
318 |
|
319 TWriteEndParams params(entryId, ETrue); |
|
320 iWriter->WriteEnd( params ); |
|
321 } |
|
322 } |
|
323 } |
|
324 |
|
325 /** |
|
326 * Callback function for Trace Activation |
|
327 * |
|
328 * @param aComponentId |
|
329 * @param aGroupId |
|
330 */ |
|
331 void DTraceCorePrintfTraceHandler::TraceActivated( TUint32 TCOM_ARG(aComponentId), TUint16 aGroupId ) |
|
332 { |
|
333 OstTraceExt2( TRACE_FLOW, DTRACECOREPRINTFTRACEHANDLER_TRACEACTIVATED,"> DTraceCorePrintfTraceHandler::TraceActivated;aComponentId=0x%x;aGroupId=0x%x", (TUint) aComponentId, (TUint) aGroupId ); |
|
334 |
|
335 switch( aGroupId ) |
|
336 { |
|
337 case BTrace::EKernPrintf: |
|
338 DTraceCorePrintfTraceHandler::iKernPrintfActive = ETrue; |
|
339 break; |
|
340 case BTrace::ERDebugPrintf: |
|
341 DTraceCorePrintfTraceHandler::iRDebugPrintfActive = ETrue; |
|
342 break; |
|
343 case BTrace::EPlatsecPrintf: |
|
344 DTraceCorePrintfTraceHandler::iPlatSecPrintfActive = ETrue; |
|
345 break; |
|
346 default: |
|
347 break; |
|
348 } |
|
349 } |
|
350 |
|
351 /** |
|
352 * Callback function for Trace Deactivation |
|
353 * |
|
354 * @param aComponentId |
|
355 * @param aGroupId |
|
356 */ |
|
357 void DTraceCorePrintfTraceHandler::TraceDeactivated( TUint32 TCOM_ARG(aComponentId), TUint16 aGroupId ) |
|
358 { |
|
359 OstTraceExt2( TRACE_FLOW, DTRACECOREPRINTFTRACEHANDLER_TRACEDEACTIVATED,"> DTraceCorePrintfTraceHandler::TraceDeactivated;aComponentId=0x%x;aGroupId=0x%x", (TUint) aComponentId, (TUint) aGroupId ); |
|
360 |
|
361 switch( aGroupId ) |
|
362 { |
|
363 case BTrace::EKernPrintf: |
|
364 DTraceCorePrintfTraceHandler::iKernPrintfActive = EFalse; |
|
365 break; |
|
366 case BTrace::ERDebugPrintf: |
|
367 DTraceCorePrintfTraceHandler::iRDebugPrintfActive = EFalse; |
|
368 break; |
|
369 case BTrace::EPlatsecPrintf: |
|
370 DTraceCorePrintfTraceHandler::iPlatSecPrintfActive = EFalse; |
|
371 break; |
|
372 default: |
|
373 break; |
|
374 } |
|
375 } |
|
376 |
|
377 /** |
|
378 * This method check if "dropped trace" notification must be sent and if so it |
|
379 * verify whether writer is able to send "dropped trace" and "new incomming trace". |
|
380 * If no the incomming trace is dropped and "dropped traces" flag is kept as set. |
|
381 * |
|
382 * @param aText Text-trace to send. |
|
383 */ |
|
384 inline void DTraceCorePrintfTraceHandler::HandleTrace( const TDesC8& aText ) |
|
385 { |
|
386 if(!DTraceCorePrintfTraceHandler::iInstance || !DTraceCorePrintfTraceHandler::iInstance->iWriter) |
|
387 return; //no writer or no handler instance - don't even try to send data |
|
388 |
|
389 DTraceCore* tracecore = DTraceCore::GetInstance(); |
|
390 DTraceCorePrintfTraceHandler* handler = DTraceCorePrintfTraceHandler::iInstance; |
|
391 DTraceCoreWriter* writer = handler->iWriter; |
|
392 |
|
393 if (tracecore->PreviousTraceDropped() ) |
|
394 { |
|
395 if( writer->AbleToWrite(KDroppedTrace().Length()+aText.Length())) |
|
396 { |
|
397 //send a "dropped trace" text trace and then the actual trace |
|
398 handler->DebugPrint(KDroppedTrace); |
|
399 handler->DebugPrint(aText); |
|
400 tracecore->SetPreviousTraceDropped(EFalse); //rested "dropped trace" flag |
|
401 } |
|
402 else |
|
403 { |
|
404 //don't send anything to the buffer |
|
405 } |
|
406 } |
|
407 else |
|
408 { |
|
409 // send the actual trace |
|
410 handler->DebugPrint(aText); |
|
411 } |
|
412 } |
|
413 |
|
414 // End of File |