/*---------------------------------------------------------------------------* Project: TwlSDK - OS - File: os_spinLock.c Copyright 2003-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: $ $Rev$ $Author$ *---------------------------------------------------------------------------*/ #include void _ISDbgLib_Initialize(void); void _ISDbgLib_AllocateEmualtor(void); void _ISDbgLib_FreeEmulator(void); void _ISTDbgLib_Initialize(void); void _ISTDbgLib_AllocateEmualtor(void); void _ISTDbgLib_FreeEmulator(void); s32 osLockWord_IrqAndFiq(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void)); s32 osUnlockByte_IrqAndFiq(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void)); s32 osTryLockByte_IrqAndFiq(u8 lockID, OSLockByte *lockp, void (*crtlFuncp) (void)); static s32 i_osDoLockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void), BOOL disableFiq); static s32 i_osDoUnlockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void), BOOL disableFIQ); static s32 i_osDoTryLockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void), BOOL disableFIQ); static void i_osAllocateCartridgeBus(void); static void i_osFreeCartridgeBus(void); static void i_osAllocateCardBus(void); static void i_osFreeCardBus(void); static void i_osWaitByLoop(void); #ifdef SDK_ARM11 #define OSi_ASSERT_ID( id ) SDK_ASSERTMSG( id >= OS_MAINP_LOCK_ID_START && id <= OS_MAINP_SYSTEM_LOCK_ID, \ "lock ID %d is out of bounds", id ) #else #define OSi_ASSERT_ID( id ) SDK_ASSERTMSG( id >= OS_SUBP_LOCK_ID_START && id <= OS_SUBP_SYSTEM_LOCK_ID, \ "lock ID %d is out of bounds", id ) #endif #define OSi_LOCKID_INITIAL_FLAG_0 0xffffffff #define OSi_LOCKID_INITIAL_FLAG_1 0xffff0000 u32 OSi_ANYP_LOCK_ID_FLAG[2]; #ifdef SDK_ARM11 //#define OSi_ANYP_LOCK_ID_FLAG HW_LOCK_ID_FLAG_MAIN #define OSi_ANYP_LOCK_ID_START OS_MAINP_LOCK_ID_START #else //#define OSi_ANYP_LOCK_ID_FLAG HW_LOCK_ID_FLAG_SUB #define OSi_ANYP_LOCK_ID_START OS_SUBP_LOCK_ID_START #endif //====================================================================== // SYNC //====================================================================== /*---------------------------------------------------------------------------* Name: i_osSyncWithOtherProc Description: sync with other processor. Arguments: type : OSi_SYNCTYPE_SENDER/RECVER syncBuf : work area. use 4byte. Returns: None. *---------------------------------------------------------------------------*/ void i_osSyncWithOtherProc( int type, void* syncBuf ) { vu8* ptr1 = (vu8*)syncBuf; vu8* ptr2 = (vu8*)syncBuf +1; vu8* pfinish = (vu8*)syncBuf +2; vu8* pconf = (vu8*)syncBuf +3; if ( type == OSi_SYNCTYPE_SENDER ) { int n=0; *pfinish = FALSE; do { *ptr1 = (u8)( 0x80 | (n&0xf) ); while ( *ptr1 != *ptr2 && *pfinish == FALSE ) { i_osWaitByLoop(); } n ++; } while( *pfinish == FALSE ); *pconf = TRUE; } else { int sum = 0; *ptr2 = 0; while( sum < 0x300 ) { if ( *ptr2 != *ptr1 ) { *ptr2 = *ptr1; sum += *ptr2; } else { i_osWaitByLoop(); } } *pconf = FALSE; *pfinish = TRUE; while( *pconf == FALSE ) { i_osWaitByLoop(); } } } //====================================================================== // DUMMY LOOP //====================================================================== /*---------------------------------------------------------------------------* Name: i_osWaitByLoop Description: wait by for() loop Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static inline void i_osWaitByLoop(void) { i_osWaitCpuCycles(0x1000 / 4); // svcWaitByLoop(0x1000 / 4); } //====================================================================== // INITIALIZE //====================================================================== /*---------------------------------------------------------------------------* Name: osInitLock Description: initialize system lock variable and privilege to access shared resources * cartridge exclusive control area is not cleared because debugger uses. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void osInitLock(void) { static BOOL isInitialized = FALSE; #ifdef SDK_NITRO OSLockByte *lockp; #endif if (isInitialized) { return; // do it only once } isInitialized = TRUE; #ifdef SDK_ARM11 // ロックIDカウンタ用フラグ 初期化 ((u32 *)OSi_ANYP_LOCK_ID_FLAG)[0] = OSi_LOCKID_INITIAL_FLAG_0; ((u32 *)OSi_ANYP_LOCK_ID_FLAG)[1] = OSi_LOCKID_INITIAL_FLAG_1; // ロックバッファ クリア(カートリッジ領域以外) // miCpuClear32((void *)HW_SHARED_LOCK_BUF, HW_CTRDG_LOCK_BUF - HW_SHARED_LOCK_BUF); // NITRO カードアクセス権 → サブプロセッサ // i_miSetCardProcessor(MI_PROCESSOR_ARM9); //---- sync with ARM7 i_osSyncWithOtherProc( OSi_SYNCTYPE_SENDER, (void*)HW_INIT_LOCK_BUF ); i_osSyncWithOtherProc( OSi_SYNCTYPE_RECVER, (void*)HW_INIT_LOCK_BUF ); //lockp->lockFlag = 0; //(void)osLockByte(OS_MAINP_SYSTEM_LOCK_ID, lockp, NULL); #else // SDK_ARM9 // ロックIDカウンタ用フラグ 初期化 ((u32 *)OSi_ANYP_LOCK_ID_FLAG)[0] = OSi_LOCKID_INITIAL_FLAG_0; ((u32 *)OSi_ANYP_LOCK_ID_FLAG)[1] = OSi_LOCKID_INITIAL_FLAG_1; //---- sync with ARM9 i_osSyncWithOtherProc( OSi_SYNCTYPE_RECVER, (void*)HW_INIT_LOCK_BUF ); i_osSyncWithOtherProc( OSi_SYNCTYPE_SENDER, (void*)HW_INIT_LOCK_BUF ); #endif // SDK_ARM9 } //====================================================================== // LOCK //====================================================================== /*---------------------------------------------------------------------------* Name: i_osDoLockByte Description: do spinlock. keep to try till success Arguments: lockID lock ID lockp pointer to lock variable ctrlFuncp function disableFiq whether do disable fiq Returns: OS_LOCK_SUCCESS success to lock *---------------------------------------------------------------------------*/ static s32 i_osDoLockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void), BOOL disableFiq) { s32 lastLockFlag; while ((lastLockFlag = i_osDoTryLockByte(lockID, lockp, ctrlFuncp, disableFiq)) > OS_LOCK_SUCCESS) { i_osWaitByLoop(); } return lastLockFlag; } /*---------------------------------------------------------------------------* Name: osLockByte Description: do spinlock. keep to try till success. Arguments: lockID lock ID lockp pointer to lock variable ctrlFuncp function Returns: OS_LOCK_SUCCESS success to lock *---------------------------------------------------------------------------*/ s32 osLockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void)) { return i_osDoLockByte(lockID, lockp, ctrlFuncp, FALSE); } /*---------------------------------------------------------------------------* Name: osLockByte_IrqAndFiq Description: do spinlock. keep to try till success. disable irq and fiq Arguments: lockID lock ID lockp pointer to lock variable ctrlFuncp function Returns: OS_LOCK_SUCCESS success to lock *---------------------------------------------------------------------------*/ s32 osLockByte_IrqAndFiq(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void)) { return i_osDoLockByte(lockID, lockp, ctrlFuncp, TRUE); } //====================================================================== // UNLOCK //====================================================================== /*---------------------------------------------------------------------------* Name: i_osDoUnlockByte Description: do unlock lock. Arguments: lockID lock ID lockp pointer to unlock variable ctrlFuncp function disableFiq whether do disable fiq Returns: OS_UNLOCK_SUCCESS success OS_UNLOCK_ERROR error of unlocking lock *---------------------------------------------------------------------------*/ static s32 i_osDoUnlockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void), BOOL disableFIQ) { OSIntrMode lastInterrupts; OSi_ASSERT_ID(lockID); if (lockID != lockp->ownerID) { return OS_UNLOCK_ERROR; } //---- Disable irq/fiq or irq lastInterrupts = (disableFIQ) ? osDisableInterrupts_IrqAndFiq() : osDisableInterrupts(); lockp->ownerID = 0; if (ctrlFuncp) { ctrlFuncp(); } lockp->lockFlag = 0; //---- Restore irq/fiq or irq if (disableFIQ) { (void)osRestoreInterrupts_IrqAndFiq(lastInterrupts); } else { (void)osRestoreInterrupts(lastInterrupts); } return OS_UNLOCK_SUCCESS; } /*---------------------------------------------------------------------------* Name: osUnlockByte Description: do unlock lock. disable irq and fiq Arguments: lockID lock ID lockp pointer to unlock variable ctrlFuncp function Returns: OS_UNLOCK_SUCCESS success OS_UNLOCK_ERROR error of unlocking lock *---------------------------------------------------------------------------*/ s32 osUnlockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void)) { return i_osDoUnlockByte(lockID, lockp, ctrlFuncp, FALSE); } /*---------------------------------------------------------------------------* Name: osUnlockByte_IrqAndFiq Description: do unlock lock. Arguments: lockID lock ID lockp pointer to unlock variable ctrlFuncp function Returns: OS_UNLOCK_SUCCESS success OS_UNLOCK_ERROR error of unlocking lock *---------------------------------------------------------------------------*/ s32 osUnlockByte_IrqAndFiq(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void)) { return i_osDoUnlockByte(lockID, lockp, ctrlFuncp, TRUE); } //====================================================================== // TRY LOCK //====================================================================== /*---------------------------------------------------------------------------* Name: i_osDoTryLockByte Description: try to lock spinlock only once. Arguments: lockID lock ID lockp pointer to trying to lock variable ctrlFuncp function disableFiq whether do disable fiq Returns: >0 value previous locked id OS_LOCK_SUCCESS success to lock *---------------------------------------------------------------------------*/ static s32 i_osDoTryLockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void), BOOL disableFIQ) { s32 lastLockFlag; OSIntrMode lastInterrupts; OSi_ASSERT_ID(lockID); //---- Disable irq/fiq or irq lastInterrupts = (disableFIQ) ? osDisableInterrupts_IrqAndFiq() : osDisableInterrupts(); lastLockFlag = (s32)miSwapByte(lockID, &lockp->lockFlag); if (lastLockFlag == OS_LOCK_SUCCESS) { if (ctrlFuncp) { ctrlFuncp(); } lockp->ownerID = lockID; } //---- Restore irq/fiq or irq if (disableFIQ) { (void)osRestoreInterrupts_IrqAndFiq(lastInterrupts); } else { (void)osRestoreInterrupts(lastInterrupts); } return lastLockFlag; } /*---------------------------------------------------------------------------* Name: osTryLockByte Description: try to lock spinlock only once. Arguments: lockID lock ID lockp pointer to trying to lock variable ctrlFuncp function Returns: >0 value previous locked id OS_LOCK_SUCCESS success to lock *---------------------------------------------------------------------------*/ s32 osTryLockByte(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void)) { return i_osDoTryLockByte(lockID, lockp, ctrlFuncp, FALSE); } /*---------------------------------------------------------------------------* Name: osTryLockByte_IrqAndFiq Description: try to lock spinlock only once. Arguments: lockID lock ID lockp pointer to trying to lock variable ctrlFuncp function Returns: >0 value previous locked id OS_LOCK_SUCCESS success to lock *---------------------------------------------------------------------------*/ s32 osTryLockByte_IrqAndFiq(u8 lockID, OSLockByte *lockp, void (*ctrlFuncp) (void)) { return i_osDoTryLockByte(lockID, lockp, ctrlFuncp, TRUE); } //====================================================================== // CARD //====================================================================== /*---------------------------------------------------------------------------* Name: osLockCard Description: lock card Arguments: lockID lock ID Returns: OS_LOCK_SUCCESS success to lock *---------------------------------------------------------------------------*/ s32 osLockCard(u8 lockID) { OSi_ASSERT_ID(lockID); return osLockByte(lockID, (OSLockByte *)HW_CARD_LOCK_BUF, i_osAllocateCardBus); } /*---------------------------------------------------------------------------* Name: osUnlockCard Description: unlock card Arguments: lockID lock ID Returns: OS_UNLOCK_SUCCESS success OS_UNLOCK_ERROR error of unlocking lock *---------------------------------------------------------------------------*/ s32 osUnlockCard(u8 lockID) { OSi_ASSERT_ID(lockID); return osUnlockByte(lockID, (OSLockByte *)HW_CARD_LOCK_BUF, i_osFreeCardBus); } /*---------------------------------------------------------------------------* Name: osTryLockCard Description: try to lock card Arguments: lockID lock ID Returns: >0 value previous locked id OS_LOCK_SUCCESS success to lock *---------------------------------------------------------------------------*/ s32 osTryLockCard(u8 lockID) { return osTryLockByte(lockID, (OSLockByte *)HW_CARD_LOCK_BUF, i_osAllocateCardBus); } //---------------- static void i_osAllocateCardBus(void) { #ifdef SDK_ARM11 #ifdef SDK_TWL // preset reset flag with status of disable interrupts in i_osDoTryLockByte if ( ((reg_MI_MC & REG_MI_MC_SL1_MODE_MASK) >> REG_MI_MC_SL1_MODE_SHIFT) == 0x2 ) { reg_MI_MCCNT1 |= REG_MI_MCCNT1_RESB_MASK; } #endif // i_miSetCardProcessor(MI_PROCESSOR_ARM9); // Card for MAIN #endif } //---------------- static void i_osFreeCardBus(void) { #ifdef SDK_ARM11 // i_miSetCardProcessor(MI_PROCESSOR_ARM7); // Card for SUB #endif } //====================================================================== // READ OWNER //====================================================================== /*---------------------------------------------------------------------------* Name: osReadOwnerOfLockWord Description: read owner id of lock ・モジュールID が非0 の場合はその時点でどちらのプロセッサ側が 所有権を持っているのかを確認できます。 ・共有リソースの場合は「メインプロセッサ側が所有権を持っている状態」 のみを割り込みを禁止することによって維持することができます。 その他の状態はサブプロセッサが変化させてしまう可能性があります。 ・所有モジュールID が 0 であってもロック変数が解除されているとは限りません。 Arguments: lockp pointer to lock Returns: owner id *---------------------------------------------------------------------------*/ u8 osReadOwnerOfLockWord(OSLockByte *lockp) { return lockp->ownerID; } //====================================================================== // LOCK ID //====================================================================== /*---------------------------------------------------------------------------* Name: osGetLockID Description: get lock ID Arguments: None. Returns: OS_LOCK_ID_ERROR, if fail to get ID if ARM9 0x40〜0x6f lockID else if ARM7 0x80〜0xaf lockID endif *Notice: ID is allocated only 48 pattern at a highest. IDは48種類までしか割り当てることができません。 モジュール内にて複数のロック変数を制御する場合は できるだけ1つのIDを使用するようにして下さい。 *---------------------------------------------------------------------------*/ #include asm s32 osGetLockID( void ) { INASM_EXTERN( OSi_ANYP_LOCK_ID_FLAG ) //---- フラグの前32ビットに立っているフラグ(空きID)があるか ldr r3, =OSi_ANYP_LOCK_ID_FLAG ldr r1, [r3, #0] #ifndef SDK_ARM7 clz r2, r1 #else mov r2, #0 mov r0, #0x80000000 _lp1: tst r1, r0 bne _ex1 add r2, r2, #1 cmp r2, #32 beq _ex1 mov r0, r0, lsr #1 b _lp1 _ex1: #endif cmp r2, #32 //---- 空きIDがあるとき movne r0, #OSi_ANYP_LOCK_ID_START bne FSYM(10) //---- 後ろ323ビットに立っているフラグ(空きID)があるか add r3, r3, #4 ldr r1, [r3, #0] #ifndef SDK_ARM7 clz r2, r1 #else mov r2, #0 mov r0, #0x80000000 _lp2: tst r1, r0 bne _ex2 add r2, r2, #1 cmp r2, #32 beq _ex2 mov r0, r0, lsr #1 b _lp2 _ex2: #endif cmp r2, #32 //---- 空きIDがない ldr r0, =OS_LOCK_ID_ERROR bxeq lr //---- 空きIDがあるとき mov r0, #OSi_ANYP_LOCK_ID_START+32 LSYM(10) add r0, r0, r2 mov r1, #0x80000000 mov r1, r1, lsr r2 ldr r2, [r3, #0] bic r2, r2, r1 str r2, [r3, #0] bx lr } /*---------------------------------------------------------------------------* Name: osReleaseLockID Description: release lock ID Arguments: id to tend to release Returns: None. *---------------------------------------------------------------------------*/ asm void osReleaseLockID( register u8 lockID ) { //#pragma unused( lockID ) ldr r3, =OSi_ANYP_LOCK_ID_FLAG cmp r0, #OSi_ANYP_LOCK_ID_START+32 addpl r3, r3, #4 subpl r0, r0, #OSi_ANYP_LOCK_ID_START+32 submi r0, r0, #OSi_ANYP_LOCK_ID_START mov r1, #0x80000000 mov r1, r1, lsr r0 ldr r2, [r3, #0] orr r2, r2, r1 str r2, [r3, #0] bx lr } #include