os/kernelhwsrv/kernel/eka/drivers/trace/btracex.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32\drivers\trace\btrace.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include <kernel/kern_priv.h>
sl@0
    19
#include "platform.h"
sl@0
    20
#include "drivers/btrace.h"
sl@0
    21
sl@0
    22
#if defined(__EPOC32__) && defined(__CPU_X86)
sl@0
    23
#include <x86.h>
sl@0
    24
#endif
sl@0
    25
sl@0
    26
TBTraceBufferK Buffer;
sl@0
    27
sl@0
    28
TBool ChannelOpen = EFalse;
sl@0
    29
sl@0
    30
const TUint KCopyBufferMaxSize = 0x10000;
sl@0
    31
sl@0
    32
TInt TBTraceBufferK::Create(TInt aSize)
sl@0
    33
	{
sl@0
    34
	if(aSize<=0)
sl@0
    35
		return KErrArgument;
sl@0
    36
	TUint pageSize = Kern::RoundToPageSize(1);
sl@0
    37
	aSize = (aSize+pageSize-1)&-(TInt)pageSize;
sl@0
    38
sl@0
    39
	TUint recordOffsets = aSize+pageSize;
sl@0
    40
	TUint recordOffsetsSize = Kern::RoundToPageSize(aSize>>2);
sl@0
    41
	TUint copyBuffer = recordOffsets+recordOffsetsSize+pageSize;
sl@0
    42
	TUint copyBufferSize = Kern::RoundToPageSize(aSize>>2);
sl@0
    43
	if(copyBufferSize>KCopyBufferMaxSize)
sl@0
    44
		copyBufferSize = KCopyBufferMaxSize;
sl@0
    45
	TUint chunkSize = copyBuffer+copyBufferSize+pageSize;
sl@0
    46
sl@0
    47
	// Create chunk...
sl@0
    48
    TChunkCreateInfo info;
sl@0
    49
    info.iType         = TChunkCreateInfo::ESharedKernelSingle;
sl@0
    50
    info.iMaxSize      = chunkSize;
sl@0
    51
#ifdef __EPOC32__
sl@0
    52
	// we want full caching, no execute, default sharing
sl@0
    53
	new (&info.iMapAttr) TMappingAttributes2(EMemAttNormalCached, EFalse, ETrue);
sl@0
    54
#endif
sl@0
    55
    info.iOwnsMemory   = ETrue; // Use memory from system's free pool
sl@0
    56
    info.iDestroyedDfc = NULL;
sl@0
    57
	TUint32 mapAttr;
sl@0
    58
	TInt r = Kern::ChunkCreate(info, iBufferChunk, iAddress, mapAttr);
sl@0
    59
	if(r==KErrNone)
sl@0
    60
		r = Kern::ChunkCommit(iBufferChunk, 0, aSize);
sl@0
    61
	if(r==KErrNone)
sl@0
    62
		r = Kern::ChunkCommit(iBufferChunk, recordOffsets, recordOffsetsSize);
sl@0
    63
	if(r==KErrNone)
sl@0
    64
		r = Kern::ChunkCommit(iBufferChunk, copyBuffer, copyBufferSize);
sl@0
    65
sl@0
    66
	// Check errors...
sl@0
    67
	if(r!=KErrNone)
sl@0
    68
		{
sl@0
    69
		Close();
sl@0
    70
		return r;
sl@0
    71
		}
sl@0
    72
sl@0
    73
	// Initialise state...
sl@0
    74
	iStart = sizeof(TBTraceBuffer);
sl@0
    75
	iEnd = aSize;
sl@0
    76
	iRecordOffsets = (TUint8*)(iAddress+recordOffsets);
sl@0
    77
sl@0
    78
	TBTraceBuffer* userBuffer = (TBTraceBuffer*)iAddress;
sl@0
    79
	userBuffer->iRecordOffsets = recordOffsets;
sl@0
    80
	userBuffer->iCopyBuffer = copyBuffer;
sl@0
    81
	userBuffer->iCopyBufferSize = copyBufferSize;
sl@0
    82
sl@0
    83
	Reset(0);
sl@0
    84
sl@0
    85
#ifndef __SMP__
sl@0
    86
	TInt irq = NKern::DisableAllInterrupts();
sl@0
    87
#endif
sl@0
    88
	iTimestamp2Enabled = EFalse;
sl@0
    89
	BTrace::SetHandlers(TBTraceBufferK::Trace,TBTraceBufferK::ControlFunction,iOldBTraceHandler,iOldBTraceControl);
sl@0
    90
#ifndef __SMP__
sl@0
    91
	NKern::RestoreInterrupts(irq);
sl@0
    92
#endif
sl@0
    93
sl@0
    94
	return KErrNone;
sl@0
    95
	}
sl@0
    96
sl@0
    97
sl@0
    98
void TBTraceBufferK::Close()
sl@0
    99
	{
sl@0
   100
#ifdef __SMP__
sl@0
   101
	if(iOldBTraceHandler)
sl@0
   102
		{
sl@0
   103
		BTrace::THandler handler;
sl@0
   104
		BTrace::TControlFunction control;
sl@0
   105
		BTrace::SetHandlers(iOldBTraceHandler,iOldBTraceControl,handler,control);
sl@0
   106
		iOldBTraceHandler = NULL;
sl@0
   107
		iOldBTraceControl = NULL;
sl@0
   108
		}
sl@0
   109
	TSpinLock* sl = BTrace::LockPtr();
sl@0
   110
	TInt irq = sl->LockIrqSave();	// guarantees handler can't run at the same time
sl@0
   111
	DChunk* chunk = iBufferChunk;
sl@0
   112
	iBufferChunk = NULL;
sl@0
   113
	iAddress = NULL;
sl@0
   114
	sl->UnlockIrqRestore(irq);
sl@0
   115
#else
sl@0
   116
	TInt irq = NKern::DisableAllInterrupts();
sl@0
   117
	if(iOldBTraceHandler)
sl@0
   118
		{
sl@0
   119
		BTrace::THandler handler;
sl@0
   120
		BTrace::TControlFunction control;
sl@0
   121
		BTrace::SetHandlers(iOldBTraceHandler,iOldBTraceControl,handler,control);
sl@0
   122
		iOldBTraceHandler = NULL;
sl@0
   123
		iOldBTraceControl = NULL;
sl@0
   124
		}
sl@0
   125
	DChunk* chunk = iBufferChunk;
sl@0
   126
	iBufferChunk = NULL;
sl@0
   127
	iAddress = NULL;
sl@0
   128
	NKern::RestoreInterrupts(irq);
sl@0
   129
#endif
sl@0
   130
	if(chunk)
sl@0
   131
		Kern::ChunkClose(chunk);
sl@0
   132
	}
sl@0
   133
sl@0
   134
sl@0
   135
sl@0
   136
sl@0
   137
/**
sl@0
   138
Helper functions for encoding pseudo- floating point values recoverable by:
sl@0
   139
sl@0
   140
	int exponent = (signed char)(encoded_val >> 24);
sl@0
   141
	int mantissa = encoded_val & 0xFFFFFF;
sl@0
   142
	double val = mantissa * pow(2, exponent);
sl@0
   143
*/
sl@0
   144
TUint EncodeFloatesque(TUint64 val64, TInt exponent)
sl@0
   145
	{
sl@0
   146
	// Lose precision until it fits in 24 bits
sl@0
   147
	TInt round_up = 0;
sl@0
   148
	while (val64>=0x1000000) 
sl@0
   149
		{
sl@0
   150
		round_up = (TInt)(val64&1);
sl@0
   151
		val64 >>= 1;
sl@0
   152
		exponent++;
sl@0
   153
		}
sl@0
   154
	if (round_up) 
sl@0
   155
		{
sl@0
   156
		val64++;
sl@0
   157
		if (val64>=0x1000000) 
sl@0
   158
			{
sl@0
   159
			val64 >>= 1;
sl@0
   160
			exponent++;
sl@0
   161
			}
sl@0
   162
		}
sl@0
   163
sl@0
   164
	// Return 8-bit exponent and 24-bit mantissa
sl@0
   165
	return (TUint)(val64 | (((unsigned char)exponent)<<24));
sl@0
   166
	}
sl@0
   167
sl@0
   168
TUint EncodeReciprocal(TUint val)
sl@0
   169
	{
sl@0
   170
	if (val==0) return val;
sl@0
   171
sl@0
   172
	// Get reciprocal * 2^64
sl@0
   173
	TUint64 val64 = val;
sl@0
   174
	TUint64 div = 0;
sl@0
   175
	div--;
sl@0
   176
	val64 = div / val64;
sl@0
   177
	
sl@0
   178
	return EncodeFloatesque(val64, -64);
sl@0
   179
	}
sl@0
   180
sl@0
   181
TUint EncodePostDiv(TUint val, TUint divisor)
sl@0
   182
	{
sl@0
   183
	TUint64 val64 = val;
sl@0
   184
	val64 <<= 32;
sl@0
   185
	val64 = val64 / divisor;
sl@0
   186
	return EncodeFloatesque(val64, -32);
sl@0
   187
	}
sl@0
   188
sl@0
   189
void BTracePrimeMetatrace()
sl@0
   190
	{
sl@0
   191
#ifdef __SMP__
sl@0
   192
	TUint period1 = EncodeReciprocal(NKern::TimestampFrequency());
sl@0
   193
	TUint period2 = period1 + (32u<<24);	// timestamp2 period is 2^32 * timestamp1 period
sl@0
   194
	BTrace12(BTrace::EMetaTrace, BTrace::EMetaTraceTimestampsInfo, period1, period2, 1);
sl@0
   195
#else
sl@0
   196
	TUint period1 = EncodeReciprocal(NKern::FastCounterFrequency());
sl@0
   197
	TUint period2 = EncodePostDiv(NKern::TickPeriod(), 1000000);
sl@0
   198
	BTrace12(BTrace::EMetaTrace, BTrace::EMetaTraceTimestampsInfo, period1, period2, 0);
sl@0
   199
#endif
sl@0
   200
	}
sl@0
   201
sl@0
   202
void TBTraceBufferK::Reset(TUint aMode)
sl@0
   203
	{
sl@0
   204
#ifdef __SMP__
sl@0
   205
	TSpinLock* sl = BTrace::LockPtr();
sl@0
   206
#endif
sl@0
   207
	TInt irq = __SPIN_LOCK_IRQSAVE(*sl);	// guarantees handler can't run at the same time
sl@0
   208
	iHead = iStart;
sl@0
   209
	TBTraceBuffer* userBuffer = (TBTraceBuffer*)iAddress;
sl@0
   210
	userBuffer->iStart = iStart;
sl@0
   211
	userBuffer->iEnd = iEnd;
sl@0
   212
	userBuffer->iHead = iHead;
sl@0
   213
	userBuffer->iTail = iHead;
sl@0
   214
	userBuffer->iGeneration = 0;
sl@0
   215
	userBuffer->iMode = aMode;
sl@0
   216
	__SPIN_UNLOCK_IRQRESTORE(*sl,irq);
sl@0
   217
	if(aMode)
sl@0
   218
		{
sl@0
   219
		if (BTrace::CheckFilter(BTrace::EMetaTrace))
sl@0
   220
			BTracePrimeMetatrace();
sl@0
   221
		BTrace::Prime();
sl@0
   222
		}
sl@0
   223
	}
sl@0
   224
sl@0
   225
sl@0
   226
TInt TBTraceBufferK::RequestData(TInt aSize, TDfc* aDfc)
sl@0
   227
	{
sl@0
   228
	if(aSize<=0)
sl@0
   229
		aSize = 1;
sl@0
   230
#ifdef __SMP__
sl@0
   231
	TSpinLock* sl = BTrace::LockPtr();
sl@0
   232
#endif
sl@0
   233
	TInt irq = __SPIN_LOCK_IRQSAVE(*sl);	// guarantees handler can't run
sl@0
   234
	TBTraceBuffer* userBuffer = (TBTraceBuffer*)iAddress;
sl@0
   235
	if(!userBuffer)
sl@0
   236
		{
sl@0
   237
		__SPIN_UNLOCK_IRQRESTORE(*sl,irq);
sl@0
   238
		return KErrNotReady;
sl@0
   239
		}
sl@0
   240
	TInt dif = userBuffer->iTail-iHead;
sl@0
   241
	if(dif>0)
sl@0
   242
		aSize = 0; // we need no more bytes because all bytes to end of buffer are available
sl@0
   243
	else
sl@0
   244
		aSize += dif; // number of bytes extra we need
sl@0
   245
	if(aSize>0)
sl@0
   246
		{
sl@0
   247
		iRequestDataSize = aSize;
sl@0
   248
		iWaitingDfc = aDfc;
sl@0
   249
		}
sl@0
   250
	__SPIN_UNLOCK_IRQRESTORE(*sl,irq);
sl@0
   251
	if(aSize<=0)
sl@0
   252
		return KErrCompletion;
sl@0
   253
	return KErrNone;
sl@0
   254
	}
sl@0
   255
sl@0
   256
sl@0
   257
#ifndef BTRACE_DRIVER_MACHINE_CODED
sl@0
   258
sl@0
   259
TBool TBTraceBufferK::Trace_Impl(TUint32 aHeader,TUint32 aHeader2,const TUint32 aContext,const TUint32 a1,const TUint32 a2,const TUint32 a3,const TUint32 aExtra, const TUint32 aPc, TBool aIncTimestamp2)
sl@0
   260
	{
sl@0
   261
#ifndef __SMP__
sl@0
   262
	TInt irq = NKern::DisableAllInterrupts();
sl@0
   263
#endif
sl@0
   264
sl@0
   265
sl@0
   266
#ifdef __SMP__
sl@0
   267
	// Header 2 always present and contains CPU number
sl@0
   268
	// If Header2 not originally there, add 4 to size
sl@0
   269
	if (!(aHeader&(BTrace::EHeader2Present<<BTrace::EFlagsIndex*8)))
sl@0
   270
		aHeader += (4<<BTrace::ESizeIndex*8) + (BTrace::EHeader2Present<<BTrace::EFlagsIndex*8), aHeader2=0;
sl@0
   271
	aHeader2 = (aHeader2 &~ BTrace::ECpuIdMask) | (NKern::CurrentCpu()<<20);
sl@0
   272
#endif
sl@0
   273
#ifdef BTRACE_INCLUDE_TIMESTAMPS
sl@0
   274
	// Add timestamp to trace...
sl@0
   275
#if defined(__SMP__)
sl@0
   276
	aHeader += 8<<BTrace::ESizeIndex*8;
sl@0
   277
	aHeader |= BTrace::ETimestampPresent<<BTrace::EFlagsIndex*8 | BTrace::ETimestamp2Present<<BTrace::EFlagsIndex*8;
sl@0
   278
	TUint64 timeStamp = NKern::Timestamp();
sl@0
   279
#elif defined(__EPOC32__) && defined(__CPU_X86)
sl@0
   280
	aHeader += 8<<BTrace::ESizeIndex*8;
sl@0
   281
	aHeader |= BTrace::ETimestampPresent<<BTrace::EFlagsIndex*8 | BTrace::ETimestamp2Present<<BTrace::EFlagsIndex*8;
sl@0
   282
	TUint64 timeStamp = X86::Timestamp();
sl@0
   283
#else
sl@0
   284
	TUint32 timeStamp = NKern::FastCounter();
sl@0
   285
	TUint32 timeStamp2 = 0;
sl@0
   286
	if (aIncTimestamp2)
sl@0
   287
		{
sl@0
   288
		timeStamp2 = NKern::TickCount();
sl@0
   289
		aHeader += 8<<BTrace::ESizeIndex*8;
sl@0
   290
		aHeader |= (BTrace::ETimestampPresent | BTrace::ETimestamp2Present) << BTrace::EFlagsIndex*8;
sl@0
   291
		}
sl@0
   292
	else
sl@0
   293
		{
sl@0
   294
		aHeader += 4<<BTrace::ESizeIndex*8;
sl@0
   295
		aHeader |= BTrace::ETimestampPresent<<BTrace::EFlagsIndex*8;
sl@0
   296
		}
sl@0
   297
#endif
sl@0
   298
#endif
sl@0
   299
	TUint size = (aHeader+3)&0xfc;
sl@0
   300
sl@0
   301
	TBTraceBufferK& buffer = Buffer;
sl@0
   302
	TLinAddr address = buffer.iAddress;
sl@0
   303
	TBTraceBuffer& user_buffer = *(TBTraceBuffer*)address;
sl@0
   304
	++user_buffer.iGeneration;	// atomic not required since only driver modifies iGeneration
sl@0
   305
#ifdef __SMP__
sl@0
   306
	__e32_memory_barrier();
sl@0
   307
#endif
sl@0
   308
	TUint start = buffer.iStart;
sl@0
   309
	TUint end = buffer.iEnd;
sl@0
   310
	TUint orig_head = buffer.iHead;
sl@0
   311
	TInt requestDataSize = buffer.iRequestDataSize;
sl@0
   312
	TUint8* recordOffsets = buffer.iRecordOffsets;
sl@0
   313
	TUint32 orig_tail = user_buffer.iTail;
sl@0
   314
	TUint32 newHead, head, tail;
sl@0
   315
sl@0
   316
	if(!(user_buffer.iMode&RBTrace::EEnable))
sl@0
   317
		goto trace_off;
sl@0
   318
sl@0
   319
retry:
sl@0
   320
	head = orig_head;
sl@0
   321
	tail = orig_tail &~ 1;
sl@0
   322
	newHead = head+size;
sl@0
   323
	if(newHead>end)
sl@0
   324
		{
sl@0
   325
		requestDataSize = 0; 
sl@0
   326
		newHead = start+size;
sl@0
   327
		if(head<tail || tail<newHead+1)
sl@0
   328
			{
sl@0
   329
			if(!(user_buffer.iMode&RBTrace::EFreeRunning))
sl@0
   330
				goto trace_dropped;
sl@0
   331
			user_buffer.iWrap = head;
sl@0
   332
			head = start;
sl@0
   333
			tail = newHead+(recordOffsets[newHead>>2]<<2);
sl@0
   334
			goto overwrite;
sl@0
   335
			}
sl@0
   336
		user_buffer.iWrap = head;
sl@0
   337
		head = start;
sl@0
   338
		}
sl@0
   339
	else if(head<tail && tail<=newHead)
sl@0
   340
		{
sl@0
   341
		{
sl@0
   342
		requestDataSize = 0; 
sl@0
   343
		TUint wrap = user_buffer.iWrap;
sl@0
   344
		if(!(user_buffer.iMode&RBTrace::EFreeRunning))
sl@0
   345
			goto trace_dropped;
sl@0
   346
		if(newHead<end && newHead<wrap)
sl@0
   347
			{
sl@0
   348
			tail = newHead+(recordOffsets[newHead>>2]<<2);
sl@0
   349
			if(tail>=end || tail>=wrap)
sl@0
   350
				tail = start;
sl@0
   351
			}
sl@0
   352
		else
sl@0
   353
			tail = start;
sl@0
   354
		}
sl@0
   355
overwrite:
sl@0
   356
		*(TUint32*)(address+tail) |= BTrace::EMissingRecord<<(BTrace::EFlagsIndex*8);
sl@0
   357
		if (!__e32_atomic_cas_ord32(&user_buffer.iTail, &orig_tail, tail|1))
sl@0
   358
			goto retry;	// go round again if user side has already updated the tail pointer
sl@0
   359
		}
sl@0
   360
sl@0
   361
	buffer.iRequestDataSize = requestDataSize-size;
sl@0
   362
sl@0
   363
	{
sl@0
   364
	recordOffsets += head>>2;
sl@0
   365
	TUint32* src;
sl@0
   366
	TUint32* dst = (TUint32*)((TUint)address+head);
sl@0
   367
	size >>= 2; // we are now counting words, not bytes
sl@0
   368
sl@0
   369
	// store first word of trace...
sl@0
   370
	TUint w = aHeader;
sl@0
   371
	if(buffer.iDropped)
sl@0
   372
		{
sl@0
   373
		buffer.iDropped = 0;
sl@0
   374
		w |= BTrace::EMissingRecord<<(BTrace::EFlagsIndex*8); 
sl@0
   375
		}
sl@0
   376
	*recordOffsets++ = (TUint8)size;
sl@0
   377
	--size;
sl@0
   378
	*dst++ = w;
sl@0
   379
sl@0
   380
#ifndef __SMP__
sl@0
   381
	if(aHeader&(BTrace::EHeader2Present<<(BTrace::EFlagsIndex*8)))
sl@0
   382
#endif
sl@0
   383
		{
sl@0
   384
		w = aHeader2;
sl@0
   385
		*recordOffsets++ = (TUint8)size;
sl@0
   386
		--size;
sl@0
   387
		*dst++ = w;
sl@0
   388
		}
sl@0
   389
sl@0
   390
#ifdef BTRACE_INCLUDE_TIMESTAMPS
sl@0
   391
	// store timestamp...
sl@0
   392
#if defined(__SMP__) || (defined(__EPOC32__) && defined(__CPU_X86))
sl@0
   393
	*recordOffsets++ = (TUint8)size;
sl@0
   394
	--size;
sl@0
   395
	*dst++ = TUint32(timeStamp);
sl@0
   396
	*recordOffsets++ = (TUint8)size;
sl@0
   397
	--size;
sl@0
   398
	*dst++ = TUint32(timeStamp>>32);
sl@0
   399
#else
sl@0
   400
	*recordOffsets++ = (TUint8)size;
sl@0
   401
	--size;
sl@0
   402
	*dst++ = timeStamp;
sl@0
   403
	if (aIncTimestamp2)
sl@0
   404
		{
sl@0
   405
		*recordOffsets++ = (TUint8)size;
sl@0
   406
		--size;
sl@0
   407
		*dst++ = timeStamp2;
sl@0
   408
		}
sl@0
   409
#endif
sl@0
   410
#endif
sl@0
   411
sl@0
   412
	if(aHeader&(BTrace::EContextIdPresent<<(BTrace::EFlagsIndex*8)))
sl@0
   413
		{
sl@0
   414
		w = aContext;
sl@0
   415
		*recordOffsets++ = (TUint8)size;
sl@0
   416
		--size;
sl@0
   417
		*dst++ = w;
sl@0
   418
		}
sl@0
   419
sl@0
   420
	if(aHeader&(BTrace::EPcPresent<<(BTrace::EFlagsIndex*8)))
sl@0
   421
		{
sl@0
   422
		w = aPc;
sl@0
   423
		*recordOffsets++ = (TUint8)size;
sl@0
   424
		--size;
sl@0
   425
		*dst++ = w;
sl@0
   426
		}
sl@0
   427
sl@0
   428
	if(aHeader&(BTrace::EExtraPresent<<(BTrace::EFlagsIndex*8)))
sl@0
   429
		{
sl@0
   430
		w = aExtra;
sl@0
   431
		*recordOffsets++ = (TUint8)size;
sl@0
   432
		--size;
sl@0
   433
		*dst++ = w;
sl@0
   434
		}
sl@0
   435
sl@0
   436
	// store remainding words of trace...
sl@0
   437
	if(size)
sl@0
   438
		{
sl@0
   439
		w = a1;
sl@0
   440
		*recordOffsets++ = (TUint8)size;
sl@0
   441
		--size;
sl@0
   442
		*dst++ = w;
sl@0
   443
		if(size)
sl@0
   444
			{
sl@0
   445
			w = a2;
sl@0
   446
			*recordOffsets++ = (TUint8)size;
sl@0
   447
			--size;
sl@0
   448
			*dst++ = w;
sl@0
   449
			if(size)
sl@0
   450
				{
sl@0
   451
				if(size==1)
sl@0
   452
					{
sl@0
   453
					w = a3;
sl@0
   454
					*recordOffsets++ = (TUint8)size;
sl@0
   455
					*dst++ = w;
sl@0
   456
					}
sl@0
   457
				else
sl@0
   458
					{
sl@0
   459
					src = (TUint32*)a3;
sl@0
   460
					do
sl@0
   461
						{
sl@0
   462
						w = *src++;
sl@0
   463
						*recordOffsets++ = (TUint8)size;
sl@0
   464
						--size;
sl@0
   465
						*dst++ = w;
sl@0
   466
						}
sl@0
   467
					while(size);
sl@0
   468
					}
sl@0
   469
				}
sl@0
   470
			}
sl@0
   471
		}
sl@0
   472
	}
sl@0
   473
	buffer.iHead = newHead;
sl@0
   474
#ifdef __SMP__
sl@0
   475
	__e32_memory_barrier();	// make sure written data is observed before head pointer update
sl@0
   476
#endif
sl@0
   477
	user_buffer.iHead = newHead;
sl@0
   478
sl@0
   479
	{
sl@0
   480
	TDfc* dfc = (TDfc*)buffer.iWaitingDfc;
sl@0
   481
	if(dfc && buffer.iRequestDataSize<=0)
sl@0
   482
		{
sl@0
   483
		buffer.iWaitingDfc = NULL;
sl@0
   484
		dfc->RawAdd();
sl@0
   485
		}
sl@0
   486
	}
sl@0
   487
sl@0
   488
#ifdef __SMP__
sl@0
   489
	__e32_memory_barrier();
sl@0
   490
#endif
sl@0
   491
	++user_buffer.iGeneration;	// atomic not required since only driver modifies iGeneration
sl@0
   492
#ifndef __SMP__
sl@0
   493
	NKern::RestoreInterrupts(irq);
sl@0
   494
#endif
sl@0
   495
	return ETrue;
sl@0
   496
sl@0
   497
sl@0
   498
trace_dropped:
sl@0
   499
	buffer.iRequestDataSize = 0; 
sl@0
   500
	buffer.iDropped = ETrue;
sl@0
   501
#ifdef __SMP__
sl@0
   502
	__e32_memory_barrier();
sl@0
   503
#endif
sl@0
   504
	++user_buffer.iGeneration;	// atomic not required since only driver modifies iGeneration
sl@0
   505
#ifndef __SMP__
sl@0
   506
	NKern::RestoreInterrupts(irq);
sl@0
   507
#endif
sl@0
   508
	return ETrue;
sl@0
   509
sl@0
   510
trace_off:
sl@0
   511
#ifdef __SMP__
sl@0
   512
	__e32_memory_barrier();
sl@0
   513
#endif
sl@0
   514
	++user_buffer.iGeneration;	// atomic not required since only driver modifies iGeneration
sl@0
   515
#ifndef __SMP__
sl@0
   516
	NKern::RestoreInterrupts(irq);
sl@0
   517
#endif
sl@0
   518
	return EFalse;
sl@0
   519
	}
sl@0
   520
sl@0
   521
TBool TBTraceBufferK::TraceWithTimestamp2(TUint32 aHeader,TUint32 aHeader2,const TUint32 aContext,const TUint32 a1,const TUint32 a2,const TUint32 a3,const TUint32 aExtra,const TUint32 aPc)
sl@0
   522
	{
sl@0
   523
	return Trace_Impl(aHeader, aHeader2, aContext, a1, a2, a3, aExtra, aPc, ETrue);
sl@0
   524
	}
sl@0
   525
sl@0
   526
TBool TBTraceBufferK::Trace(TUint32 aHeader,TUint32 aHeader2,const TUint32 aContext,const TUint32 a1,const TUint32 a2,const TUint32 a3,const TUint32 aExtra,const TUint32 aPc)
sl@0
   527
	{
sl@0
   528
	return Trace_Impl(aHeader, aHeader2, aContext, a1, a2, a3, aExtra, aPc, EFalse);
sl@0
   529
	}
sl@0
   530
sl@0
   531
#endif // BTRACE_DRIVER_MACHINE_CODED
sl@0
   532
sl@0
   533
sl@0
   534
TInt TBTraceBufferK::ControlFunction(BTrace::TControl aFunction, TAny* aArg1, TAny* aArg2)
sl@0
   535
	{
sl@0
   536
	switch(aFunction)
sl@0
   537
		{
sl@0
   538
	case BTrace::ECtrlSystemCrashed:
sl@0
   539
		if(Buffer.iAddress)
sl@0
   540
			((TBTraceBuffer*)Buffer.iAddress)->iMode = 0; // turn off trace
sl@0
   541
		return KErrNone;
sl@0
   542
		
sl@0
   543
	case BTrace::ECtrlCrashReadFirst:
sl@0
   544
		Buffer.iCrashReadPart = 0;
sl@0
   545
		// fall through...
sl@0
   546
	case BTrace::ECtrlCrashReadNext:
sl@0
   547
		Buffer.CrashRead(*(TUint8**)aArg1,*(TUint*)aArg2);
sl@0
   548
		++Buffer.iCrashReadPart;
sl@0
   549
		return KErrNone;
sl@0
   550
				
sl@0
   551
	default:
sl@0
   552
		return KErrNotSupported;
sl@0
   553
		}
sl@0
   554
	}
sl@0
   555
sl@0
   556
sl@0
   557
void TBTraceBufferK::CrashRead(TUint8*& aData, TUint& aSize)
sl@0
   558
	{
sl@0
   559
	// start by assuming no data...
sl@0
   560
	aData = 0;
sl@0
   561
	aSize = 0;
sl@0
   562
	
sl@0
   563
	TBTraceBuffer* userBuffer = (TBTraceBuffer*)iAddress;
sl@0
   564
	if(!userBuffer)
sl@0
   565
		return; // no trace buffer, so end...
sl@0
   566
sl@0
   567
	TUint head = iHead;
sl@0
   568
	TUint tail = userBuffer->iTail;
sl@0
   569
	TUint8* data = (TUint8*)userBuffer;
sl@0
   570
	
sl@0
   571
	if(head>tail)
sl@0
   572
		{
sl@0
   573
		// data is in one part...
sl@0
   574
		if(iCrashReadPart==0)
sl@0
   575
			{
sl@0
   576
			aData = data+tail;
sl@0
   577
			aSize = head-tail;
sl@0
   578
			}
sl@0
   579
		// else no more parts
sl@0
   580
		}
sl@0
   581
	else if(head<tail)
sl@0
   582
		{
sl@0
   583
		// data is in two parts...
sl@0
   584
		if(iCrashReadPart==0)
sl@0
   585
			{
sl@0
   586
			// first part...
sl@0
   587
			aData = data+tail;
sl@0
   588
			aSize = userBuffer->iWrap-tail;
sl@0
   589
			}
sl@0
   590
		else if(iCrashReadPart==1)
sl@0
   591
			{
sl@0
   592
			// second part...
sl@0
   593
			aData = data+iStart;
sl@0
   594
			aSize = head-iStart;
sl@0
   595
			}
sl@0
   596
		// else no more parts
sl@0
   597
		}
sl@0
   598
	}
sl@0
   599
sl@0
   600
sl@0
   601
//
sl@0
   602
// LDD
sl@0
   603
//
sl@0
   604
sl@0
   605
class DBTraceFactory : public DLogicalDevice
sl@0
   606
	{
sl@0
   607
public:
sl@0
   608
	virtual TInt Install();
sl@0
   609
	virtual void GetCaps(TDes8& aDes) const;
sl@0
   610
	virtual TInt Create(DLogicalChannelBase*& aChannel);
sl@0
   611
	};
sl@0
   612
sl@0
   613
sl@0
   614
class DBTraceChannel : public DLogicalChannelBase
sl@0
   615
	{
sl@0
   616
public:
sl@0
   617
	DBTraceChannel();
sl@0
   618
	virtual ~DBTraceChannel();
sl@0
   619
	//	Inherited from DObject
sl@0
   620
	virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType);
sl@0
   621
	// Inherited from DLogicalChannelBase
sl@0
   622
	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
sl@0
   623
	virtual TInt Request(TInt aReqNo, TAny* a1, TAny* a2);
sl@0
   624
	//
sl@0
   625
	static void WaitCallback(TAny* aSelf);
sl@0
   626
private:
sl@0
   627
	DThread* iClient;
sl@0
   628
	TClientRequest*	iWaitRequest;
sl@0
   629
	TDfc iWaitDfc;
sl@0
   630
	TBool iOpened;
sl@0
   631
	TInt iFilter2Count;
sl@0
   632
	TUint32* iFilter2;
sl@0
   633
	TUint32* iFilter2Set;
sl@0
   634
	TBool iTimestamp2Enabled;
sl@0
   635
	};
sl@0
   636
sl@0
   637
sl@0
   638
//
sl@0
   639
// DBTraceFactory
sl@0
   640
//
sl@0
   641
sl@0
   642
TInt DBTraceFactory::Install()
sl@0
   643
	{
sl@0
   644
	return SetName(&RBTrace::Name());
sl@0
   645
	}
sl@0
   646
sl@0
   647
void DBTraceFactory::GetCaps(TDes8& aDes) const
sl@0
   648
	{
sl@0
   649
	Kern::InfoCopy(aDes,0,0);
sl@0
   650
	}
sl@0
   651
sl@0
   652
TInt DBTraceFactory::Create(DLogicalChannelBase*& aChannel)
sl@0
   653
	{
sl@0
   654
	aChannel=new DBTraceChannel();
sl@0
   655
	if(!aChannel)
sl@0
   656
		return KErrNoMemory;
sl@0
   657
	return KErrNone;
sl@0
   658
	}
sl@0
   659
sl@0
   660
void syncDfcFn(TAny* aPtr)
sl@0
   661
	{
sl@0
   662
	NKern::FSSignal((NFastSemaphore*)aPtr);
sl@0
   663
	}
sl@0
   664
sl@0
   665
void Sync(TDfcQue* aDfcQ)
sl@0
   666
	{
sl@0
   667
	NFastSemaphore s(0);
sl@0
   668
	TDfc dfc(&syncDfcFn, &s, aDfcQ, 0);
sl@0
   669
	dfc.Enque();
sl@0
   670
	NKern::FSWait(&s);
sl@0
   671
	}
sl@0
   672
sl@0
   673
//
sl@0
   674
// DBTraceChannel
sl@0
   675
//
sl@0
   676
sl@0
   677
DBTraceChannel::DBTraceChannel()
sl@0
   678
	: iWaitDfc(WaitCallback,this,Kern::DfcQue1(),7)
sl@0
   679
	{
sl@0
   680
	}
sl@0
   681
sl@0
   682
DBTraceChannel::~DBTraceChannel()
sl@0
   683
	{
sl@0
   684
	delete iFilter2Set;
sl@0
   685
	Buffer.iWaitingDfc = NULL;
sl@0
   686
	iWaitDfc.Cancel();
sl@0
   687
	Sync(Kern::DfcQue1());
sl@0
   688
	if (iWaitRequest)
sl@0
   689
		{
sl@0
   690
		Kern::QueueRequestComplete(iClient, iWaitRequest, KErrCancel);	// does nothing if request not pending
sl@0
   691
		Kern::DestroyClientRequest(iWaitRequest);
sl@0
   692
		}
sl@0
   693
	if (iOpened)
sl@0
   694
		__e32_atomic_swp_ord32(&ChannelOpen, 0);
sl@0
   695
	}
sl@0
   696
sl@0
   697
TInt DBTraceChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
sl@0
   698
	{
sl@0
   699
//	_LIT_SECURITY_POLICY_C2(KSecurityPolicy,ECapabilityReadDeviceData,ECapabilityWriteDeviceData);
sl@0
   700
//	if(!KSecurityPolicy().CheckPolicy(&Kern::CurrentThread(),__PLATSEC_DIAGNOSTIC_STRING("Checked by BTRACE")))
sl@0
   701
//		return KErrPermissionDenied;
sl@0
   702
	iClient = &Kern::CurrentThread();
sl@0
   703
	TInt r = Kern::CreateClientRequest(iWaitRequest);
sl@0
   704
	if (r!=KErrNone)
sl@0
   705
		return r;
sl@0
   706
	if (__e32_atomic_swp_ord32(&ChannelOpen, 1))
sl@0
   707
		return KErrInUse;
sl@0
   708
	iOpened = ETrue;
sl@0
   709
	return KErrNone;
sl@0
   710
	}
sl@0
   711
sl@0
   712
sl@0
   713
TInt DBTraceChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
sl@0
   714
	{
sl@0
   715
	if (aType!=EOwnerThread || aThread!=iClient)
sl@0
   716
		return KErrAccessDenied;
sl@0
   717
	return KErrNone;
sl@0
   718
	}
sl@0
   719
sl@0
   720
void DBTraceChannel::WaitCallback(TAny* aSelf)
sl@0
   721
	{
sl@0
   722
	DBTraceChannel& c = *(DBTraceChannel*)aSelf;
sl@0
   723
	Kern::QueueRequestComplete(c.iClient, c.iWaitRequest, KErrNone);
sl@0
   724
	}
sl@0
   725
sl@0
   726
TInt DBTraceChannel::Request(TInt aReqNo, TAny* a1, TAny* a2)
sl@0
   727
	{
sl@0
   728
	TInt r;
sl@0
   729
	TBTraceBufferK& buffer = Buffer;
sl@0
   730
sl@0
   731
	switch(aReqNo)
sl@0
   732
		{
sl@0
   733
	case RBTrace::EOpenBuffer:
sl@0
   734
		NKern::ThreadEnterCS();
sl@0
   735
		if(!Buffer.iBufferChunk)
sl@0
   736
			r = buffer.Create(0x100000);
sl@0
   737
		else
sl@0
   738
			r = KErrNone;
sl@0
   739
		if(r==KErrNone)
sl@0
   740
			r = Kern::MakeHandleAndOpen(NULL, buffer.iBufferChunk);
sl@0
   741
		NKern::ThreadLeaveCS();
sl@0
   742
		return r;
sl@0
   743
sl@0
   744
	case RBTrace::EResizeBuffer:
sl@0
   745
		NKern::ThreadEnterCS();
sl@0
   746
		buffer.Close();
sl@0
   747
		r = buffer.Create((TInt)a1);
sl@0
   748
		NKern::ThreadLeaveCS();
sl@0
   749
		return r;
sl@0
   750
sl@0
   751
	case RBTrace::ESetFilter:
sl@0
   752
		{
sl@0
   753
		TInt old = BTrace::SetFilter((BTrace::TCategory)(TInt)a1,(TInt)a2);
sl@0
   754
		if((TInt)a2==1 && old==0) // filter turned on?
sl@0
   755
			{
sl@0
   756
			if ((TInt)a1==BTrace::EMetaTrace) 
sl@0
   757
				BTracePrimeMetatrace();
sl@0
   758
			BTrace::Prime((TInt)a1); // prime this trace category
sl@0
   759
			}
sl@0
   760
		return old;
sl@0
   761
		}
sl@0
   762
sl@0
   763
	case RBTrace::ESetFilter2:
sl@0
   764
		return BTrace::SetFilter2((TUint32)a1,(TBool)a2);
sl@0
   765
sl@0
   766
	case RBTrace::ESetFilter2Array:
sl@0
   767
		{
sl@0
   768
		NKern::ThreadEnterCS();
sl@0
   769
		delete iFilter2Set;
sl@0
   770
		TInt size = (TInt)a2*sizeof(TUint32);
sl@0
   771
		TUint32* buffer = (TUint32*)Kern::Alloc(size);
sl@0
   772
		iFilter2Set = buffer;
sl@0
   773
		NKern::ThreadLeaveCS();
sl@0
   774
		if(!buffer)
sl@0
   775
			return KErrNoMemory;
sl@0
   776
		kumemget32(buffer,a1,size);
sl@0
   777
		r = BTrace::SetFilter2(buffer,(TInt)a2);
sl@0
   778
		NKern::ThreadEnterCS();
sl@0
   779
		delete iFilter2Set;
sl@0
   780
		iFilter2Set = 0;
sl@0
   781
		NKern::ThreadLeaveCS();
sl@0
   782
		return r;
sl@0
   783
		}
sl@0
   784
sl@0
   785
	case RBTrace::ESetFilter2Global:
sl@0
   786
		BTrace::SetFilter2((TBool)a1);
sl@0
   787
		return KErrNone;
sl@0
   788
sl@0
   789
	case RBTrace::EGetFilter2Part1:
sl@0
   790
		{
sl@0
   791
		NKern::ThreadEnterCS();
sl@0
   792
		delete iFilter2;
sl@0
   793
		iFilter2 = 0;
sl@0
   794
		iFilter2Count = 0;
sl@0
   795
		TInt globalFilter = 0;
sl@0
   796
		iFilter2Count = BTrace::Filter2(iFilter2,globalFilter);
sl@0
   797
		NKern::ThreadLeaveCS();
sl@0
   798
		kumemput32(a2,&globalFilter,sizeof(TBool));
sl@0
   799
		return iFilter2Count;
sl@0
   800
		}
sl@0
   801
sl@0
   802
	case RBTrace::EGetFilter2Part2:
sl@0
   803
		if((TInt)a2!=iFilter2Count)
sl@0
   804
			return KErrArgument;
sl@0
   805
		if(iFilter2Count>0)
sl@0
   806
			kumemput32(a1,iFilter2,iFilter2Count*sizeof(TUint32));
sl@0
   807
		NKern::ThreadEnterCS();
sl@0
   808
		delete iFilter2;
sl@0
   809
		iFilter2 = 0;
sl@0
   810
		iFilter2Count = 0;
sl@0
   811
		NKern::ThreadLeaveCS();
sl@0
   812
		return KErrNone;
sl@0
   813
sl@0
   814
	case RBTrace::ERequestData:
sl@0
   815
		if (iWaitRequest->SetStatus((TRequestStatus*)a1) != KErrNone)
sl@0
   816
			Kern::PanicCurrentThread(RBTrace::Name(),RBTrace::ERequestAlreadyPending);
sl@0
   817
		r = buffer.RequestData((TInt)a2,&iWaitDfc);
sl@0
   818
		if (r!=KErrNone)
sl@0
   819
			{
sl@0
   820
			iWaitRequest->Reset();
sl@0
   821
			TRequestStatus* s = (TRequestStatus*)a1;
sl@0
   822
			if (r==KErrCompletion)
sl@0
   823
				r = KErrNone;
sl@0
   824
			Kern::RequestComplete(s, r);
sl@0
   825
			}
sl@0
   826
		return r;
sl@0
   827
sl@0
   828
	case RBTrace::ECancelRequestData:
sl@0
   829
		buffer.iWaitingDfc = NULL;
sl@0
   830
		iWaitDfc.Cancel();
sl@0
   831
		Kern::QueueRequestComplete(iClient, iWaitRequest, KErrCancel);
sl@0
   832
		return KErrNone;
sl@0
   833
sl@0
   834
	case RBTrace::ESetSerialPortOutput:
sl@0
   835
		{
sl@0
   836
		TUint mode = Kern::ESerialOutNever+(TUint)a1;
sl@0
   837
		mode = Kern::SetTextTraceMode(mode,Kern::ESerialOutMask);
sl@0
   838
		mode &= Kern::ESerialOutMask;
sl@0
   839
		return mode-Kern::ESerialOutNever;
sl@0
   840
		}
sl@0
   841
sl@0
   842
	case RBTrace::ESetTimestamp2Enabled:
sl@0
   843
		{
sl@0
   844
		TBool old = iTimestamp2Enabled;
sl@0
   845
		iTimestamp2Enabled = (TBool)a1;
sl@0
   846
		BTrace::TControlFunction oldControl;
sl@0
   847
		BTrace::THandler oldHandler;
sl@0
   848
		BTrace::THandler handler = iTimestamp2Enabled ? TBTraceBufferK::TraceWithTimestamp2 : TBTraceBufferK::Trace;
sl@0
   849
		BTrace::SetHandlers(handler,TBTraceBufferK::ControlFunction,oldHandler,oldControl);
sl@0
   850
		return old;
sl@0
   851
		}
sl@0
   852
sl@0
   853
	default:
sl@0
   854
		break;
sl@0
   855
		}
sl@0
   856
	return KErrNotSupported;
sl@0
   857
	}
sl@0
   858
sl@0
   859
sl@0
   860
DECLARE_EXTENSION_LDD()
sl@0
   861
	{
sl@0
   862
	return new DBTraceFactory;
sl@0
   863
	}
sl@0
   864
sl@0
   865
#ifdef __WINS__
sl@0
   866
DECLARE_STANDARD_EXTENSION()
sl@0
   867
#else
sl@0
   868
DECLARE_EXTENSION_WITH_PRIORITY(KExtensionMaximumPriority)
sl@0
   869
#endif
sl@0
   870
	{
sl@0
   871
	TSuperPage& superPage = Kern::SuperPage();
sl@0
   872
	TInt bufferSize = superPage.iInitialBTraceBuffer;
sl@0
   873
	if(!bufferSize)
sl@0
   874
		bufferSize = 0x10000;
sl@0
   875
	TInt r=Buffer.Create(bufferSize);
sl@0
   876
	if(r==KErrNone)
sl@0
   877
		Buffer.Reset(superPage.iInitialBTraceMode);
sl@0
   878
	return r;
sl@0
   879
	}
sl@0
   880