Pre-IPL RAM Stage pseudo C code
Pre-IPL RAM Stage
Dumped from Motherboard: TA-081
header file:
c file:
Dumped from Motherboard: TA-081
header file:
/*
* file: pre-IPL_ram_def.h
* pre-IPL_ram pseudo C code
* dumped from Motherboard: TA-081
*/
#define ENDIAN_SWAP(_x) ((((_x)<<24) & 0xFF000000) | (((_x)<<8) & 0x00FF0000) | (((_x)>>8) & 0x0000FF00) | (((_x)>>24) & 0x000000FF))
#define KEY_IO 11
#define SYSREG_IO0_ENABLE(DEVICE) *0xBC100078 |= 1<<DEVICE
#define SYSREG_IO1_ENABLE(DEVICE) *0xBC10007C |= 1<<DEVICE
#define REG32(ADDR) (*(vu32*)(ADDR))
#define GPIO_PORT_JIGKICK (4)
#define GPIO_MASK_JIGKICK (1<<GPIO_PORT_JIGKICK)
#define SYNC() asm("sync")
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef int (*LoadIplBlockFunc) (int iplBlockNum, void *buf);
typedef struct
{
u8 opcode:4;
u32 addr:28;
u32 val;
}regConf;
/********************************
Memroy Stick Related define
********************************/
// HW registers
#define IO_MEM_STICK_SYS *((volatile int*)(0xBD20003C))
#define IO_MEM_STICK_DATA *((volatile int*)(0xBD200034))
#define IO_MEM_STICK_CMD *((volatile int*)(0xBD200030))
#define IO_MEM_STICK_STATUS *((volatile int*)(0xBD200038))
#define MSRST 0x8000
#define SET_RW_REG_ADRS 0x8000
// SYS bit
#define MSRST 0x8000
// STATUS bit
#define MS_FIFO_RW 0x4000
#define MS_RDY 0x1000
#define MS_TIME_OUT 0x0100
#define MS_CRC_ERROR 0x0200
// MS command code
#define READ_PAGE_DATA 0x2000
#define READ_REG 0x4000
#define GET_INT 0x7000
#define SET_RW_REG_ADRS 0x8000
#define EX_SET_CMD 0x9000
#define WRITE_REG 0xB000
#define WRITE_PAGE_DATA 0xD000
#define SET_CMD 0xE000
// MS status bit
#define INT_REG_CED 0x80
#define INT_REG_ERR 0x40
#define INT_REG_BREQ 0x20
#define INT_REG_CMDNK 0x01
/********************************
IPL Decryption
********************************/
#define GET_PHYSICAL_ADDRESS(_addr) ((u32) _addr & 0x1FFFFFFF)
#define KIRK_HW_REGISTER_ADDRESS ((PspKirkRegs *)0xBDE00000)
enum PspKirkStatus
{
STATUS_FLAG0 = 0X00,
STATUS_FLAG1 = 0X01,
STATUS_FLAG2 = 0X02,
STATUS_FLAG3 = 0X04,
STATUS_FLAG4 = 0X08,
STATUS_FLAG5 = 0X10,
STATUS_FLAG6 = 0X20,
STATUS_FLAG7 = 0X40,
STATUS_FLAG8 = 0X80
};
enum PspKirkCmd
{
ASYMM_CIPHER1 = 1,
ASYMM_CIPHER2,
ASYMM_CIPHER3,
BLOCK_CIPHER4,
BLOCK_CIPHER5,
BLOCK_CIPHER6,
BLOCK_CIPHER7,
BLOCK_CIPHER8,
BLOCK_CIPHER9,
ASYMM_CIPHER_CHECK,
SHA1_CHECK,
MUL1_CHECK,
MUL2_CHECK,
PRN_GEN1,
PRN_GEN2,
SIG_GEN,
SIG_CHECK,
CERT_CHECK
};
enum PspKirkError
{
NO_ERROR = 0,
BUS_CLK_DISABLED,
INVALID_MODE,
HEADER_HASH_FAIL,
DATA_HASH_FAIL,
INVALID_CODE = 0xE,
INVALID_SIZE_A,
INVALID_SIZE_B
};
enum PspKirkPhase
{
PHASE1 = 1,
PHASE2 = 2
};
typedef volatile struct
{
const u32 signature;
const u32 version;
const u32 error;
u32 proc_phase;
u32 command;
const u32 result;
u32 unk_18;
const u32 status;
u32 status_async;
u32 status_async_end;
u32 status_end;
void *src_addr;
void *dst_addr;
} PspKirkRegs;
typedef struct
{
void *loadaddr;
int blocksize;
void (* entry)(void);
u32 checksum;
u8 data[0xF50];
} iplBlock;
/********************************
NAND Related define
********************************/
#define NAND_BUSY (0)
#define NAND_READY (1)
#define NAND_SPARE_PAGE_SIZE (16)
#define NAND_LOGICAL_PAGE_SIZE (512)
#define NAND_PHYSICAL_PAGE_SIZE (NAND_LOGICAL_PAGE_SIZE+NAND_SPARE_PAGE_SIZE)
#define NAND_PAGES_PER_BLOCK (32)
#define NAND_RESET_CMD (0xFF)
#define NAND_CMD_REG (0xBD101008)
#define NAND_STATUS_REG (0xBD101004)
#define NAND_RESET_REG (0xBD101014)
#define NAND_DMA_ADDR_REG (0xBD101020)
#define NAND_DMA_CTRL_REG (0xBD101024)
#define NAND_DMA_STAT_REG (0xBD101028)
#define NAND_PAGE_DATA_BUF_REG (0xBFF00000)
#define NAND_SPARE_BUF0_REG (0xBFF00900)
#define NAND_SPARE_BUF1_REG (0xBFF00904)
#define NAND_SPARE_BUF2_REG (0xBFF00908)
#define NAND_SET_CMD(cmd) (_sw(cmd, NAND_CMD_REG))
#define NAND_SET_RESET(v) (_sw(v, NAND_RESET_REG))
#define NAND_SET_DMA_ADDR(v) (_sw(v, NAND_DMA_ADDR_REG))
#define NAND_SET_DMA_CTRL(v) (_sw(v, NAND_DMA_CTRL_REG))
#define NAND_GET_STATUS() (_lw(NAND_STATUS_REG))
#define NAND_GET_DMA_CTRL() (_lw(NAND_DMA_CTRL_REG))
#define NAND_GET_DMA_STAT() (_lw(NAND_DMA_STAT_REG))
#define NAND_GET_PAGE_DATA() (_lw(NAND_PAGE_DATA_BUF_REG))
#define NAND_GET_SPARE_BUF0() (_lw(NAND_SPARE_BUF0_REG))
#define NAND_GET_SPARE_BUF1() (_lw(NAND_SPARE_BUF1_REG))
#define NAND_GET_SPARE_BUF2() (_lw(NAND_SPARE_BUF2_REG))
/********************************
22 functions defined in pre_ipl_ram
********************************/
void _RamEntry(void);// 0x80010000
void ReadIplNandBlockTable(void); // 0x80010130
int LoadIplBlockFromNand(int iplBlockNum, void *buf); // 0x80010194
void MsCheck(void); // 0x80010240
int LoadIplBlockFromMs(int iplBlockNum, void *buf); // 0x80010248
void ClearICache(void); //0x800102A0
void ClearDCache(void); //0x800102D8
void ResetNand(void); //0x80010308
int ReadNandPage(int pageNum, void *buf, void *spare); //0x80010334
void _MsCheck(void); //0x800103B4
int ReadMsSector(int sectNum, void * buf); //0x80010418
int SendDataAndSync(u32 arg1, u32 arg2); //0x800104C0
int ReadMsData(void * addr, int count); //0x800104CC
int WaitMsReady(void); //0x80010508
int CheckMsStatus(void); //0x80010530
int ReadMsReg(void *buffer, int reg); //0x800105A4
u8 GetMsStatus(void); //0x800105B8
void WaitMsStatus(void); //0x80010608
u32 DecryptIplBlock(void *dst, void *src); //0x80010620
u32 _Memcpy(void *dst, void *src, int size); //0x80010688
void SysRegConfig(regConf *conf); //0x800106B0
void Delay(int cnt); //0x80010768
c file:
/*
* file: pre-IPL_ram.c
* pre-IPL_ram pseudo C code
* dumped from Motherboard: TA-081
*/
/*
REG_CONF_TBL0 do the following Ops:
*(u32*)0xBC100058 = *(u32*)0xBC100058 | 0x800000; GPIO Enable
*(u32*)0xBC100050 = *(u32*)0xBC100050 | 0x608E; CLK Enable: AW/KIRK/EMCSM(nand)/UART4
*(u32*)0xBC10004C = *(u32*)0xBC10004C & 0xFFFFFBF7;
*(u32*)0xBC100078 = *(u32*)0xBC100078 | 0x2; IO Enable: USB
*(u32*)0xBE240000 = *(u32*)0xBE240000 & 0xFFFFFFEF; GPIO
*(u32*)0xBE240040 = *(u32*)0xBE240040 | 0x10;
delay(1);
*(u32*)0xBD500010 = 1; Graphics engine
while(*(u32)0xBD500010&0x1);
*(u32*)0xBD500040 = 1;
REG_CONF_TBL1 do the following Ops:
*(u32*)0xBC100054 = *(u32*)0xBC100054 | 0x100; Mem stick init
*(u32*)0xBC100050 = *(u32*)0xBC100050 | 0x400;
*(u32*)0xBC100078 = *(u32*)0xBC100078 | 0x10;
*(u32*)0xBC10004C = *(u32*)0xBC10004C & 0xFFFFFEFF;
*/
#include "preIPL_ram_def.h"
/***********************************************************************/
iplBlock *block = (void*) 0xBDF00000; //temp addr to store a single ipl block
LoadIplBlockFunc LoadIplBlock;//0x80010808
int iplBlockNumber = 0; //0x8001080C
u32 gSpare[3]; //0x80010810
u8 gIplBlkIndex[512]; //0x8001081C
u32 REG_CONF_TBL0[]={//0x80010A80
0x1C100058, 0x00800000,
0x1C100050, 0x0000608E,
0x2C10004C, 0xFFFFFBF7,
0x1C100078, 0x00000002,
0x2E240000, 0xFFFFFFEF,
0x1E240040, 0x00000010,
0x50000000, 0x00000001,
0x0D500010, 0x00000001,
0x3D500010, 0x00000001,
0x0D500040, 0x00000001,
0xF0000000,
};
u32 REG_CONF_TBL1[]={//0x80010AD4
0x1C100054, 0x00000100,
0x1C100050, 0x00000400,
0x1C100078, 0x00000010,
0x2C10004C, 0xFFFFFEFF,
0xF0000000,
}
/***********************************************************************/
// 0x80010000
void _RamEntry(void)
{
u32 checksum = 0;
SysRegConfig((regConf *)REG_CONF_TBL0);
if (*0xBC100068 >> 16)
SYSREG_IO0_ENABLE(KEY_IO);
else
SYSREG_IO1_ENABLE(4);
Delay(10);
SYNC();
// if service mode
if (REG32(0xBE240004) & GPIO_MASK_JIGKICK){
LoadIplBlock = (void *)LoadIplBlockFromMs;
MsCheck(); // will stuck here on empty MS
}else{
LoadIplBlock = (void *)LoadIplBlockFromNand;
ReadIplNandBlockTable(); // will stuck here on empty nand
}
// load/decrypt all encrypted ipl blocks
while(1){
// copy an encrypted ipl block to 0xBFD00000-0xBFD01000 (4KB temp ram)
if (LoadIplBlock(iplBlockNumber, block) < 0) while(1);
// decrypt the ipl block in place (uh oh...)
if (DecryptIplBlock(block, block)) while(1);
// note first block has zero as its checksum (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
ClearDCache();
ClearICache();
// jump to ipl - do not return
block->entry();
}
iplBlockNumber++;
}
}
/***********************************************************************/
// 0x80010130
void ReadIplNandBlockTable(void)
{
u32 iplBlkIndexPage = 128;
ResetNand();
// if empty nand, this while loop is where it'll get stuck
while(1){
if (ReadNandPage(iplBlkIndexPage, gIplBlkIndex, gSpare) >= 0)
if (gSpare[1] == 0x6DC64A38) return;
iplBlkIndexPage += NAND_PAGES_PER_BLOCK; // try next block
}
}
/***********************************************************************/
// 0x80010194
#define IPLBLOCKNUM_TO_NANDPAGENUM(b) (((*(u16 *)(gIplBlkIndex + (b>>2)<<1) << 2) | (b&3)) << 3)
#define NUMPAGES_PER_IPLBLOCK (8)
int LoadIplBlockFromNand(int iplBlockNum, void *buf)
{
int i;
int pageNum = IPLBLOCKNUM_TO_NANDPAGENUM(iplBlockNum);
*0x80010804 = iplBlockNum; //unuseful
for (i=0; i<NUMPAGES_PER_IPLBLOCK; i++){
if (ReadNandPage(pageNum+i, buf+i*NAND_LOGICAL_PAGE_SIZE, &gSpare) < 0) return -1;
if (gSpare[1] != 0x6DC64A38) return -1;
}
return 0;
}
/***********************************************************************/
// 0x80010240
void MsCheck(void)
{
_MsCheck();
}
/***********************************************************************/
// 0x80010248
int LoadIplBlockFromMs(int iplBlockNum, void *buf)
{
u32 a0, i;
for (i=0; i<8; i++){
a0 = (iplBlockNum*8)+i;
a0 += 0x10;
while(ReadMsSector(a0, buf+i*512) < 0);
}
return 0;
}
/***********************************************************************/
// 0x800102A0
void ClearICache(void)
{
__asm__ volatile
(
".word 0x40088000
" // mfc0 $t0, Config
".word 0x24091000
" // li $t1, 0x1000
".word 0x7D081240
" // ext $t0, 9, 3
".word 0x01094804
" // sllv $t1, $t0
".word 0x4080E000
" // mtc0 $0, TagLo
".word 0x4080E800
" // mtc0 $0, TagHi
".word 0x00004021
" // move $t0, $0
".word 0xBD010000
" // cache 1, 0($t0) #loop
".word 0xBD030000
" // cache 3, 0($t0)
".word 0x25080040
" // addiu $t0, 0x40
".word 0x1509FFFC
" // bne $t0, $t1, loop
".word 0x00000000
" // nop
".word 0x03E00008
" // jr $ra
".word 0x00000000
" // nop
);
}
/***********************************************************************/
// 0x800102D8
void ClearDCache(void)
{
__asm__ volatile
(
".word 0x40088000
" // mfc0 $t0, Config
".word 0x24090800
" // li $t1, 0x800
".word 0x7D081180
" // ext $t0, 6, 3
".word 0x01094804
" // sllv $t1, $t0
".word 0x00004021
" // move $t0, $0
".word 0xBD140000
" // cache 0x14, 0($t0) #loop
".word 0xBD140000
" // cache 0x14, 0($t0)
".word 0x25080040
" // addiu $t0, 0x40
".word 0x1509FFFC
" // bne $t0, $t1, loop
".word 0x00000000
" // nop
".word 0x03E00008
" // jr $ra
".word 0x0000000F
" // sync
);
}
/***********************************************************************/
//0x80010308
void ResetNand(void)
{
NAND_SET_CMD(NAND_RESET_CMD);
while((NAND_GET_STATUS() & 1) == NAND_BUSY);
NAND_SET_RESET(1);
}
/***********************************************************************/
//0x80010334
int ReadNandPage(int pageNum, void *buf, void *spare)
{
while((NAND_GET_STATUS() & 1) == NAND_BUSY);
NAND_SET_DMA_ADDR(pageNum*1024); // shouldnt this be 512?
NAND_SET_DMA_CTRL(0x00000301);
while(NAND_GET_DMA_CTRL() & 1);
if (NAND_GET_DMA_STAT()) return -1;
spare[0] = NAND_GET_SPARE_BUF0();
spare[1] = NAND_GET_SPARE_BUF1();
spare[2] = NAND_GET_SPARE_BUF2();
MEMCPY(buf, NAND_GET_PAGE_DATA(), NAND_PAGE_LOGICAL_SIZE);
return 0;
}
/***********************************************************************/
//0x800103B4
void _MsCheck(void)
{
u8 ret;
SysRegConfig((regConf *)REG_CONF_TBL1);
//reset the controller
IO_MEM_STICK_SYS = MSRST;
while(IO_MEM_STICK_SYS & MSRST);
CheckMsStatus();
WaitMsReady();
do{
ret = GetMsStatus();
} while ((ret<0) || (ret & INT_REG_CED == 0));
}
/***********************************************************************/
//0x80010418
int ReadMsSector(int sectNum, void *buf)
{
int ret;
IO_MEM_STICK_CMD = EX_SET_CMD | 0x7;
ret = SendDataAndSync(0x00010020 | ((sectNum>>24)<<24), ENDIAN_SWAP(sectNum)>>8);
if (ret<0) return -1;
WaitMsStatus();
do{
ret = GetMsStatus();
if(ret<0) return -1;
} while(!(ret & INT_REG_BREQ));
if (ret & INT_REG_ERR) return -1;
//send command to read data and get the data.
IO_MEM_STICK_CMD = READ_PAGE_DATA | 512;
ret = ReadMsData(buf, 512);
if(ret<0) return -1;
ret = WaitMsReady();
if(ret<0) return -1;
WaitMsStatus();
do{
ret = GetMsStatus();
} while ((ret<0) || (ret & INT_REG_CED == 0));
return 0;
}
/***********************************************************************/
//0x800104C0
int SendDataAndSync(u32 arg1, u32 arg2)
{
int ret;
IO_MEM_STICK_DATA = arg1;
IO_MEM_STICK_DATA = arg2;
ret = WaitMsReady();
return ret;
}
/***********************************************************************/
//0x800104CC
int ReadMsData(void *addr, int count)
{
int i;
int status;
for(i = 0; i<count; i+= 4){
do{
status = IO_MEM_STICK_STATUS;
if (status & MS_TIME_OUT) return -1;
}while(!(status & MS_FIFO_RW));
*((volatile int*)(addr + i)) = IO_MEM_STICK_DATA;
}
return 0;
}
/***********************************************************************/
//0x80010508
int WaitMsReady(void)
{
int status;
do{
status = IO_MEM_STICK_STATUS;
}while(!(status & MS_RDY));
if (status & (MS_CRC_ERROR|MS_TIME_OUT)){
return -1;
}
return 0;
}
/***********************************************************************/
//0x80010530
int CheckMsStatus(void)
{
int ret;
u8 status[8]; //80010A1C
IO_MEM_STICK_CMD = SET_RW_REG_ADRS | 0x4;
IO_MEM_STICK_DATA = 0x06100800;
IO_MEM_STICK_DATA = 0x00000000;
if (WaitMsReady() < 0) return -1;
ret = ReadMsReg(status, 8);
if (0 != (status[2] & 0x15)) return -1;
return 0;
}
/***********************************************************************/
//0x800105A4
int ReadMsReg(void *buffer, int reg)
{
int ret;
IO_MEM_STICK_CMD = READ_REG | reg;
ret = ReadMsData(buffer, reg);
return ret;
}
/***********************************************************************/
//0x800105B8
u8 GetMsStatus()
{
u32 ret, dummy;
IO_MEM_STICK_CMD = GET_INT |0x1;
do
{
if (IO_MEM_STICK_STATUS & MS_TIME_OUT)
return -1;
} while(!(IO_MEM_STICK_STATUS & MS_FIFO_RW));
ret = IO_MEM_STICK_DATA;
dummy = IO_MEM_STICK_DATA; //$zero = *0xBD200034;
do
{
if (IO_MEM_STICK_STATUS & MS_TIME_OUT)
return -1;
} while(!(IO_MEM_STICK_STATUS & MS_RDY));
return(ret & 0xFF);
}
/***********************************************************************/
//0x80010608
void WaitMsStatus(void)
{
while(!(IO_MEM_STICK_STATUS & 0x2000));
}
/***********************************************************************/
//0x80010620
u32 DecryptIplBlock(void *dst, void *src)
{
PspKirkRegs *const crypt = KIRK_HW_REGISTER_ADDRESS;
crypt->command = ASYMM_CIPHER1;
crypt->src_addr = (void *) GET_PHYSICAL_ADDRESS(src);
crypt->dst_addr = (void *) GET_PHYSICAL_ADDRESS(dst);
crypt->proc_phase = PHASE1; // tell hardware to start work
while(!(crypt->status & (STATUS_FLAG1 | STATUS_FLAG5))); // while not complete and not error?
if (crypt->status & STATUS_FLAG5){// error
crypt->proc_phase = PHASE2;
while(!(crypt->status & STATUS_FLAG2));
crypt->status_end = crypt->status;
SYNC();
return -1;
}
crypt->status_end = crypt->status;
return(crypt->result);
}
/***********************************************************************/
//0x80010688
u32 _Memcpy(void *dst, void *src, int size)
{
u32 checksum = 0;
// decrementing 'i' because more optimised in asm
for (i=size; i>0; i-=4)
{
*dst = *src;
checksum += *src;
src += 4;
dst += 4;
}
return(checksum);
}
/***********************************************************************/
//0x800106B0
void SysRegConfig(regConf *conf)
{
u8 opcode;
u32 addr, val;
regConf *p = conf;
while(1){
addr = p->addr | 0xb0000000;
val = p->val;
switch(p->opcode){
case 0:
*addr = val;
break;
case 1:
*addr = *addr | val;
break;
case 2:
*addr = *addr & val;
break;
case 3:
while(*addr & val);
break;
case 4:
while((~(*addr)) & val);
break;
case 5:
delay(val);
break;
default:
return;
}
p++;
}
}
/***********************************************************************/
//80010768
void Delay(int cnt)
{
int loop = (cnt*2+cnt)<<5;
while(loop) loop--;
return;
}