kernel/eka/drivers/trace/arm/btracex_impl.cia
changeset 0 a41df078684a
child 184 0e2270015475
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2007-2009 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 the License "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 // e32\drivers\trace\arm\btracex_impl.cia
       
    15 // 
       
    16 //
       
    17 
       
    18 	// adjust a0 for timestamp(s) 
       
    19 #ifdef BTRACE_INCLUDE_TIMESTAMPS
       
    20 #ifdef USE_TIMESTAMP2
       
    21 	asm("add	r0, r0, #8 ");
       
    22 	asm("orr	r0, r0, #%a0" : : "i" ((TInt)((BTrace::ETimestampPresent | BTrace::ETimestamp2Present)<<BTrace::EFlagsIndex*8)));
       
    23 #else
       
    24 	asm("add	r0, r0, #4 ");
       
    25 	asm("orr	r0, r0, #%a0" : : "i" ((TInt)(BTrace::ETimestampPresent<<BTrace::EFlagsIndex*8)));
       
    26 #endif
       
    27 #endif
       
    28 #ifdef __SMP__
       
    29 	// add in CPU ID field to Header2
       
    30 	asm("tst r0, #%a0" : : "i" ((TInt)(BTrace::EHeader2Present<<BTrace::EFlagsIndex*8)));
       
    31 	asm("movne r12, r1, lsl #12 ");		// if Header2 already present, r12=Header2<<12
       
    32 	asm("mrc p15, 0, r1, c0, c0, 5 ");	// r1 = CPU ID
       
    33 	asm("orr r0, r0, #%a0" : : "i" ((TInt)(BTrace::EHeader2Present<<BTrace::EFlagsIndex*8)));	// Header2 is there
       
    34 	asm("addeq r0, r0, #%a0" : : "i" ((TInt)(4<<BTrace::ESizeIndex*8)));	// if Header2 was not there, add 4 to size
       
    35 	asm("mov r1, r1, lsl #20 ");		// CPU ID into top 12 bits of Header2
       
    36 	asm("orrne r1, r1, r12, lsr #12 ");	// if Header2 was already there, keep bottom 20 bits of it
       
    37 	asm("stmdb	sp!,{r0-r12,lr} ");		// save first 4 args, callee-save registers, CPSR and return address (14 words)
       
    38 #else
       
    39 	asm("mrs	r12, cpsr ");			// r12 = save interrupt status
       
    40 	asm("stmdb	sp!,{r0-r12,lr} ");		// save first 4 args, callee-save registers, CPSR and return address (14 words)
       
    41 	INTS_OFF(r14, r12, INTS_ALL_OFF);	// disable interrupts
       
    42 #endif
       
    43 	asm("ldr	r10, __Buffer ");		// r10 = our buffer structure
       
    44 	asm("add	r4, r0, #3 ");
       
    45 	asm("and	r4, r4, #0xfc ");		// r4 = size of trace record rounded up to whole word size
       
    46 	asm("ldmia	r10, {r5-r7} ");		// r5 = Buffer.iAddress
       
    47 										// r6 = Buffer.iStart
       
    48 										// r7 = Buffer.iEnd
       
    49 	asm("ldr	r14, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iGeneration));
       
    50 	asm("ldr	r9, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iRequestDataSize));
       
    51 	asm("ldr	r12, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iRecordOffsets));
       
    52 	asm("add	r14, r14, #1 ");
       
    53 	asm("str	r14, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iGeneration));
       
    54 #ifdef __SMP__
       
    55 	__DATA_MEMORY_BARRIER_Z__(r8);
       
    56 #endif
       
    57 	asm("ldr	r2, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iTail));
       
    58 										// r2 = original iTail (might have bit 0 set)
       
    59 	asm("ldr	r14, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iMode));
       
    60 										// r14 = iMode
       
    61 
       
    62 	asm("8: ");
       
    63 	asm("ldr	r8, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iHead));
       
    64 	asm("bic	r1, r2, #1 ");			// r1 = tail (bit 0 cleared)
       
    65 	asm("add	r3, r8, r4 ");			// r3 = head+size = newHead (always multiple of 4)
       
    66 
       
    67 	/* Registers: R0=spare, R1=tail, R2=orig_tail, R3=newHead, R4=size, R5=&user_buffer, R6=iStart, R7=iEnd
       
    68 		R8=head, R9=requestDataSize, R10=&Buffer, R11=unused, R12=iRecordOffsets, R14=iMode
       
    69 	 */
       
    70 
       
    71 	asm("tst	r14, #%a0" : : "i" ((TInt)RBTrace::EEnable));
       
    72 	asm("beq	trace_off ");			// end now if tracing is disabled
       
    73 
       
    74 	asm("cmp	r3, r7 ");				// cmp newHead,end
       
    75 	asm("bls	1f "); // 1f==no_wrap
       
    76 	asm("mov	r9, #0 ");				// iRequestDataSize=0
       
    77 	asm("add	r3, r6, r4 ");			// newHead = start+size
       
    78 	asm("add	r0, r3, #1 ");			// r0 = newHead+1
       
    79 	asm("cmp	r8, r1 ");				// cmp head,tail
       
    80 	asm("cmphs	r1, r0 ");				// cmp tail,newHead+1
       
    81 	asm("strhs	r8, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iWrap));
       
    82 	asm("movhs	r8, r6 ");				// head = start
       
    83 	asm("bhs	3f ");					// ... done (3f==update_offsets)
       
    84 	// new trace would be overwriting tail pointer...
       
    85 	asm("tst	r14, #%a0" : : "i" ((TInt)RBTrace::EFreeRunning));
       
    86 	asm("beq	trace_dropped ");		// if we aren't in freerunning mode, drop the trace
       
    87 	asm("ldrb	r1, [r12, r3, lsr #2] ");// r1 = word offset to next record after newHead
       
    88 	asm("str	r8, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iWrap));
       
    89 	asm("mov	r8, r6 ");				// head = start
       
    90 	asm("add	r1, r3, r1, lsl #2 ");	// tail = newHead + offset to next record
       
    91 	asm("b		2f ");					// 2f==overwrite
       
    92 
       
    93 	asm("1: "); // no_wrap
       
    94 	asm("cmp	r8, r1 ");				// cmp head,tail
       
    95 	asm("bhs	3f ");					// if >= then done (3f==update_offsets)
       
    96 	asm("cmp	r1, r3 ");				// cmp tail,newHead
       
    97 	asm("bhi	3f ");					// if > the done (3f==update_offsets)
       
    98 	asm("ldr	r0, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iWrap)); // r0 = wrap
       
    99 	asm("tst	r14, #%a0" : : "i" ((TInt)RBTrace::EFreeRunning));
       
   100 	asm("beq	trace_dropped ");		// if we aren't in freerunning mode, drop the trace
       
   101 	asm("cmp	r3, r7 ");				// cmp newHead,end
       
   102 	asm("cmplo	r3, r0 ");				// cmp newHead,wrap
       
   103 	asm("ldrlob	r1, [r12, r3, lsr #2] ");// r1 = word offset to next record after newHead
       
   104 	asm("mov	r9, #0 ");				// iRequestDataSize=0
       
   105 	asm("addlo	r1, r3, r1, lsl #2 ");	// tail = newHead + offset to next record
       
   106 	asm("cmplo	r1, r7 ");				// cmp tail,end
       
   107 	asm("cmplo	r1, r0 ");				// cmp tail,wrap
       
   108 	asm("movhs	r1, r6 ");				// tail = start
       
   109 
       
   110 	asm("2: "); // overwrite
       
   111 	asm("ldr	r0, [r5, r1] ");			// r1 = first word of record at new tail
       
   112 #ifndef __SMP__
       
   113 	// On single processor iTail can't have been updated since interrupts are off here
       
   114 	asm("orr	r1, r1, #1 ");
       
   115 	asm("str	r1,	[r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iTail)); // update tail
       
   116 	asm("bic	r1, r1, #1 ");
       
   117 #endif
       
   118 	asm("orr	r0, r0, #%a0" : : "i" ((TInt)(BTrace::EMissingRecord<<(BTrace::EFlagsIndex*8))));
       
   119 	asm("str	r0, [r5, r1] ");			// set 'missing record' flag in next record to be read
       
   120 #ifdef __SMP__
       
   121 	// attempt to atomically update iTail
       
   122 	asm("9: ");
       
   123 	asm("add	r5,	r5, #%a0" : : "i" _FOFF(TBTraceBuffer,iTail)); // r5=&user_buffer.iTail
       
   124 	asm("orr	r1, r1, #1 ");
       
   125 	LDREX(0,5);
       
   126 	asm("cmp r0, r2 ");		// iTail = orig_tail ?
       
   127 	asm("movne r2, r0 ");	// if not, orig_tail = iTail
       
   128 	asm("bne 8b ");			// and go round again
       
   129 	STREX(0,1,5);			// else try to update iTail with tail|1
       
   130 	asm("cmp r0, #0 ");
       
   131 	asm("bne 9b ");
       
   132 	__DATA_MEMORY_BARRIER__(r0);	// ensure update to iTail observed before overwrites
       
   133 	asm("sub	r5,	r5, #%a0" : : "i" _FOFF(TBTraceBuffer,iTail)); // r5=&user_buffer.iTail
       
   134 #endif
       
   135 
       
   136 	asm("3: "); // update_offsets
       
   137 	asm("sub	r9, r9, r4 ");			// iRequestDataSize -= size
       
   138 	asm("str	r3, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iHead));	// OK to do this here since only used kernel side
       
   139 	asm("str	r9, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iRequestDataSize));
       
   140 
       
   141 	asm("add	r5, r5, r8 ");			// r5 = address+head = destination to store trace
       
   142 	asm("mov	r4, r4, asr #2 ");		// r4 = size/4 = number of words in trace record
       
   143 	asm("add	r11, r12, r8, asr #2 ");	// r11 = address to store record sizes
       
   144 	// unused regs are now r0 r1 r2 r3 r6 r7 r8 r9 r12 r14
       
   145 
       
   146 	asm("ldr	r14, [r10,#%a0]" : : "i" _FOFF(TBTraceBufferK,iDropped));
       
   147 	asm("ldmia	sp, {r6-r9} ");			// r6 = aHeader, r7 = aHeader2, r8 = aContext, r9 = a1
       
   148 	asm("cmp	r14, #0 ");
       
   149 	asm("movne	r14, #0 ");
       
   150 	asm("strne	r14, [r10,#%a0]" : : "i" _FOFF(TBTraceBufferK,iDropped));
       
   151 	asm("orrne	r6, r6, #%a0" : : "i" ((TInt)(BTrace::EMissingRecord<<BTrace::EFlagsIndex*8)));
       
   152 
       
   153 	asm("str	r6, [r5], #4 ");			// store aHeader
       
   154 	asm("strb	r4, [r11], #1 ");
       
   155 	asm("sub	r4, r4, #1 ");
       
   156 
       
   157 	asm("tst	r6, #%a0" : : "i" ((TInt)(BTrace::EHeader2Present<<BTrace::EFlagsIndex*8)));
       
   158 	asm("strne	r7, [r5], #4 ");			// store aHeader2 ?
       
   159 	asm("strneb	r4, [r11], #1 ");
       
   160 	asm("subne	r4, r4, #1 ");
       
   161 
       
   162 #ifdef BTRACE_INCLUDE_TIMESTAMPS
       
   163 #ifdef __SMP__
       
   164 	asm("bl		Timestamp__5NKern ");
       
   165 	asm("str	r0, [r5], #4 ");		// store timestamp low word
       
   166 #ifdef USE_TIMESTAMP2
       
   167 	asm("str	r1, [r5], #4 ");		// store timestamp high word
       
   168 #endif
       
   169 #else	// __SMP__
       
   170 #ifdef HAS_HIGH_RES_TIMER
       
   171 	GET_HIGH_RES_TICK_COUNT(r0);		// r0 = timestamp
       
   172 #else
       
   173 	asm("bl " CSM_ZN5NKern11FastCounterEv);
       
   174 #endif
       
   175 	asm("str	r0, [r5], #4 ");		// store timestamp
       
   176 	asm("strb	r4, [r11], #1 ");
       
   177 	asm("subs	r4, r4, #1 ");
       
   178 #ifdef USE_TIMESTAMP2
       
   179 	asm("bl " CSM_ZN5NKern9TickCountEv );
       
   180 	asm("str	r0, [r5], #4 ");		// store timestamp2
       
   181 	asm("strb	r4, [r11], #1 ");
       
   182 	asm("subs	r4, r4, #1 ");
       
   183 #endif
       
   184 #endif	// __SMP__
       
   185 #endif	// BTRACE_INCLUDE_TIMESTAMPS
       
   186 
       
   187 	asm("add	r0, sp, #14*4 ");
       
   188 	asm("ldmia	r0, {r0-r3} ");			// r0 = a2, r1 = a3, r2 = aExtra, r3 = aPc
       
   189 
       
   190 	asm("tst	r6, #%a0" : : "i" ((TInt)(BTrace::EContextIdPresent<<BTrace::EFlagsIndex*8)));
       
   191 	asm("strne	r8, [r5], #4 ");			// store aContext ?
       
   192 	asm("strneb	r4, [r11], #1 ");
       
   193 	asm("subne	r4, r4, #1 ");
       
   194 
       
   195 	asm("tst	r6, #%a0" : : "i" ((TInt)(BTrace::EPcPresent<<BTrace::EFlagsIndex*8)));
       
   196 	asm("strne	r3, [r5], #4 ");			// store aPc ?
       
   197 	asm("strneb	r4, [r11], #1 ");
       
   198 	asm("subne	r4, r4, #1 ");
       
   199 
       
   200 	asm("tst	r6, #%a0" : : "i" ((TInt)(BTrace::EExtraPresent<<BTrace::EFlagsIndex*8)));
       
   201 	asm("strne	r2, [r5], #4 ");			// store aExtra ?
       
   202 	asm("strneb	r4, [r11], #1 ");
       
   203 	asm("subne	r4, r4, #1 ");
       
   204 
       
   205 	asm("cmp	r4, #0 ");				// done?
       
   206 	asm("ble	6f ");					// 6f==trace_stored
       
   207 
       
   208 	asm("str	r9, [r5], #4 ");			// store a1
       
   209 	asm("strb	r4, [r11], #1 ");
       
   210 	asm("subs	r4, r4, #1 ");
       
   211 	asm("ble	6f ");					// 6f==trace_stored
       
   212 
       
   213 	asm("str	r0, [r5], #4 ");			// store a2
       
   214 	asm("strb	r4, [r11], #1 ");
       
   215 	asm("subs	r4, r4, #1 ");
       
   216 	asm("ble	6f ");					// 6f==trace_stored
       
   217 
       
   218 	asm("cmp	r4, #1 ");
       
   219 	asm("streq	r1, [r5], #4 ");			// store a3 ?
       
   220 	asm("streqb	r4, [r11], #1 ");
       
   221 	asm("beq	6f ");					// 6f==trace_stored
       
   222 
       
   223 	// r9 = pointer to rest of data to store...
       
   224 	asm("mov	r9, r1 ");
       
   225 
       
   226 	asm("cmp	r4, #7 ");
       
   227 	asm("blo	5f "); // store_loop_last
       
   228 
       
   229 	asm("ldr	r14, __03020100 ");
       
   230 	asm("add	r4, r4, r4, asl #8 ");
       
   231 	asm("add	r4, r4, r4, asl #16 ");
       
   232 	asm("sub	r4, r4, r14 ");
       
   233 	asm("ldr	r8, __04040404 ");
       
   234 
       
   235 	// align destination to 4 words...
       
   236 	asm("movs	r14, r5, asl #28 ");
       
   237 	asm("beq	4f "); // 4f==block_copy_loop
       
   238 	asm("rsb	r14, r14, #0 ");
       
   239 	asm("msr	cpsr_f, r14 ");
       
   240 
       
   241 	asm("ldmeqia	r9!, {r0} ");
       
   242 	asm("streqb		r4, [r11], #1 ");
       
   243 	asm("subeq		r4, r4, r8, lsr #2 ");
       
   244 	asm("stmeqia	r5!, {r0} ");
       
   245 
       
   246 	asm("ldmmiia	r9!, {r2,r3} ");
       
   247 	asm("strmih		r4, [r11], #2 ");
       
   248 	asm("submi		r4, r4, r8, lsr #1 ");
       
   249 	asm("stmmiia	r5!, {r2,r3} ");
       
   250 
       
   251 	asm("4: "); // block_copy_loop
       
   252 	asm("ldmia	r9!, {r0-r3} ");
       
   253 	asm("stmia	r5!, {r0-r3} ");
       
   254 	asm("str	r4, [r11], #4 ");
       
   255 	asm("subs	r4, r4, r8 ");
       
   256 	asm("cmphs	r4, #0x01000000 ");
       
   257 	asm("bhs	4b ");					// 4b==block_copy_loop
       
   258 
       
   259 	asm("ands	r4, r4, #3 ");
       
   260 	asm("beq	6f ");					// 6f==trace_stored
       
   261 
       
   262 	asm("5: "); // store_loop_last
       
   263 	asm("ldr	r0, [r9], #4 ");			// get next word for record
       
   264 	asm("strb	r4, [r11], #1 ");		// store size offset
       
   265 	asm("subs	r4, r4, #1 ");
       
   266 	asm("str	r0, [r5], #4 ");			// store word of trace record
       
   267 	asm("bhi	5b "); // 5b==store_loop_last
       
   268 
       
   269 	asm("6: "); // trace_stored
       
   270 	asm("ldr	r5, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iAddress));
       
   271 	asm("ldr	r6, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iHead));
       
   272 #ifdef __SMP__
       
   273 	__DATA_MEMORY_BARRIER_Z__(r8);		// make sure all buffer writes observed before head pointer update
       
   274 #endif
       
   275 	asm("ldr	r4, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iWaitingDfc));
       
   276 	asm("ldr	r7, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iGeneration));
       
   277 	asm("ldr	r0, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iRequestDataSize));
       
   278 	asm("str	r6, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iHead));	// update user-visible head pointer
       
   279 	asm("add	r7, r7, #1 ");
       
   280 #ifdef __SMP__
       
   281 	__DATA_MEMORY_BARRIER__(r8);		// make sure head pointer update seen before generation update
       
   282 #endif
       
   283 	asm("str	r7, [r5, #%a0]" : : "i" _FOFF(TBTraceBuffer,iGeneration));
       
   284 	asm("cmp	r4, #0 ");
       
   285 	asm("beq	done ");
       
   286 	asm("cmp	r0, #0 ");
       
   287 	asm("bgt	done ");
       
   288 
       
   289 	// iWaitingDfc exists and iRequestDataSize<=0 so we need to trigger the DFC...
       
   290 	asm("mov	r0, #0 ");
       
   291 	asm("str	r0, [r10, #%a0]" : : "i" _FOFF(TBTraceBufferK,iWaitingDfc)); // iWaitingDfc=0
       
   292 
       
   293 	asm("mov	r0, r4 ");
       
   294 	asm("bl	"	CSM_ZN4TDfc6RawAddEv);
       
   295 	asm("b		done ");
       
   296