Editing Iplloader
Jump to navigation
Jump to search
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
The iplloader, called "Lib-PSP iplloader" internally by Sony, also sometimes called PRE-IPL or BootROM, is the first code to run in PSP MIPS32 main CPU. Its role is to load the [[Initial Program Loader]]. iplloader contains the routines to boot into service mode and loads and decrypts the encrypted IPL from the NAND or Memory Stick. | |||
Its role is to load | |||
= Location = | = Location = | ||
Line 85: | Line 83: | ||
| style="background:#C3F500" | PSP (Retail) | | style="background:#C3F500" | PSP (Retail) | ||
| style="background:#C3F500" | Tachyon 0x00600000-0x00900000 | | style="background:#C3F500" | Tachyon 0x00600000-0x00900000 | ||
| style="background:#C3F500" | 10-09-2007 (build date in | | style="background:#C3F500" | 10-09-2007 (build date in the payload) | ||
| style="background:#C3F500" | 0xCE8 | | style="background:#C3F500" | 0xCE8 | ||
| style="background:#C3F500" | SHA-256: E511D3DC78A209610F5B3EFEA2BC64BF86B9DF14A9C279C4499FECBFD70E6BF9 (ROM) | | style="background:#C3F500" | SHA-256: E511D3DC78A209610F5B3EFEA2BC64BF86B9DF14A9C279C4499FECBFD70E6BF9 (ROM) | ||
|- | |- | ||
| style="background:#FF8B00" | PS Vita | | style="background:#FF8B00" | PS Vita | ||
| style="background:#FF8B00" | 0. | | style="background:#FF8B00" | 0.931.010-0.995.000 (inside PS Vita's Compatibility security module) | ||
| style="background:#FF8B00" | 11-17-2010 (last modified date for 0.940I compat_sm.self) | |||
| style="background:#FF8B00" | | |||
| style="background:#FF8B00" | 0x2C0 | | style="background:#FF8B00" | 0x2C0 | ||
| style="background:#FF8B00" | SHA-256: 6D75EC720739C53228B1CA1AFF6CE073AE542BBB38FCC9B8710EC5EB3889B942 (full binary) | | style="background:#FF8B00" | SHA-256: 6D75EC720739C53228B1CA1AFF6CE073AE542BBB38FCC9B8710EC5EB3889B942 (full binary) | ||
Line 194: | Line 186: | ||
== Memory mapping == | == Memory mapping == | ||
The PSP iplloader is mapped to | The PSP iplloader is mapped to 0xBFC00000 which is the reset vector of PSP's MIPS R4000 CPU. | ||
0.7.0 iplloader and onward are composed of two parts: | 0.7.0 iplloader and onward are composed of two parts: a loader from 0xBFC00000 to 0xBFC0027F and a payload from 0xBFC00280 and ending at the size specified at 0xBFC000034 (little endian 0x2 bytes). | ||
The PSP iplloader distributed in PS Vita System Software version 0.996 and onward has its payload starting at 0xBFC00180, rather than at 0xBFC00280 on previous PS Vita software and PSP hardware versions. | The PSP iplloader distributed in PS Vita System Software version 0.996 and onward has its payload starting at 0xBFC00180, rather than at 0xBFC00280 on previous PS Vita software and PSP hardware versions. | ||
Line 315: | Line 305: | ||
== Retail behaviour == | == Retail behaviour == | ||
=== 01g/02g === | |||
pseucode from Tachyon 0x00140000-0x00300000 iplloader payload: | |||
<pre> | |||
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 has zero as checksum because 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++; | |||
} | } | ||
</pre> | </pre> | ||
=== | Tachyon revisions 0x00140000 to 0x00300000 iplloader pseudo code: | ||
<pre> | |||
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 iplloader 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 | |||
if ( | 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 | |||
while ( | ; | ||
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 | |||
;------------------------------------------------------------------------------ | |||
</pre> | |||
=== 03g+ === | |||
Known changes from earlier Tachyon ROM Revisions: | |||
* IPL Load address now blacklists the CPU Scratchpad range (0x80010000/0xA0010000) | |||
<pre> | |||
ROM:8001016C ext $t0, $a0, 0x10, 0xD | |||
ROM:80010170 xori $t0, 1 | |||
ROM:80010174 beqz $t0, loc_800101F0 | |||
</pre> | |||
* | * IPL Entrypoint address now blacklists specific ranges (0xBFD00000...) | ||
* | * IPL blocks now must have a minimum size of 0x100 bytes | ||
* Kirk command 1 ECDSA is now enforced on IPL blocks | |||
* The last 0x20 bytes of the block contain a SHA1 hash encrypted with Kirk command 7 0x6C | |||
The | The block hash is calculated using | ||
<pre> | |||
sha1(block[ 8 : ] + block [ : 8]) | |||
</pre> | |||
The first 8 bytes of the payload are copied to the end before the block is hashed. | |||
The hash | The last block hash remains in memory and is xored in each SHA1 for each block, the result is used for the hash compare in the Kirk command 0x10 ECDSA check. | ||
* Kirk command 0x11 ECDSA check using a custom public key (stored inside the ROM) and the xored SHA1 sum of all blocks in the hash compare function, signature present in the last IPL block (entrypoint != 0) | |||
* The first 0x10 bytes of IPL blocks are xored using a XOR key (stored in ROM and selected from an index written by updater on nand, index 1 is used for all targets except 05g, 05g uses index 2). The XOR step is not performed when Jig/Service Mode is enabled, to allow compatibility of the Jig Memory Stick across all devices. | |||
== PS Vita Compatibility mode behaviour == | == PS Vita Compatibility mode behaviour == | ||
On PS Vita, PSP iplloader is sent by the | On PS Vita, PSP iplloader is sent by the Compatibility security module (os0:sm/compat_sm.self) to the non-secure ARM kernel which writes it to 0xE8100000 (named CompatSharedSram and mapped to the 0xBFC00000 reset vector on the emulated PSP/Tachyon side). | ||
compat_sm then sends a specific 0x40-bytes XOR key to be used by the PS Vita's iplloader as a 0x40 bytes XOR mask against the IPL header. The IPL is stored in the pcbc.skprx kernel module. | |||
Kirk command 1 is then used on the result. Unlike on actual PSP units, the IPL is decrypted in a single large block rather than in multiple blocks. | |||
The 0x40 bytes key gets updated depending on the firmware version in use. | The 0x40 bytes key gets updated depending on the firmware version in use. | ||
A 0x40 bytes XOR mask is also part of the 3.50+ DTP-T1000 security | A 0x40 bytes XOR mask is also part of the 3.50+ DTP-T1000 security. See PSP iplloader section. | ||
= Dumper = | = Dumper = | ||
As of March 21st 2018, a dumper for DTP-T1000 iplloader has been made by mathieulh | As of March 21st 2018, a dumper for DTP-T1000 iplloader has been made available on github by mathieulh: | ||
* [https://github.com/mathieulh/DTP-T1000-Pre-IPL-dumper] | |||
= | = See also = | ||
* [https://web.archive.org/web/20090826053327/http://silverspring.lan.st/NPSPTD_01.txt iplloader and IPL descriptions by SilverSpring] | * [https://web.archive.org/web/20090826053327/http://silverspring.lan.st/NPSPTD_01.txt iplloader and IPL descriptions by SilverSpring] |