1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - FS - libraries
3   File:     fs_overlay.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-10-02#$
14   $Rev: 8829 $
15   $Author: yosizaki $
16 
17  *---------------------------------------------------------------------------*/
18 
19 
20 #include <nitro/misc.h>
21 #include <nitro/types.h>
22 #include <nitro/os.h>
23 #include <nitro/mi.h>
24 
25 #include <nitro/fs.h>
26 #include <nitro/math/dgt.h>
27 
28 
29 #include "../include/util.h"
30 #include "../include/rom.h"
31 
32 
33 /*---------------------------------------------------------------------------*/
34 /* Declarations */
35 
36 // Destructor callback.
37 typedef void (*MWI_DESTRUCTOR_FUNC) (void *p_this);
38 
39 // Destructor chain (Each element is prepared by the global object itself)
40 typedef struct MWiDestructorChain
41 {
42     struct MWiDestructorChain  *next;
43     MWI_DESTRUCTOR_FUNC         dtor;
44     void                       *obj;
45 }
46 MWiDestructorChain;
47 
48 
49 /*---------------------------------------------------------------------------*/
50 /* Constants */
51 
52 /*
53 #define OVERLAYPROC_ARM9 0
54 #define OVERLAYPROC_ARM7 1
55 */
56 typedef enum
57 {
58     OVERLAYPROC_ARM9,
59     OVERLAYPROC_ARM7
60 }
61 OVERLAYPROC;
62 
63 #define FS_OVERLAY_FLAG_COMP    0x0001
64 #define FS_OVERLAY_FLAG_AUTH    0x0002
65 #define FS_OVERLAY_DIGEST_SIZE  MATH_SHA1_DIGEST_SIZE
66 
67 // Digest of the overall overlay table
68 extern u8 SDK_OVERLAYTABLE_DIGEST[];
69 #ifdef SDK_TWL
70 extern u8 SDK_LTDOVERLAYTABLE_DIGEST[];
71 #else
72 #define SDK_LTDOVERLAYTABLE_DIGEST NULL
73 #endif // SDK_TWL
74 // Overlay digest table (First half: NTR; Second half: LTD)
75 extern u8 SDK_OVERLAY_DIGEST[];
76 extern u8 SDK_OVERLAY_DIGEST_END[];
77 // Total count of the overlay
78 extern u8 SDK_OVERLAY_NUMBER[];
79 #ifdef SDK_TWL
80 extern u8 SDK_LTDOVERLAY_NUMBER[];
81 #else
82 #define SDK_LTDOVERLAY_NUMBER      0
83 #endif // SDK_TWL
84 #define FS_OVERLAY_NTR_TOTAL    (u32)SDK_OVERLAY_NUMBER
85 #define FS_OVERLAY_TWL_TOTAL    (u32)SDK_LTDOVERLAY_NUMBER
86 
87 
88 // Key constant for generating a digest with the same value as compstatic
89 static const u8 fsi_def_digest_key[64] =
90 {
91     0x21, 0x06, 0xc0, 0xde,
92     0xba, 0x98, 0xce, 0x3f,
93     0xa6, 0x92, 0xe3, 0x9d,
94     0x46, 0xf2, 0xed, 0x01,
95 
96     0x76, 0xe3, 0xcc, 0x08,
97     0x56, 0x23, 0x63, 0xfa,
98     0xca, 0xd4, 0xec, 0xdf,
99     0x9a, 0x62, 0x78, 0x34,
100 
101     0x8f, 0x6d, 0x63, 0x3c,
102     0xfe, 0x22, 0xca, 0x92,
103     0x20, 0x88, 0x97, 0x23,
104     0xd2, 0xcf, 0xae, 0xc2,
105 
106     0x32, 0x67, 0x8d, 0xfe,
107     0xca, 0x83, 0x64, 0x98,
108     0xac, 0xfd, 0x3e, 0x37,
109     0x87, 0x46, 0x58, 0x24,
110 };
111 
112 
113 /*---------------------------------------------------------------------------*/
114 /* Variables */
115 
116 // Global destructor chain
117 // Added at the top, so that they will be called in the reverse order of the ctor.
118 extern MWiDestructorChain *__global_destructor_chain;
119 
120 // Structure for overlay information management
121 typedef struct FSOverlaySource
122 {
123     // Archive of the overlay storage source
124     FSArchive      *arc;
125     // Overlay table pointer explicitly attached
126     CARDRomRegion   ovt9;
127     CARDRomRegion   ovt7;
128     // Key constant for digest generation
129     const void     *digest_key_ptr;
130     u32             digest_key_len;
131 }
132 FSOverlaySource;
133 
134 static FSOverlaySource  FSiOverlayContext;
135 
136 
137 /*---------------------------------------------------------------------------*/
138 /* functions */
139 
140 #if defined(SDK_FINALROM)
141 
142 // Invalidate the call itself of the call for debugger for FINALROM
143 #define FSi_RegisterOverlayToDebugger(ovi)      (void)0
144 #define FSi_UnregisterOverlayToDebugger(ovi)    (void)0
145 
146 #else // defined (SDK_FINALROM)
147 
148 int     _ISDbgLib_RegistOverlayInfo(OVERLAYPROC nProc, u32 nAddrRAM, u32 nAddrROM, u32 nSize);
149 int     _ISTDbgLib_RegistOverlayInfoByAddr(OVERLAYPROC nProc, u32 nAddrRAM, u32 nSlot, u32 nAddrROM, u32 nSize);
150 int     _ISDbgLib_UnregistOverlayInfo(OVERLAYPROC nProc, u32 nAddrRAM, u32 nSize);
151 int     _ISTDbgLib_UnregistOverlayInfoByAddr(OVERLAYPROC nProc, u32 nAddrRAM, u32 nSize);
152 
DUMMY_REGISTER(OVERLAYPROC nProc,u32 nAddrRAM,u32 nAddrROM,u32 nSize)153 static int DUMMY_REGISTER(OVERLAYPROC nProc, u32 nAddrRAM, u32 nAddrROM, u32 nSize)
154 {
155     (void)nProc;
156     (void)nAddrRAM;
157     (void)nAddrROM;
158     (void)nSize;
159     return 0;
160 }
DUMMY_UNREGISTER(OVERLAYPROC nProc,u32 nAddrRAM,u32 nSize)161 static int DUMMY_UNREGISTER(OVERLAYPROC nProc, u32 nAddrRAM, u32 nSize)
162 {
163     (void)nProc;
164     (void)nAddrRAM;
165     (void)nSize;
166     return 0;
167 }
168 
169 #if defined(SDK_NITRO)
170 
171 // When in NITRO-compatible mode, use the dedicated call when running the IS-NITRO-DEBUGGER
172 #define FS_REGISTER_OVERLAY_INFO(nProc, nAddrRAM, nAddrROM, nSize)  ((OS_GetConsoleType() & OS_CONSOLE_ISDEBUGGER) ? _ISDbgLib_RegistOverlayInfo(nProc, nAddrRAM, nAddrROM, nSize) : \
173 DUMMY_REGISTER(nProc, nAddrRAM, nAddrROM, nSize))
174 #define FS_UNREGISTER_OVERLAY_INFO(nProc, nAddrRAM, nSize)          ((OS_GetConsoleType() & OS_CONSOLE_ISDEBUGGER) ? _ISDbgLib_UnregistOverlayInfo(nProc, nAddrRAM, nSize) : \
175 DUMMY_UNREGISTER(nProc, nAddrRAM, nSize))
176 
177 #elif defined(SDK_TWLLTD) && defined(SDK_TWL)/*Just in case*/
178 
179 // When in TWL-dedicated mode, use the dedicated call when running the IS-TWL-DEBUGGER
180 #define FS_REGISTER_OVERLAY_INFO(nProc, nAddrRAM, nAddrROM, nSize)  ((OS_GetConsoleType() & OS_CONSOLE_TWLDEBUGGER) ? _ISTDbgLib_RegistOverlayInfoByAddr(nProc, nAddrRAM, 0, nAddrROM, nSize) : \
181 DUMMY_REGISTER(nProc, nAddrRAM, nAddrROM, nSize))
182 #define FS_UNREGISTER_OVERLAY_INFO(nProc, nAddrRAM, nSize)          ((OS_GetConsoleType() & OS_CONSOLE_TWLDEBUGGER) ? _ISTDbgLib_UnregistOverlayInfoByAddr(nProc, nAddrRAM, nSize) : \
183 DUMMY_UNREGISTER(nProc, nAddrRAM, nSize))
184 
185 #elif defined(SDK_TWLHYB) && defined(SDK_TWL)/*Just in case*/
186 
187 // When in HYBRID mode, it is necessary to use calls accordingly, by dynamically determining the environment
188 #define FS_REGISTER_OVERLAY_INFO(nProc, nAddrRAM, nAddrROM, nSize)  ((OS_GetConsoleType() & OS_CONSOLE_TWLDEBUGGER) ? _ISTDbgLib_RegistOverlayInfoByAddr(nProc, nAddrRAM, 0, nAddrROM, nSize) : \
189 (OS_GetConsoleType() & OS_CONSOLE_ISDEBUGGER) ? _ISDbgLib_RegistOverlayInfo(nProc, nAddrRAM, nAddrROM, nSize) : DUMMY_REGISTER(nProc, nAddrRAM, nAddrROM, nSize))
190 #define FS_UNREGISTER_OVERLAY_INFO(nProc, nAddrRAM, nSize)          ((OS_GetConsoleType() & OS_CONSOLE_TWLDEBUGGER) ? _ISTDbgLib_UnregistOverlayInfoByAddr(nProc, nAddrRAM, nSize) : \
191 (OS_GetConsoleType() & OS_CONSOLE_ISDEBUGGER) ? _ISDbgLib_UnregistOverlayInfo(nProc, nAddrRAM, nSize) : DUMMY_UNREGISTER(nProc, nAddrRAM, nSize))
192 
193 #else
194 
195 // Unexpected environment, such as the defined rules of the build option being changed
196 SDK_ERR("unsupported platform!\n")
197 
198 #endif
199 
200 /*---------------------------------------------------------------------------*
201   Name:         FSi_RegisterOverlayToDebugger
202 
203   Description:  Notifies the debugger that the overlay was loaded on the memory
204 
205   Arguments:    ovi:              FSOverlayInfo structure that stores the overlay information
206 
207   Returns:      None.
208  *---------------------------------------------------------------------------*/
FSi_RegisterOverlayToDebugger(const FSOverlayInfo * ovi)209 SDK_INLINE void FSi_RegisterOverlayToDebugger(const FSOverlayInfo *ovi)
210 {
211     const OVERLAYPROC   proc = (ovi->target == MI_PROCESSOR_ARM9) ? OVERLAYPROC_ARM9 : OVERLAYPROC_ARM7;
212     const u32           address = (u32)FS_GetOverlayAddress(ovi);
213     const u32           offset = ovi->file_pos.offset;
214     const u32           length = FS_GetOverlayImageSize(ovi);
215     (void)FS_REGISTER_OVERLAY_INFO(proc, address, offset, length);
216 }
217 
218 /*---------------------------------------------------------------------------*
219   Name:         FSi_UnregisterOverlayToDebugger
220 
221   Description:  Notifies the debugger that the overlay was unloaded from the memory
222 
223   Arguments:    ovi:              FSOverlayInfo structure that stores the overlay information
224 
225   Returns:      None.
226  *---------------------------------------------------------------------------*/
FSi_UnregisterOverlayToDebugger(const FSOverlayInfo * ovi)227 SDK_INLINE void FSi_UnregisterOverlayToDebugger(const FSOverlayInfo *ovi)
228 {
229     const OVERLAYPROC   proc = (ovi->target == MI_PROCESSOR_ARM9) ? OVERLAYPROC_ARM9 : OVERLAYPROC_ARM7;
230     const u32           address = (u32)FS_GetOverlayAddress(ovi);
231     const u32           length = FS_GetOverlayImageSize(ovi);
232     (void)FS_UNREGISTER_OVERLAY_INFO(proc, address, length);
233 }
234 #endif // defined (SDK_FINALROM)
235 
236 /*---------------------------------------------------------------------------*
237   Name:         __register_global_object
238 
239   Description:  Process system definition function
240                 Insert one chain at the front of the global destructor chain
241 
242   Arguments:    obj:              Pointer to the object to destroy
243                 dtor:             Destructor routine
244                 chain:            Pointer to the chain structure
245                                  (Global object provides one for each.)
246 
247   Returns:      None.
248  *---------------------------------------------------------------------------*/
249 void    __register_global_object(void *obj, MWI_DESTRUCTOR_FUNC dtor, MWiDestructorChain * chain);
250 /*
251 {
252 	chain->next = __global_destructor_chain;
253 	chain->dtor = dtor;
254 	chain->obj = obj;
255 	__global_destructor_chain = chain;
256 }
257 */
258 
259 /*---------------------------------------------------------------------------*
260   Name:         FSi_InitOverlay
261 
262   Description:  Initializes overlay management information
263 
264   Arguments:    None.
265 
266   Returns:      None.
267  *---------------------------------------------------------------------------*/
FSi_InitOverlay(void)268 void FSi_InitOverlay(void)
269 {
270     // If downloaded child device, overlay is invalid
271     if (OS_GetBootType() == OS_BOOTTYPE_DOWNLOAD_MB)
272     {
273         FSiOverlayContext.ovt9.offset = (u32)~0;
274         FSiOverlayContext.ovt9.length = 0;
275         FSiOverlayContext.ovt7.offset = (u32)~0;
276         FSiOverlayContext.ovt7.length = 0;
277     }
278     else
279     {
280         FSiOverlayContext.ovt9.offset = 0;
281         FSiOverlayContext.ovt9.length = 0;
282         FSiOverlayContext.ovt7.offset = 0;
283         FSiOverlayContext.ovt7.length = 0;
284     }
285     FSiOverlayContext.digest_key_ptr = fsi_def_digest_key;
286     FSiOverlayContext.digest_key_len = sizeof(fsi_def_digest_key);
287     FSiOverlayContext.arc = FS_FindArchive("rom", 3);
288 }
289 
290 /*---------------------------------------------------------------------------*
291   Name:         FSi_GetOverlayBinarySize
292 
293   Description:  Get file-size which contains an image of overlay module.
294 
295   Arguments:    p_ovi:       pointer to FSOverlayInfo
296 
297   Returns:      File size of overlay.
298  *---------------------------------------------------------------------------*/
FSi_GetOverlayBinarySize(const FSOverlayInfo * p_ovi)299 static u32 FSi_GetOverlayBinarySize(const FSOverlayInfo *p_ovi)
300 {
301     u32     size = (((p_ovi->header.flag & FS_OVERLAY_FLAG_COMP) != 0)
302                     ? p_ovi->header.compressed : p_ovi->header.ram_size);
303     return size;
304 }
305 
306 /*---------------------------------------------------------------------------*
307   Name:         FS_ClearOverlayImage
308 
309   Description:  0-clear the memory where FS_GetOverlayAddress() points,
310                 and invalidate its region of cache.
311                 This function is called in the FS_LoadOverlayImage function.
312 
313   Arguments:    p_ovi:       pointer to FSOverlayInfo
314 
315   Returns:      None.
316  *---------------------------------------------------------------------------*/
FS_ClearOverlayImage(FSOverlayInfo * p_ovi)317 void FS_ClearOverlayImage(FSOverlayInfo *p_ovi)
318 {
319     u8     *const addr = FS_GetOverlayAddress(p_ovi);
320     const u32 image_size = FS_GetOverlayImageSize(p_ovi);
321     const u32 total_size = FS_GetOverlayTotalSize(p_ovi);
322 #if defined(SDK_ARM9)
323     IC_InvalidateRange(addr, total_size);
324     DC_InvalidateRange(addr, total_size);
325 #endif
326     MI_CpuFill8(addr + image_size, 0, total_size - image_size);
327 }
328 
329 
330 #if defined(FS_IMPLEMENT)
331 
332 /*---------------------------------------------------------------------------*
333   Name:         FS_GetOverlayFileID
334 
335   Description:  Gets file-id which contains an image of overlay module.
336 
337   Arguments:    p_ovi:       pointer to FSOverlayInfo
338 
339   Returns:      File-id of overlay.
340  *---------------------------------------------------------------------------*/
FS_GetOverlayFileID(const FSOverlayInfo * p_ovi)341 FSFileID FS_GetOverlayFileID(const FSOverlayInfo *p_ovi)
342 {
343     FSFileID ret;
344     ret.arc = FSiOverlayContext.arc;
345     ret.file_id = p_ovi->header.file_id;
346     return ret;
347 }
348 
349 /*---------------------------------------------------------------------------*
350   Name:         FS_LoadOverlayInfo
351 
352   Description:  Loads the information for specified overlay module.
353 
354   Arguments:    p_ovi:       pointer to destination FSOverlayInfo
355                 target:      ARM9 or ARM7
356                 id:          overlay-id (FS_OVERLAY_ID(overlay-name))
357 
358   Returns:      If succeeded, TRUE.
359  *---------------------------------------------------------------------------*/
FS_LoadOverlayInfo(FSOverlayInfo * p_ovi,MIProcessor target,FSOverlayID id)360 BOOL FS_LoadOverlayInfo(FSOverlayInfo *p_ovi, MIProcessor target, FSOverlayID id)
361 {
362     BOOL                    retval = FALSE;
363     const u32               pos = (u32)id * sizeof(FSOverlayInfoHeader);
364     const CARDRomRegion    *pr = (target == MI_PROCESSOR_ARM9) ?
365                                   &FSiOverlayContext.ovt9 : &FSiOverlayContext.ovt7;
366 #if !defined(SDK_NITRO)
367     // Cannot get the overlay for the TWL mode if not in the TWL environment
368     if ((id >= FS_OVERLAY_NTR_TOTAL) && !OS_IsRunOnTwl())
369     {
370         OS_TWarning("TWL-overlay is not available on NTR-mode.\n");
371     }
372     else
373 #endif // !defined(SDK_NITRO)
374     {
375         if (pr->offset)
376         {
377             if (pos < pr->length)
378             {
379                 FSFile  file[1];
380                 FS_InitFile(file);
381                 MI_CpuCopy8((const void *)(pr->offset + pos), p_ovi, sizeof(FSOverlayInfoHeader));
382                 {
383                     {
384                         p_ovi->target = target;
385                         if (FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
386                         {
387                             p_ovi->file_pos.offset = FS_GetFileImageTop(file);
388                             p_ovi->file_pos.length = FS_GetFileLength(file);
389                             (void)FS_CloseFile(file);
390                             retval = TRUE;
391                         }
392                     }
393                 }
394             }
395         }
396         else
397         {
398             pr = (target == MI_PROCESSOR_ARM9) ?
399                   CARD_GetRomRegionOVT(MI_PROCESSOR_ARM9) :
400                   CARD_GetRomRegionOVT(MI_PROCESSOR_ARM7);
401             if (pos < pr->length)
402             {
403                 FSFile  file[1];
404                 FS_InitFile(file);
405                 if (FS_CreateFileFromRom(file, pr->offset + pos, pr->offset + pr->length))
406                 {
407                     if (FS_ReadFile(file, p_ovi, sizeof(FSOverlayInfoHeader)) !=
408                         sizeof(FSOverlayInfoHeader))
409                     {
410                         (void)FS_CloseFile(file);
411                     }
412                     else
413                     {
414                         (void)FS_CloseFile(file);
415                         p_ovi->target = target;
416                         if (FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
417                         {
418                             p_ovi->file_pos.offset = FS_GetFileImageTop(file);
419                             p_ovi->file_pos.length = FS_GetFileLength(file);
420                             (void)FS_CloseFile(file);
421                             retval = TRUE;
422                         }
423                     }
424                 }
425             }
426         }
427     }
428     return retval;
429 }
430 
431 /*---------------------------------------------------------------------------*
432   Name:         FS_LoadOverlayImageAsync
433 
434   Description:  Load the image of overlay module without 'static initializer'.
435                 By this call, the memory where FS_GetOverlayAddress() points
436                 is set to rare initial status.
437 
438   Arguments:    p_ovi:       pointer to FSOverlayInfo
439                 p_file:      pointer to FSFile for asynchronous reading
440 
441   Returns:      If succeeded, TRUE.
442  *---------------------------------------------------------------------------*/
FS_LoadOverlayImageAsync(FSOverlayInfo * p_ovi,FSFile * p_file)443 BOOL FS_LoadOverlayImageAsync(FSOverlayInfo *p_ovi, FSFile *p_file)
444 {
445     BOOL    retval = FALSE;
446     FS_InitFile(p_file);
447     if (FS_OpenFileFast(p_file, FS_GetOverlayFileID(p_ovi)))
448     {
449         s32     size = (s32)FSi_GetOverlayBinarySize(p_ovi);
450         FS_ClearOverlayImage(p_ovi);
451         if (FS_ReadFileAsync(p_file, FS_GetOverlayAddress(p_ovi), size) == size)
452         {
453             retval = TRUE;
454         }
455         else
456         {
457             (void)FS_CloseFile(p_file);
458         }
459     }
460     return retval;
461 }
462 
463 /*---------------------------------------------------------------------------*
464   Name:         FS_LoadOverlayImage
465 
466   Description:  Load the image of overlay module without 'static initializer'.
467                 By this call, the memory where FS_GetOverlayAddress() points
468                 is set to rare initial status.
469 
470   Arguments:    p_ovi:       pointer to FSOverlayInfo
471 
472   Returns:      If succeeded, TRUE.
473  *---------------------------------------------------------------------------*/
FS_LoadOverlayImage(FSOverlayInfo * p_ovi)474 BOOL FS_LoadOverlayImage(FSOverlayInfo *p_ovi)
475 {
476     BOOL    retval = FALSE;
477     FSFile  p_file[1];
478     FS_InitFile(p_file);
479     if (FS_OpenFileFast(p_file, FS_GetOverlayFileID(p_ovi)))
480     {
481         s32     size = (s32)FSi_GetOverlayBinarySize(p_ovi);
482         FS_ClearOverlayImage(p_ovi);
483         if (FS_ReadFile(p_file, FS_GetOverlayAddress(p_ovi), size) == size)
484         {
485             retval = TRUE;
486         }
487         (void)FS_CloseFile(p_file);
488     }
489     return retval;
490 }
491 
492 #else
493 
494 /*---------------------------------------------------------------------------*
495   Name:         FS_LoadOverlayInfo
496 
497   Description:  Loads the information for specified overlay module.
498 
499   Arguments:    p_ovi:       pointer to destination FSOverlayInfo
500                 target:      ARM9 or ARM7
501                 id:          overlay-id (FS_OVERLAY_ID(overlay-name))
502 
503   Returns:      If succeeded, TRUE.
504  *---------------------------------------------------------------------------*/
FS_LoadOverlayInfo(FSOverlayInfo * p_ovi,MIProcessor target,FSOverlayID id)505 BOOL FS_LoadOverlayInfo(FSOverlayInfo *p_ovi, MIProcessor target, FSOverlayID id)
506 {
507     BOOL                    retval = FALSE;
508     const u32               pos = (u32)id * sizeof(FSOverlayInfoHeader);
509     const CARDRomRegion    *pr;
510     pr = (target == MI_PROCESSOR_ARM9) ?
511          &FSiOverlayContext.ovt9 :
512          &FSiOverlayContext.ovt7;
513     if (pr->offset)
514     {
515         if (pos < pr->length)
516         {
517             MI_CpuCopy8((const void *)(pr->offset + pos), p_ovi, sizeof(FSOverlayInfoHeader));
518             p_ovi->target = target;
519             {
520                 FSFile  file[1];
521                 FS_InitFile(file);
522                 if (FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
523                 {
524                     p_ovi->file_pos.offset = FS_GetFileImageTop(file);
525                     p_ovi->file_pos.length = FS_GetLength(file);
526                     (void)FS_CloseFile(file);
527                     retval = TRUE;
528                 }
529             }
530         }
531     }
532     else
533     {
534         pr = CARD_GetRomRegionOVT(target);
535         if (pos < pr->length)
536         {
537             FSi_ReadRomDirect((const void*)(pr->offset + pos), p_ovi, sizeof(FSOverlayInfoHeader));
538             p_ovi->target = target;
539             {
540                 retval = TRUE;
541             }
542         }
543     }
544     return retval;
545 }
546 
547 /*---------------------------------------------------------------------------*
548   Name:         FS_LoadOverlayImage
549 
550   Description:  Load the image of overlay module without 'static initializer'.
551                 By this call, the memory where FS_GetOverlayAddress() points
552                 is set to rare initial status.
553 
554   Arguments:    p_ovi:       pointer to FSOverlayInfo
555 
556   Returns:      If succeeded, TRUE.
557  *---------------------------------------------------------------------------*/
FS_LoadOverlayImage(FSOverlayInfo * p_ovi)558 BOOL FS_LoadOverlayImage(FSOverlayInfo *p_ovi)
559 {
560     BOOL    retval = FALSE;
561     const CARDRomRegion    *fat = CARD_GetRomRegionFAT();
562     u32     pos = p_ovi->header.file_id * sizeof(FSArchiveFAT);
563     if (pos < fat->length)
564     {
565         FSArchiveFAT    fat_info;
566         FSi_ReadRomDirect((const void*)(fat->offset + pos), &fat_info, sizeof(FSArchiveFAT));
567         FS_ClearOverlayImage(p_ovi);
568         FSi_ReadRomDirect((const void*)(fat_info.top), p_ovi->header.ram_address, fat_info.bottom - fat_info.top);
569         retval = TRUE;
570     }
571     return retval;
572 }
573 
574 #endif /* FS_IMPLEMENT */
575 
576 /*---------------------------------------------------------------------------*
577   Name:         FSi_CompareOverlayDigest
578 
579   Description:  Compares overlay digest values
580 
581   Arguments:    spec_digest:       Comparison source digest value
582                 src:               Comparison target data.
583                 len:               src byte size.
584                 table_mode:        TRUE if calculating the overlay table
585 
586   Returns:      TRUE if comparison matches. Otherwise, FALSE.
587  *---------------------------------------------------------------------------*/
FSi_CompareDigest(const u8 * spec_digest,void * src,int len,BOOL table_mode)588 static BOOL FSi_CompareDigest(const u8 *spec_digest, void *src, int len, BOOL table_mode)
589 {
590     int     i;
591     u8      digest[FS_OVERLAY_DIGEST_SIZE];
592     u8      digest_key[64];
593 
594     MI_CpuClear8(digest, sizeof(digest));
595     MI_CpuCopy8(FSiOverlayContext.digest_key_ptr, digest_key,
596                 FSiOverlayContext.digest_key_len);
597     // If possible, use the high-speed SVC function
598 #ifdef SDK_TWL
599     if (!table_mode && OS_IsRunOnTwl())
600     {
601         SVC_CalcHMACSHA1(digest, src, (u32)len, digest_key, FSiOverlayContext.digest_key_len);
602     }
603     else
604 #endif
605     {
606         // It is necessary to consider the ID portion 0 for the digest of the overlay table
607         int     bak_ovt_mode = FALSE;
608         if (table_mode)
609         {
610             bak_ovt_mode = MATHi_SetOverlayTableMode(TRUE);
611         }
612         MATH_CalcHMACSHA1(digest, src, (u32)len, digest_key, FSiOverlayContext.digest_key_len);
613         if (table_mode)
614         {
615             (void)MATHi_SetOverlayTableMode(bak_ovt_mode);
616         }
617     }
618     for (i = 0; i < sizeof(digest); i += sizeof(u32))
619     {
620         if (*(const u32 *)(digest + i) != *(const u32 *)(spec_digest + i))
621         {
622             break;
623         }
624     }
625     return (i == sizeof(digest));
626 }
627 
628 /*---------------------------------------------------------------------------*
629   Name:         FS_StartOverlay
630 
631   Description:  Execute 'static initializer'.
632                 This function needs:
633                     the memory where FS_GetOverlayAddress() points is
634                     set by data which FS_LoadOverlayImage() makes.
635 
636   Arguments:    p_ovi:       pointer to FSOverlayInfo
637 
638   Returns:      None.
639  *---------------------------------------------------------------------------*/
FS_StartOverlay(FSOverlayInfo * p_ovi)640 void FS_StartOverlay(FSOverlayInfo *p_ovi)
641 {
642     u32     rare_size = FSi_GetOverlayBinarySize(p_ovi);
643 
644 #ifdef SDK_TWL
645     // Because there is the possibility that the application that mistakenly referenced a sampling demo prior to TWL-SDK5.0FC has an overlay that would damage the LTDMAIN, raise user caution by outputting a warning for such cases.
646     //
647     //
648     // However, because this is useful with HYBRID running in NTR, after establishing a short transition period, terminate the warning.
649     //
650     {
651         extern const u8     SDK_LTDAUTOLOAD_LTDMAIN_START[];
652         extern const u8     SDK_LTDAUTOLOAD_LTDMAIN_END[];
653         extern const u8     SDK_LTDAUTOLOAD_LTDMAIN_BSS_END[];
654         if ((p_ovi->header.ram_address >= SDK_LTDAUTOLOAD_LTDMAIN_START) &&
655             (p_ovi->header.ram_address < SDK_LTDAUTOLOAD_LTDMAIN_BSS_END) &&
656             OS_IsRunOnTwl())
657         {
658             static BOOL once = FALSE;
659             if (!once)
660             {
661                 OS_TWarning("specified overlay(%d) might have destroyed LTDMAIN segment!\n"
662                             "(please move LTDMAIN after overlay(%d))",
663                             p_ovi->header.id, p_ovi->header.id);
664                 once = TRUE;
665             }
666         }
667     }
668 #endif
669 
670     // If authentication of the overlay fails in storage other than ROM, invalidate the image.
671     if (OS_GetBootType() != OS_BOOTTYPE_ROM)
672     {
673         BOOL    ret = FALSE;
674 
675         if ((p_ovi->header.flag & FS_OVERLAY_FLAG_AUTH) != 0)
676         {
677             const u32 odt_max =
678                 (u32)((SDK_OVERLAY_DIGEST_END - SDK_OVERLAY_DIGEST) / FS_OVERLAY_DIGEST_SIZE);
679             if (p_ovi->header.id < odt_max)
680             {
681                 const u8 *spec_digest = (SDK_OVERLAY_DIGEST +
682                                          FS_OVERLAY_DIGEST_SIZE * p_ovi->header.id);
683                 ret = FSi_CompareDigest(spec_digest, p_ovi->header.ram_address, (int)rare_size, FALSE);
684             }
685         }
686         if (!ret)
687         {
688             MI_CpuClear8(p_ovi->header.ram_address, rare_size);
689             OS_TPanic("FS_StartOverlay() failed! (invalid overlay-segment data)");
690             return;
691         }
692     }
693 
694     if ((p_ovi->header.flag & FS_OVERLAY_FLAG_COMP) != 0)
695     {
696         MIi_UncompressBackward(p_ovi->header.ram_address + rare_size);
697     }
698 #if defined(SDK_ARM9)
699     DC_FlushRange(FS_GetOverlayAddress(p_ovi), FS_GetOverlayImageSize(p_ovi));
700 #endif
701     FSi_RegisterOverlayToDebugger(p_ovi);
702 
703     {
704         FSOverlayInitFunc *p = p_ovi->header.sinit_init;
705         FSOverlayInitFunc *q = p_ovi->header.sinit_init_end;
706         for (; p < q; ++p)
707         {
708             if (*p)
709             {
710                 (**p) ();
711             }
712         }
713     }
714 }
715 
716 /*---------------------------------------------------------------------------*
717   Name:         FS_EndOverlay
718 
719   Description:  Executes 'static initializer'.
720                 By this function:
721                     all the destructors in specified overlay module
722                     are removed from global destructor chain and executed.
723 
724   Arguments:    p_ovi:       pointer to FSOverlayInfo
725 
726   Returns:      None.
727  *---------------------------------------------------------------------------*/
FS_EndOverlay(FSOverlayInfo * p_ovi)728 void FS_EndOverlay(FSOverlayInfo *p_ovi)
729 {
730     for (;;)
731     {
732         // Extract the object to be released from the destructor chain
733         // Should be released if the object is in the overlay range.
734         // However, if the object is NULL, this is an array object destructor, so dtor is a target for a range check.
735         //
736         MWiDestructorChain *head = NULL, *tail = NULL;
737         const u32 region_top = (u32)FS_GetOverlayAddress(p_ovi);
738         const u32 region_bottom = region_top + FS_GetOverlayTotalSize(p_ovi);
739 
740         {
741             OSIntrMode bak_psr = OS_DisableInterrupts();
742             MWiDestructorChain *prev = NULL;
743             MWiDestructorChain *base = __global_destructor_chain;
744             MWiDestructorChain *p = base;
745             while (p)
746             {
747                 MWiDestructorChain *next = p->next;
748                 const u32 dtor = (u32)p->dtor;
749                 const u32 obj = (u32)p->obj;
750                 if (((obj == 0) && (dtor >= region_top) && (dtor < region_bottom)) ||
751                     ((obj >= region_top) && (obj < region_bottom)))
752                 {
753                     if (!tail)
754                     {
755                         head = p;
756                     }
757                     else
758                     {
759                         tail->next = p;
760                     }
761                     if (base == p)
762                     {
763                         base = __global_destructor_chain = next;
764                     }
765                     tail = p, p->next = NULL;
766                     if (prev)
767                     {
768                         prev->next = next;
769                     }
770                 }
771                 else
772                 {
773                     prev = p;
774                 }
775                 p = next;
776             }
777             (void)OS_RestoreInterrupts(bak_psr);
778         }
779 
780         // Quit if there is not even one destructor.
781         if (!head)
782         {
783             break;
784         }
785         // If one exists, execute in order from the front and destroy
786         do
787         {
788             MWiDestructorChain *next = head->next;
789             if (head->dtor)
790             {
791                 (*head->dtor) (head->obj);
792             }
793             head = next;
794         }
795         while (head);
796         // If there is a local-static-object accessed for the first time in the destructor, there are further additions to the destructor chain at this stage, so retry until not even one can be found.
797         //
798         //
799     }
800 
801     FSi_UnregisterOverlayToDebugger(p_ovi);
802 
803 }
804 
805 /*---------------------------------------------------------------------------*
806   Name:         FS_UnloadOverlayImage
807 
808   Description:  Unloads overlay module.
809 
810   Arguments:    p_ovi:       pointer to FSOverlayInfo
811 
812   Returns:      If succeeded, TRUE.
813  *---------------------------------------------------------------------------*/
FS_UnloadOverlayImage(FSOverlayInfo * p_ovi)814 BOOL FS_UnloadOverlayImage(FSOverlayInfo *p_ovi)
815 {
816     FS_EndOverlay(p_ovi);
817     return TRUE;
818 }
819 
820 /*---------------------------------------------------------------------------*
821   Name:         FS_LoadOverlay
822 
823   Description:  Loads overlay module and initializes.
824 
825   Arguments:    target:      ARM9 or ARM7
826                 id:          overlay-id (FS_OVERLAY_ID(overlay-name))
827 
828   Returns:      If succeeded, TRUE.
829  *---------------------------------------------------------------------------*/
FS_LoadOverlay(MIProcessor target,FSOverlayID id)830 BOOL FS_LoadOverlay(MIProcessor target, FSOverlayID id)
831 {
832     BOOL    retval = FALSE;
833     SDK_ASSERT(FS_IsAvailable());
834     {
835         FSOverlayInfo ovi;
836         if (FS_LoadOverlayInfo(&ovi, target, id))
837         {
838             if (FS_LoadOverlayImage(&ovi))
839             {
840                 FS_StartOverlay(&ovi);
841                 retval = TRUE;
842             }
843         }
844     }
845     return retval;
846 }
847 
848 /*---------------------------------------------------------------------------*
849   Name:         FS_UnloadOverlay
850 
851   Description:  Unloads overlay module and cleans up.
852 
853   Arguments:    target:      ARM9 or ARM7
854                 id:          overlay-id (FS_OVERLAY_ID(overlay-name))
855 
856   Returns:      If succeeded, TRUE.
857  *---------------------------------------------------------------------------*/
FS_UnloadOverlay(MIProcessor target,FSOverlayID id)858 BOOL FS_UnloadOverlay(MIProcessor target, FSOverlayID id)
859 {
860     BOOL    retval = FALSE;
861     SDK_ASSERT(FS_IsAvailable());
862     {
863         FSOverlayInfo ovi;
864         if (FS_LoadOverlayInfo(&ovi, target, id))
865         {
866             if (FS_UnloadOverlayImage(&ovi))
867             {
868                 retval = TRUE;
869             }
870         }
871     }
872     return retval;
873 }
874 
875 /*---------------------------------------------------------------------------*
876   Name:         FS_AttachOverlayTable
877 
878   Description:  Attaches the overlayinfo-table (OVT) to file-system.
879                 After setting, the FS_LoadOverlayInfo function
880                 loads overlay-info from specified memory.
881 
882   Arguments:    target:      ARM9 or ARM7
883                 ptr:         pointer to buffer which contains OVT.
884                             If ptr is NULL, reset to default (from CARD).
885                 len:         length of OVT.
886 
887   Returns:      None.
888  *---------------------------------------------------------------------------*/
FS_AttachOverlayTable(MIProcessor target,const void * ptr,u32 len)889 void FS_AttachOverlayTable(MIProcessor target, const void *ptr, u32 len)
890 {
891     if ((ptr != NULL) && (target == MI_PROCESSOR_ARM9))
892     {
893         // The overlay table is really for itself, but compare digests.
894         // Because the first half of the table element is NTR compatible and the second half is for TWL mode, it is possible that only the NTR compatible portion will be used when running in HYBRID.
895         //
896         const int   length_ntr = (int)(FS_OVERLAY_NTR_TOTAL * sizeof(FSOverlayInfoHeader));
897         const int   length_twl = (int)(FS_OVERLAY_TWL_TOTAL * sizeof(FSOverlayInfoHeader));
898         // If the specified size is incomplete, this fails
899         if ((len != length_ntr) && (len != length_ntr + length_twl))
900         {
901             OS_TPanic("specified overlay-digest-table is invalid size!");
902         }
903         else
904         {
905             // The NTR compatible portion always exists (including when the size is 0)
906             u8     *buffer_ntr = (u8 *)ptr;
907             if (!FSi_CompareDigest((const u8 *)SDK_OVERLAYTABLE_DIGEST, buffer_ntr, length_ntr, TRUE))
908             {
909                 OS_TPanic("specified overlay-digest-table is invalid!");
910             }
911             // If specified, determine the TWL mode portion too
912             else if (length_twl != 0)
913             {
914                 u8     *buffer_twl = buffer_ntr + length_ntr;
915                 if (!FSi_CompareDigest((const u8 *)SDK_LTDOVERLAYTABLE_DIGEST, buffer_twl, length_twl, TRUE))
916                 {
917                     OS_TPanic("specified overlay-digest-table is invalid!");
918                 }
919             }
920         }
921     }
922 
923     {
924         CARDRomRegion *const pr = (target == MI_PROCESSOR_ARM9) ?
925                                   &FSiOverlayContext.ovt9 : &FSiOverlayContext.ovt7;
926         OSIntrMode bak_psr = OS_DisableInterrupts();
927         pr->offset = (u32)ptr;
928         pr->length = len;
929         (void)OS_RestoreInterrupts(bak_psr);
930     }
931 }
932