PRE-IPL: Difference between revisions

From PSP Developer wiki
Jump to navigation Jump to search
(Second revision)
mNo edit summary
Line 4: Line 4:
On DTP-T1000 and DEM-1000 a different ROM and loading process are used, pre-ipl will be part of a kbooti/bootdispi/writei... file containing the encrypted pre-ipl data from 0x0 to 0x1000 followed by IPL blocks.
On DTP-T1000 and DEM-1000 a different ROM and loading process are used, pre-ipl will be part of a kbooti/bootdispi/writei... file containing the encrypted pre-ipl data from 0x0 to 0x1000 followed by IPL blocks.
these files are loaded externally through the Communication Processor using the bloadp command to the Persistent Boot Storage (0xBFE00000), the rom checks the pre-ipl data size (0x10-0x12) to know how much of the file it needs to check against the data hash (0x0-0x10), (anything over the size range is not checked/loaded), if the hash fails execution halts, it then decrypts the pre-ipl data itself and copies it to 0xBFD00000 and jumps to it, (the bootrom is capable of loading regular IPLs directly from NAND or Memory stick however the kbooti decryption behavior is dictated by a syscon register, on DTP-H1500/DTP-L1500 the normal behavior occur and the IPL is loaded from NAND, the rom itself is identical on DTP-T1000 and DTP-H1500), the decrypted kbooti (pre-ipl) will then reset the cpu the way the IPL on retail units usually does, which will map 0xBFD00000 to 0xBFC00000 and allow it to behave like a normal pre-ipl (0xBFD00000 becomes an invalid address, trying to read from or write to it at IPL time will trigger a crash), this effectively renders the pre-ipl dynamic (updatable/downgradable) at will since it is not stored in rom format. The 1.00+ pre-ipls will copy it's pre-ipl payload (stored at 0xBFC000280) to 0x80010000 (physical address 0xa0010000) and jump there, because on DTP-T1000 0xbfc00000 is writable at pre-ipl time and because 0xBFD00000 is an invalid range on DTP-T1000, the payload will purposefully use the 0xBFC00000 memory (which originally contains the whole pre-ipl including bootcode) as work ram; it will however not wipe itself so you can dump the important part (the payload) from 0xa0010000 (assuming you gain execution at IPL time), until 2.60 the payload will just overwrite 0xbfc00000 using random data  but since 2.60 the payload will instead overwrite everything after 0xbfc002c0 with 00s because some of the data stored between 0xbfc00000 and 0xbfc002c0 is used as an additional step by 2.60+ IPLs to decrypt main.bin, this also means that on a DTP-T1000 this data is retrievable if dumped early, in fact most of it remains retrievable well after boot on 1.50 if bootstrapped using the 2.60 or 2.71 pre-ipl data.
these files are loaded externally through the Communication Processor using the bloadp command to the Persistent Boot Storage (0xBFE00000), the rom checks the pre-ipl data size (0x10-0x12) to know how much of the file it needs to check against the data hash (0x0-0x10), (anything over the size range is not checked/loaded), if the hash fails execution halts, it then decrypts the pre-ipl data itself and copies it to 0xBFD00000 and jumps to it, (the bootrom is capable of loading regular IPLs directly from NAND or Memory stick however the kbooti decryption behavior is dictated by a syscon register, on DTP-H1500/DTP-L1500 the normal behavior occur and the IPL is loaded from NAND, the rom itself is identical on DTP-T1000 and DTP-H1500), the decrypted kbooti (pre-ipl) will then reset the cpu the way the IPL on retail units usually does, which will map 0xBFD00000 to 0xBFC00000 and allow it to behave like a normal pre-ipl (0xBFD00000 becomes an invalid address, trying to read from or write to it at IPL time will trigger a crash), this effectively renders the pre-ipl dynamic (updatable/downgradable) at will since it is not stored in rom format. The 1.00+ pre-ipls will copy it's pre-ipl payload (stored at 0xBFC000280) to 0x80010000 (physical address 0xa0010000) and jump there, because on DTP-T1000 0xbfc00000 is writable at pre-ipl time and because 0xBFD00000 is an invalid range on DTP-T1000, the payload will purposefully use the 0xBFC00000 memory (which originally contains the whole pre-ipl including bootcode) as work ram; it will however not wipe itself so you can dump the important part (the payload) from 0xa0010000 (assuming you gain execution at IPL time), until 2.60 the payload will just overwrite 0xbfc00000 using random data  but since 2.60 the payload will instead overwrite everything after 0xbfc002c0 with 00s because some of the data stored between 0xbfc00000 and 0xbfc002c0 is used as an additional step by 2.60+ IPLs to decrypt main.bin, this also means that on a DTP-T1000 this data is retrievable if dumped early, in fact most of it remains retrievable well after boot on 1.50 if bootstrapped using the 2.60 or 2.71 pre-ipl data.
It is also of worthy of note that prototype pre-ipl for DEM-1000 (for 0.40 and 0.60 firmwares) do not make use of 0xa0010000 as it's payload location, it is however used as work ram, the payload is instead executed in place at 0xbfc00000, as such the pre-ipl data is not wiped and can be dumped in its entirety using a custom IPL (please note that the IPL format is different than later revision IPLs, prototype IPLs are loaded in a single raw kirk cmd0 0x01 block)
It is also of worthy of note that prototype pre-ipl for DEM-1000 (for 0.40 and 0.60 firmwares) do not make use of 0xa0010000 as it's payload location, the payload is instead executed in place at 0xbfc00000, as such the pre-ipl data is not wiped and can be dumped in its entirety using a custom IPL (please note that the IPL format is different than later revision IPLs, prototype IPLs are loaded in a single raw kirk cmd0 0x01 block)
IPL blocks are then loaded from 0xBFE01000 by the pre-ipl and copied accordingly to the load address specified in the metadata (IPL blocks have no metadata in prototype IPLs instead the pre-ipl uses 0x88400000 as an hardcoded entry point, in fact the IPL payload/part3, nested inside current IPL revisions and loaded by main.bin are using the prototype format, so the prototype pre-ipl loads the IPL part 3/payload directly).
IPL blocks are then loaded from 0xBFE01000 by the pre-ipl and copied accordingly to the load address specified in the metadata (IPL blocks have no metadata in prototype IPLs instead the pre-ipl uses 0x88400000 as an hardcoded entry point, in fact the IPL payload/part3, nested inside current IPL revisions and loaded by main.bin are using the prototype format, so the prototype pre-ipl loads the IPL part 3/payload directly).
Please note that the 0xa0010000 memory does not survive reboots.


Retail behavior (pseucode from TA-079 pre-ipl payload):  
Retail behavior (pseucode from TA-079 pre-ipl payload):  

Revision as of 15:35, 14 March 2018

The PRE-IPL on retail PSP units is the Tachyon (Allegrex MIPS R4000 based SOC) bootrom. It is mapped to 0xBFC00000 which is the reset vector of PSP's MIPS R4000 CPU

Devkit behavior: On DTP-T1000 and DEM-1000 a different ROM and loading process are used, pre-ipl will be part of a kbooti/bootdispi/writei... file containing the encrypted pre-ipl data from 0x0 to 0x1000 followed by IPL blocks. these files are loaded externally through the Communication Processor using the bloadp command to the Persistent Boot Storage (0xBFE00000), the rom checks the pre-ipl data size (0x10-0x12) to know how much of the file it needs to check against the data hash (0x0-0x10), (anything over the size range is not checked/loaded), if the hash fails execution halts, it then decrypts the pre-ipl data itself and copies it to 0xBFD00000 and jumps to it, (the bootrom is capable of loading regular IPLs directly from NAND or Memory stick however the kbooti decryption behavior is dictated by a syscon register, on DTP-H1500/DTP-L1500 the normal behavior occur and the IPL is loaded from NAND, the rom itself is identical on DTP-T1000 and DTP-H1500), the decrypted kbooti (pre-ipl) will then reset the cpu the way the IPL on retail units usually does, which will map 0xBFD00000 to 0xBFC00000 and allow it to behave like a normal pre-ipl (0xBFD00000 becomes an invalid address, trying to read from or write to it at IPL time will trigger a crash), this effectively renders the pre-ipl dynamic (updatable/downgradable) at will since it is not stored in rom format. The 1.00+ pre-ipls will copy it's pre-ipl payload (stored at 0xBFC000280) to 0x80010000 (physical address 0xa0010000) and jump there, because on DTP-T1000 0xbfc00000 is writable at pre-ipl time and because 0xBFD00000 is an invalid range on DTP-T1000, the payload will purposefully use the 0xBFC00000 memory (which originally contains the whole pre-ipl including bootcode) as work ram; it will however not wipe itself so you can dump the important part (the payload) from 0xa0010000 (assuming you gain execution at IPL time), until 2.60 the payload will just overwrite 0xbfc00000 using random data but since 2.60 the payload will instead overwrite everything after 0xbfc002c0 with 00s because some of the data stored between 0xbfc00000 and 0xbfc002c0 is used as an additional step by 2.60+ IPLs to decrypt main.bin, this also means that on a DTP-T1000 this data is retrievable if dumped early, in fact most of it remains retrievable well after boot on 1.50 if bootstrapped using the 2.60 or 2.71 pre-ipl data. It is also of worthy of note that prototype pre-ipl for DEM-1000 (for 0.40 and 0.60 firmwares) do not make use of 0xa0010000 as it's payload location, the payload is instead executed in place at 0xbfc00000, as such the pre-ipl data is not wiped and can be dumped in its entirety using a custom IPL (please note that the IPL format is different than later revision IPLs, prototype IPLs are loaded in a single raw kirk cmd0 0x01 block) IPL blocks are then loaded from 0xBFE01000 by the pre-ipl and copied accordingly to the load address specified in the metadata (IPL blocks have no metadata in prototype IPLs instead the pre-ipl uses 0x88400000 as an hardcoded entry point, in fact the IPL payload/part3, nested inside current IPL revisions and loaded by main.bin are using the prototype format, so the prototype pre-ipl loads the IPL part 3/payload directly).

Please note that the 0xa0010000 memory does not survive reboots.

Retail behavior (pseucode from TA-079 pre-ipl payload):

int iplBlockNumber = 0;
u32 checksum = 0;

// load/decrypt all encrypted ipl blocks
while(1)
{
// copy an encrypted ipl block to 0xBFD00000-0xBFD01000 (4KB embedded cpu ram)
if (LoadIplBlock(iplBlockNum ber, block) < 0)
while(1);

// decrypt the ipl block in place (uh oh...)
if (DecryptIplBlock(block, block))
while(1);

// first block will have zero as its checksum since there is no previous block (another uh oh...)
if (block->checksum != checksum)
while(1);

// load the 'data' section of the ipl block to the specified address (0x040Fxxxx range)
if (block->loadaddr)
checksum = memcpy(block->loadaddr, block->data, block->blocksize);

// reached the end of the ipl, jump to the entry address (0x040F0000)
if (block->entry)
{
// clear caches
Dcache();
Icache();

// jump to ipl - do not return
block->entry();
}

iplBlockNumber++;
}

TA-079 pre-ipl pseudo code:


PSP Disassembler Ver.0.20 Copyright(c)2005,2006 BOOSTER
incl. elf-lib 0.1r2 copyright (c) 2005 djhuevo

:file name '0x80010000.bin',size = 4096
Load 3684 NID's name

:Disasm

;copied by pre-ipl bootcode, from 0xbfc00280-0xbfc00d78
;here code is 0x80010000 to 0x80010af8

;
;$bfd00000-$bfd00fff : sector read buffer
;

;-------------------------------------------------------
;recovery mode selector

;be240004 GPIO READ REG.
;		bit4 : device select ,0=NAND Flash,  1= rec-dev
;
;-------------------------------------------------------

;-------------------------------------------------------
;recovery boot device (rec-dev) HW assign
;
;bd200030	command register
				00009007 : read request (write size = 8)
				00002200 : read sector buffer (read size=200)
				00008004 : ? status (write size = 8 , read size=8)
				00004000 : ? status (read size=8)
				00007001 : ? (data size=8?)

;bd200034	data register (read / write)
;bd200038	status register
;			bit14:read data ready
;			bit13:parameter wirte ready
;			bit12:transmit finish ?
;			bit 9:???? error
;			bit 8:read data error
;
;bd20003c	???
			bit15:reset device ?
;
;-------------------------------------------------------


;---------------------------------------------------------------------------
;entry
;---------------------------------------------------------------------------
L80010000:
;
;reset I/O
	$800106B0(L80010a80)
;
  lui    r8,$bc10                           ;80010010[3C08BC10,'...<']
;
	if(r8[$68]>>16 == 0) $80010034
;
	r9 = r8[$78]
  ori    r9,r9,$0800                        ;80010028[35290800,'..)5']
  b      $80010040                          ;8001002C[10000004,'....']
  sw     r9,$78(r8)                         ;80010030[AD090078,'x...']
;
;80010034
  lw     r9,$7c(r8)                         ;80010034[8D09007C,'|...']
  ori    r9,r9,$0010                        ;80010038[35290010,'..)5']
  sw     r9,$7c(r8)                         ;8001003C[AD09007C,'|...']
  addiu  r4,0,$a                            ;80010040[2404000A,'...$']
  jal    $80010768                          ;80010044[0C0041DA,'.A..']
  sync                                      ;80010048[0000000F,'....']
;80010768
;
;check recovery boot mode switch
;
	r8 = [$be240004] & 0x10 // GPIO bit 4
;
	r9 = $80010194 // NAND read BLOCK entry
	r10= $80010130 // NAND initialize(read FAT) entry
;
	if(r8!=0)// $80010080
	{
		r9 = $80010248 // rec-dev read BLOCK entry
		r10= $80010240 // rec-dev initialize entry
	}
;80010080
	[$80010808] = r9
	[$8001080c] = 0x000000000
;
;call read FAT
;
	(r10)()
;
	r23 = 0  ; check sum of last block
;
;READ BLOCK LOOP
;
L80010098
	r25 = [$80010808] ; read BLOCK entry
	r4  = [$8001080c] ; block num of read
;
;call read body function
;
	r2 = (r25)(r4,$bfd000000);
	if(r2<0) $80010128
;
;decrypt 1000H block
;
	r2 = $80010620($bfd00000,$bfd00000)
	if(r2<0) $80010128
;
;+000c : check sum of last block ?
;
	if( [$bfd0000c] != r23) $80010128
;
;+0000 : distination address
;+0004 : block size
;
	r4 = [$bfd00000] ; +0000 : top pointer
	r6 = [$bfd00004] ; +0004 : size
	if(r4!=0)
	{
;transmit BLOCK body
		r23 = $80010688(r4,r16 + $10 , r6)
	}
;
;+0008 : entry point or continue MARK check
;
	r25 = r16[8]
	if(r25==0) //$80010114
	{
;L80010114:
		[$8001080c]++  ; next block
		goto $80010098
	}
;
;cache ?
	$800102D8()
;
;cache ?
	$800102A0()
;
;goto IPL entry point
;
	  jalr   r25                                ;8001010C[0320F809,'.. .']
;
;80010128
	while(1); // HALT
;
;---------------------------------------------------------------------------
;read IPL FAT
;---------------------------------------------------------------------------
L80010130:
	r16 =r31
;
;80010134
;NAND reset 
	$80010308()
;
;8001013C
	r17  = $80 // top of IPL-FAT sector
;80010140
;read IPL FAT
	r2 = $80010334(r17,8001081c,80010810)
	if(r2<0) $8001018c
;80010164
	r8 = r6[0]
	r9 = r6[4]
	r10= r6[8]
;ECC signature
	if(r9 != $6dc64a38) // $8001018c
	{
		r17 += $20 // next IPL sector
		goto $80010140
	}
; jr     r16                                ;80010184[02000008,'....']
	return

;------------------------------------------------------------------------
;NAND read body
;
;r4 : fat logical ptr (400H bytes lba? )
;
;------------------------------------------------------------------------
L80010194:
	[$80010800] = r31
	[$80010804] = r4
;
	r17 = r5
;get FAT location
	r8 = $8001081c ; FAT table
	r9 = (r4>>2)<<1
	r8 += r9
	r9 = (u16)r8[0]
;
	r8 = (r9<<2) | (r4 & 3)
;
	r16 = r8 << 3 ; * 8
	r18 = 0
;800101CC
	do
	{
;read body one
		r2 = $80010334(r16+r18,r17 + (r18<<9),80010810)
		if(r2<0) $80010230
		r8 = r6[0]
		r9 = r6[4]
		r10= r6[8]
;ECC signature
		if(r9 != $6dc64a38) $80010230
		r18++
	}while(r18<8);
;80010220
	r31 = [$80010800]
	return r0

L80010230:
	r31 = [$80010800]
	return -1

;------------------------------------------------------------------------
;rec-dev initialize
;------------------------------------------------------------------------
L80010240:
	return $800103B4()

;------------------------------------------------------------------------
;rec-dev read 1000H block
;------------------------------------------------------------------------
L80010248:
	[$80010$800] = r31
;
	r16 = r4
	r17 = r5
	r18 = 0
;8001025C
	do{
		r2 = $80010418(r18+0x10+r16<<3 ,r17 + r18<<9)
		if(r2<0) $8001025c
		r18++
	}while(r18<8);
;
	r31 = [$80010$800]
	return r2

;------------------------------------------------------------------------
;cache ?
;------------------------------------------------------------------------
L800102A0:
  mfc0   r8,Config                          ;800102A0[40088000,'...@']
  addiu  r9,0,$1000                         ;800102A4[24091000,'...$']
  dc.l   $7d081240 [invalid]                ;800102A8[7D081240,'@..}']
  sllv   r9,r9,r8                           ;800102AC[01094804,'.H..']
  mtc0   0,TagLo                            ;800102B0[4080E000,'...@']
  mtc0   0,TagHi                            ;800102B4[4080E800,'...@']
  addu   r8,0,0                             ;800102B8[00004021,'!@..']
;
  cache  $01,r8($0)                         ;800102BC[BD010000,'....']
  cache  $03,r8($0)                         ;800102C0[BD030000,'....']
  addiu  r8,r8,$40                          ;800102C4[25080040,'@..%']
  bne    r8,r9,$800102bc                    ;800102C8[1509FFFC,'....']
  nop                                       ;800102CC[00000000,'....']
  jr     r31                                ;800102D0[03E00008,'....']
  nop                                       ;800102D4[00000000,'....']

;------------------------------------------------------------------------
;cache ?
;------------------------------------------------------------------------
L800102D8:
  mfc0   r8,Config                          ;800102D8[40088000,'...@']
  addiu  r9,0,$800                          ;800102DC[24090800,'...$']
  dc.l   $7d081180 [invalid]                ;800102E0[7D081180,'...}']
  sllv   r9,r9,r8                           ;800102E4[01094804,'.H..']
  addu   r8,0,0                             ;800102E8[00004021,'!@..']
;
  cache  $14,r8($0)                         ;800102EC[BD140000,'....']
  cache  $14,r8($0)                         ;800102F0[BD140000,'....']
  addiu  r8,r8,$40                          ;800102F4[25080040,'@..%']
  bne    r8,r9,$800102ec                    ;800102F8[1509FFFC,'....']
  nop                                       ;800102FC[00000000,'....']
  jr     r31                                ;80010300[03E00008,'....']
  sync                                      ;80010304[0000000F,'....']

;----------------------------------------------------------------------------
;NAND reset CMD
;----------------------------------------------------------------------------
L80010308:
;nand cmd
	[$bd101008] = 0xff
;nand sts
	while( [$bd101004] & 1 ==0);
;
	[$bd101014] = 0x01
	return

;----------------------------------------------------------------------------
;NAND Read Sector
;
;r4 : sector
;r5 : data buffer
;r6 : Extra buffer
;
;----------------------------------------------------------------------------
L80010334:
;nand sts
	while([$bd101004] & 1 == 0);
;
	[$bd101020] = r4 << 10
	[$bd101024] = $301
;80010354
	while([$bd101024] & 1 == 0);
;80010364
	if([$bd101028] != 0) return -1
;
  lui    r8,$bff0                           ;80010370[3C08BFF0,'...<']
;
	r9  = r8[$900]
	r10 = r8[$904]
	r2  = r8[$908]
;
	r6[0] = r9
	r6[4] = r10
	r6[8] = r2
;
	r9 = r5
	r2 = $200
L80010394:
	do
	{
		r10 = r8[0]
		r2 -= 4
		r8 += 4
		r9[0] = r10
		r9 += 4
	}while(r2);
;800103AC
	return 0

;----------------------------------------------------------------------------
;rec-dev initialize
;----------------------------------------------------------------------------
L800103B4:
	r24 = r31
;
;rec-dev I/O init : device & clock enable ?
	$800106B0(L80010ad4)
;
;reset device ?
;
	[$bd20003c] = $8000
;800103D4
	while( [$bd20003c] & 0x8000);
;
	$80010530()
	$80010508()
;
;800103F4
	do{
		r2 = $800105B8()
		if(r2<0) continue // $800103f4
;
	}while(r2 & $0080 == 0); // $800103f4
;
;  jr     r24                                ;80010410[03000008,'....']
	return 0

;----------------------------------------------------------------------------
;rec-dev read sector one
;
;a1:sector address
;a2:buffer
;
;----------------------------------------------------------------------------
L80010418:
	r14 = r5
;	r24 = r31
;  lui    r25,$bd20
;
;read sector COMMAND ?
	[$bd200030] = $00009007
;
  dc.l   $7c0428e0 [invalid]                ;8001042C[7C0428E0,'.(.|']
;
	r5 >>= 8
	r9 = (r4 >> 24) << 24
;
	r4 = $00010020
	r4 |= r9
;
;write parameter
	r2 = $800104C0(r4,r5)
	if(r2<0) return -1
;busy wait
	$80010608()
;
;$8001045c
	do{
		r2 = $800105B8()
		if(r2<0) return -1
		r2 = r2 & $0020
	}while((r2 & $0020)==0);
;
	if(r2 & $0040) return -1
;
;read buffer COMMAND ?
	[$bd200030] = $00002200
;
;read sector data
	r2 = $800104CC(r14,$200) // r14 == r5
	if(r2<0) return -1
;wait finish
	r2 = $80010508()
	if(r2<0) return -1
;busy wait
	$80010608()
;
	goto $800103f4
;
;800104B8
;  jr     r24                                ;800104B8[03000008,'....']
	return -1

;----------------------------------------------------------------------------
;rec-dev : commmand output ?
;
;a1:1st write data
;a2:2nd write data
;----------------------------------------------------------------------------
L800104C0:
	[$bd200034] = r4
	[$bd200034] = r5
	goto $80010508

;----------------------------------------------------------------------------
;rec-dev read data block
;
;a1:distination pointer
;a2:transmit size
;
;----------------------------------------------------------------------------
L800104CC:
	do{
		do{
			r9 = [$bd200038]
			if(r9 & $0100) return -1;
		}while(r9 & $4000 == 0);
;
		r2 = [$bd200034]
		r5 -= 4
		r4[0] = r2
		r4 += 4
	}while(r5 >=0);
;
	return 0;

;----------------------------------------------------------------------------
;wait for TX finish ?
;----------------------------------------------------------------------------
L80010508:
	do{
		r9 = [$bd200038]
	}while(r9 & $1000 == 0);
;
	if(r9 & $0300) return -1// $80010528
;
	return 0

;----------------------------------------------------------------------------
;rec-dev read status ?
;----------------------------------------------------------------------------
L80010530:
;  addu   r15,r31,0                          ;80010530[03E07821,'!x..']
;  lui    r25,$bd20                          ;80010534[3C19BD20,' ..<']
;
	[$bd200030] = $00008004
	[$bd200034] = $06100800
	[$bd200034] = 0
	r2 = $80010508()
	if(r2<0) return -1
;
	$800105A4($80010a1c,8);
;
;get status ?
;
	r4 = [$80010a1c]
	r5 = [$80010a20]
;
	if( (r4>>16)&0x15 != 0) return -1
;
	return 0

;----------------------------------------------------------------------------
;rec-dev read status ?
;
;a1:buffer
;a2:size
;
;----------------------------------------------------------------------------
L800105A4:
	[$bd200030] = $00004000
;read sector body
	return $800104cc(r4,r5)

;-----------------------------------------------------------------------------
;rec-dev device ready check?
;-----------------------------------------------------------------------------
L800105B8:
;r25 = $bd200000
	[$bd200030] = $00007001
;wait
	do
	{
		r9 = [$bd200038]
	}while(r9 & $0100);
	if((r9 & $4000)==0) $800105c0
;
	r2 = [$bd200034]
	r0 = [$bd200034] // ?
;800105E0
	do{
		r9 = [$bd200038]
		if(r9 & $0100) //$80010600
		{
L80010600:
			return -1
		}
	}while( (r9 & $1000)==0);
;
	return r2 & 0xff;

;----------------------------------------------------------------------------
;wait for rec-dev busy
;----------------------------------------------------------------------------
L80010608:
	do
	{
		r9 = [$bd200038]
	}while( (r9 & $2000) == 0);
	return

;-----------------------------------------------------------------------------
;decrypt 1000H block
;-----------------------------------------------------------------------------
L80010620:
;  lui    r25,$bde0                          ;80010620[3C19BDE0,'...<']
;
	[$bde00010] = $00000001
;r8 = r4
  dc.l   $7ca8e000 [invalid]                ;8001062C[7CA8E000,'...|']
	[$bde0002c] = r8
;
;r8 = r5
  dc.l   $7c88e000 [invalid]                ;80010634[7C88E000,'...|']
	[$bde00030] = r8
;
	[$bde0000c] = $00000001
;$80010644
	do{
		r8 = [$bde0001c]
	}while(r8 & $0011 == 0)
;
	[$bde00028] = r8
	if(r8&$0010) // $80010664
	{
L80010664:
		[$bde0000c] = $00000002
;$8001066C
		do{
			r8 = [$bde0001c]
		}while(r8 & $0002 == 0)
;
		[$bde00028] = r8
		sync
		return -1
	}
;
	return [$bde00014]

;----------------------------------------------------------------------------
;transmit data with calc check sum
;
;arg1: source
;arg2: distination
;arg1: size
;
;return : 32bit check sum (add)
;
;----------------------------------------------------------------------------
L80010688:
	r2 = 0 ; clear check sum
	do{
		r3 = r5[0]
		r5 += 4
		r6 -= 4
		r4[0] = r3
		r2 += r3 ; check sum
		r4 += 4
	}while(r6>=0);
	return

;---------------------------------------------------------------------------
;script executer
;
;a1:script pointer
;
;2 word command
;
;+00[31:28] : CMD
;+00[27: 0] : OFFSET
;+04[31: 0] : VALUE
;
;CMD : command :
; 0  : store   | [$b0000000 + OFFSET]  = VALUE
; 1  : or      | [$b0000000 + OFFSET] |= VALUE
; 2  : and     | [$b0000000 + OFFSET] &= VALUE
; 3  : wait toL| while( ( [$b0000000 + OFFSET] &= VALUE) != 0)
;(4) : wait toH| while( (~[$b0000000 + OFFSET] &= VALUE) != 0)
; 5  : delay   | for(cnt=VALUE*96;cnt;cnt--)
; F  : end     | return
;
;---------------------------------------------------------------------------
L800106B0:
	r8 = r4
;addu   r25,r31,0
;
;800106b8
	do{
		// read CMD:offset + VALUE
		r4 = r8[0]
		r9 = r4 >> 28
		r4 = ( (r4 << 4)>>4 ) | $b0000000
		r5 = r4[4]
;
		if(r9==0) //$80010724
		{
;80010724
			r4[0]=r5
			goto $8001071c
		}
		if(r9==1)// $8001072c
		{
;8001072C
			r4[0] = r4[0] | r5
			goto $8001071c
		}
		if(r9==2) // $8001073c
		{
			r4[0] = r4[0] & r5
			goto $8001071c
		}
		r1 = 0
		if(r9==3) $8001074c
;
		r1 = $ffffffff ;  nor    r1,0,0
;!!!!! buggy code !!!!!
;  addiu  r10,r10,-$4
;		if(r9==4) $8001074c
		if(r9==7) $8001074c
;!!!!! buggy code !!!!!

;		if(r9==5) //$80010714
		{
L80010714:
			$80010768(r5);
			goto L8001071C
		}
;default:
;  jr     r25                                ;8001070C[03200008,'.. .']
		return;
;
;case end
L8001071C:
		// next script point
		r8 += 8
	}while(1);
;
;4,7
L8001074C:
	{
		do{
			r9 =  (r4[0] ^ r1) & r5
		}while(r9!=0);
		goto $8001071c
	}

;--------------------------------------------------------------------------
;delay
;--------------------------------------------------------------------------
L80010768:
	r1 = ((r4 << 1) + r4)<<5 // * 96
	while(r1) r1--;
	return

;--------------------------------------------------------------------------
;--------------------------------------------------------------------------
L80010784:
  nop                                       ;80010784[00000000,'....']
  nop                                       ;80010788[00000000,'....']
  nop                                       ;8001078C[00000000,'....']
  nop                                       ;80010790[00000000,'....']
  nop                                       ;80010794[00000000,'....']
  nop                                       ;80010798[00000000,'....']
  nop                                       ;8001079C[00000000,'....']
  nop                                       ;800107A0[00000000,'....']
  nop                                       ;800107A4[00000000,'....']
  nop                                       ;800107A8[00000000,'....']
  nop                                       ;800107AC[00000000,'....']
  nop                                       ;800107B0[00000000,'....']
  nop                                       ;800107B4[00000000,'....']
  nop                                       ;800107B8[00000000,'....']
  nop                                       ;800107BC[00000000,'....']
  nop                                       ;800107C0[00000000,'....']
  nop                                       ;800107C4[00000000,'....']
  nop                                       ;800107C8[00000000,'....']
  nop                                       ;800107CC[00000000,'....']
  nop                                       ;800107D0[00000000,'....']
  nop                                       ;800107D4[00000000,'....']
  nop                                       ;800107D8[00000000,'....']
  nop                                       ;800107DC[00000000,'....']
  nop                                       ;800107E0[00000000,'....']
  nop                                       ;800107E4[00000000,'....']
  nop                                       ;800107E8[00000000,'....']
  nop                                       ;800107EC[00000000,'....']
  nop                                       ;800107F0[00000000,'....']
  nop                                       ;800107F4[00000000,'....']
  nop                                       ;800107F8[00000000,'....']
  nop                                       ;800107FC[00000000,'....']

;-----------------------------------------------------------------------------
;
;r31 save buffer
;
L80010800:
	dl 800100B0

;
;r4 save buffer
;
L80010804:
	dl 0000002E
;
;read sector function entry
;
L80010808:
	dl L80010194
;
;read block number
;
L8001080C:
	dl L0000002E
;
;NAND Extra buffer
;
L80010810:
	dl	FFFFFFFF
	dl	6DC64A38
	dl	FFFFFD89

;
;NAND Data buffer (IPL FAT)
;
L8001081c
  mfhi   0                                  ;8001081C[00110010,'....']
  mflo   0                                  ;80010820[00130012,'....']
  dsllv  0,r21,0                            ;80010824[00150014,'....']
  dsrlv  0,r23,0                            ;80010828[00170016,'....']
  mult   0,r25                              ;8001082C[00190018,'....']
  div    0,r27                              ;80010830[001B001A,'....']
  nop                                       ;80010834[00000000,'....']
  nop                                       ;80010838[00000000,'....']
  nop                                       ;8001083C[00000000,'....']
  nop                                       ;80010840[00000000,'....']
  nop                                       ;80010844[00000000,'....']
  nop                                       ;80010848[00000000,'....']
  nop                                       ;8001084C[00000000,'....']
  nop                                       ;80010850[00000000,'....']
  nop                                       ;80010854[00000000,'....']
  nop                                       ;80010858[00000000,'....']
  nop                                       ;8001085C[00000000,'....']
  nop                                       ;80010860[00000000,'....']
  nop                                       ;80010864[00000000,'....']
  nop                                       ;80010868[00000000,'....']
  nop                                       ;8001086C[00000000,'....']
  nop                                       ;80010870[00000000,'....']
  nop                                       ;80010874[00000000,'....']
  nop                                       ;80010878[00000000,'....']
  nop                                       ;8001087C[00000000,'....']
  nop                                       ;80010880[00000000,'....']
  nop                                       ;80010884[00000000,'....']
  nop                                       ;80010888[00000000,'....']
  nop                                       ;8001088C[00000000,'....']
  nop                                       ;80010890[00000000,'....']
  nop                                       ;80010894[00000000,'....']
  nop                                       ;80010898[00000000,'....']
  nop                                       ;8001089C[00000000,'....']
  nop                                       ;800108A0[00000000,'....']
  nop                                       ;800108A4[00000000,'....']
  nop                                       ;800108A8[00000000,'....']
  nop                                       ;800108AC[00000000,'....']
  nop                                       ;800108B0[00000000,'....']
  nop                                       ;800108B4[00000000,'....']
  nop                                       ;800108B8[00000000,'....']
  nop                                       ;800108BC[00000000,'....']
  nop                                       ;800108C0[00000000,'....']
  nop                                       ;800108C4[00000000,'....']
  nop                                       ;800108C8[00000000,'....']
  nop                                       ;800108CC[00000000,'....']
  nop                                       ;800108D0[00000000,'....']
  nop                                       ;800108D4[00000000,'....']
  nop                                       ;800108D8[00000000,'....']
  nop                                       ;800108DC[00000000,'....']
  nop                                       ;800108E0[00000000,'....']
  nop                                       ;800108E4[00000000,'....']
  nop                                       ;800108E8[00000000,'....']
  nop                                       ;800108EC[00000000,'....']
  nop                                       ;800108F0[00000000,'....']
  nop                                       ;800108F4[00000000,'....']
  nop                                       ;800108F8[00000000,'....']
  nop                                       ;800108FC[00000000,'....']
  nop                                       ;80010900[00000000,'....']
  nop                                       ;80010904[00000000,'....']
  nop                                       ;80010908[00000000,'....']
  nop                                       ;8001090C[00000000,'....']
  nop                                       ;80010910[00000000,'....']
  nop                                       ;80010914[00000000,'....']
  nop                                       ;80010918[00000000,'....']
  nop                                       ;8001091C[00000000,'....']
  nop                                       ;80010920[00000000,'....']
  nop                                       ;80010924[00000000,'....']
  nop                                       ;80010928[00000000,'....']
  nop                                       ;8001092C[00000000,'....']
  nop                                       ;80010930[00000000,'....']
  nop                                       ;80010934[00000000,'....']
  nop                                       ;80010938[00000000,'....']
  nop                                       ;8001093C[00000000,'....']
  nop                                       ;80010940[00000000,'....']
  nop                                       ;80010944[00000000,'....']
  nop                                       ;80010948[00000000,'....']
  nop                                       ;8001094C[00000000,'....']
  nop                                       ;80010950[00000000,'....']
  nop                                       ;80010954[00000000,'....']
  nop                                       ;80010958[00000000,'....']
  nop                                       ;8001095C[00000000,'....']
  nop                                       ;80010960[00000000,'....']
  nop                                       ;80010964[00000000,'....']
  nop                                       ;80010968[00000000,'....']
  nop                                       ;8001096C[00000000,'....']
  nop                                       ;80010970[00000000,'....']
  nop                                       ;80010974[00000000,'....']
  nop                                       ;80010978[00000000,'....']
  nop                                       ;8001097C[00000000,'....']
  nop                                       ;80010980[00000000,'....']
  nop                                       ;80010984[00000000,'....']
  nop                                       ;80010988[00000000,'....']
  nop                                       ;8001098C[00000000,'....']
  nop                                       ;80010990[00000000,'....']
  nop                                       ;80010994[00000000,'....']
  nop                                       ;80010998[00000000,'....']
  nop                                       ;8001099C[00000000,'....']
  nop                                       ;800109A0[00000000,'....']
  nop                                       ;800109A4[00000000,'....']
  nop                                       ;800109A8[00000000,'....']
  nop                                       ;800109AC[00000000,'....']
  nop                                       ;800109B0[00000000,'....']
  nop                                       ;800109B4[00000000,'....']
  nop                                       ;800109B8[00000000,'....']
  nop                                       ;800109BC[00000000,'....']
  nop                                       ;800109C0[00000000,'....']
  nop                                       ;800109C4[00000000,'....']
  nop                                       ;800109C8[00000000,'....']
  nop                                       ;800109CC[00000000,'....']
  nop                                       ;800109D0[00000000,'....']
  nop                                       ;800109D4[00000000,'....']
  nop                                       ;800109D8[00000000,'....']
  nop                                       ;800109DC[00000000,'....']
  nop                                       ;800109E0[00000000,'....']
  nop                                       ;800109E4[00000000,'....']
  nop                                       ;800109E8[00000000,'....']
  nop                                       ;800109EC[00000000,'....']
  nop                                       ;800109F0[00000000,'....']
  nop                                       ;800109F4[00000000,'....']
  nop                                       ;800109F8[00000000,'....']
  nop                                       ;800109FC[00000000,'....']
  nop                                       ;80010A00[00000000,'....']
  nop                                       ;80010A04[00000000,'....']
  nop                                       ;80010A08[00000000,'....']
  nop                                       ;80010A0C[00000000,'....']
  nop                                       ;80010A10[00000000,'....']
  nop                                       ;80010A14[00000000,'....']
  nop                                       ;80010A18[00000000,'....']
;
;rec-dev status read buffer ?
L80010A1C:
	dl	00000000,00000000
;
  nop                                       ;80010A24[00000000,'....']
  nop                                       ;80010A28[00000000,'....']
  nop                                       ;80010A2C[00000000,'....']
  nop                                       ;80010A30[00000000,'....']
  nop                                       ;80010A34[00000000,'....']
  nop                                       ;80010A38[00000000,'....']
  nop                                       ;80010A3C[00000000,'....']
  nop                                       ;80010A40[00000000,'....']
  nop                                       ;80010A44[00000000,'....']
  nop                                       ;80010A48[00000000,'....']
  nop                                       ;80010A4C[00000000,'....']
  nop                                       ;80010A50[00000000,'....']
  nop                                       ;80010A54[00000000,'....']
  nop                                       ;80010A58[00000000,'....']
  nop                                       ;80010A5C[00000000,'....']
  nop                                       ;80010A60[00000000,'....']
  nop                                       ;80010A64[00000000,'....']
  nop                                       ;80010A68[00000000,'....']
  nop                                       ;80010A6C[00000000,'....']
  nop                                       ;80010A70[00000000,'....']
  nop                                       ;80010A74[00000000,'....']
  nop                                       ;80010A78[00000000,'....']
  nop                                       ;80010A7C[00000000,'....']
;
;
;script command : I/O init
;
L80010A80:
	dl	1C100058,00800000	; [$bc100058] |= 00800000
	dl	1C100050,0000608E	; [$bc100050] |= 0000608E
	dl	2C10004C,FFFFFBF7	; [$bc10004C] &= FFFFFBF7
	dl	1C100078,00000002	; [$bc100078] |= 00000002
	dl	2E240000,FFFFFFEF	; [$be240000] &= FFFFFFEF : GPIO bit4 direction read?
	dl	1E240040,00000010	; [$be240040] |= 00000010 : GPIO bit4 pullup enable ?
	dl	50000000,00000001	; delay 1
	dl	0D500010,00000001	; [$bd500010] = 00000001
	dl	3D500010,00000001	; while( [$bd500010] & 1)
	dl	0D500040,00000001	; [$bd500040] = 00000001
	dl	F0000000			; end
;
;script command : rec-dev I/O init
;
L80010AD4:
	dl	3D500010,00000001	; while( [$bd500010] & 1)
	dl	1C100054,00000100	; [$bc100054] |= 00000100
	dl	1C100050,00000400	; [$bc100050] |= 00000400
	dl	1C100078,00000010	; [$bc100078] |= 00000010
	dl	2C10004C,FFFFFEFF	; [$bc10004C] &= FFFFFEFF
	dl	F0000000			; end
;
;------------------------------------------------------------------------------
;code end
;------------------------------------------------------------------------------