rspboot0.s 6.54 KB
 #----------------------------------------------------------------------#
 #	Copyright (C) 1997, Nintendo.
 #	
 #	File		rspboot0.s
 #	Coded    by	Yoshitaka Yasumoto.	Nov 28, 1997.
 #	
 #	$Id: rspboot0.s,v 1.1.1.1 2002/05/02 03:29:12 blythe Exp $
 #----------------------------------------------------------------------#
#include <rcp.h>
#include <rsp.h>
#include <os.h>
#include <sptask.h>
#include "regdef.h"
	
		.text	0x1000

	#------ Data 領域のロード処理へ Jump ------
RSPBoot:	j	RSPBootCheck
		lw	sys2, OS_TASK_OFF_FLAGS-64(zero)
	
	#------ Text 領域のロード処理 ------
		#
		# 0x1080 へ OS_TASK_OFF_UCODE で指定したコードを
		# 0xfc0 バイト転送する.
		# sys1 に OS_TASK_OFF_UCODE がロードされている.
		#
LoadText:	ori	return, zero, TASKBASELO
		ori	sys0,   zero, 0xf80-1
		mtc0	sys1,   DMA_DRAM
		mtc0	return, DMA_CACHE
		mtc0	sys0,   DMA_READ_LENGTH
		#	
		# DMA 終了待ち
		#   終了後 Yield 要求を調べ, 要求が無ければ 
		#   $31(=0x1080)へ Jump する
		#
LoadTextWait:	mfc0	sys0,   DMA_BUSY
		bne	sys0,   zero, LoadTextWait

	#------ Yield 要求の調査 ------
		#
		# Status を調べ CPU からの Yield 要求があるかを調べる
		#
YieldCheck:	mfc0	sys0, SP_STATUS
		andi	sys0, sys0, SP_STATUS_YIELD
		bne	sys0, zero, doYield
		ori	sys0, zero, 0x1000-64
		jr	return

	#------ Yield 処理 ------
		#
		# Yield 処理を行なう.
		# BootYield の場合, SP_STATUS_YIELD はクリアしておく.
		# これにより CPU に RSP が DMEM を使用していないことを
		# 知らせる.
		#
doYield:	ori	sys2, zero, \
			SP_SET_TASKDONE|SP_SET_YIELDED|SP_CLR_YIELD # Delay
		mtc0	sys2, SP_STATUS
		break

	#------------------------------------------------
	# これ以降の IMEM は Overlay される可能性がある
	#------------------------------------------------
	##############################################
	####### マイクロコードチェック ここから ######
	##############################################
RSPBootCheck:	#
		# 不正の時の SP_STATUS へのコマンド
		#   SP_STATUS_SIG7 を 0 にする
		#
		lui	sys0, SP_CLR_SIG7>>16
		#
		# boot_dmadram($11)=前回の DMA パラメータが 0x3d8 かどうか
		#
		ori	tmp,  zero, 0x3d8
		bne	boot_dmadram, tmp, RSPBootCheckFalse
		addi	sys1, zero, RSPBootOverNG
		#
		# boot_ipl3($4) = IPL3 の先頭(0x040) $4=0x03a04820
		#
		lui	tmp,      0x03a0
		ori	tmp, tmp, 0x4820
		bne	boot_ipl3, tmp, RSPBootCheckFalse
		#
		# snap_ehandler($6) = exception handler の先頭 $6=0x25290004
		#
		lui	tmp,      0x2529
		ori	tmp, tmp, 0x0004
		bne	snap_ehandler, tmp, RSPBootCheckFalse
		#
		# count_cpudma($5) = CPU が 1M の DMA を終了するまでの時間
		#	通常 0x4c000-0x4efff 程度
		#
		srl	tmp,  count_cpudma, 12
		addi	tmp2, tmp, -0x4c
		bltz	tmp2, RSPBootCheckFalse
		addi	tmp2, tmp, -0x4f
		bgtz	tmp2, RSPBootCheckFalse
		#
		# 4k データのチェック
		#
		vxor	vsum_4k, vsum_4k, vsum_4k[1q]
		vaddc	vsum_4k, vsum_4k, vsum_4k[2h]
		vnxor	vsum_4k, vsum_4k, vsum_4k[4]
		mfc2	tmp, vsum_4k[0]
RSPBootCheck_Compare:	
		xori	tmp, tmp, 0x1234
		andi	tmp, tmp, 0xffff
		bne	tmp, zero, RSPBootCheckFalse
		#
		# DMEM の先頭データ 0x00-0x0f まで (ALL 0/ALL F ではありえない)
		#
		mfc2	tmp,  vboot_dmem[0]
		addi	tmp,  tmp,  1
		andi	tmp,  tmp,  0xfffe
		bne	tmp,  zero, RSPBootCheck_e	
		vne	vboot_dmem, vboot_dmem, vboot_dmem[0]
		cfc2	tmp2, $vcc
		beq	tmp2, zero, RSPBootCheckFalse
RSPBootCheck_e:	nop
		#
		# オーバーレイデータの決定
		#   正しいときは Jump 先を RSPBootOK にし
		#   SP_STATUS_SIG7 を 1 にする
		#
RSPBootCheckTrue:
		lui	sys0, SP_SET_SIG7>>16
		addi	sys1, zero, RSPBootOverOK
		#
		# SIG7 の変更
		# オーバーレイの開始
		#
RSPBootCheckFalse:
		mtc0	sys0, SP_STATUS		
		lw	sys0, OS_TASK_OFF_UBOOT-64(zero)
		#
		# DMA 転送を行なう
		#
RSPBootDMA:	mfc0	tmp, DMA_FULL		# Delay
		bne	tmp, tmp, RSPBootDMA
		nop
		mtc0	sys1, DMA_CACHE
		mtc0	sys0, DMA_DRAM		# 0000000000+19bit+000
		j	RSPBootOKOK
		mtc0	zero, DMA_WRITE_LENGTH

	#------ RSPBOOT の自己書き換えコード ------
		.align	8
#ifdef	PROTECT
RSPBootOverOK:	j	RSPBootOK
		lw	sys2, OS_TASK_OFF_FLAGS-64(zero)
RSPBootOverNG:	j	RSPBootNG
		lw	sys2, OS_TASK_OFF_FLAGS-64(zero)
#else
RSPBootOverOK:	j	RSPBootOKOK
		lw	sys2, OS_TASK_OFF_FLAGS-64(zero)
RSPBootOverNG:	j	RSPBootOKOK
		lw	sys2, OS_TASK_OFF_FLAGS-64(zero)
#endif
	#------ 正しいときの処理(SIG7 により改変を調べる) ------
RSPBootOK:	mfc0	sys1, SP_STATUS
		andi	sys1, sys1, SP_STATUS_SIG7
		bne	sys1, zero, RSPBootOKOK
		
	#------ 正しくないときの処理 ------
RSPBootNG:	#
		# CMD_CLOCK を処理に絡めることで原因を絞り難くする
		#
		mfc0	sys1, CMD_CLOCK
		#
		# CMD_CLOCK の値の下位 12 bit が 0 なら RDP を暴走させる
		# 1 frame に 2 回評価されるとすると平均 8192/120=68 秒で
		# 暴走する
		#
		andi	sys0, sys1, 0x1fff
		bne	sys0, zero, RSPBootNG0
		andi	sys0, sys1, 0x7f	# 0000-0000-0111-1111b
		mtc0	sys1, CMD_END
		#
		# CMD_CLOCK を取り出してその値に応じた位置へ DMA
		# 転送することでコードを徐々に破壊する.
		# アドレス 0x000000-0x3fffff のうちの 8byte へ転送する
		# ただしこれは平均 128 Boot に 1 度書換えることになる
		#
RSPBootNG0:	beq	sys0, zero, RSPBootDMA
		srl	sys0, sys1, 2	# CLOCK の値に応じた位置へ DMA する
	#------ RDP の処理終了待ち ------
RSPBootOKOK:	#
		# OS_TASK_DP_WAIT (=0x2) を処理する.
		# xbus マイクロコードの場合, DMEM を RDP のコマンド領域として
		# 使用するため, RDP の処理が終了するまで, DMEM への DMA 転送
		# はできない.
		# sys0 に OS_TASK_OFF_FLAGS の内容がロードされている.
		#
		sll	sys2, sys2, 30	# OS_TASP_DP_WAIT を MSB へ
		bgezal	sys2, LoadData	# return へ DPWait のアドレスが入る
		lw	sys1, OS_TASK_OFF_UDATA_SZ-64(zero)
		#
		# DP が BUSY かどうかを判定し BUSY なら YieldCheck へ Jump
		# YieldCheck 終了後は DPWait へ戻ってくる.
		#
DPWait:		mfc0	sys0, CMD_STATUS
		andi	sys0, sys0, 0x100
		bne	sys0, zero, YieldCheck

	#------ Data 領域のロード処理 ------
		#
		# DMA 受け付け可能待ち
		# 
LoadData:	mfc0	sys0, DMA_FULL		# Delay
		bne	sys0, zero, LoadData
		# 
		# DMA 転送パラメータ設定
		# 0x0000 へ OS_TASK_OFF_UDATA で指定したコードを
		# OS_TASK_OFF_UDATA_SZ バイト転送する.
		# sys1 には OS_TASK_OFF_UDATA_SZ がロードされている.
		#
		lw	sys0, OS_TASK_OFF_UDATA-64(zero)
		addi	sys1, sys1, -1
		mtc0	zero, DMA_CACHE
		mtc0	sys0, DMA_DRAM
		mtc0	sys1, DMA_READ_LENGTH
		#	
		# DMA 終了待ち
		#   終了後 Yield 要求を調べ, 要求が無ければ 
		#   LoadText へ Jump する
		#
LoadDataWait:	mfc0	sys0, DMA_BUSY
		bne	sys0, zero, LoadDataWait
		ori	return, zero, LoadText
		#
		# Semaphone を 0 にする
		#	audio ucode のために必要.
		#
		mtc0	$0, SP_RESERVED
		#
		# マイクロコードで使用できるようにセットする
		#   これでマイクロコードと rspboot0 の依存性を高くする
		#  (例)
		#	vconst に $v16 を加算する.
		#
		vxor	$v16, $v16, $v16
		sw	$4, OS_TASK_OFF_UBOOT-64(zero)
		j	YieldCheck
		lw	sys1, OS_TASK_OFF_UCODE-64(zero)		
		
 #======== End of rspboot0.s ========#