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