// Copyright (c) 1994-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\kernel\arm\cutils.cia
//
//
//#define __EARLY_DEBUG__
//#define __NE1__
//#define __MI920__
//#define __BOOTLDRIN__
//#define __MCOT__
#include <e32cia.h>
#include <arm_mem.h>
#include "nk_cpu.h"
#include <kernel/kern_priv.h>
#include <kernel/cache.h>
#if defined(__MEMMODEL_MOVING__) || defined(__MEMMODEL_MULTIPLE__)
#include <mmubase.h>
#endif
#ifdef __SMP__
__NAKED__ TUint __arm_cpu_number()
{
asm("mrc p15, 0, r0, c0, c0, 5 ");
asm("and r0, r0, #15 ");
__JUMP(,lr);
}
#endif
#ifdef __EARLY_DEBUG__
__NAKED__ void DebugOutputChar(TUint)
//
// Early debug print code - must hack this for the particular platform.
// We assume bootstrap trace has already initialised the port.
//
{
#if defined(__MISA__)
// Brutus debug print code.
asm("ldr r1, __UartBase ");
asm("wait_tx_rdy: ");
asm("ldr r2, [r1, #0x20] ");
asm("tst r2, #0x04 ");
asm("beq wait_tx_rdy ");
asm("str r0, [r1, #0x14] ");
__JUMP(,lr);
asm("__UartBase: ");
asm(".word 0x63001000 ");
#elif defined(__MAWD__)
// S5mx debug print code.
asm("ldr r1, __UartBase ");
asm("wait_tx_rdy: ");
asm("ldr r2, [r1, #0x10] ");
asm("tst r2, #0x20 ");
asm("bne wait_tx_rdy ");
asm("str r0, [r1, #0x00] ");
__JUMP(,lr);
asm("__UartBase: ");
asm(".word 0x63000700 ");
#elif defined(__SAWD__)
// S5mx debug print code.
asm("ldr r1, __UartBase ");
asm("wait_tx_rdy: ");
asm("ldr r2, [r1, #0x10] ");
asm("tst r2, #0x20 ");
asm("bne wait_tx_rdy ");
asm("str r0, [r1, #0x00] ");
__JUMP(,lr);
asm("__UartBase: ");
asm(".word 0x80000700 ");
#elif defined(__MI920__) || defined(__NI1136__) || defined(__BOOTLDRIN__)
// Integrator debug print code.
asm("ldr r1, __UartBase ");
asm("wait_tx_rdy: ");
asm("ldr r2, [r1, #0x18] ");
asm("tst r2, #0x20 ");
asm("bne wait_tx_rdy ");
asm("str r0, [r1, #0x00] ");
__JUMP(,lr);
asm("__UartBase: ");
#if defined(__MI920__)
asm(".word 0x63006000 ");
#elif defined(__NI1136__)
asm(".word 0xc6006000 ");
#elif defined(__BOOTLDRIN__)
asm(".word 0x16000000 ");
#endif
#elif 0
//#elif defined(__NI1136__)
// Use debug comms channel
// asm("mov r1, #0x1000 ");
// asm("mcr p14, 0, r1, c0, c1, 0 ");
// asm("1: ");
// asm("mrc p14, 0, r15, c0, c1, 0 "); // read comm channel flags into CPSR
// asm("bcs 1b "); // wait for space
// asm("mcr p14, 0, r0, c0, c5, 0 "); // output character
// __JUMP(,lr);
asm("mov r1, #0xc3000000 ");
asm("add r1, r1, #0xc000 ");
asm("str r0, [r1, #0x20] ");
__JUMP(,lr);
#elif defined(__MCOT__)
// Lubbock debug print code.
asm("ldr r1, __UartBase ");
asm("1: ");
asm("ldr r2, [r1, #0x14] ");
asm("tst r2, #0x20 ");
asm("beq 1b ");
asm("str r0, [r1, #0x00] ");
__JUMP(,lr);
asm("__UartBase: ");
asm(".word 0x63001000 ");
#elif defined(__IS_OMAP1610__) || defined(__IS_OMAP1510__)
// omap 1510 and 1610 debug print code.
// N.B. Could also use JTAG DCC code from Arm::DebugOutJTAG()
asm("ldr r1, __UartBase ");
asm("1: ");
asm("ldrb r2, [r1, #0x14] ");
asm("tst r2, #0x20 ");
asm("beq 1b ");
asm("strb r0, [r1, #0x00] ");
__JUMP(,lr);
asm("__UartBase: ");
#if defined(__MEMMODEL_DIRECT__)
asm(".word 0xFFFB0000 "); // Physical for single
#else
asm(".word 0x630B0000 "); // Virtual for normal
#endif
#elif defined(__NE1__)
asm("ldr r1, __SuperPageAddress ");
asm("adr r2, __UartBase ");
asm("ldr r1, [r1] ");
asm("ldr r1, [r1, #%a0]" : : "i" _FOFF(TSuperPage,iDebugPort));
asm("and r1, r1, #255 ");
asm("cmp r1, #0 ");
asm("ldrne r2, [r2, #4] ");
asm("ldreq r2, [r2, #0] ");
asm("1: ");
asm("ldr r3, [r2, #0x14] "); // LSR
asm("tst r3, #0x20 ");
asm("beq 1b ");
asm("str r0, [r2, #0x00] "); // THR
__JUMP(,lr);
asm("__UartBase: ");
#if defined(__MEMMODEL_DIRECT__)
asm(".word 0x18034000 ");
asm(".word 0x18034400 ");
#else
asm(".word 0xc6000000 ");
asm(".word 0xc6000400 ");
#endif
asm("__SuperPageAddress: ");
asm(".word SuperPageAddress ");
#elif defined(__REALVIEW__)
// RealView platform debug print code.
asm("ldr r1, __SuperPageBase ");
asm("ldr r1, [r1] ");
asm("ldr r1, [r1, #%a0] " : : "i" _FOFF(TSuperPage,iDebugPort));
asm("cmp r1, #%a0 " : : "i" ((TInt)KNullDebugPort));
asm("bxeq lr "); // debug output supressed
asm("adr r2, __UartBase ");
asm("ldr r1, [r2] ");
asm("1: ");
asm("ldr r2, [r1, #0x18] "); // check status Tpl011::KHoFlags
asm("tst r2, #0x20 "); // compare to Tpl011::KFlagTxFifoFull
asm("bne 1b "); // if transmit data full, wait
asm("str r0, [r1] "); // store to data register Tpl011::KHoData
asm("bx lr ");
asm("__SuperPageBase: ");
asm(".word %a0 " : : "i" ((TInt)&SuperPageAddress));
asm("__UartBase: ");
asm(".word 0xc6004000 ");
#endif
}
#endif
__NAKED__ EXPORT_C TInt Arm::DebugOutJTAG(TUint /*aChar*/)
{
#if defined(__CPU_ARM920T__) || defined(__CPU_ARM720T__) || defined(__CPU_ARM926J__)
asm("mov r2, #0x100000 "); // timeout
asm("1: ");
asm("mrc p14, 0, r1, c0, c0, 0 "); // get debug comms control register
asm("tst r1, #2 "); // test W bit (1=busy)
asm("subnes r2, r2, #1 "); // if busy, decrement timeout
asm("bne 1b "); // if busy and not timed out, loop
asm("tst r1, #2 ");
asm("mcreq p14, 0, r0, c1, c0, 0 "); // if not busy, output value
asm("moveq r0, #0 "); // and return KErrNone
asm("movne r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // else return KErrTimedOut
#elif defined(__CPU_ARM1020T__)
asm("mov r2, #0x100000 "); // timeout
asm("1: ");
asm("mrc p14, 0, r1, c0, c1, 0 "); // get DSCR
asm("movs r1, r1, lsl #25 "); // test WE bit (1=empty) - set N flag if empty
asm("subpls r2, r2, #1 "); // if busy, decrement timeout
asm("bpl 1b "); // if busy and not timed out, loop
asm("cmp r1, #0 ");
asm("mcrmi p14, 0, r0, c0, c5, 0 "); // if not busy, output value
asm("movmi r0, #0 "); // and return KErrNone
asm("movpl r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // else return KErrTimedOut
#elif defined(__CPU_ARM1136__) || defined(__CPU_ARM1176__)
asm("mov r2, #0x100000 "); // timeout
asm("1: ");
asm("mrc p14, 0, r15, c0, c1, 0 "); // test DSCR, wDTRfull->C flag (1=full)
asm("subcss r2, r2, #1 "); // if busy, decrement timeout
asm("bcs 1b "); // if busy and not timed out, loop
asm("mrc p14, 0, r15, c0, c1, 0 "); // test DSCR, wDTRfull->C flag (1=full)
asm("mcrcc p14, 0, r0, c0, c5, 0 "); // if not busy, output value
asm("movcc r0, #0 "); // and return KErrNone
asm("movcs r0, #%a0" : : "i" ((TInt)KErrTimedOut)); // else return KErrTimedOut
#else
asm("mov r0, #%a0" : : "i" ((TInt)KErrNotSupported));
#endif
__JUMP(,lr);
}
__NAKED__ EXPORT_C TInt Arm::DebugInJTAG(TUint32& /*aRxData*/)
{
#if defined(__CPU_ARM920T__) || defined(__CPU_ARM720T__) || defined(__CPU_ARM926J__)
asm("mrc p14, 0, r2, c0, c0, 0 "); // get debug comms control register
asm("tst r2, #1 "); // test R bit (1=data available)
asm("mrcne p14, 0, r2, c1, c0, 0 "); // get RX data
asm("strne r2, [r0] "); // store RX data
asm("movne r0, #0 "); // return KErrNone
asm("moveq r0, #%a0" : : "i" ((TInt)KErrNotReady)); // if no data available return KErrNotReady
#elif defined(__CPU_ARM1020T__)
asm("mrc p14, 0, r2, c0, c1, 0 "); // get DSCR
asm("tst r2, #0x80 "); // test RF bit (1=full)
asm("mrcne p14, 0, r2, c0, c5, 0 "); // get RX data
asm("strne r2, [r0] "); // store RX data
asm("movne r0, #0 "); // return KErrNone
asm("moveq r0, #%a0" : : "i" ((TInt)KErrNotReady)); // if no data available return KErrNotReady
#elif defined(__CPU_ARM1136__) || defined(__CPU_ARM1176__)
asm("mrc p14, 0, r15, c0, c1, 0 "); // test DSCR, rDTRfull->Z flag (1=full)
asm("mrceq p14, 0, r2, c0, c5, 0 "); // get RX data
asm("streq r2, [r0] "); // store RX data
asm("moveq r0, #0 "); // return KErrNone
asm("movne r0, #%a0" : : "i" ((TInt)KErrNotReady)); // if no data available return KErrNotReady
#else
asm("mov r0, #%a0" : : "i" ((TInt)KErrNotSupported));
#endif
__JUMP(,lr);
}
__NAKED__ void KPrintf(const char*, ...)
{
asm("b " CSM_ZN4Kern6PrintfEPKcz);
}
__NAKED__ TInt A::CallSupervisorFunction(TSupervisorFunction, TAny*)
//
// Execute an F32 function in supervisor mode - might be THUMB.
//
{
asm("mov r2, r0 "); // r2=function ptr
asm("mov r0, r1 "); // r0=argument
__JUMP(,r2); // call function in correct mode
}
#if defined (__DES8_MACHINE_CODED__)
/**
Checks whether the specified name is a valid DObject full name.
A name is deemed to be invalid, if it contains an asterisk or a question
mark.
@param aName Name to check.
@return KErrNone, if valid;
KErrBadName, if invalid.
*/
#ifndef __KERNEL_MODE__
#error "TDesC is not 8-bit as __KERNEL_MODE__ is not defined (see e32cmn.h)"
#endif
__NAKED__ EXPORT_C TInt Kern::ValidateFullName(const TDesC& /*aName*/)
//
// Check for * or ? in descriptor, return KErrBadName if found
//
{
asm("ldr r2, [r0], #4 "); // r2=length/type
asm("cmp r2, #0x50000000 ");
asm("mvncs r0, #%a0" : : "i" (~KErrBadDescriptor));
__JUMP(cs,lr);
asm("bics r3, r2, #0xF0000000 "); // r3=length
asm("moveq r0, #0 "); // if length=0, return KErrNone
__JUMP(eq,lr);
asm("eor r2, r2, r2, lsr #1 ");
asm("msr cpsr_flg, r2 ");
asm("addcs r0, r0, #4 ");
asm("ldrle r0, [r0] ");
asm("addeq r0, r0, #4 "); // r0=this.Ptr()
asm("ValidateFullName_1: ");
asm("ldrb r1, [r0], #1 "); // r1=*r0++
asm("cmp r1, #0x20 "); // is it < 0x20 ?
asm("rsbhss r2, r1, #0x7f "); // if not, compare 0x7f with char
asm("bls ValidateFullName_2 "); // if char < 0x20 or char >= 0x7f, error
asm("cmp r1, #'*' "); // is it *
asm("cmpne r1, #'?' "); // if not, is it ?
asm("subnes r3, r3, #1 "); // if neither of these, decrement length
asm("bne ValidateFullName_1 ");
asm("ValidateFullName_2: "); // About to return so did we
asm("cmp r3, #0 "); // reach the end of string?
asm("moveq r0, #0 "); // if we did, return KErrNone
asm("mvnne r0, #%a0" : : "i" (~KErrBadName)); // else return KErrBadName
__JUMP(,lr);
}
#endif
/**
Default implementation for Kern::NanoWait, which waits for the specified time.
@param aInterval The time to wait in nanoseconds.
*/
__NAKED__ void K::DoNanoWait(TUint32 /*aInterval*/)
{
asm("ldr r1, __NanoWaitCal ");
asm("ldr r1, [r1] "); // r1=PP::NanoWaitCal
asm(".align 8"); // to make the 'nanowait_loop' start on a cache line
asm("nanowait_loop: ");
asm("subs r0, r0, r1 ");
asm("bhi nanowait_loop ");
__JUMP(,lr);
asm("__NanoWaitCal: ");
asm(".word " CSM_ZN2PP11NanoWaitCalE );
}
__NAKED__ void A::StartCrashDebugger(const TAny*, TInt)
{
USER_MEMORY_GUARD_OFF(,r0,r0); // let crash debugger have unfettered access to user memory
asm("ldr r0, __MonitorEntryPoint ");
asm("ldmia r0, {r1-r3} "); // r1 = debugger entry point
asm("mvn r0, r2 ");
asm("cmp r1, r0 "); // r2 = complement of r1 if valid
asm("moveq r12, r1, lsr #2 ");
asm("muleq r0, r12, r2 "); // r3 = (r1*r2/4)MOD 2^32 if valid
asm("cmpeq r3, r0 ");
__JUMP(ne,lr); // if debugger entry point invalid, return
#ifdef __SMP__
GET_RWNO_TID(,r0);
asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iRegs)); // pass in address of stored registers
#else
asm("ldr r0, __TheScheduler ");
asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(TScheduler,i_Regs)); // pass in address of stored registers
#endif
__JUMP(,r1); // jump to monitor
// if it returns, return from this function and reboot
asm("__MonitorEntryPoint: ");
asm(".word " CSM_ZN2PP17MonitorEntryPointE);
}
/** Increments atomically a counter that's initially positive
It checks the previous CPU mode and if it's User, it only applies user permissions when accessing aValue.
It doesn't increment if aValue is negative or zero.
@param aValue Reference to the counter to increment
@return Previous value of counter
********** NO GOOD ON SMP ****************
*/
EXPORT_C __NAKED__ TInt Kern::KUSafeInc(TInt& /*aValue*/)
{
ASM_ASSERT_PAGING_SAFE
asm("mrs ip, cpsr ");
INTS_OFF_1(r2, ip, INTS_ALL_OFF);
asm("mrs r3, spsr "); // check caller's mode
asm("mov r1, r0 "); // address into r1
asm("tst r3, #0x0f "); // test for user mode
asm("bne 1f "); // branch if not
INTS_OFF_2(r2, ip, INTS_ALL_OFF); // interrupts off
USER_MEMORY_GUARD_OFF(,r2,r2);
asm("ldrt r0, [r1] "); // r0=original value, only allow user permissions
asm("cmp r0, #0 ");
asm("addgt r2, r0, #1 ");
asm("strgtt r2, [r1] "); // if original value >0, increment
USER_MEMORY_GUARD_ON(,r2,r2);
asm("msr cpsr, ip "); // restore interrupts
__JUMP(,lr);
asm("1: ");
INTS_OFF_2(r2, ip, INTS_ALL_OFF); // interrupts off
asm("ldr r0, [r1] "); // r0=original value
asm("cmp r0, #0 ");
asm("addgt r2, r0, #1 ");
asm("strgt r2, [r1] "); // if >0, increment
asm("msr cpsr, ip "); // restore interrupts
__JUMP(,lr);
}
/** Decrements atomically a counter that's initially positive
It checks the previous CPU mode and if it's User, it only applies user permissions when accessing aValue.
It doesn't decrement if aValue is negative or zero.
@param aValue Reference to the counter to decrement
@return Previous value of counter
********** NO GOOD ON SMP ****************
*/
EXPORT_C __NAKED__ TInt Kern::KUSafeDec(TInt& /*aValue*/)
{
ASM_ASSERT_PAGING_SAFE
asm("mrs ip, cpsr ");
INTS_OFF_1(r2, ip, INTS_ALL_OFF);
asm("mrs r3, spsr "); // check caller's mode
asm("mov r1, r0 "); // address into r1
asm("tst r3, #0x0f "); // test for user mode
asm("bne 1f "); // branch if not
INTS_OFF_2(r2, ip, INTS_ALL_OFF); // interrupts off
USER_MEMORY_GUARD_OFF(,r2,r2);
asm("ldrt r0, [r1] "); // r0=original value, only allow user permissions
asm("subs r2, r0, #1 "); // decrement
asm("strget r2, [r1] "); // update if result >=0
USER_MEMORY_GUARD_ON(,r2,r2);
asm("msr cpsr, ip "); // restore interrupts
__JUMP(,lr);
asm("1: ");
INTS_OFF_2(r2, ip, INTS_ALL_OFF); // interrupts off
asm("ldr r0, [r1] "); // r0=original value
asm("subs r2, r0, #1 "); // decrement
asm("strge r2, [r1] "); // update if result >=0
asm("msr cpsr, ip "); // restore interrupts
__JUMP(,lr);
}
#ifdef __HANDLES_MACHINE_CODED__
EXPORT_C __NAKED__ DObject* DThread::ObjectFromHandle(TInt /*aHandle*/)
{
// r0=this, r1=aHandle
asm("adds ip, r1, r1 "); // check for special handle (bit 31 set => special)
asm("bcs 2f "); // if not, N flag indicates local handle
asm("ldrpl ip, [r0, #%a0]" : : "i" _FOFF(DThread,iOwningProcess)); // if not local, ip=aThread->iOwningProcess
asm("addmi ip, r0, #%a0" : : "i" _FOFF(DThread,iHandles)); // if local, ip=&aThread->iHandles
asm("addpl ip, ip, #%a0" : : "i" _FOFF(DProcess,iHandles)); // if not, ip=&aThread->iOwningProcess->iHandles
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,r1,ip,lr} "); // save r0, r1, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15AcquireReadLockEv") // call RObjectIx::AquireReadLock
asm("ldmfd sp!, {r0,r1,ip,lr} "); // restore r0, r1, ip and lr
#else
// system lock is held
#endif
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
// TODO: If handle lookup protected only by RW spin lock, must take a reference on the object
// (__HANDLES_USE_RW_SPIN_LOCK__ is not supported or even finished)
#endif
asm("mov r3, r1, lsl #17 "); // r3=r1<<17 = index(aHandle)<<17
asm("mov r1, r1, lsl #2 "); // r1=instance(Handle)<<18
asm("ldr r0, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iCount)); // r0=iCount
asm("ldr ip, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iSlots)); // ip=iSlots
asm("subs r0, r0, r3, lsr #17 "); // r0 = iCount - index(aHandle) - 1
asm("ldrge r2, [ip, r3, lsr #14]! "); // if count-1>=index, r2=pS->uniqueID:pS->instance, ip=iSlots+index(Handle)=pS ...
asm("ldrge r0, [ip, #4] "); // ... and r0 = pointer to DObject ...
asm("andge r0, r0, #%a0" : : "i" (RObjectIx::EObjRObjMask)); // r0 = (pointer & EObjRObjMask);
asm("eorge r1, r1, r2, lsl #18 "); // ... and check if instance(aHandle)<<18 == pS->(uid:instance)<<18
asm("movges r1, r1, lsr #18 ");
asm("movne r0, #0"); // ... else r0 = 0
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,ip,lr} "); // save r0, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15ReleaseReadLockEv") // call RObjectIx::ReleaseReadLock
asm("ldmfd sp!, {r0,ip,lr} "); // restore r0, ip and lr
#else
// system lock is held, nothing to do
#endif
// r0 now either 0(EBadHandle) or valid pointer...
__JUMP(,lr);
asm("1: ");
asm("mov r0, #0 "); // if wrong, bad handle
__JUMP(,lr);
asm("2: "); // r12=handle<<1 (valid values are ffff0000 and ffff0002)
asm("bic ip, ip, #0x10000 "); // clear 'no close' flag
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("cmp ip, #0x10000000 ");
asm("blo dobj_pseudo_5 "); // if handle<0x88000000, it's an IPC client thread pseudo handle
#endif
asm("ldr r0, __TheScheduler ");
asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread)); // r0->current NThread
asm("adds ip, ip, #0x20000 "); // valid values now 0 and 2
asm("ldreq r0, [r0, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread)));
__JUMP(eq,lr); // if handle = ffff8000, return TheCurrentThread->iOwningProcess
asm("cmp ip, #2 "); // otherwise, handle = ffff8001 ?
asm("subeq r0, r0, #%a0" : : "i" _FOFF(DThread,iNThread));
__JUMP(eq,lr); // if so, return TheCurrentThread
asm("b 1b "); // else bad handle
asm("badobjectfault: ");
asm("mov r0, #%a0" : : "i" (EBadObjectType));
asm("b " CSM_ZN1K5FaultENS_6TFaultE);
}
/**
Returns the kernel object that the given handle refers.
The handle passed is looked up in the thread's handles collection if the handle is local or
in the thread's owner process' collection otherwise. If aHandle is negative or not found in
the thread's or process' collection then NULL is returned.
Two special handle values KCurrentThreadHandle and KCurrentProcessHandle can be used to get
a pointer to the current thread and the current process.
aType is used to ensure that the object referred by the handle is of desired type.
If the type of the object referred by aHandle is different from aType then NULL is returned.
If aType is negative, the type of the object is ignored and no type checking is done.
If aType is positive and greater than the maximum number of object types (ENumObjectTypes)
the kernel will fault.
@param aThread The thread that owns the handle passed.
@param aHandle Handle to the object to be returned.
@param aType TObjectType parameter specifying the type of the object referred by the handle.
@return Pointer to the DObject referred by the handle or NULL if the handle is not
found in the thread's handles collection.
@pre Call in a thread context.
@pre Can be used in a device driver.
@see TObjectType
@see DThread::ObjectFromHandle()
*/
EXPORT_C __NAKED__ DObject* Kern::ObjectFromHandle(DThread* /*aThread*/, TInt /*aHandle*/, TInt /*aType*/)
{
ASM_CHECK_PRECONDITIONS(MASK_NOT_ISR|MASK_NOT_IDFC);
// r0=aThread, r1=aHandle, r2=aType (-1=any, 0=thread, etc.)
asm("add r3, r2, #1 ");
asm("cmp r3, #%a0" : : "i" ((TInt)ENumObjectTypes));
asm("bhi badobjectfault "); // invalid object type
// fall through
}
EXPORT_C __NAKED__ DObject* DThread::ObjectFromHandle(TInt /*aHandle*/, TInt /*aType*/)
{
// r0=this, r1=aHandle, r2=aType (-1=any, 0=thread, etc.)
asm("adds ip, r1, r1 "); // check for special handle (bit 31 set => special)
asm("bcs 2f "); // if not, N flag indicates local handle
asm("ldrpl ip, [r0, #%a0]" : : "i" _FOFF(DThread,iOwningProcess)); // if not local, ip=aThread->iOwningProcess
asm("addmi ip, r0, #%a0" : : "i" _FOFF(DThread,iHandles)); // if local, ip=&aThread->iHandles
asm("addpl ip, ip, #%a0" : : "i" _FOFF(DProcess,iHandles)); // if not, ip=&aThread->iOwningProcess->iHandles
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0-r2,ip,lr} "); // save r0-r2, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15AcquireReadLockEv") // call RObjectIx::AquireReadLock
asm("ldmfd sp!, {r0-r2,ip,lr} "); // restore r0-r2, ip and lr
#else
// system lock is held
#endif
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
// TODO: If handle lookup protected only by RW spin lock, must take a reference on the object
#endif
asm("mov r3, r1, lsl #17 "); // r3=r1<<17 = index(aHandle)<<17
asm("mov r1, r1, lsl #2 "); // r1=instance(Handle)<<18
asm("ldr r0, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iCount)); // r0=iCount
asm("ldr ip, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iSlots)); // ip=iSlots
asm("mov r1, r1, lsr #18 "); // r1=instance(Handle)
asm("cmp r0, r3, lsr #17 "); // compare iCount with index(aHandle)
asm("ldrgt r0, [ip, r3, lsr #14]! "); // if count>index, r0=pS->uniqueID:pS->instance, ip=iSlots+index(Handle)=pS
asm("ble 1f "); // if count<=index, bad handle
asm("adds r3, r2, #1 "); // r3=0 if any type of object is ok, r3=UID if not
asm("biceq r0, r0, r2, lsl #14 "); // if it is, (r2 therefore -1) clear top 18 bits of r0
asm("orr r1, r1, r3, lsl #14 "); // r1=aUniqueID(bits14-19):instance(Handle)(bits0-13)
asm("mov r0, r0, lsl #12 "); // only interested in comparing lower 20 bits...
asm("mov r1, r1, lsl #12 ");
asm("cmp r0, r1 "); // check instance, and unique ID if necessary
asm("ldreq r0, [ip, #4] "); // if OK return pointer to DObject
asm("movne r0, #0"); // else r0 = 0
asm("andeq r0, r0, #%a0" : : "i" (RObjectIx::EObjRObjMask)); // r0 = (pointer & EObjRObjMask);
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,ip,lr} "); // save r0, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15ReleaseReadLockEv") // call RObjectIx::ReleaseReadLock
asm("ldmfd sp!, {r0,ip,lr} "); // restore r0, ip and lr
#else
// system lock is held, nothing to do
#endif
// r0 now either 0(EBadHandle) or valid pointer...
__JUMP(,lr);
asm("1: ");
asm("mov r0, #0 "); // if wrong, bad handle
__JUMP(,lr);
asm("2: "); // r12=handle<<1 (valid values are fffx0000 and fffx0002, x=e or f)
asm("bic ip, ip, #0x10000 "); // clear 'no close' flag
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("cmp ip, #0x10000000 ");
asm("blo 4f "); // if handle<0x88000000, it's an IPC client thread pseudo handle
#endif
asm("ldr r0, __TheScheduler ");
asm("add ip, ip, #0x20000 "); // valid values now 0 and 2
asm("cmp r2, #1 "); // r2=container number or -1 if any object OK
asm("ldrle r0, [r0, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread)); // r0->current NThread
asm("bgt 1b "); // if type is neither thread nor process nor any, bad handle
asm("beq 3f "); // skip check for KCurrentThreadHandle if process required
asm("cmp ip, #2 "); // handle = ffff8001 ?
asm("subeq r0, r0, #%a0" : : "i" _FOFF(DThread,iNThread));
__JUMP(eq,lr); // if so, return TheCurrentThread
asm("cmn r2, #1 "); // r2=-1 means any type of object will do
asm("bne 1b ");
asm("3: ");
asm("cmp ip, #0 "); // handle = ffff8000 ?
asm("ldreq r0, [r0, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread)));
__JUMP(eq,lr); // if so, return TheCurrentThread->iOwningProcess
asm("b 1b "); // else bad handle
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("4: ");
asm("cmp r2, #0 "); // type must be thread or any
asm("bgt 1b "); // if not, bad handle
asm("dobj_pseudo_5: ");
asm("add r1, r0, #%a0" : : "i" _FOFF(DThread,iNThread)); // r1->iNThread
asm("stmfd sp!, {r4,lr} ");
asm("bl do_lookup_thread_pseudo ");
asm("bcc 6f "); // skip if bad handle
asm("cmp ip, #%a0" : : "i" ((TInt)RMessage2::EDisConnect)); // else check iFunction != RMessage2::EDisConnect
asm("ldrne r0, [r0, #%a0]" : : "i" _FOFF(RMessageK,iClient));
asm("moveq r0, #0 ");
asm("6: ");
asm("ldmfd sp!, {r4,pc} ");
#endif
}
/**
Returns the kernel object that the given handle refers.
The handle passed is looked up in the thread's handles collection if the handle is local or
in the thread's owner process' collection otherwise. If aHandle is negative or not found in
the thread's or process' collection then NULL is returned.
Two special handle values KCurrentThreadHandle and KCurrentProcessHandle can be used to get
a pointer to the current thread and the current process.
aType is used to ensure that the object referred by the handle is of desired type.
If the type of the object referred by aHandle is different from aType then NULL is returned.
If aType is negative, the type of the object is ignored and no type checking is done.
If aType is positive and greater than the maximum number of object types (ENumObjectTypes)
the kernel will fault.
@param aThread The thread that owns the handle passed.
@param aHandle Handle to the object to be returned.
@param aType TObjectType parameter specifying the type of the object referred by the handle.
@param aAttr Returns the attributes for this object.
@return Pointer to the DObject referred by the handle or NULL if the handle is not
found in the thread's handles collection.
@pre Call in a thread context.
@pre Can be used in a device driver.
@see TObjectType
@see DThread::ObjectFromHandle()
*/
EXPORT_C __NAKED__ DObject* Kern::ObjectFromHandle(DThread* /*aThread*/, TInt /*aHandle*/, TInt /*aType*/, TUint& /*aAttr*/)
{
ASM_CHECK_PRECONDITIONS(MASK_NOT_ISR|MASK_NOT_IDFC);
// r0=aThread, r1=aHandle, r2=aType (-1=any, 0=thread, etc.), r3=&aAttr
asm("add r2, r2, #1 "); // compare against 0 to ENumObjectTypes
asm("cmp r2, #%a0" : : "i" ((TInt)ENumObjectTypes));
asm("sub r2, r2, #1 "); // revert the adjustment (quicker than save/restore of used register)
asm("bhi badobjectfault "); // invalid object type
// fall through
}
EXPORT_C __NAKED__ DObject* DThread::ObjectFromHandle(TInt /*aHandle*/, TInt /*aObjType*/, TUint& /*aAttr*/)
{
// r0=this, r1=aHandle, r2=aType (-1=any, 0=thread, etc.), r3=&aAttr
asm("stmfd sp!, {r3}"); // save r3
asm("adds ip, r1, r1 "); // check for special handle (bit 31 set => special)
asm("bcs 2f "); // if not, N flag indicates local handle
asm("ldrpl ip, [r0, #%a0]" : : "i" _FOFF(DThread,iOwningProcess)); // if not local, ip=aThread->iOwningProcess
asm("addmi ip, r0, #%a0" : : "i" _FOFF(DThread,iHandles)); // if local, ip=&aThread->iHandles
asm("addpl ip, ip, #%a0" : : "i" _FOFF(DProcess,iHandles)); // if not, ip=&aThread->iOwningProcess->iHandles
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0-r2,ip,lr} "); // save r0-r2, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15AcquireReadLockEv") // call RObjectIx::AquireReadLock
asm("ldmfd sp!, {r0-r2,ip,lr} "); // restore r0-r2, ip and lr
#else
// system lock is held
#endif
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
// TODO: If handle lookup protected only by RW spin lock, must take a reference on the object
#endif
asm("mov r3, r1, lsl #17 "); // r3=r1<<17 = index(aHandle)<<17
asm("mov r1, r1, lsl #2 "); // r1=instance(Handle)<<18
asm("ldr r0, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iCount)); // r0=iCount
asm("ldr ip, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iSlots)); // ip=iSlots
asm("mov r1, r1, lsr #18 "); // r1=instance(Handle)
asm("cmp r0, r3, lsr #17 "); // compare iCount with index(aHandle)
asm("ldrgt r0, [ip, r3, lsr #14]! "); // if count>index, r0=pS->uniqueID:pS->instance, ip=iSlots+index(Handle)=pS
asm("ble 1f "); // if count<=index, bad handle
asm("adds r3, r2, #1 "); // r3=0 if any type of object is ok, r3=UID if not
asm("biceq r0, r0, r2, lsl #14 "); // if it is, (r2 therefore -1) clear top 18 bits of r0
asm("orr r1, r1, r3, lsl #14 "); // r1=aUniqueID(bits14-19):instance(Handle)(bits0-13)
asm("mov r0, r0, lsl #12 "); // only interested in comparing lower 20 bits...
asm("mov r1, r1, lsl #12 ");
asm("cmp r0, r1 "); // check instance, and unique ID if necessary
asm("ldreq r0, [ip, #4] "); // if OK return pointer to DObject
asm("movne r0, #0"); // else r0 = 0
asm("mov r2, r0"); // r2 = 0 or pointer(bits2-31):flags(bits0-1)
asm("andeq r0, r0, #%a0" : : "i" (RObjectIx::EObjRObjMask)); // r0 = (pointer & EObjRObjMask);
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,r2,ip,lr}"); // save r0, r2, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15ReleaseReadLockEv") // call RObjectIx::ReleaseReadLock
asm("ldmfd sp!, {r0,r2,ip,lr}"); // restore r0, r2, ip and lr
#else
// system lock is held, nothing to do
#endif
asm("ldmfd sp!, {r3}"); // restore r3 (r3=&aAttr)
asm("cmp r0, #0"); // if r0!=0
asm("ldrne r1, [ip]"); // r1=attributes:pS->uniqueID:pS->instance
asm("movne r1, r1, lsr #20"); // r1=attributes(bits0-11)
asm("orrne r1, r1, r2, lsl #31 "); // r1=resv_flag(bit31):attributes(bits0-11)
asm("strne r1, [r3] "); // aAttr=resv_flag(bit31):attributes(bits0-11)
// r0 now either 0(EBadHandle) or valid pointer...
__JUMP(,lr);
asm("1: ");
asm("add sp, sp, #4"); // pop and discard r3 (not used)
asm("mov r0, #0 "); // if wrong, bad handle
__JUMP(,lr);
asm("2: "); // r12=handle<<1 (valid values are fffx0000 and fffx0002, x=e or f)
asm("bic ip, ip, #0x10000 "); // clear 'no close' flag
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("cmp ip, #0x10000000 ");
asm("blo 4f "); // if handle<0x88000000, it's an IPC client thread pseudo handle
#endif
asm("ldr r0, __TheScheduler ");
asm("add ip, ip, #0x20000 "); // valid values now 0 and 2
asm("cmp r2, #1 "); // r2=container number or -1 if any object OK
asm("ldrle r0, [r0, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread)); // r0->current NThread
asm("bgt 1b "); // if type is neither thread nor process nor any, bad handle
asm("beq 3f "); // skip check for KCurrentThreadHandle if process required
asm("cmp ip, #2 "); // handle = ffff8001 ?
asm("subeq r0, r0, #%a0" : : "i" _FOFF(DThread,iNThread));
asm("add sp, sp, #4"); // pop and discard r3 (not used)
__JUMP(eq,lr); // if so, return TheCurrentThread
asm("cmn r2, #1 "); // r2=-1 means any type of object will do
asm("bne 1b ");
asm("3: ");
asm("cmp ip, #0 "); // handle = ffff8000 ?
asm("ldreq r0, [r0, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread)));
asm("add sp, sp, #4"); // pop and discard r3 (not used)
__JUMP(eq,lr); // if so, return TheCurrentThread->iOwningProcess
asm("b 1b "); // else bad handle
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("4: ");
asm("cmp r2, #0 "); // type must be thread or any
asm("bgt 1b "); // if not, bad handle
asm("add sp, sp, #4"); // pop and discard r3 (not used)
asm("add r1, r0, #%a0" : : "i" _FOFF(DThread,iNThread)); // r1->iNThread
asm("stmfd sp!, {r4,lr} ");
asm("bl do_lookup_thread_pseudo ");
asm("bcc 6f "); // skip if bad handle
asm("cmp ip, #%a0" : : "i" ((TInt)RMessage2::EDisConnect)); // else check iFunction != RMessage2::EDisConnect
asm("ldrne r0, [r0, #%a0]" : : "i" _FOFF(RMessageK,iClient));
asm("moveq r0, #0 ");
asm("6: ");
asm("ldmfd sp!, {r4,pc} ");
#endif
}
__NAKED__ DObject* K::ObjectFromHandle(TInt /*aHandle*/)
//
// Look up an object in the current thread/process handles array
// Panic on bad handle
// Enter and leave with system locked
//
{
// r0=aHandle
asm("ldr r1, __TheScheduler ");
asm("adds ip, r0, r0 "); // check for special handle (bit 31 set => special)
asm("ldr r1, [r1, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread)); // r1->current NThread
asm("bcs 2f "); // if not, N flag indicates local handle
asm("ldrpl ip, [r1, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread))); // if not local, ip=aThread->iOwningProcess
asm("addmi ip, r1, #%a0" : : "i" (_FOFF(DThread,iHandles)-_FOFF(DThread,iNThread))); // if local, ip=¤t Thread->iHandles
asm("addpl ip, ip, #%a0" : : "i" _FOFF(DProcess,iHandles)); // if not, ip=¤t Thread->iOwningProcess->iHandles
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,r1,ip,lr} "); // save r0, r1, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15AcquireReadLockEv") // call RObjectIx::AquireReadLock
asm("ldmfd sp!, {r0,r1,ip,lr} "); // restore r0, r1, ip and lr
#else
// system lock is held
#endif
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
// TODO: If handle lookup protected only by RW spin lock, must take a reference on the object
#endif
asm("mov r3, r0, lsl #17 "); // r3=r0<<17 = index(aHandle)<<17
asm("mov r1, r0, lsl #2 "); // r1=instance(Handle)<<18
asm("ldr r0, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iCount)); // r0=iCount
asm("ldr ip, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iSlots)); // ip=iSlots
asm("subs r0, r0, r3, lsr #17 "); // r0 = iCount - index(aHandle) - 1
asm("ldrge r2, [ip, r3, lsr #14]! "); // if count-1>=index, r2=pS->uniqueID:pS->instance, ip=iSlots+index(Handle)=pS ...
asm("ldrge r0, [ip, #4] "); // ... and r0 = pointer to DObject ...
asm("andge r0, r0, #%a0" : : "i" (RObjectIx::EObjRObjMask)); // r0 = (pointer & EObjRObjMask);
asm("eorge r1, r1, r2, lsl #18 "); // ... and check if instance(aHandle)<<18 == pS->(uid:instance)<<18
asm("movges r1, r1, lsr #18 ");
asm("movne r0, #0"); // ... else r0 = 0
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,ip,lr} "); // save r0, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15ReleaseReadLockEv") // call RObjectIx::ReleaseReadLock
asm("ldmfd sp!, {r0,ip,lr} "); // restore r0, ip and lr
#else
// system lock is held, nothing to do
#endif
asm("cmp r0, #0 "); // check if this is a valid pointer
__JUMP(ne,lr); // if OK, return pointer to DObject
asm("1: "); // if wrong, bad handle
asm("mov r0, #%a0" : : "i" (EBadHandle));
asm("b " CSM_ZN1K18PanicCurrentThreadEi);
asm("2: "); // r12=handle<<1 (valid values are fffx0000 and fffx0002, x=e or f)
asm("bic ip, ip, #0x10000 "); // clear 'no close' flag
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("cmp ip, #0x10000000 ");
asm("blo 3f "); // if handle<0x88000000, it's an IPC client thread pseudo handle
#endif
asm("adds ip, ip, #0x20000 "); // valid values now 0 and 2
asm("ldreq r0, [r1, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread)));
__JUMP(eq,lr); // if handle = ffff8000, return TheCurrentThread->iOwningProcess
asm("cmp ip, #2 "); // otherwise, handle = ffff8001 ?
asm("subeq r0, r1, #%a0" : : "i" _FOFF(DThread,iNThread));
__JUMP(eq,lr); // if so, return TheCurrentThread
asm("b 1b "); // else bad handle
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("k_pseudo_4: ");
asm("cmp r1, #0 "); // type must be thread or any
asm("bgt 1b "); // if not, panic
asm("mov r1, r2 "); // r1->current NThread
asm("3: ");
asm("stmfd sp!, {r4,lr} ");
asm("bl do_lookup_thread_pseudo ");
asm("bcc 1b "); // panic if bad
asm("cmp ip, #%a0" : : "i" ((TInt)RMessage2::EDisConnect)); // else check iFunction != RMessage2::EDisConnect
asm("ldrne r0, [r0, #%a0]" : : "i" _FOFF(RMessageK,iClient));
asm("ldmnefd sp!, {r4,pc} ");
asm("b 1b ");
#endif
}
__NAKED__ DObject* K::ObjectFromHandle(TInt /*aHandle*/, TInt /*aType*/)
//
// Look up an object of specific type in the current thread/process handles array
// Panic on bad handle
// Enter and leave with system locked
//
{
// r0=aHandle, r1=aType (-1=any, 0=thread, etc.)
asm("ldr r2, __TheScheduler ");
asm("adds ip, r0, r0 "); // check for special handle (bit 31 set => special)
asm("ldr r2, [r2, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread)); // r2->current NThread
asm("bcs 2f "); // if not, N flag indicates local handle
asm("ldrpl ip, [r2, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread))); // if not local, ip=aThread->iOwningProcess
asm("addmi ip, r2, #%a0" : : "i" (_FOFF(DThread,iHandles)-_FOFF(DThread,iNThread))); // if local, ip=&aThread->iHandles
asm("addpl ip, ip, #%a0" : : "i" _FOFF(DProcess,iHandles)); // if not, ip=&aThread->iOwningProcess->iHandles
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,r1,ip,lr} "); // save r0, r1, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15AcquireReadLockEv") // call RObjectIx::AquireReadLock
asm("ldmfd sp!, {r0,r1,ip,lr} "); // restore r0, r1, ip and lr
#else
// system lock is held
#endif
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
// TODO: If handle lookup protected only by RW spin lock, must take a reference on the object
#endif
asm("mov r3, r0, lsl #17 "); // r3=r0<<17 = index(aHandle)<<17
asm("mov r2, r0, lsl #2 "); // r2=instance(Handle)<<18
asm("ldr r0, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iCount)); // r0=iCount
asm("ldr ip, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iSlots)); // ip=iSlots
asm("mov r2, r2, lsr #18 "); // r2=instance(Handle)
asm("cmp r0, r3, lsr #17 "); // compare iCount with index(aHandle)
asm("ldrgt r0, [ip, r3, lsr #14]! "); // if count>index, r0=pS->uniqueID:pS->instance, ip=iSlots+index(Handle)=pS
asm("ble 1f "); // if count<=index, bad handle
asm("adds r3, r1, #1 "); // r3=0 if any type of object is ok, r3=UID if not
asm("biceq r0, r0, r1, lsl #14 "); // if it is, (therefore r1=-1) clear top 18 bits of r0
asm("orr r2, r2, r3, lsl #14 "); // r2=aUniqueID(bits14-19):instance(Handle)(bits0-13)
asm("mov r0, r0, lsl #12 "); // only interested in comparing lower 20 bits...
asm("mov r2, r2, lsl #12 ");
asm("cmp r0, r2 "); // check instance, and unique ID if necessary
asm("ldreq r0, [ip, #4] "); // if OK return pointer to DObject
asm("movne r0, #0"); // else r0 = 0
asm("andeq r0, r0, #%a0" : : "i" (RObjectIx::EObjRObjMask)); // r0 = (pointer & EObjRObjMask);
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,ip,lr} "); // save r0, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15ReleaseReadLockEv") // call RObjectIx::ReleaseReadLock
asm("ldmfd sp!, {r0,ip,lr} "); // restore r0, ip and lr
#else
// system lock is held, nothing to do
#endif
asm("cmp r0, #0 "); // check if this is a valid pointer
__JUMP(ne,lr); // if OK, return pointer to DObject
asm("1: "); // if wrong, bad handle
asm("mov r0, #%a0" : : "i" (EBadHandle));
asm("b " CSM_ZN1K18PanicCurrentThreadEi);
asm("2: "); // r12=handle<<1 (valid values are fffx0000 and fffx0002, x=e or f)
asm("bic ip, ip, #0x10000 "); // clear 'no close' flag
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("cmp ip, #0x10000000 ");
asm("blo k_pseudo_4 "); // if handle<0x88000000, it's an IPC client thread pseudo handle
#endif
asm("adds ip, ip, #0x20000 "); // valid values now 0 and 2
asm("cmp r1, #1 "); // r1=container number or -1 if any object OK
asm("bgt 1b "); // if type is neither thread nor process nor any, bad handle
asm("beq 3f "); // skip check for KCurrentThreadHandle if process required
asm("cmp ip, #2 "); // handle = ffff8001 ?
asm("subeq r0, r2, #%a0" : : "i" _FOFF(DThread,iNThread));
__JUMP(eq,lr); // if so, return TheCurrentThread
asm("cmn r1, #1 "); // r1=-1 means any type of object will do
asm("bne 1b ");
asm("3: ");
asm("cmp ip, #0 "); // handle = ffff8000 ?
asm("ldreq r0, [r2, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread)));
__JUMP(eq,lr); // if so, return TheCurrentThread->iOwningProcess
asm("b 1b "); // else bad handle
}
__NAKED__ DObject* K::ObjectFromHandle(TInt /*aHandle*/, TInt /*aObjType*/, TUint& /*aAttr*/)
//
// Look up an object of specific type in the current thread/process handles array
// Panic on bad handle
// Enter and leave with system locked
//
{
// r0=aHandle, r1=aObjType (-1=any, 0=thread, etc.), r2=&aAttr
asm("stmfd sp!, {r2}"); // save r2
asm("ldr r2, __TheScheduler ");
asm("adds ip, r0, r0 "); // check for special handle (bit 31 set => special)
asm("ldr r2, [r2, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread)); // r2->current NThread
asm("bcs 2f "); // if not, N flag indicates local handle
asm("ldrpl ip, [r2, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread))); // if not local, ip=aThread->iOwningProcess
asm("addmi ip, r2, #%a0" : : "i" (_FOFF(DThread,iHandles)-_FOFF(DThread,iNThread))); // if local, ip=&aThread->iHandles
asm("addpl ip, ip, #%a0" : : "i" _FOFF(DProcess,iHandles)); // if not, ip=&aThread->iOwningProcess->iHandles
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,r1,ip,lr} "); // save r0, r1, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15AcquireReadLockEv") // call RObjectIx::AquireReadLock
asm("ldmfd sp!, {r0,r1,ip,lr} "); // restore r0, r1, ip and lr
#else
// system lock is held
#endif
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
// TODO: If handle lookup protected only by RW spin lock, must take a reference on the object
#endif
asm("mov r3, r0, lsl #17 "); // r3=r0<<17 = index(aHandle)<<17
asm("mov r2, r0, lsl #2 "); // r2=instance(Handle)<<18
asm("ldr r0, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iCount)); // r0=iCount
asm("ldr ip, [ip, #%a0]" : : "i" _FOFF(RObjectIx,iSlots)); // ip=iSlots
asm("mov r2, r2, lsr #18 "); // r2=instance(Handle)
asm("cmp r0, r3, lsr #17 "); // compare iCount with index(aHandle)
asm("ldrgt r0, [ip, r3, lsr #14]! "); // if count>index, r0=pS->uniqueID:pS->instance, ip=iSlots+index(Handle)=pS
asm("ble 1f "); // if count<=index, bad handle
asm("adds r3, r1, #1 "); // r3=0 if any type of object is ok, r3=UID if not
asm("biceq r0, r0, r1, lsl #14 "); // if it is, (therefore r1=-1) clear top 18 bits of r0
asm("orr r2, r2, r3, lsl #14 "); // r2=aUniqueID(bits14-19):instance(Handle)(bits0-13)
asm("mov r0, r0, lsl #12 "); // only interested in comparing lower 20 bits...
asm("mov r2, r2, lsl #12 ");
asm("cmp r0, r2 "); // check instance, and unique ID if necessary
asm("ldreq r0, [ip, #4] "); // if OK return pointer to DObject
asm("movne r0, #0"); // else r0 = 0
asm("mov r3, r0"); // r3=0 or pointer(bits2-31):flags(bits0-1)
asm("andeq r0, r0, #%a0" : : "i" (RObjectIx::EObjRObjMask)); // r0 = (pointer & EObjRObjMask);
#ifdef __HANDLES_USE_RW_SPIN_LOCK__
asm("stmfd sp!, {r0,r3,ip,lr} "); // save r0, r3, ip and lr
asm("mov r0, ip "); // move RObjectIx this(ip) to r0
asm("bl _ZN9RObjectIx15ReleaseReadLockEv") // call RObjectIx::ReleaseReadLock
asm("ldmfd sp!, {r0,r3,ip,lr} "); // restore r0, r3, ip and lr
#else
// system lock is held, nothing to do
#endif
asm("ldmfd sp!, {r2}"); // restore r2 (r2=&aAttr)
asm("cmp r0, #0"); // if r0!=0
asm("ldrne r1, [ip]"); // r1=attributes:pS->uniqueID:pS->instance
asm("movne r1, r1, lsr #20"); // r1=attributes(bits0-11)
asm("orrne r1, r1, r3, lsl #31 "); // r1=resv_flag(bit31):attributes(bits0-11)
asm("strne r1, [r2] "); // aAttr=resv_flag(bit31):attributes(bits0-11)
__JUMP(ne,lr); // return pointer to DObject
asm("1: "); // if wrong, bad handle
asm("mov r0, #%a0" : : "i" (EBadHandle));
asm("b " CSM_ZN1K18PanicCurrentThreadEi);
asm("2: "); // r12=handle<<1 (valid values are fffx0000 and fffx0002, x=e or f)
asm("add sp, sp, #4"); // pop and discard r2 (not used)
asm("bic ip, ip, #0x10000 "); // clear 'no close' flag
#ifdef __OBSOLETE_V1_IPC_SUPPORT__
asm("cmp ip, #0x10000000 ");
asm("blo k_pseudo_4 "); // if handle<0x88000000, it's an IPC client thread pseudo handle
#endif
asm("adds ip, ip, #0x20000 "); // valid values now 0 and 2
asm("cmp r1, #1 "); // r1=container number or -1 if any object OK
asm("bgt 1b "); // if type is neither thread nor process nor any, bad handle
asm("beq 3f "); // skip check for KCurrentThreadHandle if process required
asm("cmp ip, #2 "); // handle = ffff8001 ?
asm("subeq r0, r2, #%a0" : : "i" _FOFF(DThread,iNThread));
__JUMP(eq,lr); // if so, return TheCurrentThread
asm("cmn r1, #1 "); // r1=-1 means any type of object will do
asm("bne 1b ");
asm("3: ");
asm("cmp ip, #0 "); // handle = ffff8000 ?
asm("ldreq r0, [r2, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread)));
__JUMP(eq,lr); // if so, return TheCurrentThread->iOwningProcess
asm("b 1b "); // else bad handle
}
#endif
/** Returns the current state of interrupts
@param aRequest indicates which state of interrupts should be returned
@return if aRequest is ETrue, function returns ETrue if interrupts are enabled and EFalse otherwise
if aRequest is EFalse, function returns ETrue if interrupts are disabled and EFalse otherwise
*/
__NAKED__ TBool InterruptsStatus(TBool)
{
asm("cmp r0, #0 ");
asm("beq check_interrupts_disabled ");
//check that ints are enabled
asm("mrs r0, cpsr ");
asm("ands r0, r0, #%a0 " : : "i" ((TInt)KAllInterruptsMask));
asm("moveq r0,#1");
asm("movne r0,#0");
__JUMP(,lr);
asm("check_interrupts_disabled: ");
asm("mrs r0, cpsr ");
asm("and r0, r0, #%a0 " : : "i" ((TInt)KAllInterruptsMask));
asm("cmp r0, #%a0 " : : "i" ((TInt)KAllInterruptsMask));
asm("moveq r0,#1");
asm("movne r0,#0");
__JUMP(,lr);
}
extern "C" EXPORT_C __NAKED__ void pagecpy(TAny* /*aTrg*/, const TAny* /*aSrc*/)
{
// Source and destination 4k page aligned (and thus cache aligned)
// Fixed copy size of 4k
// - easy as pie
asm("mov r2, #12 ");
// fall through to fastcpy
}
extern "C" __NAKED__ void fastcpy(TAny* /*aTrg*/, const TAny* /*aSrc*/, TUint8 /*aPower*/)
{
asm("stmfd sp!, {r4-r9} ");
asm("mov ip, #-1 ");
asm("mvn ip, ip, lsl r2 ");
asm("pagecpy_loop: ");
PLD_ioff(1, 32);
PLD_ioff(1, 64);
asm("ldmia r1!, {r2-r9} ");
asm("stmia r0!, {r2-r9} ");
asm("ldmia r1!, {r2-r9} ");
asm("tst r1, ip ");
asm("stmia r0!, {r2-r9} ");
asm("bne pagecpy_loop ");
asm("ldmfd sp!, {r4-r9} ");
__JUMP(,lr);
asm("__TheScheduler: ");
asm(".word TheScheduler ");
}
#if defined(__MEMMODEL_MOVING__) || defined(__MEMMODEL_MULTIPLE__)
__NAKED__ TInt MmuBase::MoveKernelStackPage(DChunk* /*aChunk*/, TUint32 /*aOffset*/, TPhysAddr /*aOld*/,
TPhysAddr& /*aNew*/, TUint /*aBlockZoneId*/, TBool /*aBlockRest*/)
{
// Switch to a safe stack then call the regular MoveKernelPage
asm("mov ip, sp ");
asm("ldr sp, [r0, #%a0]" : : "i" _FOFF(MmuBase,iAltStackBase)); // r0=this
asm("stmfd sp!, {ip,lr} ");
asm("ldr lr, [ip, #8] ");
asm("str lr, [sp, #-8]! ");
asm("ldr lr, [ip, #4] ");
asm("str lr, [sp, #-4]! ");
asm("ldr lr, [ip] ");
asm("str lr, [sp, #-4]! ");
asm("bl " CSM_ZN3Mmu14MoveKernelPageEP6DChunkmmRmji);
asm("ldmfd sp, {r1,r2,r3,ip,sp,pc} ");
}
#endif
__NAKED__ TInt K::FloatingPointSystemId(TUint32& /*aSysId*/)
{
#if __CPU_HAS_VFP
VFP_FMRX(,1,VFP_XREG_FPSID);
asm("str r1, [r0] ");
asm("mov r0, #0 ");
#else
asm("mov r0, #%a0 " : : "i" ((TInt)KErrNotSupported));
#endif
__JUMP(,lr);
}
#ifdef __CLIENT_REQUEST_MACHINE_CODED__
__NAKED__ void TServerMessage::CallbackFunc(TAny* aData, TUserModeCallbackReason aReason)
{
// r0 -> TServerMessage object (this is derived from TClientRequest)
// r1 == reason code: 0 => run, 1 => cancel
asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(TClientRequest, iResult));
asm("teq r1, #%a0" : : "i" (EUserModeCallbackRun));
asm("teqeq r3, #0"); // iResult == KErrNone
asm("bne clientRequestCallback2");
asm("stmfd sp!, {r0, r4-r7, lr}");
asm("ldr ip, [r0, #%a0]" : : "i" _FOFF(TServerMessage, iMessagePtr));
asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(TServerMessage, iMessageData));
asm("ldr r1, [r0, #%a0]" : : "i" _FOFF(RMessageK, iFunction));
asm("ldr r7, [r0, #%a0]" : : "i" _FOFF(RMessageK, iSession));
// If the message is not a disconnect, load the arguments from the message.
// If it is a disconnect, set all message arguments (r2-r5) to 0 instead.
asm("cmn r1, #%a0" : : "i" (-RMessage2::EDisConnect));
asm("moveq r2, #0");
asm("addne r2, r0, #%a0" : : "i" _FOFF(RMessageK, iMsgArgs.iArgs));
asm("moveq r3, #0");
// HARDCODED(RMessageK)- this assumes KMaxMessageArguments is 4
asm("ldmneia r2, {r2-r5}");
asm("moveq r4, #0");
asm("moveq r5, #0");
asm("mov r6, #0");
asm("ldr r7, [r7, #%a0]" : : "i" _FOFF(DSession, iSessionCookie));
asm("cmp r6, #1"); // ensure Z flag is clear
USER_MEMORY_GUARD_OFF(,lr,lr);
// HARDCODED(RMessage2)- this assumes the layout of the first 8 words of this structure
asm(".global __magic_address_svr_accept_1 ");
asm("__magic_address_svr_accept_1: "); // this instruction is magically immune from exceptions
asm("strt r0, [ip], #4");
asm(".global __magic_address_svr_accept_2 ");
asm("__magic_address_svr_accept_2: "); // this instruction is magically immune from exceptions
asm("strnet r1, [ip], #4");
asm(".global __magic_address_svr_accept_3 ");
asm("__magic_address_svr_accept_3: "); // this instruction is magically immune from exceptions
asm("strnet r2, [ip], #4");
asm(".global __magic_address_svr_accept_4 ");
asm("__magic_address_svr_accept_4: "); // this instruction is magically immune from exceptions
asm("strnet r3, [ip], #4");
asm(".global __magic_address_svr_accept_5 ");
asm("__magic_address_svr_accept_5: "); // this instruction is magically immune from exceptions
asm("strnet r4, [ip], #4");
asm(".global __magic_address_svr_accept_6 ");
asm("__magic_address_svr_accept_6: "); // this instruction is magically immune from exceptions
asm("strnet r5, [ip], #4");
asm(".global __magic_address_svr_accept_7 ");
asm("__magic_address_svr_accept_7: "); // this instruction is magically immune from exceptions
asm("strnet r6, [ip], #4");
asm(".global __magic_address_svr_accept_8 ");
asm("__magic_address_svr_accept_8: "); // this instruction is magically immune from exceptions
asm("strnet r7, [ip], #4");
USER_MEMORY_GUARD_ON(,lr,lr);
asm("ldmfd sp!, {r0, r4-r7, lr}");
asm("mov r1, #%a0" : : "i" (EUserModeCallbackRun));
asm("mov r3, #0" );
asm("b clientRequestCallback2");
}
__NAKED__ void TClientRequest::CallbackFunc(TAny* /*aData*/, TUserModeCallbackReason /*aReason*/)
{
// parameters:
// r0 -> this
// r1 == reason code
// locals:
// r2 == old status
// r3 == result
asm("clientRequestCallback:");
asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(TClientRequest, iResult));
asm("clientRequestCallback2:");
asm("stmfd sp!, {r0, r1, r3, lr} ");
#ifdef _DEBUG
ASM_CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL);
#endif
asm("mov ip, #%a0" : : "i" ((TInt)KRequestPending));
asm("str ip, [r0, #%a0]" : : "i" _FOFF(TClientRequest, iResult));
asm("mov r1, #%a0" : : "i" ((TInt)KClientRequestFlagClosing));
asm("add r0, r0, #%a0 " : : "i" _FOFF(TClientRequest, iStatus));
asm("bl __e32_atomic_and_ord32 ");
asm("mov r2, r0 ");
asm("ldmfd sp!, {r0, r1, r3, lr} ");
#ifdef _DEBUG
asm("teq r2, #0");
asm("tstne r2, #%a0" : : "i" ((TInt)KClientRequestFlagInUse));
asm("moveq r0, #%a0" : : "i" (K::EClientRequestCallbackInWrongState));
asm("bleq " CSM_ZN1K5FaultENS_6TFaultE);
#endif
USER_MEMORY_GUARD_OFF(,r12,r12);
asm("bic r12, r2, #%a0 " : : "i" ((TInt)KClientRequestFlagMask));
asm("teq r12, #%a0 " : : "i" ((TInt)KClientRequestNullStatus));
asm("teqne r1, #%a0" : : "i" (EUserModeCallbackCancel));
asm(".global __magic_address_client_request_callback ");
asm("__magic_address_client_request_callback: "); // this instruction is magically immune from exceptions
asm("strnet r3, [r12]");
USER_MEMORY_GUARD_ON(,r12,r12);
asm("tst r2, #%a0" : : "i" ((TInt)KClientRequestFlagClosing));
asm("bne " CSM_ZN4Kern9AsyncFreeEPv);
__JUMP(,lr);
}
#endif
#ifdef __REQUEST_COMPLETE_MACHINE_CODED__
#ifndef __MEMMODEL_FLEXIBLE__
__NAKED__ EXPORT_C void Kern::RequestComplete(DThread* /*aThread*/, TRequestStatus*& /*aStatus*/, TInt /*aReason*/)
{
ASM_CHECK_PRECONDITIONS(MASK_THREAD_STANDARD);
ASM_ASSERT_DATA_PAGING_SAFE; // Assembler version needs paging check, c++ version calls RawWrite which checks already
ASM_DEBUG2(KernRequestComplete,r0,lr);
asm("stmfd sp!, {r0-r2,lr} ");
asm("bl " CSM_ZN5NKern10LockSystemEv);
asm("ldmfd sp!, {r0-r2,lr} ");
asm("ldr r3, [r1] ");
asm("teq r3, #0 ");
asm("beq " CSM_ZN5NKern12UnlockSystemEv);
asm("mov r12, #0 ");
asm("str r12, [r1] "); // aStatus=NULL
asm("b _asm_RequestComplete "); // call into DThread::RequestComplete with r3 == status ptr
}
#endif
__NAKED__ EXPORT_C void Kern::RequestComplete(TRequestStatus*& /*aStatus*/, TInt /*aReason*/)
{
ASM_CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED | MASK_INTERRUPTS_ENABLED | MASK_NOT_ISR | MASK_NOT_IDFC);
asm("mov r12, #0 ");
#ifdef __CPU_ARM_HAS_LDREX_STREX
asm("1: ");
LDREX( 2, 0); // read
STREX( 3, 12, 0); // write
asm("teq r3, #0 "); // success?
asm("bne 1b "); // no!
#else
asm("swp r2, r12, [r0] ");
#endif
asm("ldr r3, __TheScheduler ");
asm("teq r2, #0 "); // clear zero flag if address is not null
USER_MEMORY_GUARD_OFF(,r0,r0);
asm(".global __magic_address_kern_request_complete ");
asm("__magic_address_kern_request_complete: "); // this instruction is magically immune from exceptions
asm("strnet r1, [r2] ");
USER_MEMORY_GUARD_ON(,r0,r0);
__JUMP( eq, lr); // return if address zero or store failed
asm("ldr r0, [r3, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread)); // r0->current NThread
asm("b " CSM_ZN5NKern19ThreadRequestSignalEP7NThread);
}
#endif
extern "C" __NAKED__ TInt read_and_parse_des_header_local(TAny* aUnused, TAny* aDesPtr, TDesHeader& aOut)
{
asm("mov r0, r1 ");
asm("mov r1, r2 ");
// fall through
}
/**
Read the header of a user-side descriptor in the current process, parse it, and populate a
TDesHeader with the result.
@param aDesPtr The descriptor for which information is to be fetched.
@param aOut On return, set to the parsed contents of the descriptor header.
@return KErrNone if successful, or one of the system-wide error codes.
@pre Interrupts must be enabled.
@pre Kernel must be unlocked.
@pre No fast mutex can be held.
@pre Call in a thread context.
@pre Can be used in a device driver.
*/
__NAKED__ TInt K::USafeReadAndParseDesHeader(TAny* aDesPtr, TDesHeader& aOut)
{
// r0 -> user-side descriptor
// r1 -> parsed header out
asm("stmfd sp!, {lr} ");
USER_MEMORY_GUARD_OFF(,lr,lr);
// set condition codes to 'hi' condition (unless we're reading a null pointer)
asm("cmp r0, #0");
// read first word of descriptor...
asm(".global __magic_address_readdesheader1 ");
asm("__magic_address_readdesheader1: "); // this instruction is magically immune from exceptions
asm("ldrhit r2, [r0], #4"); // WILL SET Z FLAG AND MODIFY R12 IF EXCEPTION OCCURS
// r12 = length of this descriptor type...
asm("adrhi r12, LengthLookup");
asm("ldrhib r12, [r12, r2, lsr #28]");
asm("cmphi r12, #0"); // set zero flag for invalid descriptor type
// r3 = 2nd word of descriptor (if it is 8 bytes or more in size)...
asm("cmphi r12, #7");
asm(".global __magic_address_readdesheader2 ");
asm("__magic_address_readdesheader2: "); // this instruction is magically immune from exceptions
asm("ldrhit r3, [r0], #4"); // WILL SET Z FLAG AND MODIFY R12 IF EXCEPTION OCCURS
// r12 = 3rd word of descriptor (if it is 12 bytes or more in size)...
asm("cmphi r12, #11");
asm(".global __magic_address_readdesheader3 ");
asm("__magic_address_readdesheader3: "); // this instruction is magically immune from exceptions
asm("ldrhit r12, [r0], #4"); // WILL SET Z FLAG AND MODIFY R12 IF EXCEPTION OCCURS
USER_MEMORY_GUARD_ON(,lr,lr);
asm("beq bad_descriptor "); // Z flag set here if we took an exception
asm("eor lr, r2, r2, lsr #1 ");
asm("msr cpsr_flg, lr ");
// r12 == header_in[2]
asm("movcc r12, r3 "); // r12 = header_in[1] if EBufC, EPtrC
asm("movgt r12, r0 "); // r12 = pointer to word after header if EBufC, EBuf
asm("addeq r12, r12, #4 "); // r12 += sizeof(TDesC) if EBufCPtr
// r3 == header_in[1]
// r3 = KErrBadDescriptor if EBufC, EPtrC
asm("mvncc r3, #%a0" : : "i" (~TDesHeader::KConstMaxLength));
// r0 is an aligned pointer
asm("moveq r0, r12 "); // r0 = pointer to des data if EBufCPtr
asm("tst r0, #3 "); // if (type == EBufCPtr && ((TUint)p & 3) != 0)
asm("bne bad_descriptor "); // return KErrBadDescriptor;
asm("bic lr, r2, #0xf0000000 ");
asm("cmp lr, r3 "); // if (len > max)
asm("bhi bad_descriptor "); // return KErrBadDescriptor;
asm("stmia r1, {r2,r3,r12}");
asm("mov r0, #0 ");
__POPRET("");
asm("bad_descriptor: ");
asm("mvn r0, #%a0" : : "i" (~KErrBadDescriptor));
__POPRET("");
asm("LengthLookup:");
asm(".byte 4,8,12,8,12,0,0,0,0,0,0,0,0,0,0,0");
}
#ifdef __SMP__
extern TSpinLock BTraceFilter2Lock;
__NAKED__ TBool DBTraceFilter2::Check(TUint32 aUid)
{
asm("DBTraceFilter2_Check: ");
asm("stmdb sp!, {lr}");
asm("ldr r3, [r0,#%a0]" : : "i" _FOFF(DBTraceFilter2,iNumUids));
asm("add r0, r0, #%a0" : : "i" _FOFF(DBTraceFilter2,iUids));
asm("mov r2, #0");
asm("0:");
asm("cmp r3, r2");
asm("bls 9f");
asm("add r12, r2, r3");
asm("mov r12, r12, asr #1");
asm("ldr lr, [r0, r12, lsl #2]");
asm("cmp r1, lr");
asm("addhi r2, r12, #1");
asm("movlo r3, r12");
asm("bne 0b");
asm("movs r0, #1");
__POPRET("");
asm("9:");
asm("movs r0, #0");
__POPRET("");
}
__NAKED__ TBool SBTraceData::CheckFilter2(TUint32 aUid)
{
asm("btrace_check_filter2:");
// returns r0 = 0 or 1 indicating if trace passed the filter check
// returns r2 = trace context id
asm("stmdb sp!, {r4-r8,lr}");
asm("mov r4, r0 ");
asm("mov r8, r1 ");
asm("mrs lr, cpsr ");
__ASM_CLI();
GET_RWNO_TID(,r3);
asm("mov r5, #0 "); // r5 = TRUE if critical section entered
asm("and r6, lr, #0x0f ");
asm("cmp r6, #3 ");
asm("movhi r6, #2 "); // r6 = context ID = 1 for FIQ, 2 for IRQ/ABT/UND/SYS
asm("bne 1f "); // branch if not mode_svc
asm("ldrb r12, [r3, #%a0]" : : "i" _FOFF(TSubScheduler,iInIDFC));
asm("cmp r12, #0 ");
asm("bne 1f "); // branch if IDFC
asm("ldrb r12, [r3, #%a0]" : : "i" _FOFF(TSubScheduler,iKernLockCount));
asm("ldr r6, [r3, #%a0]" : : "i" _FOFF(TSubScheduler,iCurrentThread));
asm("cmp r12, #0 "); // kernel locked?
asm("bne 1f "); // if so, don't enter CS
asm("msr cpsr, lr "); // restore interrupts
asm("bl " CSM_ZN5NKern14_ThreadEnterCSEv );
asm("mov r5, #1 ");
asm("b 2f ");
asm("1: ");
asm("msr cpsr, lr "); // restore interrupts
asm("2: "); // r6 = context ID, r5 = TRUE if critical section entered
// DBTraceFilter2::Open()
asm("ldr r0, __BTraceFilter2Lock ");
asm("bl " CSM_ZN9TSpinLock11LockIrqSaveEv );
asm("ldr r7, [r4, #%a0]" : : "i" _FOFF(SBTraceData,iFilter2));
asm("cmp r7, #1 ");
asm("ldrhi r2, [r7, #%a0]" : : "i" _FOFF(DBTraceFilter2,iAccessCount));
asm("addhi r2, r2, #1 ");
asm("strhi r2, [r7, #%a0]" : : "i" _FOFF(DBTraceFilter2,iAccessCount));
asm("mov r1, r0 ");
asm("ldr r0, __BTraceFilter2Lock ");
asm("bl " CSM_ZN9TSpinLock16UnlockIrqRestoreEi );
asm("cmp r7, #1 ");
asm("bls 3f ");
// DBTraceFilter2::Check()
asm("mov r0, r7 ");
asm("mov r1, r8 ");
asm("bl DBTraceFilter2_Check ");
asm("mov r8, r0 ");
// DBTraceFilter2::Close()
asm("ldr r0, __BTraceFilter2Lock ");
asm("bl " CSM_ZN9TSpinLock11LockIrqSaveEv );
asm("ldr r2, [r7, #%a0]" : : "i" _FOFF(DBTraceFilter2,iAccessCount));
asm("ldr r1, __DBTraceFilter2_iCleanupHead");
asm("subs r2, r2, #1");
asm("str r2, [r7, #%a0]" : : "i" _FOFF(DBTraceFilter2,iAccessCount));
asm("ldreq r2, [r1] ");
asm("streq r7, [r1] ");
asm("streq r2, [r7, #%a0]" : : "i" _FOFF(DBTraceFilter2,iCleanupLink));
asm("mov r1, r0 ");
asm("ldr r0, __BTraceFilter2Lock ");
asm("bl " CSM_ZN9TSpinLock16UnlockIrqRestoreEi );
asm("mov r7, r8 "); // r7 = result
asm("3: ");
// NKern::ThreadLeaveCS()
asm("cmp r5, #0");
asm("blne " CSM_ZN5NKern14_ThreadLeaveCSEv );
asm("mov r0, r7 "); // r0 = result
asm("mov r2, r6 "); // r2 = context id
__POPRET("r4-r8,");
asm("__DBTraceFilter2_iCleanupHead:");
asm(".word %a0" : : "i" ((TInt)&DBTraceFilter2::iCleanupHead));
asm("__BTraceFilter2Lock: ");
asm(".word %a0" : : "i" ((TInt)&BTraceFilter2Lock));
}
#endif