kernel/eka/drivers/trace/arm/btracex_impl.cia
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// e32\drivers\trace\arm\btracex_impl.cia
// 
//

	// adjust a0 for timestamp(s) 
#ifdef BTRACE_INCLUDE_TIMESTAMPS
#ifdef USE_TIMESTAMP2
	asm("add	r0, r0, #8 ");
	asm("orr	r0, r0, #%a0" : : "i" ((TInt)((BTrace::ETimestampPresent | BTrace::ETimestamp2Present)<<BTrace::EFlagsIndex*8)));
#else
	asm("add	r0, r0, #4 ");
	asm("orr	r0, r0, #%a0" : : "i" ((TInt)(BTrace::ETimestampPresent<<BTrace::EFlagsIndex*8)));
#endif
#endif
#ifdef __SMP__
	// add in CPU ID field to Header2
	asm("tst r0, #%a0" : : "i" ((TInt)(BTrace::EHeader2Present<<BTrace::EFlagsIndex*8)));
	asm("movne r12, r1, lsl #12 ");		// if Header2 already present, r12=Header2<<12
	asm("mrc p15, 0, r1, c0, c0, 5 ");	// r1 = CPU ID
	asm("orr r0, r0, #%a0" : : "i" ((TInt)(BTrace::EHeader2Present<<BTrace::EFlagsIndex*8)));	// Header2 is there
	asm("addeq r0, r0, #%a0" : : "i" ((TInt)(4<<BTrace::ESizeIndex*8)));	// if Header2 was not there, add 4 to size
	asm("mov r1, r1, lsl #20 ");		// CPU ID into top 12 bits of Header2
	asm("orrne r1, r1, r12, lsr #12 ");	// if Header2 was already there, keep bottom 20 bits of it
	asm("stmdb	sp!,{r0-r12,lr} ");		// save first 4 args, callee-save registers, CPSR and return address (14 words)
#else
	asm("mrs	r12, cpsr ");			// r12 = save interrupt status
	asm("stmdb	sp!,{r0-r12,lr} ");		// save first 4 args, callee-save registers, CPSR and return address (14 words)
	INTS_OFF(r14, r12, INTS_ALL_OFF);	// disable interrupts
#endif
	asm("ldr	r10, __Buffer ");		// r10 = our buffer structure
	asm("add	r4, r0, #3 ");
	asm("and	r4, r4, #0xfc ");		// r4 = size of trace record rounded up to whole word size
	asm("ldmia	r10, {r5-r7} ");		// r5 = Buffer.iAddress
										// r6 = Buffer.iStart
										// r7 = Buffer.iEnd
	asm("ldr	r14, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iGeneration));
	asm("ldr	r9, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iRequestDataSize));
	asm("ldr	r12, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iRecordOffsets));
	asm("add	r14, r14, #1 ");
	asm("str	r14, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iGeneration));
#ifdef __SMP__
	__DATA_MEMORY_BARRIER_Z__(r8);
#endif
	asm("ldr	r2, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iTail));
										// r2 = original iTail (might have bit 0 set)
	asm("ldr	r14, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iMode));
										// r14 = iMode

	asm("8: ");
	asm("ldr	r8, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iHead));
	asm("bic	r1, r2, #1 ");			// r1 = tail (bit 0 cleared)
	asm("add	r3, r8, r4 ");			// r3 = head+size = newHead (always multiple of 4)

	/* Registers: R0=spare, R1=tail, R2=orig_tail, R3=newHead, R4=size, R5=&user_buffer, R6=iStart, R7=iEnd
		R8=head, R9=requestDataSize, R10=&Buffer, R11=unused, R12=iRecordOffsets, R14=iMode
	 */

	asm("tst	r14, #%a0" : : "i" ((TInt)RBTrace::EEnable));
	asm("beq	trace_off ");			// end now if tracing is disabled

	asm("cmp	r3, r7 ");				// cmp newHead,end
	asm("bls	1f "); // 1f==no_wrap
	asm("mov	r9, #0 ");				// iRequestDataSize=0
	asm("add	r3, r6, r4 ");			// newHead = start+size
	asm("add	r0, r3, #1 ");			// r0 = newHead+1
	asm("cmp	r8, r1 ");				// cmp head,tail
	asm("cmphs	r1, r0 ");				// cmp tail,newHead+1
	asm("strhs	r8, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iWrap));
	asm("movhs	r8, r6 ");				// head = start
	asm("bhs	3f ");					// ... done (3f==update_offsets)
	// new trace would be overwriting tail pointer...
	asm("tst	r14, #%a0" : : "i" ((TInt)RBTrace::EFreeRunning));
	asm("beq	trace_dropped ");		// if we aren't in freerunning mode, drop the trace
	asm("ldrb	r1, [r12, r3, lsr #2] ");// r1 = word offset to next record after newHead
	asm("str	r8, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iWrap));
	asm("mov	r8, r6 ");				// head = start
	asm("add	r1, r3, r1, lsl #2 ");	// tail = newHead + offset to next record
	asm("b		2f ");					// 2f==overwrite

	asm("1: "); // no_wrap
	asm("cmp	r8, r1 ");				// cmp head,tail
	asm("bhs	3f ");					// if >= then done (3f==update_offsets)
	asm("cmp	r1, r3 ");				// cmp tail,newHead
	asm("bhi	3f ");					// if > the done (3f==update_offsets)
	asm("ldr	r0, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iWrap)); // r0 = wrap
	asm("tst	r14, #%a0" : : "i" ((TInt)RBTrace::EFreeRunning));
	asm("beq	trace_dropped ");		// if we aren't in freerunning mode, drop the trace
	asm("cmp	r3, r7 ");				// cmp newHead,end
	asm("cmplo	r3, r0 ");				// cmp newHead,wrap
	asm("ldrlob	r1, [r12, r3, lsr #2] ");// r1 = word offset to next record after newHead
	asm("mov	r9, #0 ");				// iRequestDataSize=0
	asm("addlo	r1, r3, r1, lsl #2 ");	// tail = newHead + offset to next record
	asm("cmplo	r1, r7 ");				// cmp tail,end
	asm("cmplo	r1, r0 ");				// cmp tail,wrap
	asm("movhs	r1, r6 ");				// tail = start

	asm("2: "); // overwrite
	asm("ldr	r0, [r5, r1] ");			// r1 = first word of record at new tail
#ifndef __SMP__
	// On single processor iTail can't have been updated since interrupts are off here
	asm("orr	r1, r1, #1 ");
	asm("str	r1,	[r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iTail)); // update tail
	asm("bic	r1, r1, #1 ");
#endif
	asm("orr	r0, r0, #%a0" : : "i" ((TInt)(BTrace::EMissingRecord<<(BTrace::EFlagsIndex*8))));
	asm("str	r0, [r5, r1] ");			// set 'missing record' flag in next record to be read
#ifdef __SMP__
	// attempt to atomically update iTail
	asm("9: ");
	asm("add	r5,	r5, #%a0" : : "i" _FOFF(TBTraceBuffer,iTail)); // r5=&user_buffer.iTail
	asm("orr	r1, r1, #1 ");
	LDREX(0,5);
	asm("cmp r0, r2 ");		// iTail = orig_tail ?
	asm("movne r2, r0 ");	// if not, orig_tail = iTail
	asm("bne 8b ");			// and go round again
	STREX(0,1,5);			// else try to update iTail with tail|1
	asm("cmp r0, #0 ");
	asm("bne 9b ");
	__DATA_MEMORY_BARRIER__(r0);	// ensure update to iTail observed before overwrites
	asm("sub	r5,	r5, #%a0" : : "i" _FOFF(TBTraceBuffer,iTail)); // r5=&user_buffer.iTail
#endif

	asm("3: "); // update_offsets
	asm("sub	r9, r9, r4 ");			// iRequestDataSize -= size
	asm("str	r3, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iHead));	// OK to do this here since only used kernel side
	asm("str	r9, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iRequestDataSize));

	asm("add	r5, r5, r8 ");			// r5 = address+head = destination to store trace
	asm("mov	r4, r4, asr #2 ");		// r4 = size/4 = number of words in trace record
	asm("add	r11, r12, r8, asr #2 ");	// r11 = address to store record sizes
	// unused regs are now r0 r1 r2 r3 r6 r7 r8 r9 r12 r14

	asm("ldr	r14, [r10,#%a0]" : : "i" _FOFF(TBTraceBufferK,iDropped));
	asm("ldmia	sp, {r6-r9} ");			// r6 = aHeader, r7 = aHeader2, r8 = aContext, r9 = a1
	asm("cmp	r14, #0 ");
	asm("movne	r14, #0 ");
	asm("strne	r14, [r10,#%a0]" : : "i" _FOFF(TBTraceBufferK,iDropped));
	asm("orrne	r6, r6, #%a0" : : "i" ((TInt)(BTrace::EMissingRecord<<BTrace::EFlagsIndex*8)));

	asm("str	r6, [r5], #4 ");			// store aHeader
	asm("strb	r4, [r11], #1 ");
	asm("sub	r4, r4, #1 ");

	asm("tst	r6, #%a0" : : "i" ((TInt)(BTrace::EHeader2Present<<BTrace::EFlagsIndex*8)));
	asm("strne	r7, [r5], #4 ");			// store aHeader2 ?
	asm("strneb	r4, [r11], #1 ");
	asm("subne	r4, r4, #1 ");

#ifdef BTRACE_INCLUDE_TIMESTAMPS
#ifdef __SMP__
	asm("bl		Timestamp__5NKern ");
	asm("str	r0, [r5], #4 ");		// store timestamp low word
#ifdef USE_TIMESTAMP2
	asm("str	r1, [r5], #4 ");		// store timestamp high word
#endif
#else	// __SMP__
#ifdef HAS_HIGH_RES_TIMER
	GET_HIGH_RES_TICK_COUNT(r0);		// r0 = timestamp
#else
	asm("bl " CSM_ZN5NKern11FastCounterEv);
#endif
	asm("str	r0, [r5], #4 ");		// store timestamp
	asm("strb	r4, [r11], #1 ");
	asm("subs	r4, r4, #1 ");
#ifdef USE_TIMESTAMP2
	asm("bl " CSM_ZN5NKern9TickCountEv );
	asm("str	r0, [r5], #4 ");		// store timestamp2
	asm("strb	r4, [r11], #1 ");
	asm("subs	r4, r4, #1 ");
#endif
#endif	// __SMP__
#endif	// BTRACE_INCLUDE_TIMESTAMPS

	asm("add	r0, sp, #14*4 ");
	asm("ldmia	r0, {r0-r3} ");			// r0 = a2, r1 = a3, r2 = aExtra, r3 = aPc

	asm("tst	r6, #%a0" : : "i" ((TInt)(BTrace::EContextIdPresent<<BTrace::EFlagsIndex*8)));
	asm("strne	r8, [r5], #4 ");			// store aContext ?
	asm("strneb	r4, [r11], #1 ");
	asm("subne	r4, r4, #1 ");

	asm("tst	r6, #%a0" : : "i" ((TInt)(BTrace::EPcPresent<<BTrace::EFlagsIndex*8)));
	asm("strne	r3, [r5], #4 ");			// store aPc ?
	asm("strneb	r4, [r11], #1 ");
	asm("subne	r4, r4, #1 ");

	asm("tst	r6, #%a0" : : "i" ((TInt)(BTrace::EExtraPresent<<BTrace::EFlagsIndex*8)));
	asm("strne	r2, [r5], #4 ");			// store aExtra ?
	asm("strneb	r4, [r11], #1 ");
	asm("subne	r4, r4, #1 ");

	asm("cmp	r4, #0 ");				// done?
	asm("ble	6f ");					// 6f==trace_stored

	asm("str	r9, [r5], #4 ");			// store a1
	asm("strb	r4, [r11], #1 ");
	asm("subs	r4, r4, #1 ");
	asm("ble	6f ");					// 6f==trace_stored

	asm("str	r0, [r5], #4 ");			// store a2
	asm("strb	r4, [r11], #1 ");
	asm("subs	r4, r4, #1 ");
	asm("ble	6f ");					// 6f==trace_stored

	asm("cmp	r4, #1 ");
	asm("streq	r1, [r5], #4 ");			// store a3 ?
	asm("streqb	r4, [r11], #1 ");
	asm("beq	6f ");					// 6f==trace_stored

	// r9 = pointer to rest of data to store...
	asm("mov	r9, r1 ");

	asm("cmp	r4, #7 ");
	asm("blo	5f "); // store_loop_last

	asm("ldr	r14, __03020100 ");
	asm("add	r4, r4, r4, asl #8 ");
	asm("add	r4, r4, r4, asl #16 ");
	asm("sub	r4, r4, r14 ");
	asm("ldr	r8, __04040404 ");

	// align destination to 4 words...
	asm("movs	r14, r5, asl #28 ");
	asm("beq	4f "); // 4f==block_copy_loop
	asm("rsb	r14, r14, #0 ");
	asm("msr	cpsr_f, r14 ");

	asm("ldmeqia	r9!, {r0} ");
	asm("streqb		r4, [r11], #1 ");
	asm("subeq		r4, r4, r8, lsr #2 ");
	asm("stmeqia	r5!, {r0} ");

	asm("ldmmiia	r9!, {r2,r3} ");
	asm("strmih		r4, [r11], #2 ");
	asm("submi		r4, r4, r8, lsr #1 ");
	asm("stmmiia	r5!, {r2,r3} ");

	asm("4: "); // block_copy_loop
	asm("ldmia	r9!, {r0-r3} ");
	asm("stmia	r5!, {r0-r3} ");
	asm("str	r4, [r11], #4 ");
	asm("subs	r4, r4, r8 ");
	asm("cmphs	r4, #0x01000000 ");
	asm("bhs	4b ");					// 4b==block_copy_loop

	asm("ands	r4, r4, #3 ");
	asm("beq	6f ");					// 6f==trace_stored

	asm("5: "); // store_loop_last
	asm("ldr	r0, [r9], #4 ");			// get next word for record
	asm("strb	r4, [r11], #1 ");		// store size offset
	asm("subs	r4, r4, #1 ");
	asm("str	r0, [r5], #4 ");			// store word of trace record
	asm("bhi	5b "); // 5b==store_loop_last

	asm("6: "); // trace_stored
	asm("ldr	r5, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iAddress));
	asm("ldr	r6, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iHead));
#ifdef __SMP__
	__DATA_MEMORY_BARRIER_Z__(r8);		// make sure all buffer writes observed before head pointer update
#endif
	asm("ldr	r4, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iWaitingDfc));
	asm("ldr	r7, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iGeneration));
	asm("ldr	r0, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iRequestDataSize));
	asm("str	r6, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iHead));	// update user-visible head pointer
	asm("add	r7, r7, #1 ");
#ifdef __SMP__
	__DATA_MEMORY_BARRIER__(r8);		// make sure head pointer update seen before generation update
#endif
	asm("str	r7, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iGeneration));
	asm("cmp	r4, #0 ");
	asm("beq	done ");
	asm("cmp	r0, #0 ");
	asm("bgt	done ");

	// iWaitingDfc exists and iRequestDataSize<=0 so we need to trigger the DFC...
	asm("mov	r0, #0 ");
	asm("str	r0, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iWaitingDfc)); // iWaitingDfc=0

	asm("mov	r0, r4 ");
	asm("bl	"	CSM_ZN4TDfc6RawAddEv);
	asm("b		done ");