1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - CARD - libraries
3   File:     card_rom.c
4 
5   Copyright 2007-2009 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2009-06-04#$
14   $Rev: 10698 $
15   $Author: okubata_ryoma $
16 
17  *---------------------------------------------------------------------------*/
18 
19 
20 #include <nitro/card/rom.h>
21 #include <nitro/card/pullOut.h>
22 #include <nitro/card/rom.h>
23 
24 
25 #include "../include/card_common.h"
26 #include "../include/card_rom.h"
27 
28 
29 #if defined(SDK_ARM9) && defined(SDK_TWL)
30 #define CARD_USING_HASHCHECK
31 #endif // defined(SDK_ARM9) && defined(SDK_TWL)
32 
33 #if defined(SDK_ARM9) || (defined(SDK_ARM7) && defined(SDK_ARM7_READROM_SUPPORT))
34 #define CARD_USING_ROMREADER
35 #endif // defined(SDK_ARM9) || (defined(SDK_ARM7) && defined(SDK_ARM7_READROM_SUPPORT))
36 
37 
38 /*---------------------------------------------------------------------------*/
39 /* Constants */
40 
41 #define CARD_COMMAND_PAGE           0x01000000
42 #define CARD_COMMAND_ID             0x07000000
43 #define CARD_COMMAND_REFRESH        0x00000000
44 #define CARD_COMMAND_STAT           CARD_COMMAND_ID
45 #define CARD_COMMAND_MASK           0x07000000
46 #define CARD_RESET_HI               0x20000000
47 #define CARD_COMMAND_OP_G_READID    0xB8
48 #define CARD_COMMAND_OP_G_READPAGE  0xB7
49 #define CARD_COMMAND_OP_G_READSTAT  0xD6
50 #define CARD_COMMAND_OP_G_REFRESH   0xB5
51 #ifdef SDK_TWL
52 #define CARD_COMMAND_OP_N_READID    0x90
53 #define CARD_COMMAND_OP_N_READPAGE  0x00
54 #define CARD_COMMAND_OP_N_READSTAT  CARD_COMMAND_OP_G_READSTAT
55 #define CARD_COMMAND_OP_N_REFRESH   CARD_COMMAND_OP_G_REFRESH
56 #endif
57 
58 // ROM ID
59 
60 #define CARD_ROMID_1TROM_MASK       0x80000000UL  // 1T-ROM type
61 #define CARD_ROMID_TWLROM_MASK      0x40000000UL  // TWL-ROM
62 #define CARD_ROMID_REFRESH_MASK     0x20000000UL  // Refresh support
63 
64 // ROM STATUS
65 
66 #define CARD_ROMST_RFS_WARN_L1_MASK 0x00000004UL
67 #define CARD_ROMST_RFS_WARN_L2_MASK 0x00000008UL
68 #define CARD_ROMST_RFS_READY_MASK   0x00000020UL
69 
70 
71 /*---------------------------------------------------------------------------*/
72 /* Variables */
73 
74 // Base offset during read (normally 0)
75 u32         cardi_rom_base;
76 
77 // Other internal information
78 static int                (*CARDiReadRomFunction) (void *userdata, void *buffer, u32 offset, u32 length);
79 
80 static CARDTransferInfo     CARDiDmaReadInfo[1];
81 static CARDTransferInfo    *CARDiDmaReadRegisteredInfo;
82 
83 static u32                  cache_page = 1;
84 static u8                   CARDi_cache_buf[CARD_ROM_PAGE_SIZE] ATTRIBUTE_ALIGN(32);
85 static BOOL                 CARDiEnableCacheInvalidationIC = FALSE;
86 static BOOL                 CARDiEnableCacheInvalidationDC = TRUE;
87 
88 extern BOOL OSi_IsThreadInitialized;
89 
90 static u8                   CARDiOwnSignature[CARD_ROM_DOWNLOAD_SIGNATURE_SIZE] ATTRIBUTE_ALIGN(4);
91 
92 
93 /*---------------------------------------------------------------------------*/
94 /* Functions */
95 
96 void CARD_RefreshRom(void);
97 
98 /*---------------------------------------------------------------------------*
99   Name:         CARDi_SetRomOp
100 
101   Description:  Sets the card command.
102 
103   Arguments:    command: Command
104                 offset: Transfer page count
105 
106   Returns:      None.
107  *---------------------------------------------------------------------------*/
CARDi_SetRomOp(u32 command,u32 offset)108 static void CARDi_SetRomOp(u32 command, u32 offset)
109 {
110     u32     cmd1 = (u32)((offset >> 8) | (command << 24));
111     u32     cmd2 = (u32)((offset << 24));
112     // Just in case, waiting for completion of prior ROM command
113     while ((reg_MI_MCCNT1 & REG_MI_MCCNT1_START_MASK) != 0)
114     {
115     }
116     // Master enable
117     reg_MI_MCCNT0 = (u16)(REG_MI_MCCNT0_E_MASK | REG_MI_MCCNT0_I_MASK |
118                           (reg_MI_MCCNT0 & ~REG_MI_MCCNT0_SEL_MASK));
119     // Command settings
120     reg_MI_MCCMD0 = MI_HToBE32(cmd1);
121     reg_MI_MCCMD1 = MI_HToBE32(cmd2);
122 }
123 
124 /*---------------------------------------------------------------------------*
125   Name:         CARDi_GetRomFlag
126 
127   Description:  Gets card command control parameters.
128 
129   Arguments:    flag: Command type to issue to the card device
130                            (CARD_COMMAND_PAGE / CARD_COMMAND_ID /
131                             CARD_COMMAND_STAT / CARD_COMMAND_REFRESH)
132 
133   Returns:      Card command control parameters.
134  *---------------------------------------------------------------------------*/
CARDi_GetRomFlag(u32 flag)135 SDK_INLINE u32 CARDi_GetRomFlag(u32 flag)
136 {
137     u32     rom_ctrl = *(vu32 *)(HW_CARD_ROM_HEADER + 0x60);
138     return (u32)(flag | REG_MI_MCCNT1_START_MASK | CARD_RESET_HI | (rom_ctrl & ~CARD_COMMAND_MASK));
139 }
140 
141 /*---------------------------------------------------------------------------*
142   Name:         CARDi_IsTwlRom
143 
144   Description:  Determines whether game card is installed with ROM that supports TWL.
145                 Returns TRUE when ROM is installed that supports TWL even for a NITRO application.
146 
147   Arguments:    None.
148 
149   Returns:      If ROM supports TWL, return TRUE.
150  *---------------------------------------------------------------------------*/
CARDi_IsTwlRom(void)151 BOOL CARDi_IsTwlRom(void)
152 {
153     u32 iplCardID = *(u32 *)(HW_BOOT_CHECK_INFO_BUF);
154 
155     // If there is no card when starting up, always return FALSE
156     if ( ! iplCardID )
157     {
158         return FALSE;
159     }
160 
161     return (CARDi_ReadRomID() & CARD_ROMID_TWLROM_MASK) ? TRUE : FALSE;
162 }
163 
164 #ifdef SDK_TWL
165 
166 /*---------------------------------------------------------------------------*
167   Name:         CARDi_IsNormalMode
168 
169   Description:  Determines whether game card is in NORMAL mode.
170 
171   Arguments:    None.
172 
173   Returns:      If game card is in NORMAL mode, returns TRUE.
174  *---------------------------------------------------------------------------*/
CARDi_IsNormalMode(void)175 static BOOL CARDi_IsNormalMode(void)
176 {
177     const CARDRomHeader *ch = (void*)CARD_GetRomHeader();
178     const CARDRomHeaderTWL *oh = CARD_GetOwnRomHeaderTWL();
179 
180     return OS_IsRunOnTwl() &&
181            (OS_GetBootType() != OS_BOOTTYPE_ROM) &&
182            oh->access_control.game_card_on &&
183            ! oh->access_control.game_card_nitro_mode;
184 }
185 
186 #endif
187 
188 /*---------------------------------------------------------------------------*
189   Name:         CARDi_StartRomPageTransfer
190 
191   Description:  Starts ROM page transfers.
192 
193   Arguments:    offset: ROM offset of transfer source
194 
195   Returns:      None.
196  *---------------------------------------------------------------------------*/
CARDi_StartRomPageTransfer(u32 offset)197 static void CARDi_StartRomPageTransfer(u32 offset)
198 {
199     u8 op = CARD_COMMAND_OP_G_READPAGE;
200 #ifdef SDK_TWL
201     if ( CARDi_IsNormalMode() )
202     {
203         op = CARD_COMMAND_OP_N_READPAGE;
204     }
205 #endif
206 
207     CARDi_SetRomOp(op, offset);
208     reg_MI_MCCNT1 = CARDi_GetRomFlag(CARD_COMMAND_PAGE);
209 }
210 
211 /*---------------------------------------------------------------------------*
212   Name:         CARDi_ReadRomIDCore
213 
214   Description:  Reads the card ID.
215 
216   Arguments:    None.
217 
218   Returns:      Card ID.
219  *---------------------------------------------------------------------------*/
CARDi_ReadRomIDCore(void)220 u32 CARDi_ReadRomIDCore(void)
221 {
222     u8 op = CARD_COMMAND_OP_G_READID;
223 #ifdef SDK_TWL
224     if ( CARDi_IsNormalMode() )
225     {
226         op = CARD_COMMAND_OP_N_READID;
227     }
228 #endif
229 
230     CARDi_SetRomOp(op, 0);
231     reg_MI_MCCNT1 = (u32)(CARDi_GetRomFlag(CARD_COMMAND_ID) & ~REG_MI_MCCNT1_L1_MASK);
232     while ((reg_MI_MCCNT1 & REG_MI_MCCNT1_RDY_MASK) == 0)
233     {
234     }
235     return reg_MI_MCD1;
236 }
237 
238 /*---------------------------------------------------------------------------*
239   Name:         CARDi_ReadRomStatusCore
240 
241   Description:  Reads the card status.
242                 Issue only when detecting ROM that supports refresh.
243                 Required even for NITRO applications installed with supporting ROM.
244 
245   Arguments:    None.
246 
247   Returns:      Card status.
248  *---------------------------------------------------------------------------*/
CARDi_ReadRomStatusCore(void)249 u32 CARDi_ReadRomStatusCore(void)
250 {
251     u32 iplCardID = *(u32 *)(HW_BOOT_CHECK_INFO_BUF);
252 
253     if ( ! (iplCardID & CARD_ROMID_REFRESH_MASK) )
254     {
255         return CARD_ROMST_RFS_READY_MASK;
256     }
257 
258     CARDi_SetRomOp(CARD_COMMAND_OP_G_READSTAT, 0);
259     reg_MI_MCCNT1 = (u32)(CARDi_GetRomFlag(CARD_COMMAND_STAT) & ~REG_MI_MCCNT1_L1_MASK);
260     while ((reg_MI_MCCNT1 & REG_MI_MCCNT1_RDY_MASK) == 0)
261     {
262     }
263     return reg_MI_MCD1;
264 }
265 
266 /*---------------------------------------------------------------------------*
267   Name:         CARD_RefreshRom
268 
269   Description:  Refreshes bad blocks on card ROM.
270                 Issue only when detecting ROM that supports refresh.
271                 Required even for NITRO applications installed with this ROM.
272                 A forced refresh occurs in the extremely rare case that ECC correction is about to fail, even in the CARD_ReadRom function. However, the refresh may take approximately 50 ms, so call this function periodically at a timing that is safe for the application even if delays occur.
273 
274 
275 
276 
277   Arguments:    None.
278 
279   Returns:      None.
280  *---------------------------------------------------------------------------*/
CARD_RefreshRom(void)281 void CARD_RefreshRom(void)
282 {
283     SDK_ASSERT(CARD_IsAvailable());
284     SDK_ASSERTMSG(CARDi_GetTargetMode() == CARD_TARGET_ROM, "must be locked by CARD_LockRom()");
285 
286 #if defined(SDK_ARM9)
287     (void)CARDi_WaitForTask(&cardi_common, TRUE, NULL, NULL);
288     // Detect card removal here
289     CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
290 #endif // defined(SDK_ARM9)
291 
292     CARDi_RefreshRom(CARD_ROMST_RFS_WARN_L1_MASK | CARD_ROMST_RFS_WARN_L2_MASK);
293 
294 #if defined(SDK_ARM9)
295     cardi_common.cmd->result = CARD_RESULT_SUCCESS;
296     CARDi_EndTask(&cardi_common);
297 #endif // defined(SDK_ARM9)
298 }
299 
300 /*---------------------------------------------------------------------------*
301   Name:         CARDi_RefreshRom
302 
303   Description:  Refreshes bad blocks on card ROM.
304                 Issue only when detecting ROM that supports refresh.
305                 Required even for NITRO applications installed with this ROM.
306 
307   Arguments:    warn_mask: Warning level specification
308 
309   Returns:      None.
310  *---------------------------------------------------------------------------*/
CARDi_RefreshRom(u32 warn_mask)311 void CARDi_RefreshRom(u32 warn_mask)
312 {
313     if (CARDi_ReadRomStatusCore() & warn_mask)
314     {
315         CARDi_RefreshRomCore();
316         // There is the possibility that completion of the refresh can take more than 100 ms
317         while ( !(CARDi_ReadRomStatusCore() & CARD_ROMST_RFS_READY_MASK) )
318         {
319             // If that is possible, sleep
320             if ( OSi_IsThreadInitialized &&
321                  OS_IsAlarmAvailable() )
322             {
323                 OS_Sleep(1);
324             }
325         }
326     }
327 }
328 
329 /*---------------------------------------------------------------------------*
330   Name:         CARDi_RefreshRomCore
331 
332   Description:  Refreshes bad blocks on card ROM.
333                 Required even for NITRO applications installed with this ROM.
334                 Latency settings are invalid because the command is issued unilaterally to the card.
335 
336   Arguments:    None.
337 
338   Returns:      None.
339  *---------------------------------------------------------------------------*/
CARDi_RefreshRomCore(void)340 void CARDi_RefreshRomCore(void)
341 {
342     CARDi_SetRomOp(CARD_COMMAND_OP_G_REFRESH, 0);
343     reg_MI_MCCNT1 = (u32)(CARDi_GetRomFlag(CARD_COMMAND_REFRESH) & ~REG_MI_MCCNT1_L1_MASK);
344     while (reg_MI_MCCNT1 & REG_MI_MCCNT1_START_MASK)
345     {
346     }
347 }
348 
349 /*---------------------------------------------------------------------------*
350   Name:         CARDi_ReadRomWithCPU
351 
352   Description:  Transfers ROM using the CPU.
353                 There is no need to consider cache or page unit restrictions, but note that the function will block until the transfer is complete.
354 
355 
356   Arguments:    userdata: (Dummy to use as the other callback)
357                 buffer: Transfer destination buffer
358                 offset: Transfer source ROM offset
359                 length: Transfer size
360 
361   Returns:      None.
362  *---------------------------------------------------------------------------*/
CARDi_ReadRomWithCPU(void * userdata,void * buffer,u32 offset,u32 length)363 int CARDi_ReadRomWithCPU(void *userdata, void *buffer, u32 offset, u32 length)
364 {
365     int     retval = (int)length;
366     // Cache the global variables frequently used to the local variables
367     u32         cachedPage = cache_page;
368     u8  * const cacheBuffer = CARDi_cache_buf;
369     while (length > 0)
370     {
371         // ROM transfer is always in page units
372         u8     *ptr = (u8 *)buffer;
373         u32     n = CARD_ROM_PAGE_SIZE;
374         u32     pos = MATH_ROUNDDOWN(offset, CARD_ROM_PAGE_SIZE);
375         // Use the cache if the same as the previous page
376         if (pos == cachedPage)
377         {
378             ptr = cacheBuffer;
379         }
380         else
381         {
382             // Transfer to cache if not possible to transfer directly to the buffer
383             if(((pos != offset) || (((u32)buffer & 3) != 0) || (length < n)))
384             {
385                 cachedPage = pos;
386                 ptr = cacheBuffer;
387             }
388             // Read directly to the buffer guaranteed with 4-byte alignment using the CPU
389             CARDi_StartRomPageTransfer(pos);
390             {
391                 u32     word = 0;
392                 for (;;)
393                 {
394                     // Wait for one word transfer to be completed
395                     u32     ctrl = reg_MI_MCCNT1;
396                     if ((ctrl & REG_MI_MCCNT1_RDY_MASK) != 0)
397                     {
398                         // Read data and store in buffer if necessary
399                         u32     data = reg_MI_MCD1;
400                         if (word < (CARD_ROM_PAGE_SIZE / sizeof(u32)))
401                         {
402                             ((u32 *)ptr)[word++] = data;
403                         }
404                     }
405                     // End if 1 page transfer is completed
406                     if ((ctrl & REG_MI_MCCNT1_START_MASK) == 0)
407                     {
408                         break;
409                     }
410                 }
411             }
412         }
413         // Transfer from cache if via cache
414         if (ptr == cacheBuffer)
415         {
416             u32     mod = offset - pos;
417             n = MATH_MIN(length, CARD_ROM_PAGE_SIZE - mod);
418             MI_CpuCopy8(cacheBuffer + mod, buffer, n);
419         }
420         buffer = (u8 *)buffer + n;
421         offset += n;
422         length -= n;
423     }
424     // Determine whether card was removed while accessed
425     CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
426     // If local variables, apply to global variables
427     cache_page = cachedPage;
428     (void)userdata;
429     return retval;
430 }
431 
432 #if defined(CARD_USING_ROMREADER)
433 /*---------------------------------------------------------------------------*
434   Name:         CARDi_DmaReadPageCallback
435 
436   Description:  Callback when ROM page DMA transfer is completed.
437 
438   Arguments:    None.
439 
440   Returns:      None.
441  *---------------------------------------------------------------------------*/
CARDi_DmaReadPageCallback(void)442 static void CARDi_DmaReadPageCallback(void)
443 {
444     CARDTransferInfo   *info = CARDiDmaReadRegisteredInfo;
445     if (info)
446     {
447         info->src += CARD_ROM_PAGE_SIZE;
448         info->dst += CARD_ROM_PAGE_SIZE;
449         info->len -= CARD_ROM_PAGE_SIZE;
450         // Transfer the next page if necessary
451         if (info->len > 0)
452         {
453             CARDi_StartRomPageTransfer(info->src);
454         }
455         // Transfer completed
456         else
457         {
458             cardi_common.DmaCall->Stop(cardi_common.dma);
459             (void)OS_DisableIrqMask(OS_IE_CARD_DATA);
460             (void)OS_ResetRequestIrqMask(OS_IE_CARD_DATA);
461             CARDiDmaReadRegisteredInfo = NULL;
462             // Determine whether card was removed while accessed
463             CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
464             if (info->callback)
465             {
466                 (*info->callback)(info->userdata);
467             }
468         }
469     }
470 }
471 
472 /*---------------------------------------------------------------------------*
473   Name:         CARDi_ReadRomWithDMA
474 
475   Description:  Transfers ROM using the DMA.
476                 After transfer of the first page starts, the function returns control immediately.
477 
478   Arguments:    info: Transfer information
479 
480   Returns:      None.
481  *---------------------------------------------------------------------------*/
CARDi_ReadRomWithDMA(CARDTransferInfo * info)482 void CARDi_ReadRomWithDMA(CARDTransferInfo *info)
483 {
484     OSIntrMode bak_psr = OS_DisableInterrupts();
485     CARDiDmaReadRegisteredInfo = info;
486     // Set card transfer completion interrupt
487     (void)OS_SetIrqFunction(OS_IE_CARD_DATA, CARDi_DmaReadPageCallback);
488     (void)OS_ResetRequestIrqMask(OS_IE_CARD_DATA);
489     (void)OS_EnableIrqMask(OS_IE_CARD_DATA);
490     (void)OS_RestoreInterrupts(bak_psr);
491     // Set CARD-DMA (transfer idling)
492     cardi_common.DmaCall->Recv(cardi_common.dma, (void *)&reg_MI_MCD1, (void *)info->dst, CARD_ROM_PAGE_SIZE);
493     // Start first ROM transfer
494     CARDi_StartRomPageTransfer(info->src);
495 }
496 
CARDi_DmaReadDone(void * userdata)497 static void CARDi_DmaReadDone(void *userdata)
498 {
499     (void)userdata;
500 #ifdef SDK_ARM9
501     // Determine whether card was removed while accessed
502     CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
503 #endif
504     // Refresh at final warning stage of ROM-ECC correction
505     CARDi_RefreshRom(CARD_ROMST_RFS_WARN_L2_MASK);
506 
507     cardi_common.cmd->result = CARD_RESULT_SUCCESS;
508     CARDi_EndTask(&cardi_common);
509 }
510 
511 /*---------------------------------------------------------------------------*
512   Name:         CARDi_IsRomDmaAvailable
513 
514   Description:  Determines whether asynchronous DMA is usable in ROM transfer.
515 
516   Arguments:    dma: DMA channel
517                 dst: Transfer destination buffer
518                 src: Transfer source ROM offset
519                 len: Transfer size
520 
521   Returns:      If DMA is usable in ROM transfer, return TRUE.
522  *---------------------------------------------------------------------------*/
CARDi_IsRomDmaAvailable(u32 dma,void * dst,u32 src,u32 len)523 static BOOL CARDi_IsRomDmaAvailable(u32 dma, void *dst, u32 src, u32 len)
524 {
525     return (dma <= MI_DMA_MAX_NUM) && (len > 0) && (((u32)dst & 31) == 0) &&
526 #ifdef SDK_ARM9
527         (((u32)dst + len <= OS_GetITCMAddress()) || ((u32)dst >= OS_GetITCMAddress() + HW_ITCM_SIZE)) &&
528         (((u32)dst + len <= OS_GetDTCMAddress()) || ((u32)dst >= OS_GetDTCMAddress() + HW_DTCM_SIZE)) &&
529 #endif
530         (((src | len) & (CARD_ROM_PAGE_SIZE - 1)) == 0);
531 }
532 
533 /*---------------------------------------------------------------------------*
534   Name:         CARDi_ReadRomSyncCore
535 
536   Description:  Common process for synchronous card reads.
537 
538   Arguments:    c: CARDiCommon structure
539 
540   Returns:      None.
541  *---------------------------------------------------------------------------*/
CARDi_ReadRomSyncCore(CARDiCommon * c)542 static void CARDi_ReadRomSyncCore(CARDiCommon *c)
543 {
544     // Run ROM access routine that corresponds to the execution environment
545     (void)(*CARDiReadRomFunction)(NULL, (void*)c->dst, c->src, c->len);
546 #ifdef SDK_ARM9
547     // Determine whether card was removed while accessed
548     CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
549 #endif
550     // Refresh at final warning stage of ROM-ECC correction
551     CARDi_RefreshRom(CARD_ROMST_RFS_WARN_L2_MASK);
552 
553     cardi_common.cmd->result = CARD_RESULT_SUCCESS;
554 }
555 #endif // defined(CARD_USING_ROMREADER)
556 
557 /*---------------------------------------------------------------------------*
558   Name:         CARDi_ReadRom
559 
560   Description:  Basic function of ROM read.
561 
562   Arguments:    dma: DMA channel to use
563                 src: Transfer source offset
564                 dst: Transfer destination memory address
565                 len: Transfer size
566                 callback: Completion callback (NULL if not used)
567                 arg: Argument of completion callback (ignored if not used)
568                 is_async: If set to asynchronous mode, TRUE
569 
570   Returns:      None.
571  *---------------------------------------------------------------------------*/
CARDi_ReadRom(u32 dma,const void * src,void * dst,u32 len,MIDmaCallback callback,void * arg,BOOL is_async)572 void CARDi_ReadRom(u32 dma,
573                    const void *src, void *dst, u32 len,
574                    MIDmaCallback callback, void *arg, BOOL is_async)
575 {
576 #if defined(CARD_USING_ROMREADER)
577     CARDiCommon *const c = &cardi_common;
578 
579     SDK_ASSERT(CARD_IsAvailable());
580     SDK_ASSERT(CARDi_GetTargetMode() == CARD_TARGET_ROM);
581     SDK_ASSERTMSG((dma != 0), "cannot specify DMA channel 0");
582 
583     // Determine validity of card access
584     CARD_CheckEnabled();
585     if ((CARDi_GetAccessLevel() & CARD_ACCESS_LEVEL_ROM) == 0)
586     {
587         OS_TPanic("this program cannot access CARD-ROM!");
588     }
589 
590     // Exclusive wait on ARM9 side
591     (void)CARDi_WaitForTask(c, TRUE, callback, arg);
592 
593     // Get DMA interface
594     c->DmaCall = CARDi_GetDmaInterface(dma);
595     c->dma = (u32)((c->DmaCall != NULL) ? (dma & MI_DMA_CHANNEL_MASK) : MI_DMA_NOT_USE);
596     if (c->dma <= MI_DMA_MAX_NUM)
597     {
598         c->DmaCall->Stop(c->dma);
599     }
600 
601     // Set this time's transfer parameters
602     c->src = (u32)((u32)src + cardi_rom_base);
603     c->dst = (u32)dst;
604     c->len = (u32)len;
605 
606     // Set transfer parameter
607     {
608         CARDTransferInfo   *info = CARDiDmaReadInfo;
609         info->callback = CARDi_DmaReadDone;
610         info->userdata = NULL;
611         info->src = c->src;
612         info->dst = c->dst;
613         info->len = c->len;
614         info->work = 0;
615     }
616 
617     // DMA transfers can be used in some cases, if it is an environment where hash checks are invalid
618     if ((CARDiReadRomFunction == CARDi_ReadRomWithCPU) &&
619         CARDi_IsRomDmaAvailable(c->dma, (void *)c->dst, c->src, c->len))
620     {
621 #if defined(SDK_ARM9)
622         // Depending upon the size of the transfer range, switch the manner in which the cache is invalidated
623         OSIntrMode bak_psr = OS_DisableInterrupts();
624         if (CARDiEnableCacheInvalidationIC)
625         {
626             CARDi_ICInvalidateSmart((void *)c->dst, c->len, c->flush_threshold_ic);
627         }
628         if (CARDiEnableCacheInvalidationDC)
629         {
630             CARDi_DCInvalidateSmart((void *)c->dst, c->len, c->flush_threshold_dc);
631         }
632         (void)OS_RestoreInterrupts(bak_psr);
633 #endif
634         // Start asynchronous transfer using DMA
635         CARDi_ReadRomWithDMA(CARDiDmaReadInfo);
636         // Wait until complete here if synchronous transfer is requested
637         if (!is_async)
638         {
639             CARD_WaitRomAsync();
640         }
641     }
642     else
643     {
644         // Even with CPU transfers, it is necessary to invalidate because the instruction cache is incompatible
645         if (CARDiEnableCacheInvalidationIC)
646         {
647             CARDi_ICInvalidateSmart((void *)c->dst, c->len, c->flush_threshold_ic);
648         }
649         // Register task to thread if some form of direct processing is required by the CPU
650         (void)CARDi_ExecuteOldTypeTask(CARDi_ReadRomSyncCore, is_async);
651     }
652 #else
653     (void)dma;
654     (void)is_async;
655     (void)CARDi_ReadRomWithCPU(NULL, dst, (u32)src, len);
656     if (callback)
657     {
658         (*callback)(arg);
659     }
660 #endif // defined(CARD_USING_ROMREADER)
661 }
662 
663 /*---------------------------------------------------------------------------*
664   Name:         CARDi_ReadRomID
665 
666   Description:  Reads the card ID.
667 
668   Arguments:    None.
669 
670   Returns:      Card ID.
671  *---------------------------------------------------------------------------*/
CARDi_ReadRomID(void)672 u32 CARDi_ReadRomID(void)
673 {
674     u32     ret = 0;
675 
676     SDK_ASSERT(CARD_IsAvailable());
677     SDK_ASSERTMSG(CARDi_GetTargetMode() == CARD_TARGET_ROM, "must be locked by CARD_LockRom()");
678 
679 #if defined(SDK_ARM9)
680     (void)CARDi_WaitForTask(&cardi_common, TRUE, NULL, NULL);
681 #endif // defined(SDK_ARM9)
682 
683     /* Direct access is possible, so execute here */
684     ret = CARDi_ReadRomIDCore();
685 #ifdef SDK_ARM9
686     // Detect card removal here
687     CARDi_CheckPulledOutCore(ret);
688 #endif
689 
690 #if defined(SDK_ARM9)
691     cardi_common.cmd->result = CARD_RESULT_SUCCESS;
692     CARDi_EndTask(&cardi_common);
693 #endif // defined(SDK_ARM9)
694 
695     return ret;
696 }
697 
698 #if defined(CARD_USING_HASHCHECK)
699 #include <twl/ltdmain_begin.h>
700 
701 // ROM hash calculation buffer
702 u8     *CARDiHashBufferAddress = NULL;
703 u32     CARDiHashBufferLength = 0;
704 static CARDRomHashContext   context[1];
705 
706 /*---------------------------------------------------------------------------*
707   Name:         CARDi_ReadCardWithHash
708 
709   Description:  ROM transfer while confirming hash.
710 
711   Arguments:    buffer: Transfer destination buffer
712                 offset: Transfer source ROM offset
713                 length: Transfer size
714 
715   Returns:      None.
716  *---------------------------------------------------------------------------*/
CARDi_ReadCardWithHash(void * userdata,void * buffer,u32 offset,u32 length)717 static int CARDi_ReadCardWithHash(void *userdata, void *buffer, u32 offset, u32 length)
718 {
719     (void)userdata;
720     CARD_ReadRomHashImage(context, buffer, offset, length);
721     return (int)length;
722 }
723 
724 /*---------------------------------------------------------------------------*
725   Name:         CARDi_ReadCardWithHashInternalAsync
726 
727   Description:  Asynchronous DMA transfer for partial use internally with ROM transfers of the hash verified version.
728 
729   Arguments:    userdata: User-defined argument
730                 buffer: Transfer destination buffer
731                 offset: Transfer source ROM offset
732                 length: Transfer size
733 
734   Returns:      None.
735  *---------------------------------------------------------------------------*/
CARDi_ReadCardWithHashInternalAsync(void * userdata,void * buffer,u32 offset,u32 length)736 static int CARDi_ReadCardWithHashInternalAsync(void *userdata, void *buffer, u32 offset, u32 length)
737 {
738     if (cardi_common.dma == MI_DMA_NOT_USE)
739     {
740         length = 0;
741     }
742     else
743     {
744         CARDRomHashContext *context = (CARDRomHashContext *)userdata;
745         static CARDTransferInfo card_hash_info[1];
746         DC_FlushRange(buffer, length);
747         card_hash_info->callback = (void(*)(void*))CARD_NotifyRomHashReadAsync;
748         card_hash_info->userdata = context;
749         card_hash_info->src = offset;
750         card_hash_info->dst = (u32)buffer;
751         card_hash_info->len = length;
752         card_hash_info->command = 0;
753         card_hash_info->work = 0;
754         CARDi_ReadRomWithDMA(card_hash_info);
755     }
756     return (int)length;
757 }
758 
759 /*---------------------------------------------------------------------------*
760   Name:         CARDi_InitRomHash
761 
762   Description:  If possible, switches to hash verification version ROM transfer.
763 
764   Arguments:    None.
765 
766   Returns:      None.
767  *---------------------------------------------------------------------------*/
CARDi_InitRomHash(void)768 static void CARDi_InitRomHash(void)
769 {
770     // Because applications will often consume the entire arena before it is required by a function call such as FS_Init, always allocate a buffer for the hash context here
771     //
772     //
773     u8     *lo = (u8 *)MATH_ROUNDUP((u32)OS_GetMainArenaLo(), 32);
774     u8     *hi = (u8 *)MATH_ROUNDDOWN((u32)OS_GetMainArenaHi(), 32);
775     u32     len = CARD_CalcRomHashBufferLength(CARD_GetOwnRomHeaderTWL());
776     if (&lo[len] > hi)
777     {
778         OS_TPanic("cannot allocate memory for ROM-hash from ARENA");
779     }
780     else
781     {
782         OS_SetMainArenaLo(&lo[len]);
783         CARDiHashBufferAddress = lo;
784         CARDiHashBufferLength = len;
785         // Actually load if it is an environment where the ROM boot and hash table exist
786         if ((OS_GetBootType() == OS_BOOTTYPE_ROM) &&
787             ((((const u8 *)HW_TWL_ROM_HEADER_BUF)[0x1C] & 0x01) != 0))
788         {
789             cardi_common.dma = MI_DMA_NOT_USE;
790             CARDiReadRomFunction = CARDi_ReadCardWithHash;
791             {
792                 u16     id = (u16)OS_GetLockID();
793                 CARD_LockRom(id);
794                 CARD_InitRomHashContext(context,
795                                         CARD_GetOwnRomHeaderTWL(),
796                                         CARDiHashBufferAddress,
797                                         CARDiHashBufferLength,
798                                         CARDi_ReadRomWithCPU,
799                                         CARDi_ReadCardWithHashInternalAsync,
800                                         context);
801                 // Destroy the pointer so that there is no competition for use of the same buffer
802                 CARDiHashBufferAddress = NULL;
803                 CARDiHashBufferLength = 0;
804                 CARD_UnlockRom(id);
805                 OS_ReleaseLockID(id);
806             }
807         }
808     }
809 }
810 #include <twl/ltdmain_end.h>
811 #endif
812 
813 /*---------------------------------------------------------------------------*
814   Name:         CARDi_InitRom
815 
816   Description:  Initializes the ROM access management information.
817 
818   Arguments:    None.
819 
820   Returns:      None.
821  *---------------------------------------------------------------------------*/
CARDi_InitRom(void)822 void CARDi_InitRom(void)
823 {
824 #if defined(CARD_USING_ROMREADER)
825     CARDiReadRomFunction = CARDi_ReadRomWithCPU;
826     // Hash verification is implemented for ROM data access in the TWL-SDK, but because signature data for DS Download Play is embedded after the hash is calculated, it is prohibited to carelessly read data from this point on with CARD_ReadRom(). It must be explicitly accessed using CARDi_GetOwnSignature().
827     //
828     //
829     //
830     if ((OS_GetBootType() == OS_BOOTTYPE_ROM) && CARD_GetOwnRomHeader()->rom_size)
831     {
832         u16     id = (u16)OS_GetLockID();
833         CARD_LockRom(id);
834         (void)CARDi_ReadRomWithCPU(NULL, CARDiOwnSignature,
835                                    CARD_GetOwnRomHeader()->rom_size,
836                                    CARD_ROM_DOWNLOAD_SIGNATURE_SIZE);
837         CARD_UnlockRom(id);
838         OS_ReleaseLockID(id);
839     }
840 #if defined(CARD_USING_HASHCHECK)
841     // Adopts a routine that also verifies hash, if usable
842     if (OS_IsRunOnTwl())
843     {
844 		CARDi_InitRomHash();
845     }
846 #endif
847 #else
848     CARDiReadRomFunction = NULL;
849 #endif
850 }
851 
852 
853 /*---------------------------------------------------------------------------*
854   Name:         CARD_WaitRomAsync
855 
856   Description:  Idles until the ROM access function is completed.
857 
858   Arguments:    None.
859 
860   Returns:      None.
861  *---------------------------------------------------------------------------*/
CARD_WaitRomAsync(void)862 void CARD_WaitRomAsync(void)
863 {
864     (void)CARDi_WaitAsync();
865 }
866 
867 /*---------------------------------------------------------------------------*
868   Name:         CARD_TryWaitRomAsync
869 
870   Description:  Determines whether the ROM access function is completed.
871 
872   Arguments:    None.
873 
874   Returns:      TRUE when the ROM access function is completed.
875  *---------------------------------------------------------------------------*/
CARD_TryWaitRomAsync(void)876 BOOL CARD_TryWaitRomAsync(void)
877 {
878     return CARDi_TryWaitAsync();
879 }
880 
881 /*---------------------------------------------------------------------------*
882   Name:         CARDi_GetOwnSignature
883 
884   Description:  Gets its own DS Download Play signature data.
885 
886   Arguments:    None.
887 
888   Returns:      Its own DS Download Play signature data.
889  *---------------------------------------------------------------------------*/
CARDi_GetOwnSignature(void)890 const u8* CARDi_GetOwnSignature(void)
891 {
892     return CARDiOwnSignature;
893 }
894 
895 /*---------------------------------------------------------------------------*
896   Name:         CARDi_SetOwnSignature
897 
898   Description:  Sets its own DS Download Play signature data.
899                 Calls from the host library when booted without a card.
900 
901   Arguments:    DS Download Play signature data
902 
903   Returns:      None.
904  *---------------------------------------------------------------------------*/
CARDi_SetOwnSignature(const void * signature)905 void CARDi_SetOwnSignature(const void *signature)
906 {
907     MI_CpuCopy8(signature, CARDiOwnSignature, CARD_ROM_DOWNLOAD_SIGNATURE_SIZE);
908 }
909 
910 #if defined(SDK_ARM9)
911 /*---------------------------------------------------------------------------*
912   Name:         CARD_GetCacheFlushFlag
913 
914   Description:  Gets setting flags of whether to invalidate cache automatically.
915 
916   Arguments:    icache: Pointer to the location where the automatic invalidation flag for the instruction cache is stored
917                                   Ignore if NULL.
918                 dcache: Pointer to the location the automatic invalidation flag for the instruction cache is stored.
919                                   Ignore if NULL.
920 
921   Returns:      None.
922  *---------------------------------------------------------------------------*/
CARD_GetCacheFlushFlag(BOOL * icache,BOOL * dcache)923 void CARD_GetCacheFlushFlag(BOOL *icache, BOOL *dcache)
924 {
925     SDK_ASSERT(CARD_IsAvailable());
926     if (icache)
927     {
928         *icache = CARDiEnableCacheInvalidationIC;
929     }
930     if (dcache)
931     {
932         *dcache = CARDiEnableCacheInvalidationDC;
933     }
934 }
935 
936 /*---------------------------------------------------------------------------*
937   Name:         CARD_SetCacheFlushFlag
938 
939   Description:  Sets whether to automatically invalidate cache.
940                 By default, instruction cache is FALSE, and data cache is TRUE.
941 
942   Arguments:    icache: TRUE to enable automatic invalidation of the instruction cache
943                 dcache: TRUE to enable automatic invalidation of data caches
944 
945   Returns:      None.
946  *---------------------------------------------------------------------------*/
CARD_SetCacheFlushFlag(BOOL icache,BOOL dcache)947 void CARD_SetCacheFlushFlag(BOOL icache, BOOL dcache)
948 {
949     SDK_ASSERT(CARD_IsAvailable());
950     CARDiEnableCacheInvalidationIC = icache;
951     CARDiEnableCacheInvalidationDC = dcache;
952 }
953 #endif
954