1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - OS
3   File:     os_application_jump.c
4 
5   Copyright 2007-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-12-08#$
14   $Rev: 9571 $
15   $Author: okajima_manabu $
16  *---------------------------------------------------------------------------*/
17 
18 #include <twl/os.h>
19 #include <application_jump_private.h>
20 #include <twl/spi.h>
21 #include <twl/code32.h>
22 #include <twl/mcu.h>
23 #include <twl/hw/common/mmap_shared.h>
24 #include <twl/hw/common/mmap_parameter.h>
25 
26 // Define data-------------------------------------------------------
27 #define OSi_LAUNCHER_PARAM_MAGIC_CODE           "TLNC"
28 #define OSi_LAUNCHER_PARAM_MAGIC_CODE_LEN       4
29 #define OSi_TITLE_ID_MEDIA_FLAG_MASK            ( 0x0001ULL << 34 )
30 #define OSi_TITLE_ID_DATA_ONLY_FLAG_MASK        ( 0x0001ULL << 35 )
31 #define OSi_TMP_APP_SIZE_MAX                    ( 16 * 1024 * 1024 )
32 
33 #define OSi_TMP_APP_PATH_RAW                    "nand:/tmp/jump.app"
34 #define OSi_TMP_APP_PATH_RAW_LENGTH             18
35 
36 typedef struct NandFirmResetParameter {
37     u8      isHotStart :1;
38     u8      isResetSW :1;
39     u8      rsv :5;
40     u8      isValid :1;
41 }NandFirmResetParameter;
42 
43 // NAND firmware parameter address
44 #define OSi_GetNandFirmResetParam()         ( (NandFirmResetParameter *)HW_NAND_FIRM_HOTSTART_FLAG )
45 
46 // Launcher parameter address
47 #define OSi_GetLauncherParam()              ( (LauncherParam *)HW_PARAM_LAUNCH_PARAM )
48 
49 
50 // Extern data-------------------------------------------------------
51 
52 // Function's prototype----------------------------------------------
53 static void OSi_DoHardwareReset( void );
54 
55 // Global variables--------------------------------------------------
56 
57 // Static variables--------------------------------------------------
58 #include  <twl/ltdmain_begin.h>
59 static OSTitleId s_prevTitleId = 0;
60 #include  <twl/ltdmain_end.h>
61 // Const data--------------------------------------------------------
62 
63 #ifdef SDK_ARM9
64 
OSi_InitPrevTitleId(void)65 void OSi_InitPrevTitleId( void )
66 {
67     OSDeliverArgInfo deliverArgInfo;
68     OS_InitDeliverArgInfo( &deliverArgInfo, 0 );
69     if ( OS_DELIVER_ARG_SUCCESS == OS_DecodeDeliverArg() )
70     {
71         s_prevTitleId = OS_GetTitleIdFromDeliverArg();
72     }
73     OS_SetDeliverArgStateInvalid();
74 }
75 
76 // For safety purposes, locate this function in itcm
77 #include <twl/itcm_begin.h>
OSi_DoHardwareReset(void)78 static void OSi_DoHardwareReset( void )
79 {
80     // [TODO:] Lastly, change to HW reset via a microcomputer
81     // Issue reset command
82     PM_ForceToResetHardware();
83     OS_Terminate();
84 }
85 
86 #include <twl/itcm_end.h>
87 
88 /* The following code is located in the TWL extended memory region */
89 #ifdef    SDK_TWL
90 #include  <twl/ltdmain_begin.h>
91 #endif
92 // Hardware reset by specifying LauncherParam
OS_SetLauncherParamAndResetHardware(OSTitleId id,LauncherBootFlags * flag)93 void OS_SetLauncherParamAndResetHardware( OSTitleId id, LauncherBootFlags *flag )
94 {
95     // Copy the manufacturer and game codes
96     u32 *maker_code_dest_addr = (u32 *)((u32)(OSi_GetLauncherParam()) + HW_PARAM_DELIVER_ARG_MAKERCODE_OFS);
97     u32 *game_code_dest_addr = (u32 *)((u32)(OSi_GetLauncherParam()) + HW_PARAM_DELIVER_ARG_GAMECODE_OFS);
98     u16 *maker_code_src_addr = (u16 *)(HW_TWL_ROM_HEADER_BUF + 0x10);
99     u32 *game_code_src_addr = (u32 *)(HW_TWL_ROM_HEADER_BUF + 0xc);
100     *maker_code_dest_addr = (u32)*maker_code_src_addr;
101     *game_code_dest_addr = *game_code_src_addr;
102 
103     // Set the launcher parameter
104     OSi_GetLauncherParam()->body.v1.prevTitleID = *(OSTitleId *)(HW_TWL_ROM_HEADER_BUF + 0x230);
105     OSi_GetLauncherParam()->body.v1.bootTitleID = id;
106     OSi_GetLauncherParam()->body.v1.flags = *flag;
107     MI_CpuCopyFast( OSi_LAUNCHER_PARAM_MAGIC_CODE, (char *)&OSi_GetLauncherParam()->header.magicCode, OSi_LAUNCHER_PARAM_MAGIC_CODE_LEN);
108     OSi_GetLauncherParam()->header.bodyLength = sizeof(LauncherParamBody);
109     OSi_GetLauncherParam()->header.crc16 = SVC_GetCRC16( 65535, &OSi_GetLauncherParam()->body, OSi_GetLauncherParam()->header.bodyLength );
110     OSi_GetLauncherParam()->header.version = 1;
111 
112     if( id == 0 || OS_IsDeliverArgEncoded() != TRUE || OS_GetTitleIdLastEncoded() != OSi_GetLauncherParam()->body.v1.prevTitleID )
113     {
114         // If the DeliverArg is not encoded with the current application, force initialization of DeliverArg and encode
115         OSDeliverArgInfo deliverArgInfo;
116         OS_InitDeliverArgInfo( &deliverArgInfo, 0 );
117         (void)OS_EncodeDeliverArg();
118     }
119 
120     DC_FlushRange((const void *)HW_PARAM_DELIVER_ARG, HW_PARAM_DELIVER_ARG_SIZE + HW_PARAM_LAUNCH_PARAM_SIZE );
121     DC_WaitWriteBufferEmpty();
122 
123     OSi_DoHardwareReset();
124 }
125 
126 // Function that returns from the application after the application jump to the original application
127 // If there is no original application, FALSE
OS_ReturnToPrevApplication(void)128 BOOL OS_ReturnToPrevApplication( void )
129 {
130     if( s_prevTitleId != 0)
131     {
132         return OS_DoApplicationJump( s_prevTitleId, OS_APP_JUMP_NORMAL ); //Never return
133     }
134     return FALSE;
135 }
136 
IsSameTitleID(OSTitleId titleID,OSTitleId listedTitleID)137 static inline BOOL IsSameTitleID( OSTitleId titleID, OSTitleId listedTitleID )
138 {
139     if ((char)titleID == 'A')
140     {
141         // Corresponding to language code A option
142         return (listedTitleID >> 8) == (titleID >> 8);
143     }
144     else
145     {
146         return listedTitleID == titleID;
147     }
148 }
149 
150 // Get the ID that can actually be started for the given title ID
151 // If a startable ID exists, set that ID to the *bootableTitleID and return TRUE
152 // If a startable ID does not exist, return FALSE
OS_GetBootableTitleID(OSTitleId titleID,OSTitleId * bootableTitleID)153 static BOOL OS_GetBootableTitleID( OSTitleId titleID, OSTitleId *bootableTitleID )
154 {
155     const OSTitleIDList *list = (const OSTitleIDList *)HW_OS_TITLE_ID_LIST;
156     const int OS_TITLE_ID_LIST_MAX = sizeof(list->TitleID) / sizeof(*list->TitleID);
157     const int num = MATH_MIN(list->num, OS_TITLE_ID_LIST_MAX);
158     int i;
159     for (i = 0; i < num; ++i)
160     {
161         if (IsSameTitleID(titleID, list->TitleID[i]) && (list->appJumpFlag[i / 8] & (u8)(0x1 << (i % 8))))
162         {
163             *bootableTitleID = list->TitleID[i];
164             return TRUE;
165         }
166     }
167     return FALSE;
168 }
169 
170 // Whether an application has been installed that corresponds to that TitleID
OSi_CanApplicationJumpTo(OSTitleId titleID)171 BOOL OSi_CanApplicationJumpTo( OSTitleId titleID )
172 {
173     return OS_GetBootableTitleID(titleID, &titleID);
174 }
175 
176 // Wrapper for OS_SetLauncherParamAndResetHardware
OS_DoApplicationJump(OSTitleId id,OSAppJumpType jumpType)177 BOOL OS_DoApplicationJump( OSTitleId id, OSAppJumpType jumpType )
178 {
179     FSFile  file[1];
180     LauncherBootFlags flag;
181     u8 platform_code;
182     u8 bit_field;
183 
184     switch( jumpType )
185     {
186         case OS_APP_JUMP_NORMAL:
187             if( id & OSi_TITLE_ID_DATA_ONLY_FLAG_MASK )
188             {
189                 // Set so that it is not possible to jump to DataOnly items
190                 return FALSE;
191             }
192             if( id != 0 )
193             {
194                 if (!OS_GetBootableTitleID(id, &id))
195                 {
196                     return FALSE;
197                 }
198             }
199             // Set the bootType and jump
200             if( id & OSi_TITLE_ID_MEDIA_FLAG_MASK )
201             {
202                 flag.bootType = LAUNCHER_BOOTTYPE_NAND;
203             }else
204             {
205                 flag.bootType = LAUNCHER_BOOTTYPE_ROM;
206             }
207             break;
208         case OS_APP_JUMP_TMP:
209             // When you yourself are a TMP application, TMP jump is not possible
210             if( OS_IsTemporaryApplication() )
211             {
212                 OS_TPrintf("OS_DoApplicationJump error : tmp app can't jump to tmp app!\n");
213                 return FALSE;
214             }
215             // Get the TitleID from the file of OS_TMP_APP_PATH and check the allowed TMP jump bits
216             FS_InitFile( file );
217             if( !FS_OpenFileEx(file, OS_TMP_APP_PATH, FS_FILEMODE_R) )
218             {
219                 OS_TPrintf("OS_DoApplicationJump error : tmp app open error!\n");
220                 return FALSE;
221             }
222             // File size check
223             if( FS_GetFileLength( file ) > OSi_TMP_APP_SIZE_MAX )
224             {
225                 OS_TPrintf("OS_DoApplicationJump error : too large tmp app size!\n");
226                 return FALSE;
227             }
228 
229             if( !FS_SeekFile( file, 0x12, FS_SEEK_SET ) ||
230                 ( sizeof(platform_code) != FS_ReadFile( file, &platform_code, sizeof(platform_code) ) ) ||
231                 !FS_SeekFile( file, 0x1d, FS_SEEK_SET ) ||
232                 ( sizeof(bit_field) != FS_ReadFile( file, &bit_field, sizeof(bit_field) ) )
233             )
234             {
235                 OS_TPrintf("OS_DoApplicationJump error : tmp app read error!\n");
236                 (void)FS_CloseFile(file);
237                 return FALSE;
238             }
239 
240             if( !( bit_field & 0x2 ) )
241             {
242                 OS_TPrintf("OS_DoApplicationJump error : tmp jump bit is not enabled!\n");
243                 (void)FS_CloseFile(file);
244                 return FALSE;
245             }
246             flag.bootType = LAUNCHER_BOOTTYPE_TEMP;
247             // 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
248             if( platform_code & 0x2 )
249             {
250                 if( !FS_SeekFile( file, 0x0230, FS_SEEK_SET ) ||
251                     ( sizeof(id) != FS_ReadFile( file, &id, sizeof(id) ) )
252                 )
253                 {
254                     OS_TPrintf("OS_DoApplicationJump error : tmp app read error!\n");
255                     (void)FS_CloseFile(file);
256                     return FALSE;
257                 }
258             }else
259             {
260                 id = 0x1;
261             }
262             (void)FS_CloseFile(file);
263             break;
264         default:
265             return FALSE;
266     }
267 
268     if ( PMi_TryLockForReset() == FALSE )
269     {
270         return FALSE;
271     }
272 
273     // Shared configurations
274     flag.isValid = TRUE;
275     flag.isLogoSkip = TRUE;
276     flag.isInitialShortcutSkip = FALSE;
277     flag.isAppLoadCompleted = FALSE;
278     flag.isAppRelocate = FALSE;
279     flag.rsv = 0;
280 
281     OS_SetLauncherParamAndResetHardware( id, &flag ); // never return.
282     return TRUE;
283 }
284 
285 /* The code above is located in the TWL extended memory region */
286 #ifdef    SDK_TWL
287 #include  <twl/ltdmain_end.h>
288 #endif
289 
290 /*---------------------------------------------------------------------------*
291   Name:         OS_JumpToSystemMenu
292 
293   Description:  Run a hardware reset and jump to the system menu
294 
295   Arguments:    None.
296 
297   Returns:      FALSE ... Application jump failed for some reason
298                 * If the process was successful, a reset process occurred during this function so TRUE is not returned
299 
300  *---------------------------------------------------------------------------*/
OS_JumpToSystemMenu(void)301 BOOL OS_JumpToSystemMenu( void )
302 {
303     BOOL result = FALSE;
304 #ifdef SDK_TWL
305     if( OS_IsRunOnTwl() )
306     {
307         // ---- Application Jump with id==0
308         //      means to jump to system menu.
309         result = OS_DoApplicationJump( 0, OS_APP_JUMP_NORMAL );
310     }
311     else
312 #endif
313     {
314         OS_Warning("This Hardware don't support this funciton");
315     }
316     return result;
317 }
318 
319 /*---------------------------------------------------------------------------*
320   Name:         OS_RebootSystem
321 
322   Description:  Runs a hardware reset and restarts itself.
323 
324   Arguments:    None.
325 
326   Returns:      FALSE      Run on NITRO, or failure in restarting
327                 * If the process was successful, a reset occurred during this function so TRUE is not returned
328 
329  *---------------------------------------------------------------------------*/
OS_RebootSystem(void)330 BOOL OS_RebootSystem( void )
331 {
332 #ifdef SDK_TWL
333     if( OS_IsRunOnTwl() )
334     {
335         if( OS_IsTemporaryApplication() )
336         {
337             OS_TPrintf("OS_RebootSystem error : tmp app can't execute this function\n");
338             return FALSE;
339         }
340         // Application jump to self
341         return OS_DoApplicationJump( OS_GetTitleId(), OS_APP_JUMP_NORMAL );
342     }
343     else
344 #endif
345     {
346         OS_Warning("This Hardware don't support this funciton");
347         return FALSE;
348     }
349 }
350 
351 /*---------------------------------------------------------------------------*
352   Name:         OS_IsRebooted
353 
354   Description:  Checks whether a restart was applied using OS_RebootSystem
355 
356   Arguments:    None.
357 
358   Returns:      TRUE   Restart was applied more than one time
359                 FALSE  First startup
360  *---------------------------------------------------------------------------*/
OS_IsRebooted(void)361 BOOL OS_IsRebooted( void )
362 {
363     BOOL result = FALSE;
364 #ifdef SDK_TWL
365     if( OS_IsRunOnTwl() )
366     {
367         if( OS_GetTitleId() == s_prevTitleId )
368         {
369             result = TRUE;
370         }
371     }
372 #endif
373     return result;
374 }
375 
376 /*---------------------------------------------------------------------------*
377   Name:         OS_IsTemporaryApplication
378 
379   Description:  Checks whether self is a TMP application.
380 
381   Arguments:    None.
382 
383   Returns:      TRUE    TMP application
384                 FALSE  Other than TMP applications
385  *---------------------------------------------------------------------------*/
OS_IsTemporaryApplication(void)386 BOOL OS_IsTemporaryApplication(void)
387 {
388 #ifdef SDK_TWL
389     static BOOL isChecked = FALSE, isTmpApp = FALSE;
390     if( OS_IsRunOnTwl() )
391     {
392         if( isChecked == FALSE ) /* If already checked, flow previous results */
393         {
394             if( 0 == STD_CompareNString( OS_GetBootSRLPath(), OSi_TMP_APP_PATH_RAW, OSi_TMP_APP_PATH_RAW_LENGTH ) )
395             {
396                 isTmpApp = TRUE;
397             }
398             else
399             {
400                 isTmpApp = FALSE;
401             }
402             isChecked = TRUE;
403         }
404         return isTmpApp;
405     }
406 #endif
407     return FALSE;
408 }
409 
410 #else // SDK_ARM9
411     //----------------------------------------------------------------
412     // For ARM7
413 
OSi_IsValidLauncherParam(void)414 static BOOL OSi_IsValidLauncherParam( void )
415 {
416     return ( STD_StrNCmp( (const char *)&OSi_GetLauncherParam()->header.magicCode,
417                              OSi_LAUNCHER_PARAM_MAGIC_CODE,
418                              OSi_LAUNCHER_PARAM_MAGIC_CODE_LEN ) == 0 ) &&
419     ( OSi_GetLauncherParam()->header.bodyLength > 0 ) &&
420     ( OSi_GetLauncherParam()->header.crc16 == SVC_GetCRC16( 65535, &OSi_GetLauncherParam()->body, OSi_GetLauncherParam()->header.bodyLength ) );
421 }
422 
OSi_IsEnableJTAG(void)423 static BOOL OSi_IsEnableJTAG( void )
424 {
425     // If SCFG register is invalid, the SCFG register value becomes "0". Check the value retracted to WRAM.
426     u8 value = (u8)(( reg_SCFG_EXT & REG_SCFG_EXT_CFG_MASK ) ?
427                     ( reg_SCFG_JTAG & REG_SCFG_JTAG_CPUJE_MASK ) :
428                     ( *(u8 *)HWi_WSYS09_ADDR & HWi_WSYS09_JTAG_CPUJE_MASK ));
429     return value ? TRUE : FALSE;
430 }
431 
432 // Launcher parameter lead and determine hot/cold boot
433 // Return TRUE if launcher parameter is valid; FALSE if invalid
434 // If the launcher parameter in LauncherParam is valid, that launcher parameter is stored
435 // TRUE if hot boot in isHotstart; False is stored if a cold boot.
OS_ReadLauncherParameter(LauncherParam * buf,BOOL * isHotstart)436 BOOL OS_ReadLauncherParameter( LauncherParam *buf, BOOL *isHotstart )
437 {
438     if( !OSi_GetNandFirmResetParam()->isValid ) {
439         *(u8 *)OSi_GetNandFirmResetParam() = (u8)MCU_GetFreeRegister( OS_MCU_RESET_VALUE_OFS );
440         OSi_GetNandFirmResetParam()->isValid = 1;
441     }
442 
443     // Hot/cold boot determination
444     // If "HOTBT flag of a microcomputer free register = 0," cold boot
445     if( !OSi_GetNandFirmResetParam()->isHotStart ) {
446         *isHotstart = FALSE;
447     }else {
448         *isHotstart = TRUE;
449         // Determine launcher parameter validity
450         if(  OSi_IsValidLauncherParam() &&
451             !OSi_GetNandFirmResetParam()->isResetSW
452         ) {
453             // If launcher parameter is valid, copy to buf
454             MI_CpuCopy32 ( OSi_GetLauncherParam(), buf, sizeof(LauncherParam) );
455             return TRUE;
456         }else {
457             // Else, clear the transfer destination buffer
458             MI_CpuClear32 ( buf, sizeof(LauncherParam) );
459         }
460     }
461     return FALSE;
462 }
463 
464 #endif // SDK_ARM9
465