1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - FS - libraries
3   File:     fs_overlay.c
4 
5   Copyright 2007-2009 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:: 2009-06-04#$
14   $Rev: 10698 $
15   $Author: okubata_ryoma $
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 // It is necessary to use calls accordingly, by dynamically determining the environment
170 #define FS_REGISTER_OVERLAY_INFO(nProc, nAddrRAM, nAddrROM, nSize)  ((OS_GetConsoleType() & OS_CONSOLE_TWLDEBUGGER) ? _ISTDbgLib_RegistOverlayInfoByAddr(nProc, nAddrRAM, 0, nAddrROM, nSize) : \
171 (OS_GetConsoleType() & OS_CONSOLE_ISDEBUGGER) ? _ISDbgLib_RegistOverlayInfo(nProc, nAddrRAM, nAddrROM, nSize) : DUMMY_REGISTER(nProc, nAddrRAM, nAddrROM, nSize))
172 #define FS_UNREGISTER_OVERLAY_INFO(nProc, nAddrRAM, nSize)          ((OS_GetConsoleType() & OS_CONSOLE_TWLDEBUGGER) ? _ISTDbgLib_UnregistOverlayInfoByAddr(nProc, nAddrRAM, nSize) : \
173 (OS_GetConsoleType() & OS_CONSOLE_ISDEBUGGER) ? _ISDbgLib_UnregistOverlayInfo(nProc, nAddrRAM, nSize) : DUMMY_UNREGISTER(nProc, nAddrRAM, nSize))
174 
175 
176 /*---------------------------------------------------------------------------*
177   Name:         FSi_RegisterOverlayToDebugger
178 
179   Description:  Notifies the debugger that the overlay was loaded on the memory
180 
181   Arguments:    ovi:            FSOverlayInfo structure that stores the overlay information
182 
183   Returns:      None.
184  *---------------------------------------------------------------------------*/
FSi_RegisterOverlayToDebugger(const FSOverlayInfo * ovi)185 SDK_INLINE void FSi_RegisterOverlayToDebugger(const FSOverlayInfo *ovi)
186 {
187     const OVERLAYPROC   proc = (ovi->target == MI_PROCESSOR_ARM9) ? OVERLAYPROC_ARM9 : OVERLAYPROC_ARM7;
188     const u32           address = (u32)FS_GetOverlayAddress(ovi);
189     const u32           offset = ovi->file_pos.offset;
190     const u32           length = FS_GetOverlayImageSize(ovi);
191     (void)FS_REGISTER_OVERLAY_INFO(proc, address, offset, length);
192 }
193 
194 /*---------------------------------------------------------------------------*
195   Name:         FSi_UnregisterOverlayToDebugger
196 
197   Description:  Notifies the debugger that the overlay was unloaded from the memory
198 
199   Arguments:    ovi:            FSOverlayInfo structure that stores the overlay information
200 
201   Returns:      None.
202  *---------------------------------------------------------------------------*/
FSi_UnregisterOverlayToDebugger(const FSOverlayInfo * ovi)203 SDK_INLINE void FSi_UnregisterOverlayToDebugger(const FSOverlayInfo *ovi)
204 {
205     const OVERLAYPROC   proc = (ovi->target == MI_PROCESSOR_ARM9) ? OVERLAYPROC_ARM9 : OVERLAYPROC_ARM7;
206     const u32           address = (u32)FS_GetOverlayAddress(ovi);
207     const u32           length = FS_GetOverlayImageSize(ovi);
208     (void)FS_UNREGISTER_OVERLAY_INFO(proc, address, length);
209 }
210 #endif // defined (SDK_FINALROM)
211 
212 /*---------------------------------------------------------------------------*
213   Name:         __register_global_object
214 
215   Description:  Process system definition function
216                 Insert one chain at the front of the global destructor chain
217 
218   Arguments:    obj:              Pointer to the object to destroy
219                 dtor:             Destructor routine
220                 chain:            Pointer to the chain structure
221                                  (Global object provides one for each)
222 
223   Returns:      None.
224  *---------------------------------------------------------------------------*/
225 void    __register_global_object(void *obj, MWI_DESTRUCTOR_FUNC dtor, MWiDestructorChain * chain);
226 /*
227 {
228 	chain->next = __global_destructor_chain;
229 	chain->dtor = dtor;
230 	chain->obj = obj;
231 	__global_destructor_chain = chain;
232 }
233 */
234 
235 /*---------------------------------------------------------------------------*
236   Name:         FSi_InitOverlay
237 
238   Description:  Initializes overlay management information
239 
240   Arguments:    None.
241 
242   Returns:      None.
243  *---------------------------------------------------------------------------*/
FSi_InitOverlay(void)244 void FSi_InitOverlay(void)
245 {
246     // If downloaded child device, overlay is invalid
247     if (OS_GetBootType() == OS_BOOTTYPE_DOWNLOAD_MB)
248     {
249         FSiOverlayContext.ovt9.offset = (u32)~0;
250         FSiOverlayContext.ovt9.length = 0;
251         FSiOverlayContext.ovt7.offset = (u32)~0;
252         FSiOverlayContext.ovt7.length = 0;
253     }
254     else
255     {
256         FSiOverlayContext.ovt9.offset = 0;
257         FSiOverlayContext.ovt9.length = 0;
258         FSiOverlayContext.ovt7.offset = 0;
259         FSiOverlayContext.ovt7.length = 0;
260     }
261     FSiOverlayContext.digest_key_ptr = fsi_def_digest_key;
262     FSiOverlayContext.digest_key_len = sizeof(fsi_def_digest_key);
263     FSiOverlayContext.arc = FS_FindArchive("rom", 3);
264 }
265 
266 /*---------------------------------------------------------------------------*
267   Name:         FSi_GetOverlayBinarySize
268 
269   Description:  Gets file-size that contains an image of overlay module.
270 
271   Arguments:    p_ovi:       Pointer to FSOverlayInfo
272 
273   Returns:      File size of overlay.
274  *---------------------------------------------------------------------------*/
FSi_GetOverlayBinarySize(const FSOverlayInfo * p_ovi)275 static u32 FSi_GetOverlayBinarySize(const FSOverlayInfo *p_ovi)
276 {
277     u32     size = (((p_ovi->header.flag & FS_OVERLAY_FLAG_COMP) != 0)
278                     ? p_ovi->header.compressed : p_ovi->header.ram_size);
279     return size;
280 }
281 
282 /*---------------------------------------------------------------------------*
283   Name:         FS_ClearOverlayImage
284 
285   Description:  Zero-clear the memory where FS_GetOverlayAddress() points,
286                 and invalidate its region of cache.
287                 This function is called in FS_LoadOverlayImage().
288 
289   Arguments:    p_ovi:       Pointer to FSOverlayInfo
290 
291   Returns:      None.
292  *---------------------------------------------------------------------------*/
FS_ClearOverlayImage(FSOverlayInfo * p_ovi)293 void FS_ClearOverlayImage(FSOverlayInfo *p_ovi)
294 {
295     u8     *const addr = FS_GetOverlayAddress(p_ovi);
296     const u32 image_size = FS_GetOverlayImageSize(p_ovi);
297     const u32 total_size = FS_GetOverlayTotalSize(p_ovi);
298 #if defined(SDK_ARM9)
299     IC_InvalidateRange(addr, total_size);
300     DC_InvalidateRange(addr, total_size);
301 #endif
302     MI_CpuFill8(addr + image_size, 0, total_size - image_size);
303 }
304 
305 
306 #if defined(FS_IMPLEMENT)
307 
308 /*---------------------------------------------------------------------------*
309   Name:         FS_GetOverlayFileID
310 
311   Description:  Gets file-id that contains an image of overlay module.
312 
313   Arguments:    p_ovi:       Pointer to FSOverlayInfo
314 
315   Returns:      File-id of overlay.
316  *---------------------------------------------------------------------------*/
FS_GetOverlayFileID(const FSOverlayInfo * p_ovi)317 FSFileID FS_GetOverlayFileID(const FSOverlayInfo *p_ovi)
318 {
319     FSFileID ret;
320     ret.arc = FSiOverlayContext.arc;
321     ret.file_id = p_ovi->header.file_id;
322     return ret;
323 }
324 
325 /*---------------------------------------------------------------------------*
326   Name:         FS_LoadOverlayInfo
327 
328   Description:  Loads the information of specified overlay module.
329 
330   Arguments:    p_ovi:       Pointer to destination FSOverlayInfo
331                 target:      ARM9 or ARM7
332                 id:          Overlay-id (FS_OVERLAY_ID(overlay-name))
333 
334   Returns:      If succeeded, TRUE.
335  *---------------------------------------------------------------------------*/
FS_LoadOverlayInfo(FSOverlayInfo * p_ovi,MIProcessor target,FSOverlayID id)336 BOOL FS_LoadOverlayInfo(FSOverlayInfo *p_ovi, MIProcessor target, FSOverlayID id)
337 {
338     BOOL                    retval = FALSE;
339     const u32               pos = (u32)id * sizeof(FSOverlayInfoHeader);
340     const CARDRomRegion    *pr = (target == MI_PROCESSOR_ARM9) ?
341                                   &FSiOverlayContext.ovt9 : &FSiOverlayContext.ovt7;
342 #if !defined(SDK_NITRO)
343     // Cannot get the overlay for the TWL mode if not in the TWL environment
344     if ((id >= FS_OVERLAY_NTR_TOTAL) && !OS_IsRunOnTwl())
345     {
346         OS_TWarning("TWL-overlay is not available on NTR-mode.\n");
347     }
348     else
349 #endif // !defined(SDK_NITRO)
350     {
351         if (pr->offset)
352         {
353             if (pos < pr->length)
354             {
355                 FSFile  file[1];
356                 FS_InitFile(file);
357                 MI_CpuCopy8((const void *)(pr->offset + pos), p_ovi, sizeof(FSOverlayInfoHeader));
358                 {
359                     {
360                         p_ovi->target = target;
361                         if (FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
362                         {
363                             p_ovi->file_pos.offset = FS_GetFileImageTop(file);
364                             p_ovi->file_pos.length = FS_GetFileLength(file);
365                             (void)FS_CloseFile(file);
366                             retval = TRUE;
367                         }
368                     }
369                 }
370             }
371         }
372         else
373         {
374             pr = (target == MI_PROCESSOR_ARM9) ?
375                   CARD_GetRomRegionOVT(MI_PROCESSOR_ARM9) :
376                   CARD_GetRomRegionOVT(MI_PROCESSOR_ARM7);
377             if (pos < pr->length)
378             {
379                 FSFile  file[1];
380                 FS_InitFile(file);
381                 if (FS_CreateFileFromRom(file, pr->offset + pos, pr->offset + pr->length))
382                 {
383                     if (FS_ReadFile(file, p_ovi, sizeof(FSOverlayInfoHeader)) !=
384                         sizeof(FSOverlayInfoHeader))
385                     {
386                         (void)FS_CloseFile(file);
387                     }
388                     else
389                     {
390                         (void)FS_CloseFile(file);
391                         p_ovi->target = target;
392                         if (FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
393                         {
394                             p_ovi->file_pos.offset = FS_GetFileImageTop(file);
395                             p_ovi->file_pos.length = FS_GetFileLength(file);
396                             (void)FS_CloseFile(file);
397                             retval = TRUE;
398                         }
399                     }
400                 }
401             }
402         }
403     }
404     return retval;
405 }
406 
407 /*---------------------------------------------------------------------------*
408   Name:         FS_LoadOverlayImageAsync
409 
410   Description:  Loads the image of overlay module without 'static initializer'.
411                 By this call, the memory where FS_GetOverlayAddress() points
412                 is set to rare initial status.
413 
414   Arguments:    p_ovi:       Pointer to FSOverlayInfo
415                 p_file:      Pointer to FSFile for asynchronous reading
416 
417   Returns:      If succeeded, TRUE.
418  *---------------------------------------------------------------------------*/
FS_LoadOverlayImageAsync(FSOverlayInfo * p_ovi,FSFile * p_file)419 BOOL FS_LoadOverlayImageAsync(FSOverlayInfo *p_ovi, FSFile *p_file)
420 {
421     BOOL    retval = FALSE;
422     FS_InitFile(p_file);
423     if (FS_OpenFileFast(p_file, FS_GetOverlayFileID(p_ovi)))
424     {
425         s32     size = (s32)FSi_GetOverlayBinarySize(p_ovi);
426         FS_ClearOverlayImage(p_ovi);
427         if (FS_ReadFileAsync(p_file, FS_GetOverlayAddress(p_ovi), size) == size)
428         {
429             retval = TRUE;
430         }
431         else
432         {
433             (void)FS_CloseFile(p_file);
434         }
435     }
436     return retval;
437 }
438 
439 /*---------------------------------------------------------------------------*
440   Name:         FS_LoadOverlayImage
441 
442   Description:  Loads the image of overlay module without 'static initializer'.
443                 By this call, the memory where FS_GetOverlayAddress() points
444                 is set to rare initial status.
445 
446   Arguments:    p_ovi:       Pointer to FSOverlayInfo
447 
448   Returns:      If succeeded, TRUE.
449  *---------------------------------------------------------------------------*/
FS_LoadOverlayImage(FSOverlayInfo * p_ovi)450 BOOL FS_LoadOverlayImage(FSOverlayInfo *p_ovi)
451 {
452     BOOL    retval = FALSE;
453     FSFile  p_file[1];
454     FS_InitFile(p_file);
455     if (FS_OpenFileFast(p_file, FS_GetOverlayFileID(p_ovi)))
456     {
457         s32     size = (s32)FSi_GetOverlayBinarySize(p_ovi);
458         FS_ClearOverlayImage(p_ovi);
459         if (FS_ReadFile(p_file, FS_GetOverlayAddress(p_ovi), size) == size)
460         {
461             retval = TRUE;
462         }
463         (void)FS_CloseFile(p_file);
464     }
465     return retval;
466 }
467 
468 #else
469 
470 /*---------------------------------------------------------------------------*
471   Name:         FS_LoadOverlayInfo
472 
473   Description:  Loads the information of specified overlay module.
474 
475   Arguments:    p_ovi:       Pointer to destination FSOverlayInfo
476                 target:      ARM9 or ARM7
477                 id:          Overlay-id (FS_OVERLAY_ID(overlay-name))
478 
479   Returns:      If succeeded, TRUE.
480  *---------------------------------------------------------------------------*/
FS_LoadOverlayInfo(FSOverlayInfo * p_ovi,MIProcessor target,FSOverlayID id)481 BOOL FS_LoadOverlayInfo(FSOverlayInfo *p_ovi, MIProcessor target, FSOverlayID id)
482 {
483     BOOL                    retval = FALSE;
484     const u32               pos = (u32)id * sizeof(FSOverlayInfoHeader);
485     const CARDRomRegion    *pr;
486     pr = (target == MI_PROCESSOR_ARM9) ?
487          &FSiOverlayContext.ovt9 :
488          &FSiOverlayContext.ovt7;
489     if (pr->offset)
490     {
491         if (pos < pr->length)
492         {
493             MI_CpuCopy8((const void *)(pr->offset + pos), p_ovi, sizeof(FSOverlayInfoHeader));
494             p_ovi->target = target;
495             {
496                 FSFile  file[1];
497                 FS_InitFile(file);
498                 if (FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi)))
499                 {
500                     p_ovi->file_pos.offset = FS_GetFileImageTop(file);
501                     p_ovi->file_pos.length = FS_GetLength(file);
502                     (void)FS_CloseFile(file);
503                     retval = TRUE;
504                 }
505             }
506         }
507     }
508     else
509     {
510         pr = CARD_GetRomRegionOVT(target);
511         if (pos < pr->length)
512         {
513             FSi_ReadRomDirect((const void*)(pr->offset + pos), p_ovi, sizeof(FSOverlayInfoHeader));
514             p_ovi->target = target;
515             {
516                 retval = TRUE;
517             }
518         }
519     }
520     return retval;
521 }
522 
523 /*---------------------------------------------------------------------------*
524   Name:         FS_LoadOverlayImage
525 
526   Description:  Loads the image of overlay module without 'static initializer'.
527                 By this call, the memory where FS_GetOverlayAddress() points
528                 is set to rare initial status.
529 
530   Arguments:    p_ovi:       Pointer to FSOverlayInfo
531 
532   Returns:      If succeeded, TRUE.
533  *---------------------------------------------------------------------------*/
FS_LoadOverlayImage(FSOverlayInfo * p_ovi)534 BOOL FS_LoadOverlayImage(FSOverlayInfo *p_ovi)
535 {
536     BOOL    retval = FALSE;
537     const CARDRomRegion    *fat = CARD_GetRomRegionFAT();
538     u32     pos = p_ovi->header.file_id * sizeof(FSArchiveFAT);
539     if (pos < fat->length)
540     {
541         FSArchiveFAT    fat_info;
542         FSi_ReadRomDirect((const void*)(fat->offset + pos), &fat_info, sizeof(FSArchiveFAT));
543         FS_ClearOverlayImage(p_ovi);
544         FSi_ReadRomDirect((const void*)(fat_info.top), p_ovi->header.ram_address, fat_info.bottom - fat_info.top);
545         retval = TRUE;
546     }
547     return retval;
548 }
549 
550 #endif /* FS_IMPLEMENT */
551 
552 /*---------------------------------------------------------------------------*
553   Name:         FSi_CompareOverlayDigest
554 
555   Description:  Compares overlay digest values
556 
557   Arguments:    spec_digest:       Comparison source digest value
558                 src:               Comparison target data
559                 len:               src byte size
560                 table_mode:       TRUE if calculating the overlay table
561 
562   Returns:      TRUE if comparison matches. Otherwise, FALSE.
563  *---------------------------------------------------------------------------*/
FSi_CompareDigest(const u8 * spec_digest,void * src,int len,BOOL table_mode)564 static BOOL FSi_CompareDigest(const u8 *spec_digest, void *src, int len, BOOL table_mode)
565 {
566     int     i;
567     u8      digest[FS_OVERLAY_DIGEST_SIZE];
568     u8      digest_key[64];
569 
570     MI_CpuClear8(digest, sizeof(digest));
571     MI_CpuCopy8(FSiOverlayContext.digest_key_ptr, digest_key,
572                 FSiOverlayContext.digest_key_len);
573     // If possible, use the high-speed SVC function
574 #ifdef SDK_TWL
575     if (!table_mode && OS_IsRunOnTwl())
576     {
577         SVC_CalcHMACSHA1(digest, src, (u32)len, digest_key, FSiOverlayContext.digest_key_len);
578     }
579     else
580 #endif
581     {
582         // It is necessary to consider the ID portion 0 for the digest of the overlay table
583         int     bak_ovt_mode = FALSE;
584         if (table_mode)
585         {
586             bak_ovt_mode = MATHi_SetOverlayTableMode(TRUE);
587         }
588         MATH_CalcHMACSHA1(digest, src, (u32)len, digest_key, FSiOverlayContext.digest_key_len);
589         if (table_mode)
590         {
591             (void)MATHi_SetOverlayTableMode(bak_ovt_mode);
592         }
593     }
594     for (i = 0; i < sizeof(digest); i += sizeof(u32))
595     {
596         if (*(const u32 *)(digest + i) != *(const u32 *)(spec_digest + i))
597         {
598             break;
599         }
600     }
601     return (i == sizeof(digest));
602 }
603 
604 /*---------------------------------------------------------------------------*
605   Name:         FS_StartOverlay
606 
607   Description:  Executes 'static initializer'.
608                 This function needs:
609                     the memory where FS_GetOverlayAddress() points is
610                     set by data which FS_LoadOverlayImage() makes.
611 
612   Arguments:    p_ovi:       Pointer to FSOverlayInfo
613 
614   Returns:      None.
615  *---------------------------------------------------------------------------*/
FS_StartOverlay(FSOverlayInfo * p_ovi)616 void FS_StartOverlay(FSOverlayInfo *p_ovi)
617 {
618     u32     rare_size = FSi_GetOverlayBinarySize(p_ovi);
619 
620 #ifdef SDK_TWL
621     // It is possible that an application has the overlays that would damage the LTDMAIN after using a sample demo from TWL-SDK 5.0 FC and earlier incorrectly. In such cases, output a warning.
622     //
623     //
624     // However, because this is sometimes useful with a hybrid running on NTR, after a short transition period, terminate the warning.
625     //
626     {
627         extern const u8     SDK_LTDAUTOLOAD_LTDMAIN_START[];
628         extern const u8     SDK_LTDAUTOLOAD_LTDMAIN_END[];
629         extern const u8     SDK_LTDAUTOLOAD_LTDMAIN_BSS_END[];
630         if ((p_ovi->header.ram_address >= SDK_LTDAUTOLOAD_LTDMAIN_START) &&
631             (p_ovi->header.ram_address < SDK_LTDAUTOLOAD_LTDMAIN_BSS_END) &&
632             OS_IsRunOnTwl())
633         {
634             static BOOL once = FALSE;
635             if (!once)
636             {
637                 OS_TWarning("specified overlay(%d) might have destroyed LTDMAIN segment!\n"
638                             "(please move LTDMAIN after overlay(%d))",
639                             p_ovi->header.id, p_ovi->header.id);
640                 once = TRUE;
641             }
642         }
643     }
644 #endif
645 
646     // If authentication of the overlay fails in storage other than ROM, invalidate the image
647     if (OS_GetBootType() != OS_BOOTTYPE_ROM)
648     {
649         BOOL    ret = FALSE;
650 
651         if ((p_ovi->header.flag & FS_OVERLAY_FLAG_AUTH) != 0)
652         {
653             const u32 odt_max =
654                 (u32)((SDK_OVERLAY_DIGEST_END - SDK_OVERLAY_DIGEST) / FS_OVERLAY_DIGEST_SIZE);
655             if (p_ovi->header.id < odt_max)
656             {
657                 const u8 *spec_digest = (SDK_OVERLAY_DIGEST +
658                                          FS_OVERLAY_DIGEST_SIZE * p_ovi->header.id);
659                 ret = FSi_CompareDigest(spec_digest, p_ovi->header.ram_address, (int)rare_size, FALSE);
660             }
661         }
662         if (!ret)
663         {
664             MI_CpuClear8(p_ovi->header.ram_address, rare_size);
665             OS_TPanic("FS_StartOverlay() failed! (invalid overlay-segment data)");
666             return;
667         }
668     }
669 
670     if ((p_ovi->header.flag & FS_OVERLAY_FLAG_COMP) != 0)
671     {
672         MIi_UncompressBackward(p_ovi->header.ram_address + rare_size);
673     }
674 #if defined(SDK_ARM9)
675     DC_FlushRange(FS_GetOverlayAddress(p_ovi), FS_GetOverlayImageSize(p_ovi));
676 #endif
677     FSi_RegisterOverlayToDebugger(p_ovi);
678 
679     {
680         FSOverlayInitFunc *p = p_ovi->header.sinit_init;
681         FSOverlayInitFunc *q = p_ovi->header.sinit_init_end;
682         for (; p < q; ++p)
683         {
684             if (*p)
685             {
686                 (**p) ();
687             }
688         }
689     }
690 }
691 
692 /*---------------------------------------------------------------------------*
693   Name:         FS_EndOverlay
694 
695   Description:  Executes 'static initializer'.
696                 By this function:
697                     all the destructors in specified overlay module
698                     are removed from global destructor chain and executed.
699 
700   Arguments:    p_ovi:       Pointer to FSOverlayInfo
701 
702   Returns:      None.
703  *---------------------------------------------------------------------------*/
FS_EndOverlay(FSOverlayInfo * p_ovi)704 void FS_EndOverlay(FSOverlayInfo *p_ovi)
705 {
706     for (;;)
707     {
708         // Extract the object to be released from the destructor chain
709         // Should be released if the object is in the overlay range.
710         // However, if the object is NULL, this is an array object destructor, so dtor is the target for the range check.
711         //
712         MWiDestructorChain *head = NULL, *tail = NULL;
713         const u32 region_top = (u32)FS_GetOverlayAddress(p_ovi);
714         const u32 region_bottom = region_top + FS_GetOverlayTotalSize(p_ovi);
715 
716         {
717             OSIntrMode bak_psr = OS_DisableInterrupts();
718             MWiDestructorChain *prev = NULL;
719             MWiDestructorChain *base = __global_destructor_chain;
720             MWiDestructorChain *p = base;
721             while (p)
722             {
723                 MWiDestructorChain *next = p->next;
724                 const u32 dtor = (u32)p->dtor;
725                 const u32 obj = (u32)p->obj;
726                 if (((obj == 0) && (dtor >= region_top) && (dtor < region_bottom)) ||
727                     ((obj >= region_top) && (obj < region_bottom)))
728                 {
729                     if (!tail)
730                     {
731                         head = p;
732                     }
733                     else
734                     {
735                         tail->next = p;
736                     }
737                     if (base == p)
738                     {
739                         base = __global_destructor_chain = next;
740                     }
741                     tail = p, p->next = NULL;
742                     if (prev)
743                     {
744                         prev->next = next;
745                     }
746                 }
747                 else
748                 {
749                     prev = p;
750                 }
751                 p = next;
752             }
753             (void)OS_RestoreInterrupts(bak_psr);
754         }
755 
756         // Quit if there is not even one destructor
757         if (!head)
758         {
759             break;
760         }
761         // If one exists, execute in order from the front and destroy
762         do
763         {
764             MWiDestructorChain *next = head->next;
765             if (head->dtor)
766             {
767                 (*head->dtor) (head->obj);
768             }
769             head = next;
770         }
771         while (head);
772         // 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.
773         //
774         //
775     }
776 
777     FSi_UnregisterOverlayToDebugger(p_ovi);
778 
779 }
780 
781 /*---------------------------------------------------------------------------*
782   Name:         FS_UnloadOverlayImage
783 
784   Description:  Unloads overlay module.
785 
786   Arguments:    p_ovi:       Pointer to FSOverlayInfo
787 
788   Returns:      If succeeded, TRUE.
789  *---------------------------------------------------------------------------*/
FS_UnloadOverlayImage(FSOverlayInfo * p_ovi)790 BOOL FS_UnloadOverlayImage(FSOverlayInfo *p_ovi)
791 {
792     FS_EndOverlay(p_ovi);
793     return TRUE;
794 }
795 
796 /*---------------------------------------------------------------------------*
797   Name:         FS_LoadOverlay
798 
799   Description:  Loads overlay module and initializes.
800 
801   Arguments:    target:      ARM9 or ARM7
802                 id:          Overlay-id (FS_OVERLAY_ID(overlay-name))
803 
804   Returns:      If succeeded, TRUE.
805  *---------------------------------------------------------------------------*/
FS_LoadOverlay(MIProcessor target,FSOverlayID id)806 BOOL FS_LoadOverlay(MIProcessor target, FSOverlayID id)
807 {
808     BOOL    retval = FALSE;
809     SDK_ASSERT(FS_IsAvailable());
810     {
811         FSOverlayInfo ovi;
812         if (FS_LoadOverlayInfo(&ovi, target, id))
813         {
814             if (FS_LoadOverlayImage(&ovi))
815             {
816                 FS_StartOverlay(&ovi);
817                 retval = TRUE;
818             }
819         }
820     }
821     return retval;
822 }
823 
824 /*---------------------------------------------------------------------------*
825   Name:         FS_UnloadOverlay
826 
827   Description:  Unloads overlay module and cleans up.
828 
829   Arguments:    target:      ARM9 or ARM7
830                 id:          Overlay-id (FS_OVERLAY_ID(overlay-name))
831 
832   Returns:      If succeeded, TRUE.
833  *---------------------------------------------------------------------------*/
FS_UnloadOverlay(MIProcessor target,FSOverlayID id)834 BOOL FS_UnloadOverlay(MIProcessor target, FSOverlayID id)
835 {
836     BOOL    retval = FALSE;
837     SDK_ASSERT(FS_IsAvailable());
838     {
839         FSOverlayInfo ovi;
840         if (FS_LoadOverlayInfo(&ovi, target, id))
841         {
842             if (FS_UnloadOverlayImage(&ovi))
843             {
844                 retval = TRUE;
845             }
846         }
847     }
848     return retval;
849 }
850 
851 /*---------------------------------------------------------------------------*
852   Name:         FS_AttachOverlayTable
853 
854   Description:  Attaches the overlayinfo-table (OVT) to file-system.
855                 After setting, FS_LoadOverlayInfo()
856                 loads overlay-info from specified memory.
857 
858   Arguments:    target:      ARM9 or ARM7
859                 ptr:         Pointer to buffer which contains OVT.
860                             If ptr is NULL, reset to default(from CARD).
861                 len:         Length of OVT
862 
863   Returns:      None.
864  *---------------------------------------------------------------------------*/
FS_AttachOverlayTable(MIProcessor target,const void * ptr,u32 len)865 void FS_AttachOverlayTable(MIProcessor target, const void *ptr, u32 len)
866 {
867     if ((ptr != NULL) && (target == MI_PROCESSOR_ARM9))
868     {
869         // The overlay table is really for itself, but compare digests.
870         // Because the first half of the elements in the table is NTR compatible and the second half is for TWL mode, it is possible that only the NTR compatible portion is used when running a hybrid.
871         //
872         const int   length_ntr = (int)(FS_OVERLAY_NTR_TOTAL * sizeof(FSOverlayInfoHeader));
873         const int   length_twl = (int)(FS_OVERLAY_TWL_TOTAL * sizeof(FSOverlayInfoHeader));
874         // If the specified size is incomplete, this fails
875         if ((len != length_ntr) && (len != length_ntr + length_twl))
876         {
877             OS_TPanic("specified overlay-digest-table is invalid size!");
878         }
879         else
880         {
881             // The NTR compatible portion always exists (including when the size is 0)
882             u8     *buffer_ntr = (u8 *)ptr;
883             if (!FSi_CompareDigest((const u8 *)SDK_OVERLAYTABLE_DIGEST, buffer_ntr, length_ntr, TRUE))
884             {
885                 OS_TPanic("specified overlay-digest-table is invalid!");
886             }
887             // If specified, determine the TWL mode portion, too
888             else if (length_twl != 0)
889             {
890                 u8     *buffer_twl = buffer_ntr + length_ntr;
891                 if (!FSi_CompareDigest((const u8 *)SDK_LTDOVERLAYTABLE_DIGEST, buffer_twl, length_twl, TRUE))
892                 {
893                     OS_TPanic("specified overlay-digest-table is invalid!");
894                 }
895             }
896         }
897     }
898 
899     {
900         CARDRomRegion *const pr = (target == MI_PROCESSOR_ARM9) ?
901                                   &FSiOverlayContext.ovt9 : &FSiOverlayContext.ovt7;
902         OSIntrMode bak_psr = OS_DisableInterrupts();
903         pr->offset = (u32)ptr;
904         pr->length = len;
905         (void)OS_RestoreInterrupts(bak_psr);
906     }
907 }
908