TwlIPL/build/libraries/fatfs/ARM7/src/fatfs_loader.c
yutaka 36354e62c0 MIライブラリのSetup、Restartを利用するように修正
TwlSDKのcrt0に合わた修正(使っていないが)
1つ残っていたAPI名のFirmをFIRMに修正
sdmc-launcherでブート前にprofileのダンプ表示の追加

git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@96 b08762b0-b915-fc4b-9d8c-17b2551a87ff
2007-11-02 02:35:02 +00:00

492 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*---------------------------------------------------------------------------*
Project: TwlIPL - libraries - fatfs
File: fatfs_loader.c
Copyright 2007 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Date:: $
$Rev$
$Author$
*---------------------------------------------------------------------------*/
#include <symbols.h>
#include <firm.h>
#include <firm/format/format_rom.h>
#include <rtfs.h>
#include <devices/sdif_reg.h>
/*
PROFILE_ENABLE を定義するとある程度のパフォーマンスチェックができます。
利用するためには、main.cかどこかに、u32 profile[256]; u32 pf_cnt; を
定義する必要があります。
*/
//#define PROFILE_ENABLE
#define MODULE_ALIGNMENT 0x10 // 16バイト単位で読み込む
//#define MODULE_ALIGNMENT 0x200 // 512バイト単位で読み込む
#define RoundUpModuleSize(value) (((value) + MODULE_ALIGNMENT - 1) & -MODULE_ALIGNMENT)
#ifdef SDK_FINALROM // FINALROMで無効化
#undef PROFILE_ENABLE
#endif
#ifdef PROFILE_ENABLE
#define PROFILE_PXI_SEND 0x10000000
#define PROFILE_PXI_RECV 0x20000000
extern u32 profile[];
extern u32 pf_cnt;
#endif
#define PXI_FIFO_TAG_DATA PXI_FIFO_TAG_USER_0
static ROM_Header* const rh= (ROM_Header*)HW_TWL_ROM_HEADER_BUF;
static int menu_fd = -1;
/*---------------------------------------------------------------------------*
Name: FATFS_OpenRecentMenu
Description: open recent menu file
システムメニューのファイルを特定し、オープンし、ファイルIDを
menu_fdにセットします。
最終的には、固定のタイトルメタデータを読み込み、eTicketの処理
をして、システムメニューのファイルを特定することになる予定。
Arguments: driveno drive number ('A' is 0)
Returns: None
*---------------------------------------------------------------------------*/
BOOL FATFS_OpenRecentMenu( int driveno )
{
char *menufile = (char*)L"A:\\ipl\\menu.srl";
if (driveno < 0 || driveno >= 26)
{
return FALSE;
}
menufile[0] += (char)driveno;
menu_fd = po_open((u8*)menufile, PO_BINARY, 0);
if (menu_fd < 0)
{
return FALSE;
}
return TRUE;
}
/*---------------------------------------------------------------------------*
Name: FATFS_OpenSpecifiedSrl
Description: open specified menu file
任意のファイルをオープンし、ファイルIDをmenu_fdにセットします。
Arguments: menufile target filename
Returns: None
*---------------------------------------------------------------------------*/
BOOL FATFS_OpenSpecifiedSrl( const char* menufile )
{
menu_fd = po_open((u8*)menufile, PO_BINARY, 0);
if (menu_fd < 0)
{
return FALSE;
}
return TRUE;
}
#define HEADER_SIZE 0x1000
#define AUTH_SIZE ROM_HEADER_SIGN_TARGET_SIZE
/*---------------------------------------------------------------------------*
Name: FATFS_LoadBuffer
Description: load data and pass to ARM9 via WRAM[B]
LoadBufferメカニズムで、FAT中のファイルの内容をARM9に転送します。
[LoadBufferメカニズム]
WRAM[B]を利用して、ARM7,ARM9間のデータ転送を行います。
WRAM[B]の各スロットをバケツリレー方式で渡します。
1スロット分のデータまたは全データが格納できたとき、ARM9へ
FIRM_PXI_ID_LOAD_PIRIODを送信します。
データ残がある場合は次のスロットの処理に移ります。
2回目以降の呼び出しでは、前回最後のスロットの続きから使用します。
使用したいスロットがARM9側に割り当てられているときは、ARM7側に
なるまでストールします。
[使用条件]
WRAM[B]をロックせず、初期状態としてARM7側に倒しておくこと。
[注意点]
offsetとsizeはARM9に通知されません。別の経路で同期を取ってください。
SRLファイルを読み込む場合は、互いにROMヘッダを参照できれば十分です。
(ROMヘッダ部分は元から知っているはず)
補足:
ここでは、あるライブラリ内でARM7/ARM9側で歩調を合わせられることを
前提にしているが、汎用的にするには(独立ライブラリ化するなら)、
送受信でスロットを半分ずつとし、それぞれに受信側のPXIコールバック
スレッドを用意し、送信側APIがデータをWRAMに格納した後、他方に
destとsizeを通知するという形でOKではないか
(で完了したら返事を返す)
Arguments: offset offset of the file to load (512 bytes alignment)
size size to load
Returns: None
*---------------------------------------------------------------------------*/
static BOOL FATFS_LoadBuffer(u32 offset, u32 size)
{
u8* base = (u8*)HW_FIRM_LOAD_BUFFER_BASE;
static int count = 0;
// seek first
// OS_TPrintf("po_lseek(offset=%X);\n", offset);
if (po_lseek(menu_fd, (s32)offset, PSEEK_SET) < 0)
{
return FALSE;
}
#ifdef PROFILE_ENABLE
// x2: after Seek
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
#endif
// loading loop
while (size > 0)
{
u8* dest = base + count * HW_FIRM_LOAD_BUFFER_UNIT_SIZE; // target buffer address
u32 unit = size < HW_FIRM_LOAD_BUFFER_UNIT_SIZE ? size : HW_FIRM_LOAD_BUFFER_UNIT_SIZE; // size
while (MI_GetWramBankMaster_B(count) != MI_WRAM_ARM7) // waiting to be master
{
}
#ifdef PROFILE_ENABLE
// x3...: after to wait ARM9
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
#endif
// OS_TPrintf("po_read(dest=%X, unit=%X);\n", dest, unit);
if (po_read(menu_fd, (u8*)dest, (int)unit) < 0) // reading
{
return FALSE;
}
#ifdef PROFILE_ENABLE
// x4...: before PXI
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
profile[pf_cnt++] = (u32)PROFILE_PXI_SEND | FIRM_PXI_ID_LOAD_PIRIOD; // checkpoint
#endif
PXI_NotifyID( FIRM_PXI_ID_LOAD_PIRIOD );
count = (count + 1) % HW_FIRM_LOAD_BUFFER_UNIT_NUMS;
size -= unit;
}
return TRUE;
}
/*---------------------------------------------------------------------------*
Name: FATFS_LoadHeader
Description: load header
SRLのROMヘッダ部分を読み込み、ARM9に渡します。
送信前に、ARM9へ FIRM_PXI_ID_LOAD_HEADER を送信します。
送信後、ARM9から FIRM_PXI_ID_AUTH_HEADER を受信します。
この時点で、メインメモリの所定の位置にROMヘッダが格納されたと
想定します。
問題なければ、seedデータを16バイト受信します。
受け取ったseedはSeedAとKeyCに設定されます。
makerom.TWLまたはIPLの仕様に依存します。
Arguments: None
Returns: TRUE if success
*---------------------------------------------------------------------------*/
BOOL FATFS_LoadHeader( void )
{
// open the file in FATFS_InitFIRM()
if (menu_fd < 0)
{
return FALSE;
}
#ifdef PROFILE_ENABLE
// 10: before PXI
pf_cnt = 0x10;
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
profile[pf_cnt++] = (u32)PROFILE_PXI_SEND | FIRM_PXI_ID_LOAD_HEADER; // checkpoint
#endif
// load header without AES
PXI_NotifyID( FIRM_PXI_ID_LOAD_HEADER );
FATFS_DisableAES();
if (!FATFS_LoadBuffer(0, AUTH_SIZE) ||
#ifdef PROFILE_ENABLE
// 12: after to load half
((profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick())), FALSE) ||
#endif
!FATFS_LoadBuffer(AUTH_SIZE, HEADER_SIZE - AUTH_SIZE) ||
#ifdef PROFILE_ENABLE
// 1x: after to load remain
((profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick())), FALSE) ||
#endif
PXI_RecvID() != FIRM_PXI_ID_AUTH_HEADER )
{
return FALSE;
}
#ifdef PROFILE_ENABLE
// 1x: after PXI
profile[pf_cnt++] = (u32)PROFILE_PXI_RECV | FIRM_PXI_ID_AUTH_HEADER; // checkpoint
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
#endif
// set id depends on game_code and seed to use (or all?)
{
AESKeySeed seed;
AESi_InitGameKeys((u8*)rh->s.game_code);
PXI_RecvDataByFifo( PXI_FIFO_TAG_DATA, &seed, AES_BLOCK_SIZE );
AESi_WaitKey();
AESi_SetKeySeedA(&seed); // APP
//AESi_WaitKey();
//AESi_SetKeySeedB(&seed); // APP & HARD
//AESi_WaitKey();
//AESi_SetKeySeedC(&seed); //
//AESi_WaitKey();
//AESi_SetKeySeedD(&seed); // HARD
AESi_WaitKey();
AESi_SetKeyC(&seed); // Direct
}
return TRUE;
}
/*---------------------------------------------------------------------------*
Name: FATFSi_GetCounter
Description: get counter
offsetに対応したAESのカウンタ値を計算します。
makerom.TWL内のコードに依存します。
Arguments: offset offset from head of ROM_Header
Returns: counter
*---------------------------------------------------------------------------*/
static AESCounter* FATFSi_GetCounter( u32 offset )
{
static AESCounter counter;
MI_CpuCopy8( rh->s.main_static_digest, &counter, 16 );
AESi_AddCounter( &counter, offset - rh->s.aes_target_rom_offset );
return &counter;
}
/*---------------------------------------------------------------------------*
Name: FATFSi_SetupAES
Description: setup whiere to use AES
AES暗号化されたデータを読み込むためのセットアップを行います。
fatfs_sdmc.cのドライバを使用していることが条件となります。
(TwlSDK標準で行う場合は、その仕様に合わせて修正が必要)
このAPIを呼び出す前に、メインメモリの所定の位置にROMヘッダが
格納されている必要があります。
鍵の選択も行っていますが、鍵の設定は別の場所で行っておく
必要があります。
転送範囲がAES領域をまたぐ場合は、境界までのサイズ (引数より
小さなサイズ) を返します。
makerom.TWLまたはIPLの使用に依存します。
Arguments: offset offset of region from head of ROM_Header
size size of region
Returns: size to transfer once
*---------------------------------------------------------------------------*/
static u32 FATFSi_SetupAES( u32 offset, u32 size )
{
u32 aes_offset = rh->s.aes_target_rom_offset;
u32 aes_end = aes_offset + RoundUpModuleSize(rh->s.aes_target_size);
u32 end = offset + RoundUpModuleSize(size);
if ( rh->s.enable_aes )
{
if ( offset >= aes_offset && offset < aes_end )
{
if ( end > aes_end )
{
size = aes_end - offset;
}
AESi_WaitKey();
if (rh->s.developer_encrypt)
{
AESi_LoadKey( AES_KEY_SLOT_C );
}
else
{
AESi_LoadKey( AES_KEY_SLOT_A );
}
FATFS_EnableAES( FATFSi_GetCounter( offset ) );
}
else
{
if ( offset < aes_offset && offset + size > aes_offset )
{
size = aes_offset - offset;
}
FATFS_DisableAES();
}
}
else
{
FATFS_DisableAES();
}
return size;
}
/*---------------------------------------------------------------------------*
Name: FATFSi_LoadModule
Description: transfer module to ARM9 via WRAM[B]
FATFSi_LoadBufferの上位APIです。
AES境界をまたぐときに2回に分けるだけです。
Arguments: offset offset from head of ROM_Header
size size to load
Returns: TRUE if success
*---------------------------------------------------------------------------*/
static /*inline*/ BOOL FATFSi_LoadModule(u32 offset, u32 size)
{
size = RoundUpModuleSize( size ); // アラインメント調整
while ( size > 0 )
{
u32 unit = FATFSi_SetupAES( offset, size ); // 一度の転送サイズ
if ( !FATFS_LoadBuffer( offset, unit ) )
{
return FALSE;
}
offset += unit;
size -= unit;
}
return TRUE;
}
/*---------------------------------------------------------------------------*
Name: FATFS_LoadStatic
Description: load static binary
ARM9/ARM7のStaticおよびLTD Staticを読み込みます。
送信前に、ARM9へFIRM_PXI_ID_LOAD_*_STATICを送信します。
送信後は、ARM9からFIRM_PXI_ID_AUTH_*_STATICを受信します。
サイズが0の場合は、そのパートのPXI通信すら行いません。
このAPIを呼び出す前に、メインメモリの所定の位置にROMヘッダが
格納されている必要があります。
ARM9側と異なり、デバイス依存のアライメント修正を行っています。
(サイズのみ)
Arguments: None
Returns: TRUE if success
*---------------------------------------------------------------------------*/
BOOL FATFS_LoadStatic( void )
{
#ifdef PROFILE_ENABLE
// 30: LoadStatic
pf_cnt = 0x30;
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
profile[pf_cnt++] = (u32)PROFILE_PXI_SEND | FIRM_PXI_ID_LOAD_STATIC; // checkpoint
#endif
PXI_NotifyID( FIRM_PXI_ID_LOAD_STATIC );
// load ARM9 static region without AES
if ( rh->s.main_size > 0 )
{
#ifdef PROFILE_ENABLE
// 31: before PXI
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
#endif
if ( !FATFSi_LoadModule( rh->s.main_rom_offset, rh->s.main_size ) )
{
return FALSE;
}
}
// load ARM7 static region without AES
if ( rh->s.sub_size > 0 )
{
#ifdef PROFILE_ENABLE
// 50: before PXI
pf_cnt = 0x50;
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
#endif
if ( !FATFSi_LoadModule( rh->s.sub_rom_offset, rh->s.sub_size ) )
{
return FALSE;
}
}
// load ARM9 extended static region with AES
if ( rh->s.main_ltd_size > 0 )
{
#ifdef PROFILE_ENABLE
// 70: before PXI
pf_cnt = 0x70;
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
#endif
if ( !FATFSi_LoadModule( rh->s.main_ltd_rom_offset, rh->s.main_ltd_size ) )
{
return FALSE;
}
}
// load ARM7 extended static region with AES
if ( rh->s.sub_ltd_size > 0 )
{
#ifdef PROFILE_ENABLE
// 90: before PXI
pf_cnt = 0x90;
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
#endif
if ( !FATFSi_LoadModule( rh->s.sub_ltd_rom_offset, rh->s.sub_ltd_size ) )
{
return FALSE;
}
}
// waiting result
if ( PXI_RecvID() != FIRM_PXI_ID_AUTH_STATIC )
{
return FALSE;
}
#ifdef PROFILE_ENABLE
// 9x: after PXI
profile[pf_cnt++] = (u32)PROFILE_PXI_RECV | FIRM_PXI_ID_AUTH_STATIC; // checkpoint
profile[pf_cnt++] = (u32)OS_TicksToMicroSeconds(OS_GetTick());
#endif
return TRUE;
}
/*---------------------------------------------------------------------------*
Name: FATFS_Boot
Description: boot
ROMヘッダの情報を引数に、OSi_Bootを呼び出すだけです。
このAPIを呼び出す前に、メインメモリの所定の位置にROMヘッダが
格納されている必要があります。
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void FATFS_Boot( void )
{
OSi_Boot( rh->s.sub_entry_address, (MIHeader_WramRegs*)rh->s.main_wram_config_data );
}