|
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 "TraceCoreWriter.h" |
|
18 #include "TraceCore.h" |
|
19 #include "TraceCoreDebug.h" |
|
20 |
|
21 #include "TraceCoreConstants.h" |
|
22 #include "OstTraceDefinitions.h" |
|
23 #ifdef OST_TRACE_COMPILER_IN_USE |
|
24 #include "TraceCoreWriterTraces.h" |
|
25 #endif |
|
26 |
|
27 #ifdef WRITE_OST_HEADER |
|
28 |
|
29 const TUint KDWordShift = 32; |
|
30 const TUint KDWordMask = 0xFFFFFFFF; |
|
31 const TUint KNanoSeconds = 1000000000; |
|
32 |
|
33 /** |
|
34 * Musti timestamp mask. First 4 bits are reserved for flags |
|
35 */ |
|
36 const TUint KTimestampMask = 0x0FFFFFFF; |
|
37 |
|
38 /** |
|
39 * Musti timestamp flags for XTIv2 |
|
40 */ |
|
41 const TUint KTimestampFlags = 0xD0000000; |
|
42 |
|
43 const TUint KComponentIdLength(4); |
|
44 const TUint KGroupIdLength(4); |
|
45 const TUint KTimestampLenght(8); |
|
46 |
|
47 #endif // WRITE_OST_HEADER |
|
48 |
|
49 /** |
|
50 * Constructor |
|
51 */ |
|
52 EXPORT_C DTraceCoreWriter::DTraceCoreWriter( TWriterType aWriterType ) |
|
53 : iWriterType( aWriterType ) |
|
54 { |
|
55 } |
|
56 |
|
57 |
|
58 /** |
|
59 * Destructor |
|
60 */ |
|
61 EXPORT_C DTraceCoreWriter::~DTraceCoreWriter() |
|
62 { |
|
63 Unregister(); |
|
64 } |
|
65 |
|
66 |
|
67 /** |
|
68 * Registers this writer to TraceCore |
|
69 */ |
|
70 EXPORT_C TInt DTraceCoreWriter::Register() |
|
71 { |
|
72 TInt ret= KErrGeneral; |
|
73 // Get TraceCore |
|
74 DTraceCore* traceCore = DTraceCore::GetInstance(); |
|
75 if ( traceCore != NULL ) |
|
76 { |
|
77 // Register this writer |
|
78 ret = traceCore->RegisterWriter( *this ); |
|
79 } |
|
80 OstTrace1( TRACE_BORDER, DTRACECOREWRITER_REGISTER_EXIT, "< DTraceCoreWriter::Register %d", ret ); |
|
81 return ret; |
|
82 } |
|
83 |
|
84 |
|
85 /** |
|
86 * Unregisters this writer from TraceCore |
|
87 */ |
|
88 void DTraceCoreWriter::Unregister() |
|
89 { |
|
90 // Get TraceCore |
|
91 DTraceCore* traceCore = DTraceCore::GetInstance(); |
|
92 if ( traceCore != NULL ) |
|
93 { |
|
94 // Unregister this writer |
|
95 traceCore->UnregisterWriter( *this ); |
|
96 } |
|
97 } |
|
98 |
|
99 |
|
100 /** |
|
101 * Gets the writer type |
|
102 */ |
|
103 TWriterType DTraceCoreWriter::GetWriterType() |
|
104 { |
|
105 return iWriterType; |
|
106 } |
|
107 |
|
108 |
|
109 /** |
|
110 * Outputs a TraceCore frame. This calls WriteStart, writes the component and group ID's, |
|
111 * calls WriteBTraceFrame and calls WriteEnd. |
|
112 * |
|
113 * Tracing is not allowed from this method. |
|
114 * |
|
115 * @param aComponentId the component ID |
|
116 * @param aTraceWord The trace word containing the group ID and the trace ID to write |
|
117 * @param aHeader BTrace header |
|
118 * @param aHeader2 Extra header data |
|
119 * @param aContext The thread context in which this function was called |
|
120 * @param a1 The first trace parameter |
|
121 * @param a2 The second trace parameter |
|
122 * @param a3 The third trace parameter |
|
123 * @param aExtra Extra trace data |
|
124 * @param aPc The program counter value |
|
125 * @param aRecordSize The record size |
|
126 */ |
|
127 EXPORT_C void DTraceCoreWriter::WriteTraceCoreFrame( const TUint32 aComponentId, const TUint32 aTraceWord, |
|
128 TUint32 aHeader, TUint32 aHeader2, const TUint32 aContext, const TUint32 a1, |
|
129 const TUint32 a2, const TUint32 a3, const TUint32 aExtra, const TUint32 aPc, TUint32 aRecordSize ) |
|
130 { |
|
131 //TODO: tidy up code from #ifdef's |
|
132 |
|
133 #ifdef USE_OPTIMIZED_WRITE |
|
134 if ( iWriterType == EWriterTypeXTI ) |
|
135 #else |
|
136 if ( false ) |
|
137 #endif |
|
138 { |
|
139 } |
|
140 else |
|
141 { |
|
142 TUint32 entryId = WriteStart( EWriterEntryTrace ); |
|
143 |
|
144 #ifdef WRITE_OST_HEADER |
|
145 if ( iWriterType == EWriterTypeXTI ) |
|
146 { |
|
147 // Size is in the beginning of the |
|
148 TUint32 size = aRecordSize + KTimestampLenght + KComponentIdLength + KGroupIdLength; //+(aHeader & 0xff) |
|
149 #ifdef AUTOGEN_ADD_BTRACE_TIMESTAMP |
|
150 size += KTimestampSize; |
|
151 #endif |
|
152 |
|
153 // Decrease component, group and trace ID (8 bytes) from the size as they are also included in the BTrace |
|
154 // variables and they won't be written in the BTrace packet anymore |
|
155 size -= ( KA1Size + KA2Size ); |
|
156 |
|
157 // version(0x05); // OST Base Protocol version "1.0" (v00-80-00_r1-04.pdf) |
|
158 // entityId(0x01); // Entity id TODO: check if this needs to change with CPU |
|
159 // protocolId(0x03); // Simple Application Trace Protocol (Not in MIPI specs 08 yet) |
|
160 |
|
161 WriteData( entryId, ( TUint8 )0x05 ); // Version "0.5" because BTrace header included with protocol id 0x03 |
|
162 WriteData( entryId, ( TUint8 )0x01 ); // EntityId |
|
163 WriteData( entryId, ( TUint8 )0x03 ); // ProtocolId (not specified in MIPI specs yet) |
|
164 |
|
165 // Set length |
|
166 // If write size less than 256 |
|
167 if(size < 256 ) |
|
168 { |
|
169 // length(size); |
|
170 WriteData( entryId, ( TUint8 )size ); |
|
171 |
|
172 } |
|
173 else |
|
174 { |
|
175 // extendedLengthBits0_7(0x00); |
|
176 // extendedLengthBits8_15(0x00); |
|
177 // extendedLengthBits16_23(0x00); |
|
178 // extendedLengthBits24_31(0x00); |
|
179 WriteData( entryId, ( TUint8 )0x00 ); // length field 0 if extended length in use |
|
180 //WriteData( entryId, ( TUint32 )size );// No swap, Length in protocol is little endian //SWAP_DATA( size ) ); |
|
181 // Swap needed after all to make little endian in XTI trace?? |
|
182 WriteData( entryId, ( TUint32 )SWAP_DATA( size ) ); |
|
183 } |
|
184 |
|
185 // Write timestamp |
|
186 TUint64 timestamp = NKern::FastCounter(); |
|
187 timestamp = (timestamp * KNanoSeconds ) / NKern::FastCounterFrequency(); |
|
188 |
|
189 TUint32 timestampLSB = timestamp & KDWordMask; |
|
190 TUint32 timestampMSB = ( (timestamp >> KDWordShift ) & KTimestampMask ) | KTimestampFlags; |
|
191 |
|
192 WriteData( entryId, SWAP_ID( timestampMSB ) ); |
|
193 WriteData( entryId, SWAP_ID( timestampLSB ) ); |
|
194 } |
|
195 |
|
196 // Write Component and groupid (including traceid ) |
|
197 WriteData( entryId, SWAP_ID( aComponentId ) ); |
|
198 WriteData( entryId, SWAP_ID( aTraceWord ) ); |
|
199 |
|
200 #else // WRITE_OST_HEADER |
|
201 WriteData( entryId, SWAP_ID( aComponentId ) ); |
|
202 WriteData( entryId, SWAP_ID( aTraceWord ) ); |
|
203 #endif |
|
204 WriteBTraceFrame( entryId, aHeader, aHeader2, aContext, a1, a2, a3, aExtra, aPc, aRecordSize ); |
|
205 |
|
206 WriteEnd( entryId ); |
|
207 } |
|
208 |
|
209 } |
|
210 |
|
211 |
|
212 /** |
|
213 * Outputs a BTrace frame into this writer. |
|
214 * Tracing is not allowed from this method. |
|
215 * |
|
216 * @param aEntryId the entry ID returned by WriteStart |
|
217 * @param aHeader BTrace header |
|
218 * @param aHeader2 Extra header data |
|
219 * @param aContext The thread context in which this function was called |
|
220 * @param a1 The first trace parameter |
|
221 * @param a2 The second trace parameter |
|
222 * @param a3 The third trace parameter |
|
223 * @param aExtra Extra trace data |
|
224 * @param aPc The program counter value |
|
225 * @param aRecordSize The record size |
|
226 */ |
|
227 void DTraceCoreWriter::WriteBTraceFrame( const TUint32 aEntryId, TUint32 aHeader, TUint32 aHeader2, |
|
228 const TUint32 aContext, const TUint32 a1, const TUint32 a2, const TUint32 a3, |
|
229 const TUint32 aExtra, const TUint32 aPc, TUint32 aRecordSize ) |
|
230 { |
|
231 // BTrace frame header. Don't read size from the header because Multipart trace can bigger than can fit to one byte. |
|
232 TUint32 size = aRecordSize; |
|
233 TUint8 flags = static_cast< TUint8 >( ( aHeader >> ( BTrace::EFlagsIndex * KByteSize ) ) & KByteMask ); |
|
234 TUint8 category = static_cast< TUint8 >( ( aHeader >> ( BTrace::ECategoryIndex * KByteSize ) ) & KByteMask ); |
|
235 TUint8 subcategory = static_cast< TUint8 >( ( aHeader >> ( BTrace::ESubCategoryIndex * KByteSize ) ) & KByteMask ); |
|
236 |
|
237 #ifdef __SMP__ |
|
238 // Header 2 always present and contains CPU number |
|
239 // If Header2 not originally there, add 4 to size |
|
240 if (!( flags & BTrace::EHeader2Present)) |
|
241 { |
|
242 flags |= BTrace::EHeader2Present; |
|
243 aHeader2 = 0; |
|
244 size += KHeader2Size; |
|
245 } |
|
246 aHeader2 = (aHeader2 &~ BTrace::ECpuIdMask) | (NKern::CurrentCpu()<<20); |
|
247 #endif |
|
248 |
|
249 // If timestamp is added to frame, the timestamp flag is also set to the header |
|
250 // and the header size is increased by the size of the timestamp |
|
251 #ifdef AUTOGEN_ADD_BTRACE_TIMESTAMP |
|
252 if (!( flags & BTrace::ETimestampPresent)) |
|
253 { |
|
254 size += KTimestampSize; |
|
255 flags |= BTrace::ETimestampPresent; |
|
256 } |
|
257 #endif |
|
258 |
|
259 // In case of autogen and OST categories, the BTrace frame size needs to be adjusted |
|
260 // depending on whether the group / trace ID info is replicated into the |
|
261 // frame or not. |
|
262 if ( category == KCategoryNokiaAutogen ) |
|
263 { |
|
264 // Group and trace ID's are not written -> Skip a1 |
|
265 size -= KA1Size; |
|
266 } |
|
267 |
|
268 // Same applies to OST categories |
|
269 else if (category >= KMaxKernelCategory && // category <= KMaxCategory && // Not needed since category is a TUint8 |
|
270 category != KCategoryNokiaBranchCoverage) |
|
271 { |
|
272 // Component, group and trace ID's from a1 and a2 are skipped |
|
273 size -= ( KA1Size + KA2Size ); |
|
274 } |
|
275 else |
|
276 { |
|
277 // Other categories do not have component / group / trace ID's |
|
278 // -> No flagging is needed here |
|
279 } |
|
280 |
|
281 // Insert possibly changed values to BTrace header |
|
282 TUint8 sizeToHeader = size; |
|
283 if (size >= KByteMask ) |
|
284 { |
|
285 sizeToHeader = KByteMask; |
|
286 } |
|
287 |
|
288 aHeader = ( sizeToHeader << ( BTrace::ESizeIndex * KByteSize ) ) |
|
289 | ( flags << ( BTrace::EFlagsIndex * KByteSize ) ) |
|
290 | ( category << ( BTrace::ECategoryIndex * KByteSize ) ) |
|
291 | ( subcategory << ( BTrace::ESubCategoryIndex * KByteSize ) ); |
|
292 |
|
293 // Writes the header |
|
294 WriteData( aEntryId, SWAP_DATA( aHeader ) ); |
|
295 size -= KHeaderSize; // Subtract header size |
|
296 |
|
297 if ( flags & BTrace::EHeader2Present ) |
|
298 { |
|
299 WriteData( aEntryId, SWAP_DATA( aHeader2 ) ); |
|
300 size -= KHeader2Size; |
|
301 } |
|
302 |
|
303 #ifdef AUTOGEN_ADD_BTRACE_TIMESTAMP |
|
304 // Timestamp is written after header2 |
|
305 TUint32 timestamp = NKern::FastCounter(); |
|
306 WriteData( aEntryId, SWAP_DATA( timestamp ) ); |
|
307 size -= KTimestampSize; |
|
308 #endif |
|
309 |
|
310 if ( flags & BTrace::EContextIdPresent ) |
|
311 { |
|
312 WriteData( aEntryId, SWAP_DATA( aContext ) ); |
|
313 size -= KContextIdSize; |
|
314 } |
|
315 if ( flags & BTrace::EPcPresent ) |
|
316 { |
|
317 WriteData( aEntryId, SWAP_DATA( aPc ) ); |
|
318 size -= KPcSize; |
|
319 } |
|
320 if ( flags & BTrace::EExtraPresent ) |
|
321 { |
|
322 WriteData( aEntryId, SWAP_DATA( aExtra ) ); |
|
323 size -= KExtraSize; |
|
324 } |
|
325 // If A1 is present, it is written |
|
326 if ( size >= KA1Size ) |
|
327 { |
|
328 if ( category == KCategoryNokiaAutogen ) |
|
329 { |
|
330 // Don't write anything |
|
331 } |
|
332 else if (category >= KMaxKernelCategory && // category <= KMaxCategory && // Not needed since category is a TUint8 |
|
333 category != KCategoryNokiaBranchCoverage) |
|
334 { |
|
335 // Don't write anything |
|
336 } |
|
337 else |
|
338 { |
|
339 WriteData( aEntryId, SWAP_DATA( a1 ) ); |
|
340 size -= KA1Size; |
|
341 } |
|
342 |
|
343 // If A2 is present, it is written |
|
344 if ( size >= KA2Size ) |
|
345 { |
|
346 if (category >= KMaxKernelCategory && // category <= KMaxCategory && // Not needed since category is a TUint8 |
|
347 category != KCategoryNokiaBranchCoverage) |
|
348 { |
|
349 // In OST, group / trace ID is in a2 -> Not written |
|
350 } |
|
351 else |
|
352 { |
|
353 WriteData( aEntryId, SWAP_DATA( a2 ) ); |
|
354 size -= KA2Size; |
|
355 } |
|
356 |
|
357 // If there is 4 bytes of data left, A3 is written as is |
|
358 // If more, the data is read from buffer pointed by A3 |
|
359 if ( size <= KA3Size && size > 0 ) |
|
360 { |
|
361 WriteData( aEntryId, SWAP_DATA( a3 ) ); |
|
362 } |
|
363 else if ( size > 0 ) |
|
364 { |
|
365 WriteRemainingBytes( aEntryId, size, a3 ); |
|
366 } |
|
367 } |
|
368 } |
|
369 } |
|
370 |
|
371 |
|
372 /** |
|
373 * Writes the remaining bytes if data is not 32-bit aligned |
|
374 */ |
|
375 void DTraceCoreWriter::WriteRemainingBytes( TUint32 aEntryId, TUint32 aSize, TUint32 a3 ) |
|
376 { |
|
377 TUint8 extra = aSize % 4; // CodForChk_Dis_Magic |
|
378 TUint32* ptr = ( TUint32* )a3; |
|
379 TUint32* end = ( TUint32* )( ( ( TUint8* )a3 ) + ( aSize - extra ) ); |
|
380 TUint32 val; |
|
381 while( ptr < end ) |
|
382 { |
|
383 val = *ptr++; |
|
384 WriteData( aEntryId, SWAP_DATA( val ) ); |
|
385 } |
|
386 // Write remaining bytes and aligns to 32-bit boundary |
|
387 if ( extra > 0 ) |
|
388 { |
|
389 TUint8* ptr8 = ( TUint8* )ptr; |
|
390 TUint8* end8 = ptr8 + extra; |
|
391 TUint8* alignEnd = ( TUint8* )( end + 1 ); |
|
392 while ( ptr8 < alignEnd ) |
|
393 { |
|
394 if ( ptr8 < end8 ) |
|
395 { |
|
396 WriteData( aEntryId, *ptr8++ ); |
|
397 } |
|
398 else |
|
399 { |
|
400 WriteData( aEntryId, ( TUint8 )0 ); |
|
401 ptr8++; |
|
402 } |
|
403 } |
|
404 } |
|
405 } |
|
406 |
|
407 |
|
408 EXPORT_C void DTraceCoreWriter::WriteEnd( const TWriteEndParams& aWriteEndParams ) |
|
409 { |
|
410 WriteEnd( aWriteEndParams.iEntryId ); |
|
411 } |
|
412 |
|
413 |
|
414 /** |
|
415 * Signal to TraceCore if there has been a dropped trace |
|
416 * |
|
417 * @param aDropped ETrue if the writer dropped the trace - otherwise EFalse |
|
418 * |
|
419 */ |
|
420 |
|
421 EXPORT_C void DTraceCoreWriter::TraceDropped(TBool aDropped) |
|
422 { |
|
423 DTraceCore* tracecore = DTraceCore::GetInstance(); |
|
424 tracecore->SetPreviousTraceDropped(aDropped); |
|
425 } |
|
426 |
|
427 |
|
428 /** |
|
429 * Interrogates tracecore if the last trace was dropped |
|
430 * |
|
431 * @return returns ETrue if the trace was dropped otherwise EFalse |
|
432 * |
|
433 */ |
|
434 EXPORT_C TBool DTraceCoreWriter::WasLastTraceDropped() const |
|
435 { |
|
436 TBool ret = EFalse; |
|
437 DTraceCore* tracecore = DTraceCore::GetInstance(); |
|
438 ret = tracecore->PreviousTraceDropped(); |
|
439 return ret; |
|
440 } |
|
441 |
|
442 |
|
443 |
|
444 EXPORT_C TBool DTraceCoreWriter::AbleToWrite(TUint /*aTraceSize*/) |
|
445 { |
|
446 return ETrue; |
|
447 } |
|
448 |
|
449 // End of File |