/*---------------------------------------------------------------------------*
  Project:  NitroSDK - libraries - loader
  File:     loader.c

  Copyright 2003-2006 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.

  Revision 1.7  2006/01/18 02:11:19  kitase_hirotake
  do-indent

  Revision 1.6  2005/11/21 10:52:28  kitase_hirotake
  PXI_Init の削除

  Revision 1.5  2005/02/28 05:26:01  yosizaki
  do-indent.

  Revision 1.4  2004/09/04 10:01:14  sato_masaki
  includeヘッダを、mb_private.hに変更。

  Revision 1.3  2004/09/03 11:48:54  yasu
  fix typo

  Revision 1.2  2004/09/03 07:09:25  sato_masaki
  MBライブラリのファイル分割による更新。NVRAMまわりのリネームに対応。

  Revision 1.1  2004/08/31 11:00:13  sato_masaki
  initial check-in

 *---------------------------------------------------------------------------*/

#include <nitro.h>

#if	defined(SDK_ARM7)
#include <nitro_wl/ARM7/WlLib.h>
#else
#ifdef SDK_SMALL_BUILD
#include "IPL_work.h"
#endif
#endif


#include <nitro/mb.h>
#include <mb_private.h>
#include "loader.h"

// --------------------------------------------------------------------------
#define GAME_MAINP_ENTRY_POINT			(HW_ROM_HEADER_BUF+0x24)
#define GAME_SUBP_ENTRY_POINT			(HW_ROM_HEADER_BUF+0x34)

// Download情報のサイズ

#define MB_OVT_MAX_SIZE					MB_COMM_BLOCK_SIZE      // OVTの最大サイズ（Blockサイズを最大サイズとする）

/*----------------------------------------------------------------------------*/
#define MB_TRIGGER_SIGNAL_TO_ARM7		(0x00000001)

/*----------------------------------------------------------------------------*/
static void MIm_CpuClear32(register u32 data, register void *destp, register u32 size);
static void MIm_CpuClear32(register u32 data, register void *destp, register u32 size);
static void LOADERi_LocateAllSegments(MBDownloadFileInfo * mdfi);
static void MBi_SearchAndLocateSegmentInfo(MBDownloadFileInfo * mdfi, u16 processor);
static void LOADERi_Jump(void);
static void MBi_fifo_callback_arm7(PXIFifoTag tag, u32 msg_adr, BOOL err);

/*----------------------------------------------------------------------------*/
static MB_LoaderCallback loader_precallback = NULL;

/*----------------------------------------------------------------------------*/


#if	defined(SDK_ARM7)

/*---------------------------------------------------------------------------*
  Name:         MIm_CpuCopy32

  Description:  ローダー用CpuCopy

  Arguments:    srcp, destp, size

  Returns:      void
 *---------------------------------------------------------------------------*/

#include <nitro/code32.h>

asm void MIm_CpuCopy32( register const void *srcp, register void *destp, register u32 size )
{
        add     r12, r1, r2             // r12: destEndp = destp + size

@30:
        cmp     r1, r12                 // while (destp < destEndp)
        ldmltia r0!, {r2}               // *((vu32 *)(destp)++) = *((vu32 *)(srcp)++)
        stmltia r1!, {r2}
        blt     @30

        bx      lr
}

#ifndef SDK_SMALL_BUILD
static asm void MIm_CpuClear32( register u32 data, register void *destp, register u32 size )
{
        add     r12, r1, r2             // r12: destEndp = destp + size

@20:
        cmp     r1, r12                 // while (destp < destEndp)
        stmltia r1!, {r0}               // *((vu32 *)(destp++)) = data
        blt     @20

        bx      lr
}
#endif

#include <nitro/codereset.h>


/*---------------------------------------------------------------------------*
  Name:         LOADERi_LocateAllSegments

  Description:  ARM9,ARM7の各セグメントを必要に応じて再配置する。

  Arguments:    mdfi

  Returns:      void
 *---------------------------------------------------------------------------*/

static void LOADERi_LocateAllSegments(MBDownloadFileInfo * mdfi)
{
    MBi_SearchAndLocateSegmentInfo(mdfi, MI_PROCESSOR_ARM9);    // ARM9セグメントについての配置処理
    MBi_SearchAndLocateSegmentInfo(mdfi, MI_PROCESSOR_ARM7);    // ARM7セグメントについての配置処理
}


/* 指定のセグメントを検索し, 再配置する */
static void MBi_SearchAndLocateSegmentInfo(MBDownloadFileInfo * mdfi, u16 processor)
{
    int     i;
    MbSegmentInfo *seg_info;

    if (mdfi)
    {
        for (i = 0; i < MB_DL_SEGMENT_NUM; ++i)
        {
            seg_info = &mdfi->seg[i];
            if (seg_info->target == processor)
            {
                if (seg_info->recv_addr != seg_info->load_addr)
                {
                    MIm_CpuCopy32((void *)seg_info->recv_addr, (void *)seg_info->load_addr,
                                  seg_info->size);
#ifndef SDK_SMALL_BUILD                // ※IPLの場合は、このメモリクリアはIPLで行う。
                    MIm_CpuClear32(0, (void *)seg_info->recv_addr, seg_info->size);
#endif
                }
            }
        }
    }
}


/*---------------------------------------------------------------------------*
  Name:         LOADERi_Jump

  Description:  ローダーを起動 (ARM7/9 共通)

  Arguments:    無し

  Returns:      void
 *---------------------------------------------------------------------------*/

static void LOADERi_Jump(void)
{
#if	defined(SDK_ARM7)

    MBDownloadFileInfo *mdfi = (MBDownloadFileInfo *) MB_DOWNLOAD_FILEINFO_ADDRESS;
    MBParam *p_param = (MBParam *)HW_WM_BOOT_BUF;

    if (p_param->boot_type != MB_TYPE_MULTIBOOT)
    {                                  // ブートタイプがマルチブートでない場合は、何もせずにTRUEリターン。
        return;
    }

    LOADERi_LocateAllSegments(mdfi);   // ブートプログラムの再配置を行う。

#endif
}


/*---------------------------------------------------------------------------*
  Name:         MBi_fifo_callback_arm7

  Description:  専用 PXI タグ経由でローダー起動

  Arguments:    

  Returns:      None.
 *---------------------------------------------------------------------------*/

static void MBi_fifo_callback_arm7(PXIFifoTag tag, u32 msg_adr, BOOL err)
{
#pragma unused( err )

    if (tag == PXI_FIFO_TAG_MB && msg_adr == (u32)MB_TRIGGER_SIGNAL_TO_ARM7)
    {
        if (loader_precallback)
        {
            (*loader_precallback) ();
        }
    }
}

#endif /* defined(SDK_ARM7) */


/*---------------------------------------------------------------------------*
  Name:         LOADER_Start

  Description:  ローダーのスタート

  Arguments:    None.

  Returns:      TRUE - success FALSE - failed
 *---------------------------------------------------------------------------*/


void LOADER_Start(void)
{

#if	defined(SDK_ARM9)
    int     result;
    MBDownloadFileInfo *mdfi = (MBDownloadFileInfo *) MB_DOWNLOAD_FILEINFO_ADDRESS;
    MBParam *p_param = (MBParam *)HW_WM_BOOT_BUF;

    // エントリポイントをROM内登録エリアの該当アドレスにコピー（※最終的には、ROM内登録エリアもダウンロードするので必要なくなる）
    *(u32 *)GAME_SUBP_ENTRY_POINT = mdfi->header.arm7EntryAddr;
    *(u32 *)GAME_MAINP_ENTRY_POINT = mdfi->header.arm9EntryAddr;

    // マルチブートの時はデバッガエントリに飛ばないようクリアする。
#ifdef SDK_SMALL_BUILD
    GetSharedWorkAddr()->isOnDebugger = 0;
#endif

    // システム領域へマルチブートフラグを書き込み
    p_param->boot_type = MB_TYPE_MULTIBOOT;
    // 親機情報をシステム領域へ書き込み
    MI_CpuCopy8((void *)MB_BSSDESC_ADDRESS, &p_param->parent_bss_desc, MB_BSSDESC_SIZE);

    // ARM7側へローダー起動を通知
    result = PXI_SendWordByFifo(PXI_FIFO_TAG_MB, (u32)MB_TRIGGER_SIGNAL_TO_ARM7, FALSE);
    SDK_ASSERTMSG((result >= 0), "ARM9:FIFO SEND ERROR!\n");

    return;

#else  /* defined(SDK_ARM9) */

    // ローダーをコール
    LOADERi_Jump();

#endif
}


/*---------------------------------------------------------------------------*
  Name:         LOADER_Init

  Description:  ローダーの初期化

  Arguments:    callback - ブートの準備が出来たときに返すコールバック

  Returns:      None.
 *---------------------------------------------------------------------------*/

void LOADER_Init(MB_LoaderCallback callback)
{
    MBParam *p_param = (MBParam *)HW_WM_BOOT_BUF;

#if	defined(SDK_ARM7)

    loader_precallback = callback;

    /* ブートフラグの補正(マルチブートフラグが指定されていない場合はROMとみなす。) */
    if (p_param->boot_type != MB_TYPE_MULTIBOOT)
    {
        p_param->boot_type = MB_TYPE_NORMAL;
    }
    /* 上の処理で, 必ず MB_TYPE_MULTIBOOT か MB_TYPE_NORMAL になる */

    // マルチブート監視FIFOコールバックをセット
    PXI_SetFifoRecvCallback(PXI_FIFO_TAG_MB, MBi_fifo_callback_arm7);

#else  /* defined(SDK_ARM7) */

#pragma unused(callback)

#endif
}



/*----------------------------------------------------------------------------*
/* 現状 不使用
 *----------------------------------------------------------------------------*/

#if	defined(LOADER_USE_OVT_BUF)

//----------------------------------------------------------------------
// オーバーレイテーブル
//----------------------------------------------------------------------
typedef struct
{
    u32     id;                        // オーバーレイ ID 
    void   *ram_address;               // ロード先頭位置 
    u32     ram_size;                  // ロードサイズ 
    u32     bss_size;                  // bss 領域サイズ 
    void   *sinit_init;                // static initializer 先頭アドレス 
    void   *sinit_init_end;            // static initializer 最終アドレス
    u32     file_id;                   // オーバーレイファイルID
    u32     rsv;                       // 予約。
}
ROM_OVT;


// OVTの最大サイズ（これについては再考の余地あり）
#define MB_OVT_MAX_SIZE		MB_COMM_BLOCKSIZE

// Overlay Table Buffer
// マルチブートするプログラム上で、スタティックイニシャライザを起動するのに必要
// オーバーレイテーブル数で容量が変わってくる。
// IPLにおける仕様が固まるまで、ここに置いておく
static u32 mb_ovt_buf[MB_OVT_MAX_SIZE / sizeof(u32)];

static void MB_SetOverlayTable(ROM_OVT * srcp, u16 sec_num)
{
    if (srcp && sec_num)
    {
        MI_CpuCopy8((void *)srcp, (void *)mb_ovt_buf, sec_num * sizeof(ROM_OVT));
    }
}

#endif
