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-07-14#$
14   $Rev: 10904 $
15   $Author: yosizaki $
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 CARDRomHeaderTWL *oh = CARD_GetOwnRomHeaderTWL();
178 
179     return OS_IsRunOnTwl() &&
180            (OS_GetBootType() != OS_BOOTTYPE_ROM) &&
181            oh->access_control.game_card_on &&
182            ! oh->access_control.game_card_nitro_mode;
183 }
184 
185 #endif
186 
187 /*---------------------------------------------------------------------------*
188   Name:         CARDi_StartRomPageTransfer
189 
190   Description:  Starts ROM page transfers.
191 
192   Arguments:    offset: ROM offset of transfer source
193 
194   Returns:      None.
195  *---------------------------------------------------------------------------*/
CARDi_StartRomPageTransfer(u32 offset)196 static void CARDi_StartRomPageTransfer(u32 offset)
197 {
198     u8 op = CARD_COMMAND_OP_G_READPAGE;
199 #ifdef SDK_TWL
200     if ( CARDi_IsNormalMode() )
201     {
202         op = CARD_COMMAND_OP_N_READPAGE;
203     }
204 #endif
205 
206     CARDi_SetRomOp(op, offset);
207     reg_MI_MCCNT1 = CARDi_GetRomFlag(CARD_COMMAND_PAGE);
208 }
209 
210 /*---------------------------------------------------------------------------*
211   Name:         CARDi_ReadRomIDCore
212 
213   Description:  Reads the card ID.
214 
215   Arguments:    None.
216 
217   Returns:      Card ID.
218  *---------------------------------------------------------------------------*/
CARDi_ReadRomIDCore(void)219 u32 CARDi_ReadRomIDCore(void)
220 {
221     u8 op = CARD_COMMAND_OP_G_READID;
222 #ifdef SDK_TWL
223     if ( CARDi_IsNormalMode() )
224     {
225         op = CARD_COMMAND_OP_N_READID;
226     }
227 #endif
228 
229     CARDi_SetRomOp(op, 0);
230     reg_MI_MCCNT1 = (u32)(CARDi_GetRomFlag(CARD_COMMAND_ID) & ~REG_MI_MCCNT1_L1_MASK);
231     while ((reg_MI_MCCNT1 & REG_MI_MCCNT1_RDY_MASK) == 0)
232     {
233     }
234     return reg_MI_MCD1;
235 }
236 
237 /*---------------------------------------------------------------------------*
238   Name:         CARDi_ReadRomStatusCore
239 
240   Description:  Reads the card status.
241                 Issue only when detecting ROM that supports refresh.
242                 Required even for NITRO applications installed with supporting ROM.
243 
244   Arguments:    None.
245 
246   Returns:      Card status.
247  *---------------------------------------------------------------------------*/
CARDi_ReadRomStatusCore(void)248 u32 CARDi_ReadRomStatusCore(void)
249 {
250     u32 iplCardID = *(u32 *)(HW_BOOT_CHECK_INFO_BUF);
251 
252     if ( ! (iplCardID & CARD_ROMID_REFRESH_MASK) )
253     {
254         return CARD_ROMST_RFS_READY_MASK;
255     }
256 
257     CARDi_SetRomOp(CARD_COMMAND_OP_G_READSTAT, 0);
258     reg_MI_MCCNT1 = (u32)(CARDi_GetRomFlag(CARD_COMMAND_STAT) & ~REG_MI_MCCNT1_L1_MASK);
259     while ((reg_MI_MCCNT1 & REG_MI_MCCNT1_RDY_MASK) == 0)
260     {
261     }
262     return reg_MI_MCD1;
263 }
264 
265 /*---------------------------------------------------------------------------*
266   Name:         CARD_RefreshRom
267 
268   Description:  Refreshes bad blocks on card ROM.
269                 Issue only when detecting ROM that supports refresh.
270                 Required even for NITRO applications installed with this ROM.
271                 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.
272 
273 
274 
275 
276   Arguments:    None.
277 
278   Returns:      None.
279  *---------------------------------------------------------------------------*/
CARD_RefreshRom(void)280 void CARD_RefreshRom(void)
281 {
282     SDK_ASSERT(CARD_IsAvailable());
283     SDK_TASSERTMSG(CARDi_GetTargetMode() == CARD_TARGET_ROM, "must be locked by CARD_LockRom()");
284 
285 #if defined(SDK_ARM9)
286     (void)CARDi_WaitForTask(&cardi_common, TRUE, NULL, NULL);
287     // Detect card removal here
288     CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
289 #endif // defined(SDK_ARM9)
290 
291     CARDi_RefreshRom(CARD_ROMST_RFS_WARN_L1_MASK | CARD_ROMST_RFS_WARN_L2_MASK);
292 
293 #if defined(SDK_ARM9)
294     cardi_common.cmd->result = CARD_RESULT_SUCCESS;
295     CARDi_EndTask(&cardi_common);
296 #endif // defined(SDK_ARM9)
297 }
298 
299 /*---------------------------------------------------------------------------*
300   Name:         CARDi_RefreshRom
301 
302   Description:  Refreshes bad blocks on card ROM.
303                 Issue only when detecting ROM that supports refresh.
304                 Required even for NITRO applications installed with this ROM.
305 
306   Arguments:    warn_mask: Warning level specification
307 
308   Returns:      None.
309  *---------------------------------------------------------------------------*/
CARDi_RefreshRom(u32 warn_mask)310 void CARDi_RefreshRom(u32 warn_mask)
311 {
312     if (CARDi_ReadRomStatusCore() & warn_mask)
313     {
314         CARDi_RefreshRomCore();
315         // There is the possibility that completion of the refresh can take more than 100 ms
316         while ( !(CARDi_ReadRomStatusCore() & CARD_ROMST_RFS_READY_MASK) )
317         {
318             // If that is possible, sleep
319             if ( OSi_IsThreadInitialized &&
320                  OS_IsAlarmAvailable() )
321             {
322                 OS_Sleep(1);
323             }
324         }
325     }
326 }
327 
328 /*---------------------------------------------------------------------------*
329   Name:         CARDi_RefreshRomCore
330 
331   Description:  Refreshes bad blocks on card ROM.
332                 Required even for NITRO applications installed with this ROM.
333                 Latency settings are invalid because the command is issued unilaterally to the card.
334 
335   Arguments:    None.
336 
337   Returns:      None.
338  *---------------------------------------------------------------------------*/
CARDi_RefreshRomCore(void)339 void CARDi_RefreshRomCore(void)
340 {
341     CARDi_SetRomOp(CARD_COMMAND_OP_G_REFRESH, 0);
342     reg_MI_MCCNT1 = (u32)(CARDi_GetRomFlag(CARD_COMMAND_REFRESH) & ~REG_MI_MCCNT1_L1_MASK);
343     while (reg_MI_MCCNT1 & REG_MI_MCCNT1_START_MASK)
344     {
345     }
346 }
347 
348 /*---------------------------------------------------------------------------*
349   Name:         CARDi_ReadRomWithCPU
350 
351   Description:  Transfers ROM using the CPU.
352                 There is no need to consider cache or page unit restrictions, but note that the function will block until the transfer is complete.
353 
354 
355   Arguments:    userdata: (Dummy to use as the other callback)
356                 buffer: Transfer destination buffer
357                 offset: Transfer source ROM offset
358                 length: Transfer size
359 
360   Returns:      None.
361  *---------------------------------------------------------------------------*/
CARDi_ReadRomWithCPU(void * userdata,void * buffer,u32 offset,u32 length)362 int CARDi_ReadRomWithCPU(void *userdata, void *buffer, u32 offset, u32 length)
363 {
364     int     retval = (int)length;
365     // Cache the global variables frequently used to the local variables
366     u32         cachedPage = cache_page;
367     u8  * const cacheBuffer = CARDi_cache_buf;
368     while (length > 0)
369     {
370         // ROM transfer is always in page units
371         u8     *ptr = (u8 *)buffer;
372         u32     n = CARD_ROM_PAGE_SIZE;
373         u32     pos = MATH_ROUNDDOWN(offset, CARD_ROM_PAGE_SIZE);
374         // Use the cache if the same as the previous page
375         if (pos == cachedPage)
376         {
377             ptr = cacheBuffer;
378         }
379         else
380         {
381             // Transfer to cache if not possible to transfer directly to the buffer
382             if(((pos != offset) || (((u32)buffer & 3) != 0) || (length < n)))
383             {
384                 cachedPage = pos;
385                 ptr = cacheBuffer;
386             }
387             // Read directly to the buffer guaranteed with 4-byte alignment using the CPU
388             CARDi_StartRomPageTransfer(pos);
389             {
390                 u32     word = 0;
391                 for (;;)
392                 {
393                     // Wait for one word transfer to be completed
394                     u32     ctrl = reg_MI_MCCNT1;
395                     if ((ctrl & REG_MI_MCCNT1_RDY_MASK) != 0)
396                     {
397                         // Read data and store in buffer if necessary
398                         u32     data = reg_MI_MCD1;
399                         if (word < (CARD_ROM_PAGE_SIZE / sizeof(u32)))
400                         {
401                             ((u32 *)ptr)[word++] = data;
402                         }
403                     }
404                     // End if 1 page transfer is completed
405                     if ((ctrl & REG_MI_MCCNT1_START_MASK) == 0)
406                     {
407                         break;
408                     }
409                 }
410             }
411         }
412         // Transfer from cache if via cache
413         if (ptr == cacheBuffer)
414         {
415             u32     mod = offset - pos;
416             n = MATH_MIN(length, CARD_ROM_PAGE_SIZE - mod);
417             MI_CpuCopy8(cacheBuffer + mod, buffer, n);
418         }
419         buffer = (u8 *)buffer + n;
420         offset += n;
421         length -= n;
422     }
423     // Determine whether card was removed while accessed
424     CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
425     // If local variables, apply to global variables
426     cache_page = cachedPage;
427     (void)userdata;
428     return retval;
429 }
430 
431 #if defined(CARD_USING_ROMREADER)
432 /*---------------------------------------------------------------------------*
433   Name:         CARDi_DmaReadPageCallback
434 
435   Description:  Callback when ROM page DMA transfer is completed.
436 
437   Arguments:    None.
438 
439   Returns:      None.
440  *---------------------------------------------------------------------------*/
CARDi_DmaReadPageCallback(void)441 static void CARDi_DmaReadPageCallback(void)
442 {
443     CARDTransferInfo   *info = CARDiDmaReadRegisteredInfo;
444     if (info)
445     {
446         info->src += CARD_ROM_PAGE_SIZE;
447         info->dst += CARD_ROM_PAGE_SIZE;
448         info->len -= CARD_ROM_PAGE_SIZE;
449         // Transfer the next page if necessary
450         if (info->len > 0)
451         {
452             CARDi_StartRomPageTransfer(info->src);
453         }
454         // Transfer completed
455         else
456         {
457             cardi_common.DmaCall->Stop(cardi_common.dma);
458             (void)OS_DisableIrqMask(OS_IE_CARD_DATA);
459             (void)OS_ResetRequestIrqMask(OS_IE_CARD_DATA);
460             CARDiDmaReadRegisteredInfo = NULL;
461             // Determine whether card was removed while accessed
462             CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
463             if (info->callback)
464             {
465                 (*info->callback)(info->userdata);
466             }
467         }
468     }
469 }
470 
471 /*---------------------------------------------------------------------------*
472   Name:         CARDi_ReadRomWithDMA
473 
474   Description:  Transfers ROM using the DMA.
475                 After transfer of the first page starts, the function returns control immediately.
476 
477   Arguments:    info: Transfer information
478 
479   Returns:      None.
480  *---------------------------------------------------------------------------*/
CARDi_ReadRomWithDMA(CARDTransferInfo * info)481 void CARDi_ReadRomWithDMA(CARDTransferInfo *info)
482 {
483     OSIntrMode bak_psr = OS_DisableInterrupts();
484     CARDiDmaReadRegisteredInfo = info;
485     // Set card transfer completion interrupt
486     (void)OS_SetIrqFunction(OS_IE_CARD_DATA, CARDi_DmaReadPageCallback);
487     (void)OS_ResetRequestIrqMask(OS_IE_CARD_DATA);
488     (void)OS_EnableIrqMask(OS_IE_CARD_DATA);
489     (void)OS_RestoreInterrupts(bak_psr);
490     // Set CARD-DMA (transfer idling)
491     cardi_common.DmaCall->Recv(cardi_common.dma, (void *)&reg_MI_MCD1, (void *)info->dst, CARD_ROM_PAGE_SIZE);
492     // Start first ROM transfer
493     CARDi_StartRomPageTransfer(info->src);
494 }
495 
CARDi_DmaReadDone(void * userdata)496 static void CARDi_DmaReadDone(void *userdata)
497 {
498     (void)userdata;
499 #ifdef SDK_ARM9
500     // Determine whether card was removed while accessed
501     CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
502 #endif
503     // Refresh at final warning stage of ROM-ECC correction
504     CARDi_RefreshRom(CARD_ROMST_RFS_WARN_L2_MASK);
505 
506     cardi_common.cmd->result = CARD_RESULT_SUCCESS;
507     CARDi_EndTask(&cardi_common);
508 }
509 
510 /*---------------------------------------------------------------------------*
511   Name:         CARDi_IsRomDmaAvailable
512 
513   Description:  Determines whether asynchronous DMA is usable in ROM transfer.
514 
515   Arguments:    dma: DMA channel
516                 dst: Transfer destination buffer
517                 src: Transfer source ROM offset
518                 len: Transfer size
519 
520   Returns:      If DMA is usable in ROM transfer, return TRUE.
521  *---------------------------------------------------------------------------*/
CARDi_IsRomDmaAvailable(u32 dma,void * dst,u32 src,u32 len)522 static BOOL CARDi_IsRomDmaAvailable(u32 dma, void *dst, u32 src, u32 len)
523 {
524     return (dma <= MI_DMA_MAX_NUM) && (len > 0) && (((u32)dst & 31) == 0) &&
525 #ifdef SDK_ARM9
526         (((u32)dst + len <= OS_GetITCMAddress()) || ((u32)dst >= OS_GetITCMAddress() + HW_ITCM_SIZE)) &&
527         (((u32)dst + len <= OS_GetDTCMAddress()) || ((u32)dst >= OS_GetDTCMAddress() + HW_DTCM_SIZE)) &&
528 #endif
529         (((src | len) & (CARD_ROM_PAGE_SIZE - 1)) == 0);
530 }
531 
532 /*---------------------------------------------------------------------------*
533   Name:         CARDi_ReadRomSyncCore
534 
535   Description:  Common process for synchronous card reads.
536 
537   Arguments:    c: CARDiCommon structure
538 
539   Returns:      None.
540  *---------------------------------------------------------------------------*/
CARDi_ReadRomSyncCore(CARDiCommon * c)541 static void CARDi_ReadRomSyncCore(CARDiCommon *c)
542 {
543     // Run ROM access routine that corresponds to the execution environment
544     (void)(*CARDiReadRomFunction)(NULL, (void*)c->dst, c->src, c->len);
545 #ifdef SDK_ARM9
546     // Determine whether card was removed while accessed
547     CARDi_CheckPulledOutCore(CARDi_ReadRomIDCore());
548 #endif
549     // Refresh at final warning stage of ROM-ECC correction
550     CARDi_RefreshRom(CARD_ROMST_RFS_WARN_L2_MASK);
551 
552     cardi_common.cmd->result = CARD_RESULT_SUCCESS;
553 }
554 #endif // defined(CARD_USING_ROMREADER)
555 
556 /*---------------------------------------------------------------------------*
557   Name:         CARDi_ReadRom
558 
559   Description:  Basic function of ROM read.
560 
561   Arguments:    dma: DMA channel to use
562                 src: Transfer source offset
563                 dst: Transfer destination memory address
564                 len: Transfer size
565                 callback: Completion callback (NULL if not used)
566                 arg: Argument of completion callback (ignored if not used)
567                 is_async: If set to asynchronous mode, TRUE
568 
569   Returns:      None.
570  *---------------------------------------------------------------------------*/
CARDi_ReadRom(u32 dma,const void * src,void * dst,u32 len,MIDmaCallback callback,void * arg,BOOL is_async)571 void CARDi_ReadRom(u32 dma,
572                    const void *src, void *dst, u32 len,
573                    MIDmaCallback callback, void *arg, BOOL is_async)
574 {
575 #if defined(CARD_USING_ROMREADER)
576     CARDiCommon *const c = &cardi_common;
577 
578     SDK_ASSERT(CARD_IsAvailable());
579     SDK_ASSERT(CARDi_GetTargetMode() == CARD_TARGET_ROM);
580     SDK_TASSERTMSG((dma != 0), "cannot specify DMA channel 0");
581 
582     // Determine validity of card access
583     CARD_CheckEnabled();
584     if ((CARDi_GetAccessLevel() & CARD_ACCESS_LEVEL_ROM) == 0)
585     {
586         OS_TPanic("this program cannot access CARD-ROM!");
587     }
588 
589     // Exclusive wait on ARM9 side
590     (void)CARDi_WaitForTask(c, TRUE, callback, arg);
591 
592     // Get DMA interface
593     c->DmaCall = CARDi_GetDmaInterface(dma);
594     c->dma = (u32)((c->DmaCall != NULL) ? (dma & MI_DMA_CHANNEL_MASK) : MI_DMA_NOT_USE);
595     if (c->dma <= MI_DMA_MAX_NUM)
596     {
597         c->DmaCall->Stop(c->dma);
598     }
599 
600     // Set this time's transfer parameters
601     c->src = (u32)((u32)src + cardi_rom_base);
602     c->dst = (u32)dst;
603     c->len = (u32)len;
604 
605     // Set transfer parameter
606     {
607         CARDTransferInfo   *info = CARDiDmaReadInfo;
608         info->callback = CARDi_DmaReadDone;
609         info->userdata = NULL;
610         info->src = c->src;
611         info->dst = c->dst;
612         info->len = c->len;
613         info->work = 0;
614     }
615 
616     // DMA transfers can be used in some cases, if it is an environment where hash checks are invalid
617     if ((CARDiReadRomFunction == CARDi_ReadRomWithCPU) &&
618         CARDi_IsRomDmaAvailable(c->dma, (void *)c->dst, c->src, c->len))
619     {
620 #if defined(SDK_ARM9)
621         // Depending upon the size of the transfer range, switch the manner in which the cache is invalidated
622         OSIntrMode bak_psr = OS_DisableInterrupts();
623         if (CARDiEnableCacheInvalidationIC)
624         {
625             CARDi_ICInvalidateSmart((void *)c->dst, c->len, c->flush_threshold_ic);
626         }
627         if (CARDiEnableCacheInvalidationDC)
628         {
629             CARDi_DCInvalidateSmart((void *)c->dst, c->len, c->flush_threshold_dc);
630         }
631         (void)OS_RestoreInterrupts(bak_psr);
632 #endif
633         // Start asynchronous transfer using DMA
634         CARDi_ReadRomWithDMA(CARDiDmaReadInfo);
635         // Wait until complete here if synchronous transfer is requested
636         if (!is_async)
637         {
638             CARD_WaitRomAsync();
639         }
640     }
641     else
642     {
643         // Even with CPU transfers, it is necessary to invalidate because the instruction cache is incompatible
644         if (CARDiEnableCacheInvalidationIC)
645         {
646             CARDi_ICInvalidateSmart((void *)c->dst, c->len, c->flush_threshold_ic);
647         }
648         // Register task to thread if some form of direct processing is required by the CPU
649         (void)CARDi_ExecuteOldTypeTask(CARDi_ReadRomSyncCore, is_async);
650     }
651 #else
652     (void)dma;
653     (void)is_async;
654     (void)CARDi_ReadRomWithCPU(NULL, dst, (u32)src, len);
655     if (callback)
656     {
657         (*callback)(arg);
658     }
659 #endif // defined(CARD_USING_ROMREADER)
660 }
661 
662 /*---------------------------------------------------------------------------*
663   Name:         CARDi_ReadRomID
664 
665   Description:  Reads the card ID.
666 
667   Arguments:    None.
668 
669   Returns:      Card ID.
670  *---------------------------------------------------------------------------*/
CARDi_ReadRomID(void)671 u32 CARDi_ReadRomID(void)
672 {
673     u32     ret = 0;
674 
675     SDK_ASSERT(CARD_IsAvailable());
676     SDK_TASSERTMSG(CARDi_GetTargetMode() == CARD_TARGET_ROM, "must be locked by CARD_LockRom()");
677 
678 #if defined(SDK_ARM9)
679     (void)CARDi_WaitForTask(&cardi_common, TRUE, NULL, NULL);
680 #endif // defined(SDK_ARM9)
681 
682     /* Direct access is possible, so execute here */
683     ret = CARDi_ReadRomIDCore();
684 #ifdef SDK_ARM9
685     // Detect card removal here
686     CARDi_CheckPulledOutCore(ret);
687 #endif
688 
689 #if defined(SDK_ARM9)
690     cardi_common.cmd->result = CARD_RESULT_SUCCESS;
691     CARDi_EndTask(&cardi_common);
692 #endif // defined(SDK_ARM9)
693 
694     return ret;
695 }
696 
697 #if defined(CARD_USING_HASHCHECK)
698 #include <twl/ltdmain_begin.h>
699 
700 // ROM hash calculation buffer
701 u8     *CARDiHashBufferAddress = NULL;
702 u32     CARDiHashBufferLength = 0;
703 static CARDRomHashContext   context[1];
704 
705 /*---------------------------------------------------------------------------*
706   Name:         CARDi_ReadCardWithHash
707 
708   Description:  ROM transfer while confirming hash.
709 
710   Arguments:    buffer: Transfer destination buffer
711                 offset: Transfer source ROM offset
712                 length: Transfer size
713 
714   Returns:      None.
715  *---------------------------------------------------------------------------*/
CARDi_ReadCardWithHash(void * userdata,void * buffer,u32 offset,u32 length)716 static int CARDi_ReadCardWithHash(void *userdata, void *buffer, u32 offset, u32 length)
717 {
718     (void)userdata;
719     CARD_ReadRomHashImage(context, buffer, offset, length);
720     return (int)length;
721 }
722 
723 /*---------------------------------------------------------------------------*
724   Name:         CARDi_ReadCardWithHashInternalAsync
725 
726   Description:  Asynchronous DMA transfer for partial use internally with ROM transfers of the hash verified version.
727 
728   Arguments:    userdata: User-defined argument
729                 buffer: Transfer destination buffer
730                 offset: Transfer source ROM offset
731                 length: Transfer size
732 
733   Returns:      None.
734  *---------------------------------------------------------------------------*/
CARDi_ReadCardWithHashInternalAsync(void * userdata,void * buffer,u32 offset,u32 length)735 static int CARDi_ReadCardWithHashInternalAsync(void *userdata, void *buffer, u32 offset, u32 length)
736 {
737     if (cardi_common.dma == MI_DMA_NOT_USE)
738     {
739         length = 0;
740     }
741     else
742     {
743         CARDRomHashContext *context = (CARDRomHashContext *)userdata;
744         static CARDTransferInfo card_hash_info[1];
745         DC_FlushRange(buffer, length);
746         card_hash_info->callback = (void(*)(void*))CARD_NotifyRomHashReadAsync;
747         card_hash_info->userdata = context;
748         card_hash_info->src = offset;
749         card_hash_info->dst = (u32)buffer;
750         card_hash_info->len = length;
751         card_hash_info->command = 0;
752         card_hash_info->work = 0;
753         CARDi_ReadRomWithDMA(card_hash_info);
754     }
755     return (int)length;
756 }
757 
758 /*---------------------------------------------------------------------------*
759   Name:         CARDi_InitRomHash
760 
761   Description:  If possible, switches to hash verification version ROM transfer.
762 
763   Arguments:    None.
764 
765   Returns:      None.
766  *---------------------------------------------------------------------------*/
CARDi_InitRomHash(void)767 static void CARDi_InitRomHash(void)
768 {
769     // 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
770     //
771     //
772     u8     *lo = (u8 *)MATH_ROUNDUP((u32)OS_GetMainArenaLo(), 32);
773     u8     *hi = (u8 *)MATH_ROUNDDOWN((u32)OS_GetMainArenaHi(), 32);
774     u32     len = CARD_CalcRomHashBufferLength(CARD_GetOwnRomHeaderTWL());
775     if (&lo[len] > hi)
776     {
777         OS_TPanic("cannot allocate memory for ROM-hash from ARENA");
778     }
779     else
780     {
781         OS_SetMainArenaLo(&lo[len]);
782         CARDiHashBufferAddress = lo;
783         CARDiHashBufferLength = len;
784         // Actually load if it is an environment where the ROM boot and hash table exist
785         if ((OS_GetBootType() == OS_BOOTTYPE_ROM) &&
786             ((((const u8 *)HW_TWL_ROM_HEADER_BUF)[0x1C] & 0x01) != 0))
787         {
788             cardi_common.dma = MI_DMA_NOT_USE;
789             CARDiReadRomFunction = CARDi_ReadCardWithHash;
790             {
791                 u16     id = (u16)OS_GetLockID();
792                 CARD_LockRom(id);
793                 CARD_InitRomHashContext(context,
794                                         CARD_GetOwnRomHeaderTWL(),
795                                         CARDiHashBufferAddress,
796                                         CARDiHashBufferLength,
797                                         CARDi_ReadRomWithCPU,
798                                         CARDi_ReadCardWithHashInternalAsync,
799                                         context);
800                 // Destroy the pointer so that there is no competition for use of the same buffer
801                 CARDiHashBufferAddress = NULL;
802                 CARDiHashBufferLength = 0;
803                 CARD_UnlockRom(id);
804                 OS_ReleaseLockID(id);
805             }
806         }
807     }
808 }
809 #include <twl/ltdmain_end.h>
810 #endif
811 
812 /*---------------------------------------------------------------------------*
813   Name:         CARDi_InitRom
814 
815   Description:  Initializes the ROM access management information.
816 
817   Arguments:    None.
818 
819   Returns:      None.
820  *---------------------------------------------------------------------------*/
CARDi_InitRom(void)821 void CARDi_InitRom(void)
822 {
823 #if defined(CARD_USING_ROMREADER)
824     CARDiReadRomFunction = CARDi_ReadRomWithCPU;
825     // 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().
826     //
827     //
828     //
829     if ((OS_GetBootType() == OS_BOOTTYPE_ROM) && CARD_GetOwnRomHeader()->rom_size)
830     {
831         u16     id = (u16)OS_GetLockID();
832         CARD_LockRom(id);
833         (void)CARDi_ReadRomWithCPU(NULL, CARDiOwnSignature,
834                                    CARD_GetOwnRomHeader()->rom_size,
835                                    CARD_ROM_DOWNLOAD_SIGNATURE_SIZE);
836         CARD_UnlockRom(id);
837         OS_ReleaseLockID(id);
838     }
839 #if defined(CARD_USING_HASHCHECK)
840     // Adopts a routine that also verifies hash, if usable
841     if (OS_IsRunOnTwl())
842     {
843 		CARDi_InitRomHash();
844     }
845 #endif
846 #else
847     CARDiReadRomFunction = NULL;
848 #endif
849 }
850 
851 
852 /*---------------------------------------------------------------------------*
853   Name:         CARD_WaitRomAsync
854 
855   Description:  Idles until the ROM access function is completed.
856 
857   Arguments:    None.
858 
859   Returns:      None.
860  *---------------------------------------------------------------------------*/
CARD_WaitRomAsync(void)861 void CARD_WaitRomAsync(void)
862 {
863     (void)CARDi_WaitAsync();
864 }
865 
866 /*---------------------------------------------------------------------------*
867   Name:         CARD_TryWaitRomAsync
868 
869   Description:  Determines whether the ROM access function is completed.
870 
871   Arguments:    None.
872 
873   Returns:      TRUE when the ROM access function is completed.
874  *---------------------------------------------------------------------------*/
CARD_TryWaitRomAsync(void)875 BOOL CARD_TryWaitRomAsync(void)
876 {
877     return CARDi_TryWaitAsync();
878 }
879 
880 /*---------------------------------------------------------------------------*
881   Name:         CARDi_GetOwnSignature
882 
883   Description:  Gets its own DS Download Play signature data.
884 
885   Arguments:    None.
886 
887   Returns:      Its own DS Download Play signature data.
888  *---------------------------------------------------------------------------*/
CARDi_GetOwnSignature(void)889 const u8* CARDi_GetOwnSignature(void)
890 {
891     return CARDiOwnSignature;
892 }
893 
894 /*---------------------------------------------------------------------------*
895   Name:         CARDi_SetOwnSignature
896 
897   Description:  Sets its own DS Download Play signature data.
898                 Calls from the host library when booted without a card.
899 
900   Arguments:    DS Download Play signature data
901 
902   Returns:      None.
903  *---------------------------------------------------------------------------*/
CARDi_SetOwnSignature(const void * signature)904 void CARDi_SetOwnSignature(const void *signature)
905 {
906     MI_CpuCopy8(signature, CARDiOwnSignature, CARD_ROM_DOWNLOAD_SIGNATURE_SIZE);
907 }
908 
909 #if defined(SDK_ARM9)
910 /*---------------------------------------------------------------------------*
911   Name:         CARD_GetCacheFlushFlag
912 
913   Description:  Gets setting flags of whether to invalidate cache automatically.
914 
915   Arguments:    icache: Pointer to the location where the automatic invalidation flag for the instruction cache is stored
916                                   Ignore if NULL.
917                 dcache: Pointer to the location the automatic invalidation flag for the instruction cache is stored.
918                                   Ignore if NULL.
919 
920   Returns:      None.
921  *---------------------------------------------------------------------------*/
CARD_GetCacheFlushFlag(BOOL * icache,BOOL * dcache)922 void CARD_GetCacheFlushFlag(BOOL *icache, BOOL *dcache)
923 {
924     SDK_ASSERT(CARD_IsAvailable());
925     if (icache)
926     {
927         *icache = CARDiEnableCacheInvalidationIC;
928     }
929     if (dcache)
930     {
931         *dcache = CARDiEnableCacheInvalidationDC;
932     }
933 }
934 
935 /*---------------------------------------------------------------------------*
936   Name:         CARD_SetCacheFlushFlag
937 
938   Description:  Sets whether to automatically invalidate cache.
939                 By default, instruction cache is FALSE, and data cache is TRUE.
940 
941   Arguments:    icache: TRUE to enable automatic invalidation of the instruction cache
942                 dcache: TRUE to enable automatic invalidation of data caches
943 
944   Returns:      None.
945  *---------------------------------------------------------------------------*/
CARD_SetCacheFlushFlag(BOOL icache,BOOL dcache)946 void CARD_SetCacheFlushFlag(BOOL icache, BOOL dcache)
947 {
948     SDK_ASSERT(CARD_IsAvailable());
949     CARDiEnableCacheInvalidationIC = icache;
950     CARDiEnableCacheInvalidationDC = dcache;
951 }
952 #endif
953