1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - libraries
3   File:     mb_fileinfo.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-19#$
14   $Rev: 10786 $
15   $Author: okajima_manabu $
16  *---------------------------------------------------------------------------*/
17 
18 #include "mb_private.h"
19 
20 // Definitions
21 
22 /*
23  * Cache page unit.
24  * The parent header was originally 16 KB, but problems could occur when crossing boundaries, so it was increased to 17 KB.
25  *
26  */
27 #define	MB_CACHE_PAGE_SIZE	(17 * 1024)
28 
29 /* Determine the correctness of the value of the buffer definition required by the MB_ReadSegment function */
30 SDK_COMPILER_ASSERT(ROM_HEADER_SIZE_FULL +
31                     MB_AUTHCODE_SIZE +
32                     sizeof(MBiCacheList) +
33                     sizeof(u32) * 4 + MB_CACHE_PAGE_SIZE * 3 <= MB_SEGMENT_BUFFER_MIN);
34 
35 // Constant variables
36 
37 /*
38     The default segment list.
39     The segment type and storage order is fixed with this.
40  */
41 const MbSegmentType MBi_defaultLoadSegList[MB_DL_SEGMENT_NUM] = {
42     MB_SEG_ROMHEADER,                  /* ROM HEADER  */
43     MB_SEG_ARM9STATIC,                 /* ARM9 static */
44     MB_SEG_ARM7STATIC,                 /* ARM7 static */
45 };
46 
47 
48 /* The segment header region */
49 #define	MB_SEGMENT_HEADER_MIN	0x4000
50 #define	MB_SEGMENT_HEADER_MAX	0x8000
51 
52 
53 /* Valid segment header region (to make this changeable in the future, prepare a setting function) */
54 static const CARDRomRegion mbi_seg_header_default[] = {
55     {0x4000, 0x1000,},
56     {0x7000, 0x1000,},
57     {0, 0},
58 };
59 static const CARDRomRegion *mbi_seg_header = mbi_seg_header_default;
60 
61 /* Information needed when reading the segment's header part */
62 typedef struct
63 {
64     u32     rom_src;
65     u32     mem_src;
66     u32     mem_dst;
67     u32     len;
68 }
69 MBiSegmentHeaderInfo;
70 
71 
72 // ----------------------------------------------------------------------------
73 // Static Function Prototypes
74 
75 static void MBi_MakeDownloadFileInfo(MbDownloadFileInfoHeader * mbdlFileInfop, const void *buf);
76 static void MBi_SetSegmentInfo(const RomHeader * mbRomHeaderp, const MbSegmentType * loadSegListp,
77                                MbSegmentInfo * seg_infop, u32 *child_recv_buff_addr);
78 static void MBi_ReadSegmentHeader(const MBiSegmentHeaderInfo * p, u32 top, u32 bottom, BOOL clean);
79 static BOOL IsAbleToLoad(u8 segment_no, u32 address, u32 size);
80 
81 /*---------------------------------------------------------------------------*
82   Name:         MB_GetSegmentLength
83 
84   Description:  Gets the length of the segment buffer that is required for the specified binary file.
85 
86   Arguments:    file: FSFile structure that indicates the binary file
87                        If NULL, uses itself. (Parent/Child shared binary)
88 
89   Returns:      Returns a positive value if it can properly get size. Otherwise returns 0.
90  *---------------------------------------------------------------------------*/
91 
MB_GetSegmentLength(FSFile * file)92 u32 MB_GetSegmentLength(FSFile *file)
93 {
94     enum
95     { ROM_HEADER_SIZE_SMALL = 0x60 };
96     u8      rom[ROM_HEADER_SIZE_SMALL];
97     const RomHeader *p = NULL;
98 
99     u32     ret = 0;
100 
101     SDK_ASSERT(!file || FS_IsFile(file));
102 
103     /* Specify a stand-alone binary file */
104     if (file)
105     {
106         /* Remember the current position */
107         const u32 bak_pos = FS_GetFilePosition(file);
108         /* For now, read the ROM header part */
109         if (FS_ReadFile(file, &rom, sizeof(rom)) >= sizeof(rom))
110         {
111             p = (const RomHeader *)rom;
112         }
113         /* Return to initial position */
114         (void)FS_SeekFile(file, (int)bak_pos, FS_SEEK_SET);
115     }
116     /* Binary shared by parent and child */
117     else
118     {
119         p = (const RomHeader *)HW_ROM_HEADER_BUF;
120     }
121     if (p)
122     {
123         ret = (u32)(ROM_HEADER_SIZE_FULL +      /* ROM header */
124                     MB_AUTHCODE_SIZE + /* Auth code */
125                     sizeof(MBiCacheList) +      /* Cache structure */
126                     sizeof(u32) * 4 +  /* segment - CARD mapping */
127                     p->main_size +     /* ARM9 static segment */
128                     p->sub_size        /* ARM7 static segment */
129             );
130         if (ret < MB_SEGMENT_BUFFER_MIN)
131             ret = MB_SEGMENT_BUFFER_MIN;
132     }
133     return ret;
134 }
135 
136 /*---------------------------------------------------------------------------*
137   Name:         MBi_AdjustSegmentMapForCloneboot
138 
139   Description:  Unpublished function that appropriately adjusts the .parent section location to use the clone booting feature with programs in HYBRID mode.
140 
141                 Because TWL-SDK 5.1 PR and later are officially supported by the SDK, nothing happens even if this function is called.
142                 This will be discarded in the future.
143 
144   Arguments:    None.
145 
146   Returns:      None.
147  *---------------------------------------------------------------------------*/
MBi_AdjustSegmentMapForCloneboot(void)148 void MBi_AdjustSegmentMapForCloneboot(void)
149 {
150     OS_TWarning("\"%s\" is already obsolete. "
151                 "(automatically supported in TWL-SDK 5.1 PR or later)\n",
152                 __func__);
153 }
154 
155 /*---------------------------------------------------------------------------*
156   Name:         MB_ReadSegment
157 
158   Description:  Reads the required segment data from the specified binary file.
159 
160   Arguments:    file: FSFile structure that indicates the binary file
161                        If NULL, uses itself. (Parent/Child shared binary)
162                 buf: Buffer that reads the segment data
163                 len: buf size
164 
165   Returns:      Returns TRUE if it properly reads segment data. Otherwise returns FALSE.
166  *---------------------------------------------------------------------------*/
167 
MB_ReadSegment(FSFile * file,void * buf,u32 len)168 BOOL MB_ReadSegment(FSFile *file, void *buf, u32 len)
169 {
170     BOOL    ret = FALSE;
171     SDK_ASSERT(!file || FS_IsFile(file));
172 
173     /*
174      * Cut the specified buffer by the following format.
175      *
176      * [RomHeader]
177      * [AuthCode]
178      * [CacheList]
179      * [CardMapping]
180      * [ARM9 static]
181      * [ARM7 static]
182      *
183      * If the size of the last two segments is insufficient, you can get around this by realizing virtual memory in cache format.
184      *
185      */
186 
187     /*
188      * Adjust .parent section location for clone boot.
189      * Because the size of crt0.o increased along with the feature extensions of TWL-SDK, the location of the .parent section was shifted by 1Kb depending on whether it was an NTR-only program or a TWL-only program.
190      *
191      *
192      */
193     if (!file)
194     {
195         // As in the past if it is an NTR-only program
196         if (!CARD_IsExecutableOnTWL((const CARDRomHeader *)CARD_GetOwnRomHeader()))
197         {
198             mbi_seg_header = mbi_seg_header_default;
199         }
200         // TWL-supported programs (HYBRID/LIMITED) shifted 1 KB because of crt0.o increase
201         else
202         {
203             static const CARDRomRegion mbi_seg_header_twl[3] =
204             {
205                 { 0x4000, 0x1400, },
206                 { 0x7400, 0x0C00, },
207                 { 0, 0, },
208             };
209             mbi_seg_header = mbi_seg_header_twl;
210         }
211     }
212 
213     if (len >= ROM_HEADER_SIZE_FULL + 4)
214     {
215 
216         BOOL    is_own_binary = FALSE;
217 
218         u32     rest = len;
219         u8     *dst = (u8 *)buf;
220         u32     bak_pos;
221         FSFile  own_bin[1];
222         u32     own_size;
223         RomHeader *p_rom;
224 
225         MBiCacheList *p_cache = NULL;
226         u32    *p_map = NULL;
227 
228         p_rom = (RomHeader *) dst;
229         dst += ROM_HEADER_SIZE_FULL, rest -= ROM_HEADER_SIZE_FULL;
230 
231         /* Normal multiboot */
232         if (file)
233         {
234             bak_pos = FS_GetFilePosition(file);
235             if (FS_ReadFile(file, p_rom, ROM_HEADER_SIZE_FULL) < ROM_HEADER_SIZE_FULL)
236                 rest = 0;
237             own_size = p_rom->own_size;
238             if (!own_size)
239                 own_size = 16 * 1024 * 1024;
240         }
241         /* Clone boot */
242         else
243         {
244             const RomHeader *mem_rom = (RomHeader *) HW_ROM_HEADER_BUF;
245             own_size = mem_rom->own_size;
246             if (!own_size)
247                 own_size = 16 * 1024 * 1024;
248             is_own_binary = TRUE;
249             /* Directly open file indicating self */
250             FS_InitFile(own_bin);
251             if ( FALSE == FS_OpenFileDirect(own_bin, FS_FindArchive("rom", 3), 0,
252                                             (u32)(own_size + MB_AUTHCODE_SIZE), (u32)~0) )
253             {
254                 return FALSE;
255             }
256             file = own_bin;
257             bak_pos = FS_GetFilePosition(file);
258             /* For now, copy the ROM header part */
259             MI_CpuCopy8(mem_rom, p_rom, ROM_HEADER_SIZE_FULL);
260             /* Correct the converted location */
261             *(u32 *)((u32)p_rom + 0x60) |= 0x00406000;
262         }
263 
264         /* ROM size check */
265         SDK_ASSERT( p_rom->main_size  > 0 && p_rom->sub_size > 0);
266 
267         /* Read binary value of size MB_AUTHCODE_SIZE */
268         if (rest >= MB_AUTHCODE_SIZE)
269         {
270             if (is_own_binary)
271             {
272                 MI_CpuCopy8(CARDi_GetOwnSignature(), dst, CARD_ROM_DOWNLOAD_SIGNATURE_SIZE);
273             }
274             else
275             {
276                 (void)FS_SeekFile(file, (int)(bak_pos + own_size), FS_SEEK_SET);
277                 (void)FS_ReadFile(file, dst, MB_AUTHCODE_SIZE);
278             }
279             dst += MB_AUTHCODE_SIZE, rest -= MB_AUTHCODE_SIZE;
280         }
281         else
282         {
283             rest = 0;
284         }
285 
286         /* Secure a cache list structure */
287         if (rest >= sizeof(MBiCacheList))
288         {
289             p_cache = (MBiCacheList *) dst;
290             MBi_InitCache(p_cache);
291             dst += sizeof(MBiCacheList), rest -= sizeof(MBiCacheList);
292             /* Register ROM header in first cache */
293             MBi_AttachCacheBuffer(p_cache, 0, ROM_HEADER_SIZE_FULL, p_rom, MB_CACHE_STATE_LOCKED);
294             /* Remembers target archive name (specified when load is delayed) */
295             {
296                 FSArchive *p_arc = FS_GetAttachedArchive(file);
297                 int     i = 0;
298                 while ((i < FS_ARCHIVE_NAME_LEN_MAX) && p_arc->name.ptr[i])
299                     ++i;
300                 MI_CpuCopy8(p_arc->name.ptr, p_cache->arc_name, (u32)i);
301                 p_cache->arc_name_len = (u32)i;
302                 p_cache->arc_pointer = p_arc;
303             }
304         }
305         else
306         {
307             rest = 0;
308         }
309 
310         /* Secure segment-CARD mapping region */
311         if (rest >= sizeof(u32) * 4)
312         {
313             p_map = (u32 *)dst;
314             p_map[0] = 0;              /* ROM header */
315             p_map[1] = FS_GetFileImageTop(file) + bak_pos + p_rom->main_rom_offset;     /* ARM9 static */
316             p_map[2] = FS_GetFileImageTop(file) + bak_pos + p_rom->sub_rom_offset;      /* ARM7 static */
317             dst += sizeof(u32) * 4, rest -= sizeof(u32) * 4;
318         }
319         else
320         {
321             rest = 0;
322         }
323 
324         /* Read each segment */
325         if (rest >= p_rom->main_size + p_rom->sub_size)
326         {
327             /* If there is enough room to read all at once */
328             const u32 base = FS_GetFileImageTop(file);
329             // Avoid ROM accesses to the secure region to prevent CARD library hash errors from occurring
330             //
331             u32     mainTop = p_map[1] - base;
332             u32     mainSize = p_rom->main_size;
333             u8     *mainBuf = dst;
334             if (is_own_binary && (mainTop < 0x8000UL))
335             {
336                 mainSize -= (0x8000UL - mainTop);
337                 mainBuf += (0x8000UL - mainTop);
338                 mainTop = 0x8000UL;
339             }
340             (void)FS_SeekFile(file, (int)mainTop, FS_SEEK_SET);
341             (void)FS_ReadFile(file, mainBuf, (int)mainSize);
342             MBi_AttachCacheBuffer(p_cache, p_map[1], p_rom->main_size, dst, MB_CACHE_STATE_LOCKED);
343             dst += p_rom->main_size, rest -= p_rom->main_size;
344             (void)FS_SeekFile(file, (int)(p_map[2] - base), FS_SEEK_SET);
345             (void)FS_ReadFile(file, dst, (int)p_rom->sub_size);
346             MBi_AttachCacheBuffer(p_cache, p_map[2], p_rom->sub_size, dst, MB_CACHE_STATE_LOCKED);
347             dst += p_rom->sub_size, rest -= p_rom->sub_size;
348             /* Preparations complete */
349             ret = TRUE;
350         }
351         else if (rest >= MB_CACHE_PAGE_SIZE * 3)
352         {
353             /* If there is enough room to support 3-page cache method */
354             const u32 base = FS_GetFileImageTop(file);
355             u32     offset = p_map[1];
356             // Avoid ROM accesses to the secure region to prevent CARD library hash errors from occurring
357             //
358             u32     mainTop = p_map[1] - base;
359             u32     mainSize = MB_CACHE_PAGE_SIZE;
360             u8     *mainBuf = dst;
361             if (is_own_binary && (mainTop < 0x8000UL))
362             {
363                 mainSize -= (0x8000UL - mainTop);
364                 mainBuf += (0x8000UL - mainTop);
365                 mainTop = 0x8000UL;
366             }
367             /* First page (fixed) */
368             (void)FS_SeekFile(file, (int)mainTop, FS_SEEK_SET);
369             (void)FS_ReadFile(file, mainBuf, (int)mainSize);
370             MBi_AttachCacheBuffer(p_cache, offset, MB_CACHE_PAGE_SIZE, dst, MB_CACHE_STATE_LOCKED);
371             dst += MB_CACHE_PAGE_SIZE, rest -= MB_CACHE_PAGE_SIZE;
372             offset += MB_CACHE_PAGE_SIZE;
373             /* Second page */
374             (void)FS_SeekFile(file, (int)(offset - base), FS_SEEK_SET);
375             (void)FS_ReadFile(file, dst, MB_CACHE_PAGE_SIZE);
376             MBi_AttachCacheBuffer(p_cache, offset, MB_CACHE_PAGE_SIZE, dst, MB_CACHE_STATE_READY);
377             dst += MB_CACHE_PAGE_SIZE, rest -= MB_CACHE_PAGE_SIZE;
378             offset += MB_CACHE_PAGE_SIZE;
379             /* Third page */
380             (void)FS_SeekFile(file, (int)(offset - base), FS_SEEK_SET);
381             (void)FS_ReadFile(file, dst, MB_CACHE_PAGE_SIZE);
382             MBi_AttachCacheBuffer(p_cache, offset, MB_CACHE_PAGE_SIZE, dst, MB_CACHE_STATE_READY);
383             dst += MB_CACHE_PAGE_SIZE, rest -= MB_CACHE_PAGE_SIZE;
384             /* Preparations complete */
385             ret = TRUE;
386         }
387 
388         /* Return to initial position */
389         (void)FS_SeekFile(file, (int)bak_pos, FS_SEEK_SET);
390 
391         /* Clone boot */
392         if (is_own_binary)
393         {
394             // If the .parent section position is shifted, consider that portion
395             (void)FS_CloseFile(own_bin);
396             if (ret)
397             {
398                 const CARDRomRegion *p_header = mbi_seg_header;
399                 MBiSegmentHeaderInfo info;
400                 info.rom_src = p_rom->main_rom_offset;
401                 info.mem_src = (u32)((u32)p_rom->main_ram_address - p_rom->main_rom_offset);
402                 info.mem_dst = (u32)((u32)p_cache->list[1].ptr - p_rom->main_rom_offset);
403                 info.len = len;
404                 /* Initialize the first appropriate region */
405                 MBi_ReadSegmentHeader(&info, MB_SEGMENT_HEADER_MIN, MB_SEGMENT_HEADER_MAX, TRUE);
406                 /* Sequentially transfer header */
407                 for (; p_header->length != 0; ++p_header)
408                 {
409                     MBi_ReadSegmentHeader(&info,
410                                           p_header->offset,
411                                           (u32)(p_header->offset + p_header->length), FALSE);
412                 }
413                 {
414                     /* Restore the debugger's autoload patch process */
415                     extern u32 _start_AutoloadDoneCallback[1];
416                     u8     *dst = (u8 *)p_cache->list[1].ptr;
417                     dst += ((u32)&_start_AutoloadDoneCallback - (u32)p_rom->main_ram_address);
418                     *(u32 *)dst = 0xE12FFF1E;   /* asm { bx, lr } (always code32) */
419                 }
420             }
421         }
422 
423         if (ret)
424         {
425             DC_FlushRange(buf, len);
426         }
427     }
428 
429     return ret;
430 }
431 
432 /*
433  * Load the header section of the segment
434  */
MBi_ReadSegmentHeader(const MBiSegmentHeaderInfo * p,u32 top,u32 bottom,BOOL clean)435 static void MBi_ReadSegmentHeader(const MBiSegmentHeaderInfo * p, u32 top, u32 bottom, BOOL clean)
436 {
437     /* Adjust the header range */
438     if (top < MB_SEGMENT_HEADER_MIN)
439         top = MB_SEGMENT_HEADER_MIN;
440     if (bottom > MB_SEGMENT_HEADER_MAX)
441         bottom = MB_SEGMENT_HEADER_MAX;
442     /* Adjust the actual transfer region */
443     if (top < p->rom_src)
444         top = p->rom_src;
445     if (bottom > p->rom_src + p->len)
446         bottom = p->rom_src + p->len;
447     /* Transfer if the region is valid */
448     if (top < bottom)
449     {
450         if (clean)
451         {                              /* 0 Initialize */
452             MI_CpuClear8((void *)(p->mem_dst + top), (u32)(bottom - top));
453         }
454         else
455         {                              /* Transfer */
456             MI_CpuCopy8((const void *)(p->mem_src + top),
457                         (void *)(p->mem_dst + top), (u32)(bottom - top));
458         }
459     }
460 }
461 
462 
463 /*---------------------------------------------------------------------------*
464   Name:         MB_RegisterFile
465 
466   Description:  Registers the download source file in the Parent Device.
467 
468   Arguments:    game_reg: Game registration information
469                 buf: Segment buffer already loaded by MB_ReadSegment
470 
471   Returns:
472  *---------------------------------------------------------------------------*/
473 
MB_RegisterFile(const MBGameRegistry * game_reg,const void * buf)474 BOOL MB_RegisterFile(const MBGameRegistry *game_reg, const void *buf)
475 {
476     MbDownloadFileInfoHeader *mdfi;
477     static u8 update = 0;
478     u8     *appname = (u8 *)game_reg->gameNamep;
479     u8      fileID = 0xff, i;
480 
481     OSIntrMode enabled = OS_DisableInterrupts();        /* Interrupts prohibited */
482 
483     /* Return FALSE if MB has not been started */
484     if (!MBi_IsStarted())
485     {
486         OS_TWarning("MB has not started yet. Cannot Register File\n");
487         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
488         return FALSE;
489     }
490 
491     if (pPwork->file_num + 1 > MB_MAX_FILE)
492     {
493         OS_TWarning("The number of registered files has exceeded.\n");
494         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
495         return FALSE;
496     }
497 
498     /* Search for empty fileinfo */
499     for (i = 0; i < MB_MAX_FILE; i++)
500     {
501         /* Return FALSE if this GameRegistry has been registered already */
502         if (pPwork->fileinfo[i].game_reg == (MBGameRegistry *)game_reg)
503         {
504             MB_DEBUG_OUTPUT("Already Registered \"%s\"\n", game_reg->gameNamep);
505             (void)OS_RestoreInterrupts(enabled);        /* Remove interrupt prohibition */
506             return FALSE;
507         }
508 
509         if (pPwork->fileinfo[i].active == 0)
510         {
511             fileID = i;
512             break;
513         }
514     }
515 
516     /* Abnormal termination if empty fileinfo cannot be found */
517     if (i == MB_MAX_FILE)
518     {
519         OS_TWarning("Too many Files! \"%s\"\n", game_reg->gameNamep);
520         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
521         return FALSE;
522     }
523 
524 
525     // Register the GameRegistry pointer
526     pPwork->fileinfo[fileID].game_reg = (MBGameRegistry *)game_reg;
527 
528     // Set the pointer to DownloadFileInfo
529     mdfi = &pPwork->fileinfo[fileID].dl_fileinfo.header;
530 
531     // Generate the MBDownloadFileInfo
532     MBi_MakeDownloadFileInfo(mdfi, buf);
533     /* Copy user-defined extended parameters */
534     MI_CpuCopy8(game_reg->userParam,
535                 ((MBDownloadFileInfo *) mdfi)->reserved, HW_DOWNLOAD_PARAMETER_SIZE);
536 
537     // Create block information table
538     if (FALSE == MBi_MakeBlockInfoTable(&pPwork->fileinfo[fileID].blockinfo_table, mdfi))
539     {
540         OS_TWarning("Cannot make block information!\n");
541         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
542         return FALSE;
543     }
544 
545     // Generate the MBGameInfo
546     MBi_MakeGameInfo(&pPwork->fileinfo[fileID].game_info, game_reg, &pPwork->common.user);
547 
548     /* Set the file number in GameInfo */
549     pPwork->fileinfo[fileID].game_info.fileNo = fileID;
550 
551     /* Register GameInfo in the beacon list */
552     MB_AddGameInfo(&pPwork->fileinfo[fileID].game_info);
553 
554     /* Set the file update number in GameInfo */
555     pPwork->fileinfo[fileID].game_info.seqNoFixed = update++;
556 
557     pPwork->fileinfo[fileID].gameinfo_child_bmp = MB_GAMEINFO_PARENT_FLAG;
558 
559     pPwork->fileinfo[fileID].src_adr = (u32 *)buf;
560 
561     /* Save the various pointers for the cache */
562     pPwork->fileinfo[fileID].cache_list = (MBiCacheList *)
563         ((u32)buf + ROM_HEADER_SIZE_FULL + MB_AUTHCODE_SIZE);
564     pPwork->fileinfo[fileID].card_mapping = (u32 *)
565         ((u32)buf + ROM_HEADER_SIZE_FULL + MB_AUTHCODE_SIZE + sizeof(MBiCacheList));
566 
567     /* Start task thread if needed */
568     if (pPwork->fileinfo[fileID].cache_list->list[3].state != MB_CACHE_STATE_EMPTY)
569     {
570         if (!MBi_IsTaskAvailable())
571         {
572             MBi_InitTaskInfo(&pPwork->cur_task);
573             MBi_InitTaskThread(pPwork->task_work, sizeof(pPwork->task_work));
574         }
575     }
576 
577     /* Make the registered file active */
578     pPwork->fileinfo[fileID].active = 1;
579 
580     // Increment the number of files
581     pPwork->file_num++;
582 
583     MB_DEBUG_OUTPUT("Register Game \"%s\"\n", game_reg->gameNamep);
584 
585     (void)OS_RestoreInterrupts(enabled);        /* Remove interrupt prohibition */
586 
587     return TRUE;
588 
589 }
590 
591 /*---------------------------------------------------------------------------*
592   Name:         MB_UnregisterFile
593 
594   Description:  Deletes the specified file from the download list.
595 
596   Arguments:    game_reg: Game registration information
597 
598   Returns:
599  *---------------------------------------------------------------------------*/
600 
601 /* Deletes the specified file from the download list */
MB_UnregisterFile(const MBGameRegistry * game_reg)602 void   *MB_UnregisterFile(const MBGameRegistry *game_reg)
603 {
604     u8      fileID, i;
605     void   *ret_bufp;
606     OSIntrMode enabled = OS_DisableInterrupts();        /* Interrupts prohibited */
607 
608     /* Search for fileinfo that matches GameRegistry */
609     for (i = 0; i < MB_MAX_FILE; i++)
610     {
611         if (pPwork->fileinfo[i].game_reg == (MBGameRegistry *)game_reg)
612         {
613             fileID = i;
614             break;
615         }
616     }
617 
618     /* If no matching fileinfo is found, terminate abnormally (change location to avoid a situation where fileID is uninitialized) */
619     if (i == MB_MAX_FILE)
620     {
621         OS_TWarning("Cannot find corresponding GameRegistry\n");
622         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
623         return NULL;
624     }
625 
626     if (fileID != pPwork->fileinfo[fileID].game_info.fileNo)
627     {
628         OS_TWarning("Registerd File ID does not correspond with File ID in Registry List.\n");
629         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
630         return NULL;
631     }
632 
633     /* Delete from GameInfo */
634     if (FALSE == MB_DeleteGameInfo(&pPwork->fileinfo[fileID].game_info))
635     {
636         OS_TWarning("Cannot delete GameInfo %s\n",
637                     pPwork->fileinfo[fileID].game_info.fixed.gameName);
638         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
639         return NULL;
640     }
641 
642     ret_bufp = pPwork->fileinfo[fileID].src_adr;
643 
644     pPwork->fileinfo[fileID].active = 0;
645 
646     /* Delete the target fileinfo */
647     MI_CpuClear16(&pPwork->fileinfo[fileID], sizeof(pPwork->fileinfo[0]));
648 
649     pPwork->file_num--;
650 
651     MB_DEBUG_OUTPUT("Delete Game \"%s\"\n", game_reg->gameNamep);
652 
653     (void)OS_RestoreInterrupts(enabled);        /* Remove interrupt prohibition */
654 
655     return ret_bufp;
656 }
657 
658 /*---------------------------------------------------------------------------*
659   Name:         MBi_MakeDownloadFileInfo
660 
661   Description:  Builds the download file information from the designated multiboot game registration.
662 
663   Arguments:    mbdlFileInfop: Pointer to the MbDownloadFileInfo to be built
664                 buf: Pointer to the file image buffer
665 
666   Returns:      None.
667  *---------------------------------------------------------------------------*/
668 
MBi_MakeDownloadFileInfo(MbDownloadFileInfoHeader * mbdlFileInfop,const void * buf)669 static void MBi_MakeDownloadFileInfo(MbDownloadFileInfoHeader * mbdlFileInfop, const void *buf)
670 {
671     const RomHeader *mbRomHeaderp;
672     const MbSegmentType *loadSegListp;
673     MbSegmentInfo *seg_infop;
674     int     seg_num;
675     const u16 *auth_code;
676     u32     child_recv_buff_addr = MB_ARM7_STATIC_RECV_BUFFER;
677 
678     mbRomHeaderp = (const RomHeader *)buf;
679     auth_code = (const u16 *)((u32)buf + ROM_HEADER_SIZE_FULL);
680 
681     /*
682        Note: Maybe it would be good to check the ROM header and determine if it is a ROM binary?
683      */
684 
685     // Build the initial download file information based on multiboot game information
686     mbdlFileInfop->arm9EntryAddr = (u32)mbRomHeaderp->main_entry_address;
687     mbdlFileInfop->arm7EntryAddr = (u32)mbRomHeaderp->sub_entry_address;
688     seg_infop = (MbSegmentInfo *) (mbdlFileInfop + 1);
689     loadSegListp = MBi_defaultLoadSegList;
690     MB_DEBUG_OUTPUT("\t<segment list>         recv_adr load_adr     size  rom_adr (base)\n");
691 
692     /*
693      * Delete all because we reached an agreement to make the segments static.
694      * overlay: Impossible, since management for loading/unloading cannot be done.
695      * file: Impossible in terms of scheduling because specifications such as capacity must be formulated and put into the reference.
696      */
697     for (seg_num = 0; seg_num < MB_DL_SEGMENT_NUM; seg_num++)
698     {
699         /* Process for getting each segment's load address and size information */
700         MB_DEBUG_OUTPUT("\t SEG%2d : ", seg_num);
701         MBi_SetSegmentInfo(mbRomHeaderp, loadSegListp, seg_infop, &child_recv_buff_addr);
702         seg_infop++;
703         loadSegListp++;
704     }
705 
706     /* Set authentication-use code in MBDownloadFileInfo */
707     {
708         MBDownloadFileInfo *pMdfi = (MBDownloadFileInfo *) mbdlFileInfop;
709         MI_CpuCopy8(auth_code, &pMdfi->auth_code[0], MB_AUTHCODE_SIZE);
710     }
711 }
712 
713 /*---------------------------------------------------------------------------*
714   Name:         MBi_SetSegmentInfo
715 
716   Description:  Sets the segment information.
717 
718   Arguments:    mbRomHeaderp
719                 loadSegListp
720                 seg_infop
721                 child_recv_buffer
722 
723   Returns:      None.
724  *---------------------------------------------------------------------------*/
MBi_SetSegmentInfo(const RomHeader * mbRomHeaderp,const MbSegmentType * loadSegListp,MbSegmentInfo * seg_infop,u32 * child_recv_buff_addr)725 static void MBi_SetSegmentInfo(const RomHeader * mbRomHeaderp,
726                                const MbSegmentType * loadSegListp,
727                                MbSegmentInfo * seg_infop, u32 *child_recv_buff_addr)
728 {
729     CARDRomRegion *romRegp;
730 
731     /* Process for getting each segment's load address and size information */
732 
733     switch (*loadSegListp)
734     {
735     case MB_SEG_ARM9STATIC:
736         romRegp = (CARDRomRegion *)(&mbRomHeaderp->main_ram_address);
737 
738         if (((u32)romRegp->offset >= MB_LOAD_AREA_LO)
739             && ((u32)romRegp->offset < MB_LOAD_AREA_HI)
740             && (((u32)romRegp->offset + romRegp->length) <= MB_LOAD_AREA_HI))
741         {
742 
743             seg_infop->size = romRegp->length;
744             seg_infop->load_addr = (u32)romRegp->offset;
745             /* Note: Considering data compression and decompression, load_addr == recv_addr should not be used in the future */
746             seg_infop->recv_addr = seg_infop->load_addr;
747             seg_infop->target = MI_PROCESSOR_ARM9;
748             MB_DEBUG_OUTPUT("arm9 static :");
749         }
750         else
751         {
752             // The address or the address + size of the load program exceeds the loadable area
753             OS_TPanic("ARM9 boot code out of the load area. : addr = %x  size = %x\n",
754                      (u32)romRegp->offset, romRegp->length);
755         }
756         break;
757 
758     case MB_SEG_ARM7STATIC:
759         {
760             BOOL    error_flag = FALSE;
761             BOOL    reload_flag = FALSE;
762             u32     load_last_addr;
763 
764             romRegp = (CARDRomRegion *)(&mbRomHeaderp->sub_ram_address);
765             load_last_addr = (u32)((u32)romRegp->offset + romRegp->length);
766 
767             // Location address, size determination.
768             /* For the address of the starting position (when placed in main memory). */
769             if (((u32)romRegp->offset >= MB_LOAD_AREA_LO)
770                 && ((u32)romRegp->offset < MB_BSSDESC_ADDRESS))
771             {
772                 /* Regarding the end of the location address */
773                 if (load_last_addr <= MB_ARM7_STATIC_LOAD_AREA_HI)      // Set as is if relocation is not necessary.
774                 {
775                 }
776                 else if ((load_last_addr < MB_BSSDESC_ADDRESS)
777                          && (romRegp->length <= MB_ARM7_STATIC_RECV_BUFFER_SIZE))
778                 {                      // If there is a need to relocate, behave like so
779                     reload_flag = TRUE;
780                 }
781                 else
782                 {
783                     error_flag = TRUE;
784                 }
785             }
786             else
787                 /* For the address of the starting position (when placed in WRAM) */
788             if (((u32)romRegp->offset >= HW_WRAM)
789                     && ((u32)romRegp->offset < HW_WRAM + MB_ARM7_STATIC_LOAD_WRAM_MAX_SIZE))
790             {
791 
792                 if (load_last_addr <= (HW_WRAM + MB_ARM7_STATIC_LOAD_WRAM_MAX_SIZE))
793                 {                      // To be relocated
794                     reload_flag = TRUE;
795                 }
796                 else
797                 {
798                     error_flag = TRUE;
799                 }
800             }
801             else
802             {                          // An error when in regions other than this
803                 error_flag = TRUE;
804             }
805 
806             // Error determination
807             if (error_flag == TRUE)
808             {
809                 OS_TPanic("ARM7 boot code out of the load area. : addr = %x  size = %x\n",
810                          (u32)romRegp->offset, romRegp->length);
811             }
812 
813             // The segment information set
814             {
815                 seg_infop->size = romRegp->length;
816                 seg_infop->load_addr = (u32)romRegp->offset;
817                 if (!reload_flag)
818                 {
819                     seg_infop->recv_addr = seg_infop->load_addr;
820                 }
821                 else
822                 {
823                     /*
824                      * If the execution address on ARM7 is a region that needs to be relocated, set the receive address to the main memory receive buffer
825                      *
826                      */
827                     seg_infop->recv_addr = *child_recv_buff_addr;
828                     *child_recv_buff_addr += seg_infop->size;
829                 }
830             }
831 
832             seg_infop->target = MI_PROCESSOR_ARM7;
833             MB_DEBUG_OUTPUT("arm7 static :");
834         }
835         break;
836 
837     case MB_SEG_ROMHEADER:
838         seg_infop->size = ROM_HEADER_SIZE_FULL;
839         seg_infop->load_addr = (u32)MB_ROM_HEADER_ADDRESS;
840         seg_infop->recv_addr = seg_infop->load_addr;
841         // Take the 'target' for ROMHEADER to be MI_PROCESSOR_ARM9
842         seg_infop->target = MI_PROCESSOR_ARM9;
843         MB_DEBUG_OUTPUT("rom header  :");
844         break;
845     }
846 
847     MB_DEBUG_OUTPUT(" %8x %8x %8x %8x\n",
848                     seg_infop->recv_addr, seg_infop->load_addr,
849                     seg_infop->size,
850                     (*loadSegListp == MB_SEG_ROMHEADER) ? 0 : *((u32 *)romRegp - 2));
851 
852 }
853 
854 /*	----------------------------------------------------------------------------
855 
856     Block information control function (for Parent)
857 
858     ----------------------------------------------------------------------------*/
859 
860 /*---------------------------------------------------------------------------*
861   Name:         MBi_MakeBlockInfoTable
862 
863   Description:  Creates a table used to get the block information.
864 
865   Arguments:
866 
867   Returns:
868  *---------------------------------------------------------------------------*/
869 
870 
MBi_MakeBlockInfoTable(MB_BlockInfoTable * table,MbDownloadFileInfoHeader * mdfi)871 BOOL MBi_MakeBlockInfoTable(MB_BlockInfoTable * table, MbDownloadFileInfoHeader * mdfi)
872 {
873     u16    *seg_headB = table->seg_head_blockno;
874     u32    *seg_src = table->seg_src_offset;
875     u8      i;
876     u32     src_ofs = 0;
877 
878     if (!mdfi)
879         return FALSE;
880 
881     for (i = 0; i < MB_DL_SEGMENT_NUM; ++i)
882     {
883         MbSegmentInfo *si = MBi_GetSegmentInfo(mdfi, i);
884         seg_src[i] = src_ofs;
885         src_ofs += si->size;
886     }
887 
888     seg_headB[0] = 0;                  // Segment 0
889 
890     for (i = 0; i < MB_DL_SEGMENT_NUM; ++i)
891     {
892         MbSegmentInfo *si = MBi_GetSegmentInfo(mdfi, i);
893         u16     next_block_head =
894             (u16)(seg_headB[i] + (u16)((si->size + mbc->block_size_max - 1) / mbc->block_size_max));
895 
896         if (FALSE == IsAbleToLoad(i, si->load_addr, si->size))
897         {
898             return FALSE;
899         }
900 
901         if (i < MB_DL_SEGMENT_NUM - 1)
902         {
903             seg_headB[i + 1] = next_block_head;
904         }
905         else
906         {
907             table->block_num = next_block_head;
908         }
909 
910     }
911 
912     return TRUE;
913 }
914 
915 
916 /*---------------------------------------------------------------------------*
917   Name:         MBi_get_blockinfo
918 
919   Description:  Gets the block information.
920 
921   Arguments:
922 
923   Returns:
924  *---------------------------------------------------------------------------*/
925 
MBi_get_blockinfo(MB_BlockInfo * bi,MB_BlockInfoTable * table,u32 block,MbDownloadFileInfoHeader * mdfi)926 BOOL MBi_get_blockinfo(MB_BlockInfo * bi, MB_BlockInfoTable * table,
927                        u32 block, MbDownloadFileInfoHeader * mdfi)
928 {
929     s8      i;
930     u32     seg_block, block_adr_offset;
931 
932     if (block >= table->block_num)
933     {
934         return FALSE;
935     }
936 
937     for (i = MB_DL_SEGMENT_NUM - 1; i >= 0; i--)
938     {
939         if (block >= table->seg_head_blockno[i])
940         {
941             break;
942         }
943     }
944 
945     if (i < 0)
946         return FALSE;
947 
948     seg_block = block - table->seg_head_blockno[i];
949     block_adr_offset = seg_block * mbc->block_size_max;
950 
951     {
952         MbSegmentInfo *si = MBi_GetSegmentInfo(mdfi, i);
953         bi->size = si->size - block_adr_offset;
954         if (bi->size > mbc->block_size_max)
955             bi->size = (u32)mbc->block_size_max;
956         bi->offset = (u32)(block_adr_offset + table->seg_src_offset[i]);
957         bi->child_address = (u32)(block_adr_offset + (u32)(si->recv_addr));
958         bi->segment_no = (u8)i;
959     }
960 
961     MB_DEBUG_OUTPUT("blockNo:%d \n", block);
962     MB_DEBUG_OUTPUT("Segment %d [block:%d offset(%08x) destination(%08x) size(%04x)]\n",
963                     i, seg_block, bi->offset, bi->child_address, bi->size);
964 
965     return TRUE;
966 }
967 
968 /*---------------------------------------------------------------------------*
969   Name:         MBi_get_blocknum
970 
971   Description:  Gets the total number of blocks.
972 
973   Arguments:
974 
975   Returns:
976  *---------------------------------------------------------------------------*/
977 
MBi_get_blocknum(MB_BlockInfoTable * table)978 u16 MBi_get_blocknum(MB_BlockInfoTable * table)
979 {
980     SDK_ASSERT(table != 0);
981     return table->block_num;
982 }
983 
984 
985 /*---------------------------------------------------------------------------*
986   Name:         MBi_IsAbleToRecv
987 
988   Description:  Checks for validity of the receive address.
989 
990   Arguments:
991 
992   Returns:
993  *---------------------------------------------------------------------------*/
994 
MBi_IsAbleToRecv(u8 segment_no,u32 address,u32 size)995 BOOL MBi_IsAbleToRecv(u8 segment_no, u32 address, u32 size)
996 {
997     MbSegmentType seg_type;
998 
999     SDK_ASSERT(segment_no < MB_DL_SEGMENT_NUM);
1000 
1001     seg_type = MBi_defaultLoadSegList[segment_no];
1002 
1003     switch (seg_type)
1004     {
1005     case MB_SEG_ROMHEADER:
1006         if (address >= MB_ROM_HEADER_ADDRESS
1007             && address + size <= MB_ROM_HEADER_ADDRESS + ROM_HEADER_SIZE_FULL)
1008         {
1009             return TRUE;
1010         }
1011         break;
1012 
1013     case MB_SEG_ARM9STATIC:
1014         if (address >= MB_LOAD_AREA_LO && address + size <= MB_LOAD_AREA_HI)
1015         {
1016             return TRUE;
1017         }
1018         break;
1019 
1020     case MB_SEG_ARM7STATIC:
1021         /* WRAM mapping */
1022         if (address >= MB_ARM7_STATIC_RECV_BUFFER
1023             && address + size <= MB_ARM7_STATIC_RECV_BUFFER_END)
1024         {
1025             return TRUE;
1026         }
1027         else
1028             /* Main memory mapping */
1029         if (address >= MB_LOAD_AREA_LO && address + size <= MB_ARM7_STATIC_RECV_BUFFER_END)
1030         {
1031             return TRUE;
1032         }
1033         break;
1034 
1035     default:
1036         return FALSE;
1037     }
1038 
1039     return FALSE;
1040 }
1041 
IsAbleToLoad(u8 segment_no,u32 address,u32 size)1042 static BOOL IsAbleToLoad(u8 segment_no, u32 address, u32 size)
1043 {
1044     MbSegmentType seg_type;
1045 
1046     SDK_ASSERT(segment_no < MB_DL_SEGMENT_NUM);
1047 
1048     seg_type = MBi_defaultLoadSegList[segment_no];
1049 
1050     switch (seg_type)
1051     {
1052     case MB_SEG_ROMHEADER:
1053     case MB_SEG_ARM9STATIC:
1054         return MBi_IsAbleToRecv(segment_no, address, size);
1055 
1056     case MB_SEG_ARM7STATIC:
1057         /* Main memory */
1058         if (address >= MB_LOAD_AREA_LO && address < MB_BSSDESC_ADDRESS)
1059         {
1060             u32     end_adr = address + size;
1061 
1062             if (MB_ARM7_STATIC_RECV_BUFFER_END > address
1063                 && MB_ARM7_STATIC_RECV_BUFFER_END < end_adr)
1064 
1065             {
1066                 return FALSE;          // NG
1067             }
1068             else if (end_adr <= MB_ARM7_STATIC_LOAD_AREA_HI)
1069             {
1070                 return TRUE;           // OK
1071             }
1072             else if (end_adr < MB_BSSDESC_ADDRESS && size <= MB_ARM7_STATIC_RECV_BUFFER_SIZE)
1073             {
1074                 return TRUE;           // OK (needs relocation)
1075             }
1076             else
1077             {
1078                 return FALSE;          // NG
1079             }
1080         }
1081         else
1082             /* WRAM */
1083         if (address >= HW_WRAM && address < HW_WRAM + MB_ARM7_STATIC_LOAD_WRAM_MAX_SIZE)
1084         {
1085             u32     end_adr = address + size;
1086             if (end_adr <= (HW_WRAM + MB_ARM7_STATIC_LOAD_WRAM_MAX_SIZE))
1087             {
1088                 return TRUE;           // OK
1089             }
1090             else
1091             {
1092                 return FALSE;          // NG
1093             }
1094         }
1095         break;
1096 
1097     default:
1098         return FALSE;
1099     }
1100 
1101     return FALSE;
1102 }
1103