bootdisk.c 7.22 KB
/*
 * Copyright 1996, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED
 *
 * UNPUBLISHED -- Rights reserved under the copyright laws of the United
 * States.   Use of a copyright notice is precautionary only and does not
 * imply publication or disclosure.
 *
 * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to restrictions
 * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
 * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
 * in similar or successor clauses in the FAR, or the DOD or NASA FAR
 * Supplement.  Contractor/manufacturer is Silicon Graphics, Inc.,
 * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
 *
 * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
 * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
 * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
 * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
 * GRAPHICS, INC.
 *
 */

/*---------------------------------------------------------------------
        Copyright (C) 1998 Nintendo.
        
        File            bootdisk.c
        Modified by     Takayuki Hashida             September, 1998.
        Comments        reboot function
   
        $Id: bootdisk.c,v 1.1.1.1 2002/05/02 03:28:40 blythe Exp $
   ---------------------------------------------------------------------*/


#include <ultra64.h>
#include <os_internal.h>

extern void 	__LeoBootGame3(void *);
extern u32    	LEO_country_code;
extern s32	__osShutdown;   /* 1 = pre-NMI interrupt has occured */


/*
 * 注 意 ! XXXXXXXXXXXXXXXXXXXXXXXXXXX
 *
 * このルーチンと、bootstrap.s のサイズが変わったときは、忘れずに
 * 下記の BOOT*_SIZE の値を変えるようにしてください。
 * これらの数値は、暗号化/復号化に必要です。
 */

/*
 * IPL4 bootstrap loader code
 *
 * This is the code that will bootstrap into running the game that
 * has been read off of disk. The game has already been successfully read
 * off of the disk and is in the correct spot in RDRAM. The goal is to 
 * reinitialize the system and begin running the game. Some of the IP1,
 * IP2, and IP3 initializations will be done again.
 *
 * ASSUMPTIONS on call:
 *   - Graphics and Audio have just been stopped. The RSP and RDP are unused
 *   - No outstanding PI DMAs are in progress (includes disk)
 *   - New game has been loaded off of the disk and is awaiting execution
 *     in RDRAM
 *
 * Reinitialize the system to the same state as at the end of IPL3:
 *
 * Final intialization and jump to preamble code in game by calling 
 * assembly routine
 *
 */

/*
 * 同じ定義が makerom, makedisk, mild の segment.c にもあるので、これを
 * 変更したときは忘れずに変更すること
 */
#define BOOT0_SIZE	0x13c		/* LeoBootGame のサイズ */
#define BOOT1_SIZE	0x344		/* __LeoBootGame2 のサイズ */
#define BOOT2_SIZE	0x50		/* __LeoBootGame3 のサイズ */


void 	__LeoBootGame2(void *entry);

void LeoBootGame(void *entry)
{
    u8		*ptr;
    u8		seed;
    u32		i;
    
    seed = (u8)( ( ( ( (u32)__LeoBootGame2 & 0xff000000 ) >> 24 ) + 
		  ( ( (u32)__LeoBootGame2 & 0x00ff0000 ) >> 16 ) + 
		  ( ( (u32)__LeoBootGame2 & 0x0000ff00 ) >> 8 ) + 
		  ( ( (u32)__LeoBootGame2 & 0x000000ff ) ) ) & 0xff );
    
    /*
     * 本体を復号化
     */
    ptr = (u8 *)__LeoBootGame2;

    for(i = 0; i < BOOT1_SIZE; i += 4)
    {
	ptr[2] -= seed;
	ptr[3] += seed;
	ptr += 4;
    }

    osWritebackDCacheAll();

    osInvalICache((void *)__LeoBootGame2, BOOT1_SIZE);    

    /*
     * 本体を復号化
     */
    ptr = (u8 *)__LeoBootGame3;

    for(i = 0; i < BOOT2_SIZE; i += 4)
    {
	ptr[2] -= seed;
	ptr[3] += seed;
	ptr += 4;
    }

    osWritebackDCacheAll();

    osInvalICache((void *)__LeoBootGame3, BOOT2_SIZE);    

    __LeoBootGame2(entry);

}


void
__LeoBootGame2(void *entry)
{
    u32 	i;
    vu32 	*memp;
    int		k = 0;
    char	buf[256];
    char	*Ptr = (char *)entry;

    /*
     * 復号ルーチンの痕跡を消す
     */
    bzero( (void *)LeoBootGame, BOOT0_SIZE );
    osWritebackDCache( (void *)LeoBootGame, BOOT0_SIZE );


    /* put the system in the same state as after IPL1, IPL2 and IPL3 */
    __osSetSR(SR_CU1|SR_CU0);		/* disable interrupts (IPL1) */

    if(__osShutdown)
	for(;;);

    *(u8*)OS_PHYSICAL_TO_K1(0x00000010) =
	(u8)((LEO_country_code & 0xff000000) >> 24);

    /* no need to set C0_CONFIG */

    /* make sure RSP is halted (IPL1) */
    while (!IO_READ(SP_STATUS_REG) & SP_STATUS_HALT)
	;

    IO_WRITE(SP_STATUS_REG, SP_SET_HALT|SP_CLR_INTR);

    /*
     * 復号化(その1)
     */
    while(k < 80)
    {
	buf[(k * 17) % 256] = Ptr[k];
	k++;
    }

    while (IO_READ(SP_DMA_BUSY_REG) & 0x1)
	;

    /* reset PI (IPL1) */
    IO_WRITE(PI_STATUS_REG, PI_STATUS_RESET|PI_STATUS_CLR_INTR);

    /*
     * 復号化(その2)
     */
    while(k < 170)
    {
	buf[(k * 17) % 256] = Ptr[k];
	k++;
    }

    /* blank the video */
    /* Spin until we are in the pre-blank stage */
    while (IO_READ(VI_CURRENT_REG) > 10)
	;

    /* Zero out control register so that reset to LAN1 is safe */
    IO_WRITE(VI_V_INTR_REG, 0x3ff);
    IO_WRITE(VI_H_START_REG, 0);
    IO_WRITE(VI_V_CURRENT_LINE_REG, 0);

    *(u8*)OS_PHYSICAL_TO_K1(0x00000190) =
	(u8)(LEO_country_code & 0x000000ff);

    /* stop audio */
    IO_WRITE(AI_BASE_REG, 0);
    IO_WRITE(AI_LEN_REG, 0);

    /*
     * 復号化(その3)
     */
    while(k < 256)
    {
	buf[(k * 17) % 256] = Ptr[k];
	k++;
    }
    bcopy((void *)buf, (void *)Ptr, 256);

    *(u8*)OS_PHYSICAL_TO_K1(0x00000110) =
	(u8)((LEO_country_code & 0x0000ff00) >> 8);

    /* IPL2 work */
    /* no need to get info from pif on video, reset, rom */
    /* no need to set PI rom speed */

    /* on to IPL3 work */
    __osSetCause(0);
    __osSetCount(0);
    __osSetCompare(0);

    /* no need to initialize RD-RAM */

    /* section 19  - Clear RCP status ?? */
    /* should I do the checking if PC is 0? */
    IO_WRITE(SP_STATUS_REG, SP_SET_HALT|SP_CLR_BROKE|SP_CLR_INTR| \
		SP_CLR_SSTEP|SP_CLR_SIG0|SP_CLR_SIG1|SP_CLR_SIG2| \
		SP_CLR_SIG3|SP_CLR_SIG4|SP_CLR_SIG5|SP_CLR_SIG6|  \
		SP_CLR_SIG7|SP_CLR_INTR_BREAK);

    *(u8*)OS_PHYSICAL_TO_K1(0x00000090) = 
	(u8)((LEO_country_code & 0x00ff0000) >> 16);
    
    /* clear interrupt mask */
    IO_WRITE(MI_INTR_MASK_REG, 0);

    /* rest of RCP interrupts (already did SP, PI and VI) */
    IO_WRITE(SI_STATUS_REG, 0);
    IO_WRITE(AI_STATUS_REG, 0);
    IO_WRITE(MI_MODE_REG, MI_CLR_DP_INTR);
    IO_WRITE(PI_STATUS_REG, PI_STATUS_CLR_INTR);

    /*
     * osResetType を 2 にする
     */
    osResetType = 2;

    /*
     * The os variables in locore should already be valid.
     * These are osTvType, osRomType, osResetType, osVersion
     */

    /* clear IMEM and DMEM */
    memp = (vu32 *)PHYS_TO_K1(SP_IMEM_START);
    for (i=0; i<256; i++)
	*memp++ = 0;

    memp = (vu32 *)PHYS_TO_K1(SP_DMEM_START);
    for (i=0; i<256; i++)
	*memp++ = 0;

    /*
     * 自分自身を消す
     * 64 を引くのは、自分自身のこの部分を消してしまうと大変だから
     */
    bzero( (void *)__LeoBootGame2, BOOT1_SIZE - 64 );
    osWritebackDCache( (void *)__LeoBootGame2, BOOT1_SIZE - 64 );

    /*
     * now call the assembly language routine to flush/invalidate
     * caches, and jump to game
     */
     __LeoBootGame3(entry);

}

/* details to work out:  NMI vs cold reset, global variables, ... */