1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - libraries
3   File:     mb_fileinfo.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:: 2009-02-24#$
14   $Rev: 10072 $
15   $Author: yosizaki $
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: The 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                 Because TWL-SDK 5.1 PR and later are officially supported by the SDK, nothing happens even if this function is called.
141 
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: The FSFile structure that indicates the binary file
161                        If NULL, uses itself. (Parent/Child shared binary)
162                 buf: The buffer that reads the segment data
163                 len: The 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 1kB 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         /* Read binary value of size MB_AUTHCODE_SIZE */
265         if (rest >= MB_AUTHCODE_SIZE)
266         {
267             if (is_own_binary)
268             {
269                 MI_CpuCopy8(CARDi_GetOwnSignature(), dst, CARD_ROM_DOWNLOAD_SIGNATURE_SIZE);
270             }
271             else
272             {
273                 (void)FS_SeekFile(file, (int)(bak_pos + own_size), FS_SEEK_SET);
274                 (void)FS_ReadFile(file, dst, MB_AUTHCODE_SIZE);
275             }
276             dst += MB_AUTHCODE_SIZE, rest -= MB_AUTHCODE_SIZE;
277         }
278         else
279         {
280             rest = 0;
281         }
282 
283         /* Secure a cache list structure */
284         if (rest >= sizeof(MBiCacheList))
285         {
286             p_cache = (MBiCacheList *) dst;
287             MBi_InitCache(p_cache);
288             dst += sizeof(MBiCacheList), rest -= sizeof(MBiCacheList);
289             /* Register ROM header in first cache */
290             MBi_AttachCacheBuffer(p_cache, 0, ROM_HEADER_SIZE_FULL, p_rom, MB_CACHE_STATE_LOCKED);
291             /* Remembers target archive name (specified when load is delayed) */
292             {
293                 FSArchive *p_arc = FS_GetAttachedArchive(file);
294                 int     i = 0;
295                 while ((i < FS_ARCHIVE_NAME_LEN_MAX) && p_arc->name.ptr[i])
296                     ++i;
297                 MI_CpuCopy8(p_arc->name.ptr, p_cache->arc_name, (u32)i);
298                 p_cache->arc_name_len = (u32)i;
299                 p_cache->arc_pointer = p_arc;
300             }
301         }
302         else
303         {
304             rest = 0;
305         }
306 
307         /* Secure segment-CARD mapping region */
308         if (rest >= sizeof(u32) * 4)
309         {
310             p_map = (u32 *)dst;
311             p_map[0] = 0;              /* ROM header */
312             p_map[1] = FS_GetFileImageTop(file) + bak_pos + p_rom->main_rom_offset;     /* ARM9 static */
313             p_map[2] = FS_GetFileImageTop(file) + bak_pos + p_rom->sub_rom_offset;      /* ARM7 static */
314             dst += sizeof(u32) * 4, rest -= sizeof(u32) * 4;
315         }
316         else
317         {
318             rest = 0;
319         }
320 
321         /* Read each segment */
322         if (rest >= p_rom->main_size + p_rom->sub_size)
323         {
324             /* If there is enough room to read all at once */
325             const u32 base = FS_GetFileImageTop(file);
326             // Avoid ROM accesses to the secure region to prevent CARD library hash errors from occurring.
327             //
328             u32     mainTop = p_map[1] - base;
329             u32     mainSize = p_rom->main_size;
330             u8     *mainBuf = dst;
331             if (is_own_binary && (mainTop < 0x8000UL))
332             {
333                 mainSize -= (0x8000UL - mainTop);
334                 mainBuf += (0x8000UL - mainTop);
335                 mainTop = 0x8000UL;
336             }
337             (void)FS_SeekFile(file, (int)mainTop, FS_SEEK_SET);
338             (void)FS_ReadFile(file, mainBuf, (int)mainSize);
339             MBi_AttachCacheBuffer(p_cache, p_map[1], p_rom->main_size, dst, MB_CACHE_STATE_LOCKED);
340             dst += p_rom->main_size, rest -= p_rom->main_size;
341             (void)FS_SeekFile(file, (int)(p_map[2] - base), FS_SEEK_SET);
342             (void)FS_ReadFile(file, dst, (int)p_rom->sub_size);
343             MBi_AttachCacheBuffer(p_cache, p_map[2], p_rom->sub_size, dst, MB_CACHE_STATE_LOCKED);
344             dst += p_rom->sub_size, rest -= p_rom->sub_size;
345             /* Preparations complete */
346             ret = TRUE;
347         }
348         else if (rest >= MB_CACHE_PAGE_SIZE * 3)
349         {
350             /* If there is enough room to support 3-page cache method */
351             const u32 base = FS_GetFileImageTop(file);
352             u32     offset = p_map[1];
353             // Avoid ROM accesses to the secure region to prevent CARD library hash errors from occurring.
354             //
355             u32     mainTop = p_map[1] - base;
356             u32     mainSize = MB_CACHE_PAGE_SIZE;
357             u8     *mainBuf = dst;
358             if (is_own_binary && (mainTop < 0x8000UL))
359             {
360                 mainSize -= (0x8000UL - mainTop);
361                 mainBuf += (0x8000UL - mainTop);
362                 mainTop = 0x8000UL;
363             }
364             /* First page (fixed) */
365             (void)FS_SeekFile(file, (int)mainTop, FS_SEEK_SET);
366             (void)FS_ReadFile(file, mainBuf, (int)mainSize);
367             MBi_AttachCacheBuffer(p_cache, offset, MB_CACHE_PAGE_SIZE, dst, MB_CACHE_STATE_LOCKED);
368             dst += MB_CACHE_PAGE_SIZE, rest -= MB_CACHE_PAGE_SIZE;
369             offset += MB_CACHE_PAGE_SIZE;
370             /* Second page */
371             (void)FS_SeekFile(file, (int)(offset - base), FS_SEEK_SET);
372             (void)FS_ReadFile(file, dst, MB_CACHE_PAGE_SIZE);
373             MBi_AttachCacheBuffer(p_cache, offset, MB_CACHE_PAGE_SIZE, dst, MB_CACHE_STATE_READY);
374             dst += MB_CACHE_PAGE_SIZE, rest -= MB_CACHE_PAGE_SIZE;
375             offset += MB_CACHE_PAGE_SIZE;
376             /* Third page */
377             (void)FS_SeekFile(file, (int)(offset - base), FS_SEEK_SET);
378             (void)FS_ReadFile(file, dst, MB_CACHE_PAGE_SIZE);
379             MBi_AttachCacheBuffer(p_cache, offset, MB_CACHE_PAGE_SIZE, dst, MB_CACHE_STATE_READY);
380             dst += MB_CACHE_PAGE_SIZE, rest -= MB_CACHE_PAGE_SIZE;
381             /* Preparations complete */
382             ret = TRUE;
383         }
384 
385         /* Return to initial position */
386         (void)FS_SeekFile(file, (int)bak_pos, FS_SEEK_SET);
387 
388         /* Clone boot */
389         if (is_own_binary)
390         {
391             // If the .parent section position is shifted, consider that portion
392             (void)FS_CloseFile(own_bin);
393             if (ret)
394             {
395                 const CARDRomRegion *p_header = mbi_seg_header;
396                 MBiSegmentHeaderInfo info;
397                 info.rom_src = p_rom->main_rom_offset;
398                 info.mem_src = (u32)((u32)p_rom->main_ram_address - p_rom->main_rom_offset);
399                 info.mem_dst = (u32)((u32)p_cache->list[1].ptr - p_rom->main_rom_offset);
400                 info.len = len;
401                 /* Initialize the first appropriate region */
402                 MBi_ReadSegmentHeader(&info, MB_SEGMENT_HEADER_MIN, MB_SEGMENT_HEADER_MAX, TRUE);
403                 /* Sequentially transfer header */
404                 for (; p_header->length != 0; ++p_header)
405                 {
406                     MBi_ReadSegmentHeader(&info,
407                                           p_header->offset,
408                                           (u32)(p_header->offset + p_header->length), FALSE);
409                 }
410                 {
411                     /* Restore the debugger's autoload patch process */
412                     extern u32 _start_AutoloadDoneCallback[1];
413                     u8     *dst = (u8 *)p_cache->list[1].ptr;
414                     dst += ((u32)&_start_AutoloadDoneCallback - (u32)p_rom->main_ram_address);
415                     *(u32 *)dst = 0xE12FFF1E;   /* asm { bx, lr } (always code32) */
416                 }
417             }
418         }
419 
420         if (ret)
421         {
422             DC_FlushRange(buf, len);
423         }
424     }
425 
426     return ret;
427 }
428 
429 /*
430  * Load the header section of the segment
431  */
MBi_ReadSegmentHeader(const MBiSegmentHeaderInfo * p,u32 top,u32 bottom,BOOL clean)432 static void MBi_ReadSegmentHeader(const MBiSegmentHeaderInfo * p, u32 top, u32 bottom, BOOL clean)
433 {
434     /* Adjust the header range */
435     if (top < MB_SEGMENT_HEADER_MIN)
436         top = MB_SEGMENT_HEADER_MIN;
437     if (bottom > MB_SEGMENT_HEADER_MAX)
438         bottom = MB_SEGMENT_HEADER_MAX;
439     /* Adjust the actual transfer region */
440     if (top < p->rom_src)
441         top = p->rom_src;
442     if (bottom > p->rom_src + p->len)
443         bottom = p->rom_src + p->len;
444     /* Transfer if the region is valid */
445     if (top < bottom)
446     {
447         if (clean)
448         {                              /* 0 Initialize */
449             MI_CpuClear8((void *)(p->mem_dst + top), (u32)(bottom - top));
450         }
451         else
452         {                              /* Transfer */
453             MI_CpuCopy8((const void *)(p->mem_src + top),
454                         (void *)(p->mem_dst + top), (u32)(bottom - top));
455         }
456     }
457 }
458 
459 
460 /*---------------------------------------------------------------------------*
461   Name:         MB_RegisterFile
462 
463   Description:  Registers the download source file in the Parent Device.
464 
465   Arguments:    game_reg: The game registration information
466                 buf: The segment buffer already loaded by MB_ReadSegment
467 
468   Returns:
469  *---------------------------------------------------------------------------*/
470 
MB_RegisterFile(const MBGameRegistry * game_reg,const void * buf)471 BOOL MB_RegisterFile(const MBGameRegistry *game_reg, const void *buf)
472 {
473     MbDownloadFileInfoHeader *mdfi;
474     static u8 update = 0;
475     u8     *appname = (u8 *)game_reg->gameNamep;
476     u8      fileID = 0xff, i;
477 
478     OSIntrMode enabled = OS_DisableInterrupts();        /* Interrupts disabled */
479 
480     /* Return FALSE if MB has not been started */
481     if (!MBi_IsStarted())
482     {
483         OS_TWarning("MB has not started yet. Cannot Register File\n");
484         (void)OS_RestoreInterrupts(enabled);    /* Cancel interrupt disabling. */
485         return FALSE;
486     }
487 
488     if (pPwork->file_num + 1 > MB_MAX_FILE)
489     {
490         OS_TWarning("The number of registered files has exceeded.\n");
491         (void)OS_RestoreInterrupts(enabled);    /* Cancel interrupt disabling. */
492         return FALSE;
493     }
494 
495     /* Search for empty fileinfo */
496     for (i = 0; i < MB_MAX_FILE; i++)
497     {
498         /* Return FALSE if this GameRegistry has been registered already */
499         if (pPwork->fileinfo[i].game_reg == (MBGameRegistry *)game_reg)
500         {
501             MB_DEBUG_OUTPUT("Already Registered \"%s\"\n", game_reg->gameNamep);
502             (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling. */
503             return FALSE;
504         }
505 
506         if (pPwork->fileinfo[i].active == 0)
507         {
508             fileID = i;
509             break;
510         }
511     }
512 
513     /* Abnormal termination if empty fileinfo cannot be found */
514     if (i == MB_MAX_FILE)
515     {
516         OS_TWarning("Too many Files! \"%s\"\n", game_reg->gameNamep);
517         (void)OS_RestoreInterrupts(enabled);    /* Cancel interrupt disabling. */
518         return FALSE;
519     }
520 
521 
522     // Register the GameRegistry pointer
523     pPwork->fileinfo[fileID].game_reg = (MBGameRegistry *)game_reg;
524 
525     // Set the pointer to DownloadFileInfo
526     mdfi = &pPwork->fileinfo[fileID].dl_fileinfo.header;
527 
528     // Generate the MBDownloadFileInfo
529     MBi_MakeDownloadFileInfo(mdfi, buf);
530     /* Copy user-defined extended parameters */
531     MI_CpuCopy8(game_reg->userParam,
532                 ((MBDownloadFileInfo *) mdfi)->reserved, HW_DOWNLOAD_PARAMETER_SIZE);
533 
534     // Create block information table
535     if (FALSE == MBi_MakeBlockInfoTable(&pPwork->fileinfo[fileID].blockinfo_table, mdfi))
536     {
537         OS_TWarning("Cannot make block information!\n");
538         (void)OS_RestoreInterrupts(enabled);    /* Cancel interrupt disabling. */
539         return FALSE;
540     }
541 
542     // Generate the MBGameInfo
543     MBi_MakeGameInfo(&pPwork->fileinfo[fileID].game_info, game_reg, &pPwork->common.user);
544 
545     /* Set the file number in GameInfo */
546     pPwork->fileinfo[fileID].game_info.fileNo = fileID;
547 
548     /* Register GameInfo in the beacon list */
549     MB_AddGameInfo(&pPwork->fileinfo[fileID].game_info);
550 
551     /* Set the file update number in GameInfo */
552     pPwork->fileinfo[fileID].game_info.seqNoFixed = update++;
553 
554     pPwork->fileinfo[fileID].gameinfo_child_bmp = MB_GAMEINFO_PARENT_FLAG;
555 
556     pPwork->fileinfo[fileID].src_adr = (u32 *)buf;
557 
558     /* Save the various pointers for the cache */
559     pPwork->fileinfo[fileID].cache_list = (MBiCacheList *)
560         ((u32)buf + ROM_HEADER_SIZE_FULL + MB_AUTHCODE_SIZE);
561     pPwork->fileinfo[fileID].card_mapping = (u32 *)
562         ((u32)buf + ROM_HEADER_SIZE_FULL + MB_AUTHCODE_SIZE + sizeof(MBiCacheList));
563 
564     /* Start task thread if needed */
565     if (pPwork->fileinfo[fileID].cache_list->list[3].state != MB_CACHE_STATE_EMPTY)
566     {
567         if (!MBi_IsTaskAvailable())
568         {
569             MBi_InitTaskInfo(&pPwork->cur_task);
570             MBi_InitTaskThread(pPwork->task_work, sizeof(pPwork->task_work));
571         }
572     }
573 
574     /* Make the registered file active */
575     pPwork->fileinfo[fileID].active = 1;
576 
577     // Increment the number of files
578     pPwork->file_num++;
579 
580     MB_DEBUG_OUTPUT("Register Game \"%s\"\n", game_reg->gameNamep);
581 
582     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling. */
583 
584     return TRUE;
585 
586 }
587 
588 /*---------------------------------------------------------------------------*
589   Name:         MB_UnregisterFile
590 
591   Description:  Deletes the specified file from the download list.
592 
593   Arguments:    game_reg: The game registration information
594 
595   Returns:
596  *---------------------------------------------------------------------------*/
597 
598 /* Deletes the specified file from the download list. */
MB_UnregisterFile(const MBGameRegistry * game_reg)599 void   *MB_UnregisterFile(const MBGameRegistry *game_reg)
600 {
601     u8      fileID, i;
602     void   *ret_bufp;
603     OSIntrMode enabled = OS_DisableInterrupts();        /* interrupts disabled */
604 
605     /* Search for fileinfo that matches GameRegistry */
606     for (i = 0; i < MB_MAX_FILE; i++)
607     {
608         if (pPwork->fileinfo[i].game_reg == (MBGameRegistry *)game_reg)
609         {
610             fileID = i;
611             break;
612         }
613     }
614 
615     if (fileID != pPwork->fileinfo[fileID].game_info.fileNo)
616     {
617         OS_TWarning("Registerd File ID does not correspond with File ID in Registry List.\n");
618         (void)OS_RestoreInterrupts(enabled);    /* Cancel interrupt disabling. */
619         return NULL;
620     }
621 
622     /* Abnormal termination if cannot find matching fileinfo */
623     if (i == MB_MAX_FILE)
624     {
625         OS_TWarning("Cannot find corresponding GameRegistry\n");
626         (void)OS_RestoreInterrupts(enabled);    /* Cancel interrupt disabling. */
627         return NULL;
628     }
629 
630     /* Delete from GameInfo */
631     if (FALSE == MB_DeleteGameInfo(&pPwork->fileinfo[fileID].game_info))
632     {
633         OS_TWarning("Cannot delete GameInfo %s\n",
634                     pPwork->fileinfo[fileID].game_info.fixed.gameName);
635         (void)OS_RestoreInterrupts(enabled);    /* Cancel interrupt disabling. */
636         return NULL;
637     }
638 
639     ret_bufp = pPwork->fileinfo[fileID].src_adr;
640 
641     pPwork->fileinfo[fileID].active = 0;
642 
643     /* Delete the target fileinfo */
644     MI_CpuClear16(&pPwork->fileinfo[fileID], sizeof(pPwork->fileinfo[0]));
645 
646     pPwork->file_num--;
647 
648     MB_DEBUG_OUTPUT("Delete Game \"%s\"\n", game_reg->gameNamep);
649 
650     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling. */
651 
652     return ret_bufp;
653 }
654 
655 /*---------------------------------------------------------------------------*
656   Name:         MBi_MakeDownloadFileInfo
657 
658   Description:  Builds the download file information from the designated multiboot game registration.
659 
660   Arguments:    mbdlFileInfop: Pointer to the MbDownloadFileInfo to be built
661                 buf: Pointer to the file image buffer
662 
663   Returns:      None.
664  *---------------------------------------------------------------------------*/
665 
MBi_MakeDownloadFileInfo(MbDownloadFileInfoHeader * mbdlFileInfop,const void * buf)666 static void MBi_MakeDownloadFileInfo(MbDownloadFileInfoHeader * mbdlFileInfop, const void *buf)
667 {
668     const RomHeader *mbRomHeaderp;
669     const MbSegmentType *loadSegListp;
670     MbSegmentInfo *seg_infop;
671     int     seg_num;
672     const u16 *auth_code;
673     u32     child_recv_buff_addr = MB_ARM7_STATIC_RECV_BUFFER;
674 
675     mbRomHeaderp = (const RomHeader *)buf;
676     auth_code = (const u16 *)((u32)buf + ROM_HEADER_SIZE_FULL);
677 
678     /*
679        NOTE: Maybe it would be good to check the ROM header and determine if it is a ROM binary?
680      */
681 
682     // Build the initial download file information based on multiboot game information.
683     mbdlFileInfop->arm9EntryAddr = (u32)mbRomHeaderp->main_entry_address;
684     mbdlFileInfop->arm7EntryAddr = (u32)mbRomHeaderp->sub_entry_address;
685     seg_infop = (MbSegmentInfo *) (mbdlFileInfop + 1);
686     loadSegListp = MBi_defaultLoadSegList;
687     MB_DEBUG_OUTPUT("\t<segment list>         recv_adr load_adr     size  rom_adr (base)\n");
688 
689     /*
690      * Delete all because we reached an agreement to make the segments static.
691      * overlay: Impossible, since management for loading/unloading cannot be done.
692      * file: Impossible in terms of scheduling because specifications such as capacity must be formulated and put into the reference.
693      */
694     for (seg_num = 0; seg_num < MB_DL_SEGMENT_NUM; seg_num++)
695     {
696         /* Process for getting each segment's load address and size information */
697         MB_DEBUG_OUTPUT("\t SEG%2d : ", seg_num);
698         MBi_SetSegmentInfo(mbRomHeaderp, loadSegListp, seg_infop, &child_recv_buff_addr);
699         seg_infop++;
700         loadSegListp++;
701     }
702 
703     /* Set authentication-use code in MBDownloadFileInfo */
704     {
705         MBDownloadFileInfo *pMdfi = (MBDownloadFileInfo *) mbdlFileInfop;
706         MI_CpuCopy8(auth_code, &pMdfi->auth_code[0], MB_AUTHCODE_SIZE);
707     }
708 }
709 
710 /*---------------------------------------------------------------------------*
711   Name:         MBi_SetSegmentInfo
712 
713   Description:  Sets the segment information.
714 
715   Arguments:    mbRomHeaderp
716                 loadSegListp
717                 seg_infop
718                 child_recv_buffer
719 
720   Returns:      None.
721  *---------------------------------------------------------------------------*/
MBi_SetSegmentInfo(const RomHeader * mbRomHeaderp,const MbSegmentType * loadSegListp,MbSegmentInfo * seg_infop,u32 * child_recv_buff_addr)722 static void MBi_SetSegmentInfo(const RomHeader * mbRomHeaderp,
723                                const MbSegmentType * loadSegListp,
724                                MbSegmentInfo * seg_infop, u32 *child_recv_buff_addr)
725 {
726     CARDRomRegion *romRegp;
727 
728     /* Process for getting each segment's load address and size information */
729 
730     switch (*loadSegListp)
731     {
732     case MB_SEG_ARM9STATIC:
733         romRegp = (CARDRomRegion *)(&mbRomHeaderp->main_ram_address);
734 
735         if (((u32)romRegp->offset >= MB_LOAD_AREA_LO)
736             && ((u32)romRegp->offset < MB_LOAD_AREA_HI)
737             && (((u32)romRegp->offset + romRegp->length) <= MB_LOAD_AREA_HI))
738         {
739 
740             seg_infop->size = romRegp->length;
741             seg_infop->load_addr = (u32)romRegp->offset;
742             /* Note: Considering data compression and decompression, load_addr == recv_addr should not be used in the future */
743             seg_infop->recv_addr = seg_infop->load_addr;
744             seg_infop->target = MI_PROCESSOR_ARM9;
745             MB_DEBUG_OUTPUT("arm9 static :");
746         }
747         else
748         {
749             // The address or the address + size of the load program exceeds the loadable area.
750             OS_Panic("ARM9 boot code out of the load area. : addr = %x  size = %x\n",
751                      (u32)romRegp->offset, romRegp->length);
752         }
753         break;
754 
755     case MB_SEG_ARM7STATIC:
756         {
757             BOOL    error_flag = FALSE;
758             BOOL    reload_flag = FALSE;
759             u32     load_last_addr;
760 
761             romRegp = (CARDRomRegion *)(&mbRomHeaderp->sub_ram_address);
762             load_last_addr = (u32)((u32)romRegp->offset + romRegp->length);
763 
764             // Location address, size determination.
765             /* For the address of the starting position (when placed in main memory). */
766             if (((u32)romRegp->offset >= MB_LOAD_AREA_LO)
767                 && ((u32)romRegp->offset < MB_BSSDESC_ADDRESS))
768             {
769                 /* Regarding the end of the location address */
770                 if (load_last_addr <= MB_ARM7_STATIC_LOAD_AREA_HI)      // Set as is if relocation is not necessary.
771                 {
772                 }
773                 else if ((load_last_addr < MB_BSSDESC_ADDRESS)
774                          && (romRegp->length <= MB_ARM7_STATIC_RECV_BUFFER_SIZE))
775                 {                      // If there is a need to relocate, behave like so
776                     reload_flag = TRUE;
777                 }
778                 else
779                 {
780                     error_flag = TRUE;
781                 }
782             }
783             else
784                 /* For the address of the starting position (when placed in WRAM) */
785             if (((u32)romRegp->offset >= HW_WRAM)
786                     && ((u32)romRegp->offset < HW_WRAM + MB_ARM7_STATIC_LOAD_WRAM_MAX_SIZE))
787             {
788 
789                 if (load_last_addr <= (HW_WRAM + MB_ARM7_STATIC_LOAD_WRAM_MAX_SIZE))
790                 {                      // To be relocated
791                     reload_flag = TRUE;
792                 }
793                 else
794                 {
795                     error_flag = TRUE;
796                 }
797             }
798             else
799             {                          // An error when in regions other than this
800                 error_flag = TRUE;
801             }
802 
803             // Error determination
804             if (error_flag == TRUE)
805             {
806                 OS_Panic("ARM7 boot code out of the load area. : addr = %x  size = %x\n",
807                          (u32)romRegp->offset, romRegp->length);
808             }
809 
810             // The segment information set
811             {
812                 seg_infop->size = romRegp->length;
813                 seg_infop->load_addr = (u32)romRegp->offset;
814                 if (!reload_flag)
815                 {
816                     seg_infop->recv_addr = seg_infop->load_addr;
817                 }
818                 else
819                 {
820                     /*
821                      * If the execution address on ARM7 is a region that needs to be relocated, set the receive address to the main memory receive buffer
822                      *
823                      */
824                     seg_infop->recv_addr = *child_recv_buff_addr;
825                     *child_recv_buff_addr += seg_infop->size;
826                 }
827             }
828 
829             seg_infop->target = MI_PROCESSOR_ARM7;
830             MB_DEBUG_OUTPUT("arm7 static :");
831         }
832         break;
833 
834     case MB_SEG_ROMHEADER:
835         seg_infop->size = ROM_HEADER_SIZE_FULL;
836         seg_infop->load_addr = (u32)MB_ROM_HEADER_ADDRESS;
837         seg_infop->recv_addr = seg_infop->load_addr;
838         // Target for ROMHEADER is MI_PROCESSOR_ARM9
839         seg_infop->target = MI_PROCESSOR_ARM9;
840         MB_DEBUG_OUTPUT("rom header  :");
841         break;
842     }
843 
844     MB_DEBUG_OUTPUT(" %8x %8x %8x %8x\n",
845                     seg_infop->recv_addr, seg_infop->load_addr,
846                     seg_infop->size,
847                     (*loadSegListp == MB_SEG_ROMHEADER) ? 0 : *((u32 *)romRegp - 2));
848 
849 }
850 
851 /*	----------------------------------------------------------------------------
852 
853     Block information control function (for Parent)
854 
855     ----------------------------------------------------------------------------*/
856 
857 /*---------------------------------------------------------------------------*
858   Name:         MBi_MakeBlockInfoTable
859 
860   Description:  Creates a table used to get the block information.
861 
862   Arguments:
863 
864   Returns:
865  *---------------------------------------------------------------------------*/
866 
867 
MBi_MakeBlockInfoTable(MB_BlockInfoTable * table,MbDownloadFileInfoHeader * mdfi)868 BOOL MBi_MakeBlockInfoTable(MB_BlockInfoTable * table, MbDownloadFileInfoHeader * mdfi)
869 {
870     u16    *seg_headB = table->seg_head_blockno;
871     u32    *seg_src = table->seg_src_offset;
872     u8      i;
873     u32     src_ofs = 0;
874 
875     if (!mdfi)
876         return FALSE;
877 
878     for (i = 0; i < MB_DL_SEGMENT_NUM; ++i)
879     {
880         MbSegmentInfo *si = MBi_GetSegmentInfo(mdfi, i);
881         seg_src[i] = src_ofs;
882         src_ofs += si->size;
883     }
884 
885     seg_headB[0] = 0;                  // Segment 0
886 
887     for (i = 0; i < MB_DL_SEGMENT_NUM; ++i)
888     {
889         MbSegmentInfo *si = MBi_GetSegmentInfo(mdfi, i);
890         u16     next_block_head =
891             (u16)(seg_headB[i] + (u16)((si->size + mbc->block_size_max - 1) / mbc->block_size_max));
892 
893         if (FALSE == IsAbleToLoad(i, si->load_addr, si->size))
894         {
895             return FALSE;
896         }
897 
898         if (i < MB_DL_SEGMENT_NUM - 1)
899         {
900             seg_headB[i + 1] = next_block_head;
901         }
902         else
903         {
904             table->block_num = next_block_head;
905         }
906 
907     }
908 
909     return TRUE;
910 }
911 
912 
913 /*---------------------------------------------------------------------------*
914   Name:         MBi_get_blockinfo
915 
916   Description:  Gets the block information.
917 
918   Arguments:
919 
920   Returns:
921  *---------------------------------------------------------------------------*/
922 
MBi_get_blockinfo(MB_BlockInfo * bi,MB_BlockInfoTable * table,u32 block,MbDownloadFileInfoHeader * mdfi)923 BOOL MBi_get_blockinfo(MB_BlockInfo * bi, MB_BlockInfoTable * table,
924                        u32 block, MbDownloadFileInfoHeader * mdfi)
925 {
926     s8      i;
927     u32     seg_block, block_adr_offset;
928 
929     if (block >= table->block_num)
930     {
931         return FALSE;
932     }
933 
934     for (i = MB_DL_SEGMENT_NUM - 1; i >= 0; i--)
935     {
936         if (block >= table->seg_head_blockno[i])
937         {
938             break;
939         }
940     }
941 
942     if (i < 0)
943         return FALSE;
944 
945     seg_block = block - table->seg_head_blockno[i];
946     block_adr_offset = seg_block * mbc->block_size_max;
947 
948     {
949         MbSegmentInfo *si = MBi_GetSegmentInfo(mdfi, i);
950         bi->size = si->size - block_adr_offset;
951         if (bi->size > mbc->block_size_max)
952             bi->size = (u32)mbc->block_size_max;
953         bi->offset = (u32)(block_adr_offset + table->seg_src_offset[i]);
954         bi->child_address = (u32)(block_adr_offset + (u32)(si->recv_addr));
955         bi->segment_no = (u8)i;
956     }
957 
958     MB_DEBUG_OUTPUT("blockNo:%d \n", block);
959     MB_DEBUG_OUTPUT("Segment %d [block:%d offset(%08x) destination(%08x) size(%04x)]\n",
960                     i, seg_block, bi->offset, bi->child_address, bi->size);
961 
962     return TRUE;
963 }
964 
965 /*---------------------------------------------------------------------------*
966   Name:         MBi_get_blocknum
967 
968   Description:  Gets the total number of blocks.
969 
970   Arguments:
971 
972   Returns:
973  *---------------------------------------------------------------------------*/
974 
MBi_get_blocknum(MB_BlockInfoTable * table)975 u16 MBi_get_blocknum(MB_BlockInfoTable * table)
976 {
977     SDK_ASSERT(table != 0);
978     return table->block_num;
979 }
980 
981 
982 /*---------------------------------------------------------------------------*
983   Name:         MBi_IsAbleToRecv
984 
985   Description:  Check for validity of the receive address.
986 
987   Arguments:
988 
989   Returns:
990  *---------------------------------------------------------------------------*/
991 
MBi_IsAbleToRecv(u8 segment_no,u32 address,u32 size)992 BOOL MBi_IsAbleToRecv(u8 segment_no, u32 address, u32 size)
993 {
994     MbSegmentType seg_type;
995 
996     SDK_ASSERT(segment_no < MB_DL_SEGMENT_NUM);
997 
998     seg_type = MBi_defaultLoadSegList[segment_no];
999 
1000     switch (seg_type)
1001     {
1002     case MB_SEG_ROMHEADER:
1003         if (address >= MB_ROM_HEADER_ADDRESS
1004             && address + size <= MB_ROM_HEADER_ADDRESS + ROM_HEADER_SIZE_FULL)
1005         {
1006             return TRUE;
1007         }
1008         break;
1009 
1010     case MB_SEG_ARM9STATIC:
1011         if (address >= MB_LOAD_AREA_LO && address + size <= MB_LOAD_AREA_HI)
1012         {
1013             return TRUE;
1014         }
1015         break;
1016 
1017     case MB_SEG_ARM7STATIC:
1018         /* wram mapping */
1019         if (address >= MB_ARM7_STATIC_RECV_BUFFER
1020             && address + size <= MB_ARM7_STATIC_RECV_BUFFER_END)
1021         {
1022             return TRUE;
1023         }
1024         else
1025             /* main memory mapping */
1026         if (address >= MB_LOAD_AREA_LO && address + size <= MB_ARM7_STATIC_RECV_BUFFER_END)
1027         {
1028             return TRUE;
1029         }
1030         break;
1031 
1032     default:
1033         return FALSE;
1034     }
1035 
1036     return FALSE;
1037 }
1038 
IsAbleToLoad(u8 segment_no,u32 address,u32 size)1039 static BOOL IsAbleToLoad(u8 segment_no, u32 address, u32 size)
1040 {
1041     MbSegmentType seg_type;
1042 
1043     SDK_ASSERT(segment_no < MB_DL_SEGMENT_NUM);
1044 
1045     seg_type = MBi_defaultLoadSegList[segment_no];
1046 
1047     switch (seg_type)
1048     {
1049     case MB_SEG_ROMHEADER:
1050     case MB_SEG_ARM9STATIC:
1051         return MBi_IsAbleToRecv(segment_no, address, size);
1052 
1053     case MB_SEG_ARM7STATIC:
1054         /* main memory */
1055         if (address >= MB_LOAD_AREA_LO && address < MB_BSSDESC_ADDRESS)
1056         {
1057             u32     end_adr = address + size;
1058 
1059             if (MB_ARM7_STATIC_RECV_BUFFER_END > address
1060                 && MB_ARM7_STATIC_RECV_BUFFER_END < end_adr)
1061 
1062             {
1063                 return FALSE;          // NG
1064             }
1065             else if (end_adr <= MB_ARM7_STATIC_LOAD_AREA_HI)
1066             {
1067                 return TRUE;           // OK
1068             }
1069             else if (end_adr < MB_BSSDESC_ADDRESS && size <= MB_ARM7_STATIC_RECV_BUFFER_SIZE)
1070             {
1071                 return TRUE;           // OK (needs relocation)
1072             }
1073             else
1074             {
1075                 return FALSE;          // NG
1076             }
1077         }
1078         else
1079             /* wram */
1080         if (address >= HW_WRAM && address < HW_WRAM + MB_ARM7_STATIC_LOAD_WRAM_MAX_SIZE)
1081         {
1082             u32     end_adr = address + size;
1083             if (end_adr <= (HW_WRAM + MB_ARM7_STATIC_LOAD_WRAM_MAX_SIZE))
1084             {
1085                 return TRUE;           // OK
1086             }
1087             else
1088             {
1089                 return FALSE;          // NG
1090             }
1091         }
1092         break;
1093 
1094     default:
1095         return FALSE;
1096     }
1097 
1098     return FALSE;
1099 }
1100