/*---------------------------------------------------------------------------* Project: TwlSDK - OS File: os_application_jump.c Copyright 2007-2009 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:: 2009-06-04#$ $Rev: 10698 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include // Define data------------------------------------------------------- #define OSi_LAUNCHER_PARAM_MAGIC_CODE "TLNC" #define OSi_LAUNCHER_PARAM_MAGIC_CODE_LEN 4 #define OSi_TITLE_ID_MEDIA_FLAG_MASK ( 0x0001ULL << 34 ) #define OSi_TITLE_ID_DATA_ONLY_FLAG_MASK ( 0x0001ULL << 35 ) #define OSi_TMP_APP_SIZE_MAX ( 16 * 1024 * 1024 ) #define OSi_TMP_APP_PATH_RAW "nand:/tmp/jump.app" #define OSi_TMP_APP_PATH_RAW_LENGTH 18 typedef struct NandFirmResetParameter { u8 isHotStart :1; u8 isResetSW :1; u8 rsv :5; u8 isValid :1; }NandFirmResetParameter; // NAND firmware parameter address #define OSi_GetNandFirmResetParam() ( (NandFirmResetParameter *)HW_NAND_FIRM_HOTSTART_FLAG ) // Launcher parameter address #define OSi_GetLauncherParam() ( (LauncherParam *)HW_PARAM_LAUNCH_PARAM ) // Extern data------------------------------------------------------- // Function's prototype---------------------------------------------- static void OSi_DoHardwareReset( void ); static BOOL OSi_IsNandApp( OSTitleId id ); static BOOL OSi_IsSameMakerCode(OSTitleId id); static OSTitleId OSi_SearchTitleIdFromList(OSTitleId id, u64 mask); // Global variables-------------------------------------------------- // Static variables-------------------------------------------------- #include static OSTitleId s_prevTitleId = 0; #include // Const data-------------------------------------------------------- #include static BOOL OSi_IsNandApp( OSTitleId id ) { if( id & OSi_TITLE_ID_MEDIA_FLAG_MASK ) { return TRUE; } return FALSE; } static BOOL OSi_IsSameMakerCode(OSTitleId id) { const OSTitleIDList *list = (const OSTitleIDList *)HW_OS_TITLE_ID_LIST; const int total = MATH_MIN( list->num, OS_TITLEIDLIST_MAX ); int i; for (i = 0; i < total; ++i) { if (list->TitleID[i] == id) { int pos = (i >> 3); int bit = (0x01 << (i & 7)); if (( list->sameMakerFlag[pos] & bit) != 0) { /* The maker code is the same */ return TRUE; } else { /* The maker code is different */ return FALSE; } } } /* The target TitleID is not in the list */ return FALSE; } static OSTitleId OSi_SearchTitleIdFromList( OSTitleId id, u64 mask ) { const OSTitleIDList *list = (const OSTitleIDList *)HW_OS_TITLE_ID_LIST; const int OS_TITLE_ID_LIST_MAX = sizeof(list->TitleID) / sizeof(*list->TitleID); const int num = MATH_MIN(list->num, OS_TITLE_ID_LIST_MAX); int i; /* Under the assumption that game codes are unique, extract the relevant TitleID from the list */ for (i = 0; i < num; ++i) { if ( (id & mask) == (list->TitleID[i] & mask) /* Do the game codes match? */ && !(list->TitleID[i] & OSi_TITLE_ID_DATA_ONLY_FLAG_MASK) ) /* Is this not a data-only title? */ { return list->TitleID[i]; } } return 0; } #include #ifdef SDK_ARM9 void OSi_InitPrevTitleId( void ) { OSDeliverArgInfo deliverArgInfo; OS_InitDeliverArgInfo( &deliverArgInfo, 0 ); if ( OS_DELIVER_ARG_SUCCESS == OS_DecodeDeliverArg() ) { s_prevTitleId = OS_GetTitleIdFromDeliverArg(); } if ( (s_prevTitleId != 0 && !OSi_SearchTitleIdFromList(s_prevTitleId, 0xffffffffffffffff)) || (char)(s_prevTitleId >>24) == '0' || (char)(s_prevTitleId >>24) == '1' || (char)(s_prevTitleId >>24) == '2' || (char)(s_prevTitleId >>24) == '3' || (char)(s_prevTitleId >>24) == '4' ) { /* Make it look like this was started from the launcher and delete DeliverArg as well */ s_prevTitleId = 0; OS_InitDeliverArgInfo( &deliverArgInfo, 0 ); (void)OS_EncodeDeliverArg(); } else { OS_SetDeliverArgStateInvalid(); } } // For safety purposes, locate this function in itcm #include static void OSi_DoHardwareReset( void ) { // [TODO:] Lastly, change to HW reset via a microcomputer // Issue reset command PM_ForceToResetHardware(); OS_Terminate(); } #include /* The following code is located in the TWL extended memory region */ #ifdef SDK_TWL #include #endif // Hardware reset by specifying LauncherParam void OS_SetLauncherParamAndResetHardware( OSTitleId id, LauncherBootFlags *flag ) { // Copy the manufacturer and game codes u32 *maker_code_dest_addr = (u32 *)((u32)(OSi_GetLauncherParam()) + HW_PARAM_DELIVER_ARG_MAKERCODE_OFS); u32 *game_code_dest_addr = (u32 *)((u32)(OSi_GetLauncherParam()) + HW_PARAM_DELIVER_ARG_GAMECODE_OFS); u16 *maker_code_src_addr = (u16 *)(HW_TWL_ROM_HEADER_BUF + 0x10); u32 *game_code_src_addr = (u32 *)(HW_TWL_ROM_HEADER_BUF + 0xc); *maker_code_dest_addr = (u32)*maker_code_src_addr; *game_code_dest_addr = *game_code_src_addr; // Set the launcher parameter OSi_GetLauncherParam()->body.v1.prevTitleID = *(OSTitleId *)(HW_TWL_ROM_HEADER_BUF + 0x230); OSi_GetLauncherParam()->body.v1.bootTitleID = id; OSi_GetLauncherParam()->body.v1.flags = *flag; MI_CpuCopyFast( OSi_LAUNCHER_PARAM_MAGIC_CODE, (char *)&OSi_GetLauncherParam()->header.magicCode, OSi_LAUNCHER_PARAM_MAGIC_CODE_LEN); OSi_GetLauncherParam()->header.bodyLength = sizeof(LauncherParamBody); OSi_GetLauncherParam()->header.crc16 = SVC_GetCRC16( 65535, &OSi_GetLauncherParam()->body, OSi_GetLauncherParam()->header.bodyLength ); OSi_GetLauncherParam()->header.version = 1; if( id == 0 || OS_IsDeliverArgEncoded() != TRUE || OS_GetTitleIdLastEncoded() != OSi_GetLauncherParam()->body.v1.prevTitleID ) { // If the DeliverArg is not encoded with the current application, force initialization of DeliverArg and encode OSDeliverArgInfo deliverArgInfo; OS_InitDeliverArgInfo( &deliverArgInfo, 0 ); (void)OS_EncodeDeliverArg(); } DC_FlushRange((const void *)HW_PARAM_DELIVER_ARG, HW_PARAM_DELIVER_ARG_SIZE + HW_PARAM_LAUNCH_PARAM_SIZE ); DC_WaitWriteBufferEmpty(); OSi_DoHardwareReset(); } // Function that returns from the application after the application jump to the original application // If there is no original application, FALSE BOOL OS_ReturnToPrevApplication( void ) { if( s_prevTitleId != 0) { return OS_DoApplicationJump( s_prevTitleId, OS_APP_JUMP_NORMAL ); //Never return } return FALSE; } static inline BOOL IsSameTitleID( OSTitleId titleID, OSTitleId listedTitleID ) { if ((char)titleID == 'A') { // Corresponding to language code A option return (listedTitleID >> 8) == (titleID >> 8); } else { return listedTitleID == titleID; } } // Get the ID that can actually be started for the given title ID // If a startable ID exists, set that ID to the *bootableTitleID and return TRUE // If a startable ID does not exist, return FALSE static BOOL OS_GetBootableTitleID( OSTitleId titleID, OSTitleId *bootableTitleID ) { const OSTitleIDList *list = (const OSTitleIDList *)HW_OS_TITLE_ID_LIST; const int OS_TITLE_ID_LIST_MAX = sizeof(list->TitleID) / sizeof(*list->TitleID); const int num = MATH_MIN(list->num, OS_TITLE_ID_LIST_MAX); int i; for (i = 0; i < num; ++i) { if (IsSameTitleID(titleID, list->TitleID[i]) && (list->appJumpFlag[i / 8] & (u8)(0x1 << (i % 8)))) { *bootableTitleID = list->TitleID[i]; return TRUE; } } return FALSE; } // Whether an application has been installed that corresponds to that TitleID BOOL OSi_CanApplicationJumpTo( OSTitleId titleID ) { return OS_GetBootableTitleID(titleID, &titleID); } // Wrapper for OS_SetLauncherParamAndResetHardware BOOL OS_DoApplicationJump( OSTitleId id, OSAppJumpType jumpType ) { FSFile file[1]; LauncherBootFlags flag; u8 platform_code; u8 bit_field; switch( jumpType ) { case OS_APP_JUMP_NORMAL: if( id & OSi_TITLE_ID_DATA_ONLY_FLAG_MASK ) { // Set so that it is not possible to jump to DataOnly items return FALSE; } if( id != 0 ) { if (!OS_GetBootableTitleID(id, &id)) { return FALSE; } } // Set the bootType and jump if( id & OSi_TITLE_ID_MEDIA_FLAG_MASK ) { flag.bootType = LAUNCHER_BOOTTYPE_NAND; }else { flag.bootType = LAUNCHER_BOOTTYPE_ROM; } break; case OS_APP_JUMP_TMP: // When you yourself are a TMP application, TMP jump is not possible if( OS_IsTemporaryApplication() ) { OS_TPrintf("OS_DoApplicationJump error : tmp app can't jump to tmp app!\n"); return FALSE; } // Get the TitleID from the file of OS_TMP_APP_PATH and check the allowed TMP jump bits FS_InitFile( file ); if( !FS_OpenFileEx(file, OS_TMP_APP_PATH, FS_FILEMODE_R) ) { OS_TPrintf("OS_DoApplicationJump error : tmp app open error!\n"); return FALSE; } // File size check if( FS_GetFileLength( file ) > OSi_TMP_APP_SIZE_MAX ) { OS_TPrintf("OS_DoApplicationJump error : too large tmp app size!\n"); return FALSE; } if( !FS_SeekFile( file, 0x12, FS_SEEK_SET ) || ( sizeof(platform_code) != FS_ReadFile( file, &platform_code, sizeof(platform_code) ) ) || !FS_SeekFile( file, 0x1d, FS_SEEK_SET ) || ( sizeof(bit_field) != FS_ReadFile( file, &bit_field, sizeof(bit_field) ) ) ) { OS_TPrintf("OS_DoApplicationJump error : tmp app read error!\n"); (void)FS_CloseFile(file); return FALSE; } if( !( bit_field & 0x2 ) ) { OS_TPrintf("OS_DoApplicationJump error : tmp jump bit is not enabled!\n"); (void)FS_CloseFile(file); return FALSE; } flag.bootType = LAUNCHER_BOOTTYPE_TEMP; // The TWL application gets the title ID from the header and enters it. For NTR applications, for the time being enter TitleIDs other than 0 if( platform_code & 0x2 ) { if( !FS_SeekFile( file, 0x0230, FS_SEEK_SET ) || ( sizeof(id) != FS_ReadFile( file, &id, sizeof(id) ) ) ) { OS_TPrintf("OS_DoApplicationJump error : tmp app read error!\n"); (void)FS_CloseFile(file); return FALSE; } }else { id = 0x1; } (void)FS_CloseFile(file); break; default: return FALSE; } if ( PMi_TryLockForReset() == FALSE ) { return FALSE; } // Shared configurations flag.isValid = TRUE; flag.isLogoSkip = TRUE; flag.isInitialShortcutSkip = FALSE; flag.isAppLoadCompleted = FALSE; flag.isAppRelocate = FALSE; flag.rsv = 0; OS_SetLauncherParamAndResetHardware( id, &flag ); // never return. return TRUE; } /* The code above is located in the TWL extended memory region */ #ifdef SDK_TWL #include #endif /*---------------------------------------------------------------------------* Name: OS_JumpToSystemMenu Description: Runs a hardware reset and jumps to the system menu. Arguments: None. Returns: FALSE: Application jump failed for some reason. * If the process was successful, a reset occurred during this function, so TRUE is not returned. *---------------------------------------------------------------------------*/ BOOL OS_JumpToSystemMenu( void ) { BOOL result = FALSE; #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { // ---- Application Jump with id==0 // means to jump to system menu result = OS_DoApplicationJump( 0, OS_APP_JUMP_NORMAL ); } else #endif { OS_Warning("This Hardware don't support this funciton"); } return result; } /*---------------------------------------------------------------------------* Name: OS_RebootSystem Description: Runs a hardware reset and restarts itself. Arguments: None. Returns: FALSE: Run on NITRO, or failure in restarting. * If the process was successful, a reset occurred during this function, so TRUE is not returned. *---------------------------------------------------------------------------*/ BOOL OS_RebootSystem( void ) { #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { if( OS_IsTemporaryApplication() ) { OS_TPrintf("OS_RebootSystem error : tmp app can't execute this function\n"); return FALSE; } // Application jump to self return OS_DoApplicationJump( OS_GetTitleId(), OS_APP_JUMP_NORMAL ); } else #endif { OS_Warning("This Hardware don't support this funciton"); return FALSE; } } /*---------------------------------------------------------------------------* Name: OS_IsRebooted Description: Checks whether a restart was applied using OS_RebootSystem. Arguments: None. Returns: TRUE: Restart was applied more than one time. FALSE: First startup. *---------------------------------------------------------------------------*/ BOOL OS_IsRebooted( void ) { BOOL result = FALSE; #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { if( OS_GetTitleId() == s_prevTitleId ) { result = TRUE; } } #endif return result; } /*---------------------------------------------------------------------------* Name: OSi_CanArbitraryJumpTo Description: Checks whether a jump to the specified (arbitrary) application is possible. Arguments: Game code of the application to jump to Returns: TRUE: Execution can jump to the target application. FALSE: Execution cannot jump to the target application. *---------------------------------------------------------------------------*/ BOOL OSi_CanArbitraryJumpTo(u32 initialCode) { #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { OSTitleId id = OSi_SearchTitleIdFromList( (OSTitleId)initialCode, 0x00000000ffffffff ); /* Non-NAND application are exceptions */ if( OSi_IsNandApp(id) ) { return OSi_CanApplicationJumpTo( id ) && OSi_IsSameMakerCode( id ); } } #endif return FALSE; } /*---------------------------------------------------------------------------* Name: OSi_JumpToArbitraryApplication Description: Jumps to the specified (arbitrary) application. Arguments: Game code of the application to jump to Returns: FALSE: Application jump failed for some reason. * If the process was successful, a reset occurred during this function, so TRUE is not returned. *---------------------------------------------------------------------------*/ BOOL OSi_JumpToArbitraryApplication(u32 initialCode) { #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { OSTitleId id = OSi_SearchTitleIdFromList( (OSTitleId)initialCode, 0x00000000ffffffff ); if( OSi_CanArbitraryJumpTo( initialCode ) ) { return OS_DoApplicationJump( id, OS_APP_JUMP_NORMAL ); } } #endif return FALSE; } /*---------------------------------------------------------------------------* Name: OSi_GetPrevTitleId Description: Gets the Title ID of the application that used the OS_JumpToArbitraryApplication function to jump here. Arguments: None. Returns: The Title ID of the application that used the OS_JumpToArbitraryApplication function to jump here. Returns 0 if this application was started from the System Menu or debugger, or if it was run on NITRO. *---------------------------------------------------------------------------*/ OSTitleId OSi_GetPrevTitleId(void) { #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { const OSTitleIDList *list = (const OSTitleIDList *)HW_OS_TITLE_ID_LIST; const int total = MATH_MIN( list->num, OS_TITLEIDLIST_MAX ); int i; for (i = 0; i < total; ++i) { if (list->TitleID[i] == s_prevTitleId ) { return s_prevTitleId; } } } #endif return 0; } /*---------------------------------------------------------------------------* Name: OS_IsBootFromSystemMenu Description: Determines whether this application was started from the System Menu. Arguments: None. Returns: TRUE: This application was started from the System Menu. FALSE: This application was started from another application. *---------------------------------------------------------------------------*/ BOOL OS_IsBootFromSystemMenu( void ) { #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { if( OSi_GetPrevTitleId() == 0 ) { return TRUE; } else { return FALSE; } } #endif return TRUE; } /*---------------------------------------------------------------------------* Name: OSi_IsJumpFromSameMaker Description: Determines whether this application was started from an application with the same maker code. Arguments: None. Returns: TRUE: This application was started from an application with the same maker code. FALSE: This application was started from another application or the System Menu. *---------------------------------------------------------------------------*/ BOOL OSi_IsJumpFromSameMaker( void ) { #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { if( OS_IsBootFromSystemMenu() ) { /* Exclude this application in advance if it was started from the System Menu */ return FALSE; } return OSi_IsSameMakerCode( s_prevTitleId ); } #endif return FALSE; } /*---------------------------------------------------------------------------* Name: OSi_GetInitialCode Description: Gets the game code of the running application. Arguments: None. Returns: The game code. This cannot be obtained when run on NITRO, so 0 will be returned. *---------------------------------------------------------------------------*/ u32 OSi_GetInitialCode(void) { #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { return (u32)( OS_GetTitleId() ); } #endif return 0; } /*---------------------------------------------------------------------------* Name: OSi_GetPrevInitialCode Description: Gets the game code of the application that used the OS_JumpToArbitraryApplication function to jump here. Arguments: None. Returns: The game code. Returns 0 if this application was started from the System Menu or debugger, or if it was run on NITRO because the value cannot be obtained. *---------------------------------------------------------------------------*/ u32 OSi_GetPrevInitialCode(void) { #ifdef SDK_TWL if( OS_IsRunOnTwl() ) { return (u32)( OSi_GetPrevTitleId() ); } #endif return 0; } /*---------------------------------------------------------------------------* Name: OS_IsTemporaryApplication Description: Checks whether self is a TMP application. Arguments: None. Returns: TRUE: TMP application. FALSE: Other than TMP applications. *---------------------------------------------------------------------------*/ BOOL OS_IsTemporaryApplication(void) { #ifdef SDK_TWL static BOOL isChecked = FALSE, isTmpApp = FALSE; if( OS_IsRunOnTwl() ) { if( isChecked == FALSE ) /* If already checked, flow previous results */ { if( 0 == STD_CompareNString( OS_GetBootSRLPath(), OSi_TMP_APP_PATH_RAW, OSi_TMP_APP_PATH_RAW_LENGTH ) ) { isTmpApp = TRUE; } else { isTmpApp = FALSE; } isChecked = TRUE; } return isTmpApp; } #endif return FALSE; } #else // SDK_ARM9 //---------------------------------------------------------------- // For ARM7 static BOOL OSi_IsValidLauncherParam( void ) { return ( STD_StrNCmp( (const char *)&OSi_GetLauncherParam()->header.magicCode, OSi_LAUNCHER_PARAM_MAGIC_CODE, OSi_LAUNCHER_PARAM_MAGIC_CODE_LEN ) == 0 ) && ( OSi_GetLauncherParam()->header.bodyLength > 0 ) && ( OSi_GetLauncherParam()->header.crc16 == SVC_GetCRC16( 65535, &OSi_GetLauncherParam()->body, OSi_GetLauncherParam()->header.bodyLength ) ); } static BOOL OSi_IsEnableJTAG( void ) { // If SCFG register is invalid, the SCFG register value becomes "0". Check the value retracted to WRAM. u8 value = (u8)(( reg_SCFG_EXT & REG_SCFG_EXT_CFG_MASK ) ? ( reg_SCFG_JTAG & REG_SCFG_JTAG_CPUJE_MASK ) : ( *(u8 *)HWi_WSYS09_ADDR & HWi_WSYS09_JTAG_CPUJE_MASK )); return value ? TRUE : FALSE; } // Launcher parameter lead and determine hot/cold boot // Return TRUE if launcher parameter is valid; FALSE if invalid // If the launcher parameter in LauncherParam is valid, that launcher parameter is stored // TRUE if hot boot in isHotstart; False is stored if a cold boot. BOOL OS_ReadLauncherParameter( LauncherParam *buf, BOOL *isHotstart ) { if( !OSi_GetNandFirmResetParam()->isValid ) { *(u8 *)OSi_GetNandFirmResetParam() = (u8)MCU_GetFreeRegister( OS_MCU_RESET_VALUE_OFS ); OSi_GetNandFirmResetParam()->isValid = 1; } // Hot/cold boot determination // If "HOTBT flag of a microcomputer free register = 0," cold boot if( !OSi_GetNandFirmResetParam()->isHotStart ) { *isHotstart = FALSE; }else { *isHotstart = TRUE; // Determine launcher parameter validity if( OSi_IsValidLauncherParam() && !OSi_GetNandFirmResetParam()->isResetSW ) { // If launcher parameter is valid, copy to buf MI_CpuCopy32 ( OSi_GetLauncherParam(), buf, sizeof(LauncherParam) ); return TRUE; }else { // Else clear the transfer destination buffer MI_CpuClear32 ( buf, sizeof(LauncherParam) ); } } return FALSE; } #endif // SDK_ARM9