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