Merge branch 'CTurt:master' into patch-1
This commit is contained in:
commit
e8ae772c35
73 changed files with 1200 additions and 895 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
77
PAYLOADS/1.00-2.13/Mainrules.mk
Normal file
77
PAYLOADS/1.00-2.13/Mainrules.mk
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
EE_CC = ee-gcc
|
||||
EE_LD = ee-ld
|
||||
EE_AS = ee-as
|
||||
EE_OBJCOPY = ee-objcopy
|
||||
|
||||
IOP_CC = iop-gcc
|
||||
IOP_LD = iop-ld
|
||||
IOP_AS = iop-as
|
||||
IOP_OBJCOPY = iop-objcopy
|
||||
IOP_OBJDUMP = iop-objdump
|
||||
|
||||
IOP_SYMBOLS = -DREAD_SECTORS_210=$(IOP_READ_SECTORS_210) -DORIGINAL_RETURN_ADDRESS_210=$(IOP_ORIGINAL_RETURN_ADDRESS_210) -DRETURN_ADDRESS_LOCATION_210=$(IOP_RETURN_ADDRESS_LOCATION_210) \
|
||||
-DREAD_SECTORS_212=$(IOP_READ_SECTORS_212) -DORIGINAL_RETURN_ADDRESS_212=$(IOP_ORIGINAL_RETURN_ADDRESS_212) -DRETURN_ADDRESS_LOCATION_212=$(IOP_RETURN_ADDRESS_LOCATION_212) \
|
||||
-DREAD_SECTORS_213=$(IOP_READ_SECTORS_213) -DORIGINAL_RETURN_ADDRESS_213=$(IOP_ORIGINAL_RETURN_ADDRESS_213) -DRETURN_ADDRESS_LOCATION_213=$(IOP_RETURN_ADDRESS_LOCATION_213) \
|
||||
-DREAD_SECTORS_110=$(IOP_READ_SECTORS_110) -DORIGINAL_RETURN_ADDRESS_110=$(IOP_ORIGINAL_RETURN_ADDRESS_110) -DRETURN_ADDRESS_LOCATION_110=$(IOP_RETURN_ADDRESS_LOCATION_110)
|
||||
|
||||
IOP_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -g $(IOP_SYMBOLS)
|
||||
|
||||
EE_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
|
||||
IOP_STAGE1_SIZE_210_212 = `stat -c '%s' stage1_210_212.iop.bin`
|
||||
IOP_STAGE1_SIZE_213 = `stat -c '%s' stage1_213.iop.bin`
|
||||
IOP_PAYLOAD_SIZE = `stat -c '%s' ioppayload.iop.bin`
|
||||
|
||||
dvd.iso: dvd.base.iso stage1_210_212.iop.bin stage1_213.iop.bin ioppayload.iop.bin
|
||||
#genisoimage -udf -o dvd.iso udf/
|
||||
# @echo Insert 0x00000048 to offset 0x0818AC in dvd.iso
|
||||
# @echo Insert 0x00004000 to offset 0x0818B0 in dvd.iso
|
||||
# @echo Insert 0x000B7548 to offset 0x0818F4 in dvd.iso
|
||||
|
||||
# For now it's easier to just use a base dvd rather than attempting to generate an image and patch it
|
||||
cp dvd.base.iso dvd.iso
|
||||
|
||||
# Return address (2.10 - 2.13) 0x00818f4 = 530676
|
||||
printf $(STAGE1_LOAD_ADDRESS_STRING_210_212) | dd of=dvd.iso bs=1 seek=530676 count=4 conv=notrunc
|
||||
|
||||
# Return address 1.10 (0x000818bc = 530620)
|
||||
printf $(STAGE1_LOAD_ADDRESS_STRING_110) | dd of=dvd.iso bs=1 seek=530620 count=4 conv=notrunc
|
||||
|
||||
# Old toolchains don't support this option, so just copy byte-by-byte...
|
||||
# bs=4096 iflag=skip_bytes,count_bytes
|
||||
|
||||
dd if=stage1_210_212.iop.bin of=dvd.iso bs=1 seek=$(STAGE1_ISO_210_212) count=$(IOP_STAGE1_SIZE_210_212) conv=notrunc
|
||||
dd if=stage1_213.iop.bin of=dvd.iso bs=1 seek=$(STAGE1_ISO_213) count=$(IOP_STAGE1_SIZE_213) conv=notrunc
|
||||
|
||||
# 0x700000 = 7340032
|
||||
dd if=ioppayload.iop.bin of=dvd.iso bs=1 seek=7340032 count=$(IOP_PAYLOAD_SIZE) conv=notrunc
|
||||
|
||||
%.iop.bin: %.iop.elf
|
||||
$(IOP_OBJCOPY) -O binary $< $@
|
||||
|
||||
%.iop.o: %.iop.S
|
||||
$(IOP_AS) $< -o $@
|
||||
|
||||
stage1_210_212.iop.elf: stage1_210_212.iop.S ioppayload.iop.bin
|
||||
$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"
|
||||
$(IOP_CC) $< -DENTRY=$(IOP_PAYLOAD_ENTRY) -DIOP_PAYLOAD_SIZE=$(IOP_PAYLOAD_SIZE) $(IOP_CFLAGS) -o $@
|
||||
|
||||
stage1_213.iop.elf: stage1_213.iop.S ioppayload.iop.bin
|
||||
$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"
|
||||
$(IOP_CC) $< -DENTRY=$(IOP_PAYLOAD_ENTRY) -DIOP_PAYLOAD_SIZE=$(IOP_PAYLOAD_SIZE) $(IOP_CFLAGS) -o $@
|
||||
|
||||
%.iop.elf: %.iop.c eepayload.ee.bin
|
||||
$(IOP_CC) -Ttext=$(IOP_PAYLOAD_ADDRESS) -DLOAD_ELF_FROM_OFFSET=$(LOAD_ELF_FROM_OFFSET) ioppayload.iop.c $(IOP_CFLAGS) -o $@
|
||||
|
||||
|
||||
%.ee.bin: %.ee.elf
|
||||
$(EE_OBJCOPY) -O binary $< $@ -Wl,-z,max-page-size=0x1
|
||||
|
||||
%.ee.o: %.ee.S
|
||||
$(EE_AS) $< -o $@
|
||||
|
||||
eepayload.ee.elf: eecrt0.ee.o syscalls.ee.o eepayload.ee.c
|
||||
$(EE_CC) -Ttext=$(EE_PAYLOAD_ADDRESS) $^ $(EE_CFLAGS) -o $@
|
||||
|
||||
clean:
|
||||
rm -rf *.elf *.bin *.o dvd.iso
|
||||
BIN
PAYLOADS/1.00-2.13/dvd.base.iso
Normal file
BIN
PAYLOADS/1.00-2.13/dvd.base.iso
Normal file
Binary file not shown.
25
PAYLOADS/1.00-2.13/eecrt0.ee.S
Normal file
25
PAYLOADS/1.00-2.13/eecrt0.ee.S
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# ElReino & CTurt 2020
|
||||
|
||||
.section .text.startup
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
# Point stack to end of scratchpad RAM
|
||||
#la $sp, 0x70004000
|
||||
|
||||
.global main
|
||||
#la $v1, 0x01
|
||||
#la $a0, 0x7f
|
||||
#syscall 0x01 # ResetEE
|
||||
|
||||
la $a0, main
|
||||
la $a1, 0
|
||||
la $a2, 0
|
||||
la $a3, 0
|
||||
|
||||
jr $a0
|
||||
|
||||
# Don't use on phat PS2... completely broken syscall
|
||||
#ExecPS2:
|
||||
# la $v1, 0x07
|
||||
# syscall 0x07 # ExecPS2
|
||||
67
PAYLOADS/1.00-2.13/eepayload.ee.c
Normal file
67
PAYLOADS/1.00-2.13/eepayload.ee.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// ElReino & CTurt 2020
|
||||
|
||||
//int (*SifIopReset)(char *, int) = (void *)0x85360;
|
||||
//void (*SifInitRpc)(int) = (void *)0x84500;
|
||||
//void (*SifExitRpc)(void) = (void *)0x84690;
|
||||
|
||||
extern void SifWriteBackDCache(void *ptr, int size);
|
||||
extern int SifSetReg(unsigned int register_num, unsigned int register_value);
|
||||
extern int SifGetReg(unsigned int register_num);
|
||||
|
||||
static int SifIopSync(void) {
|
||||
#define SIF_REG_SMFLAG 4
|
||||
#define SIF_STAT_BOOTEND 0x40000
|
||||
return((SifGetReg(SIF_REG_SMFLAG) & SIF_STAT_BOOTEND) != 0);
|
||||
}
|
||||
|
||||
static void flush(void) {
|
||||
asm volatile("la $v1, 0x64; la $a0, 0; syscall 0x64"); // FlushCache data writeback
|
||||
asm volatile("la $v1, 0x64; la $a0, 2; syscall 0x64"); // FlushCache instruction invalidate
|
||||
}
|
||||
|
||||
int GetThreadId(void);
|
||||
void ChangeThreadPriority(int thread_id, int priority);
|
||||
int CancelWakeupThread(int thread_id);
|
||||
void TerminateThread(int thread_id);
|
||||
void DeleteThread(int thread_id);
|
||||
|
||||
static void TerminateAllThreads(void) {
|
||||
int i, ThreadID;
|
||||
|
||||
ThreadID=GetThreadId();
|
||||
ChangeThreadPriority(ThreadID, 0);
|
||||
CancelWakeupThread(ThreadID);
|
||||
for(i=1; i<256; i++){ //Skip idle thread.
|
||||
if(i!=ThreadID){
|
||||
TerminateThread(i);
|
||||
DeleteThread(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
// ExecPS2 is broken on Phat PS2... manually kill other threads instead
|
||||
TerminateAllThreads();
|
||||
|
||||
// Signal IOP that EE is Ready, willing, and fully enabled!
|
||||
SifSetReg(3, 1);
|
||||
|
||||
volatile int *waitAddress = (void *)0x21FFF7F0;
|
||||
while(!*waitAddress);
|
||||
|
||||
volatile void **entry_point_address = (void *)0x01FFF7E0;
|
||||
|
||||
// cdrom0:
|
||||
volatile void **argument = (void *)0x01FFF7D0;
|
||||
*(volatile int *)0x01FFF7D0 = 0x01FFF7D8;
|
||||
*(volatile int *)0x01FFF7D8 = 0x6F726463;
|
||||
*(volatile int *)0x01FFF7DC = 0x003A306D;
|
||||
|
||||
flush();
|
||||
|
||||
//SifIopReset("rom0:UDNL rom0:EELOADCNF", 0);
|
||||
//while(!SifIopSync());
|
||||
|
||||
//ExecPS2(*entry_point_address, 0, 0, 0);
|
||||
ExecPS2(*entry_point_address, 0, 1, argument); // kHn: arg == cdrom0:
|
||||
}
|
||||
37
PAYLOADS/1.00-2.13/emulator.mk
Normal file
37
PAYLOADS/1.00-2.13/emulator.mk
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#STAGE1_LOAD_ADDRESS_110 = 0xa00b66a8
|
||||
#STAGE1_LOAD_ADDRESS_STRING_110 = '\xa8\x66\x0b\xa0'
|
||||
|
||||
STAGE1_LOAD_ADDRESS_210_212 = 0xa00b7548
|
||||
STAGE1_LOAD_ADDRESS_STRING_210_212 = '\x48\x75\x0b\xa0'
|
||||
|
||||
STAGE1_LOAD_ADDRESS_213 = 0xa00b6fc8
|
||||
STAGE1_LOAD_ADDRESS_STRING_213 = '\xc8\x6f\x0b\xa0'
|
||||
|
||||
STAGE1_ISO_210_212 = 532728 # 0x820f8
|
||||
STAGE1_ISO_213 = 534136 # 0x82678
|
||||
|
||||
IOP_READ_SECTORS_110 = 0xb19e4
|
||||
IOP_READ_SECTORS_210 = 0xb260c
|
||||
IOP_READ_SECTORS_212 = 0xb25f8
|
||||
IOP_READ_SECTORS_213 = 0xb21f8
|
||||
IOP_ORIGINAL_RETURN_ADDRESS_210 = 0xb3630
|
||||
IOP_ORIGINAL_RETURN_ADDRESS_212 = 0xB35D8
|
||||
IOP_ORIGINAL_RETURN_ADDRESS_213 = 0xB31EC
|
||||
IOP_RETURN_ADDRESS_LOCATION_210 = 0x1f62ac
|
||||
IOP_RETURN_ADDRESS_LOCATION_212 = 0x1f62b4
|
||||
IOP_RETURN_ADDRESS_LOCATION_213 = 0x1F62B4
|
||||
|
||||
|
||||
#IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"`
|
||||
IOP_PAYLOAD_ENTRY = 0xa00fd178 # Set this manually for now.
|
||||
|
||||
IOP_PAYLOAD_ADDRESS = 0xa00fd000
|
||||
|
||||
EE_PAYLOAD_ADDRESS = 0x01fff800
|
||||
|
||||
#isoinfo -l -i dvd.iso | grep "BOOT.ELF"
|
||||
#var=`isoinfo -l -i dvd.iso | grep "BOOT.ELF" | grep -o -P "[0-9]*? -"`
|
||||
# LOAD_ELF_FROM_OFFSET =
|
||||
LOAD_ELF_FROM_OFFSET = 0x5BB000 # Set this manually for now
|
||||
|
||||
include Mainrules.mk
|
||||
36
PAYLOADS/1.00-2.13/hardware.mk
Normal file
36
PAYLOADS/1.00-2.13/hardware.mk
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
|
||||
|
||||
STAGE1_LOAD_ADDRESS_210_212 = 0xa0062C48
|
||||
STAGE1_LOAD_ADDRESS_STRING_210_212 = '\x48\x2c\x06\xa0'
|
||||
|
||||
STAGE1_LOAD_ADDRESS_213 = 0xA00626C8 # 0xa00b6fc8 + 0x5c700 - 0xb1000
|
||||
STAGE1_LOAD_ADDRESS_STRING_213 = '\xc8\x26\x06\xa0'
|
||||
|
||||
STAGE1_ISO_210_212 = 532728 # 0x820f8
|
||||
STAGE1_ISO_213 = 534136 # 0x82678
|
||||
|
||||
IOP_READ_SECTORS_210 = 0x5DD0C # 0xb260c + 0x5c700 - 0xb1000
|
||||
IOP_READ_SECTORS_212 = 0x5DCF8 # 0xb25f8 + 0x5c700 - 0xb1000
|
||||
IOP_READ_SECTORS_213 = 0x5D8F8 # 0xb21f8 + 0x5c700 - 0xb1000
|
||||
IOP_ORIGINAL_RETURN_ADDRESS_210 = 0x5ED30 # 0xb3630 + 0x5c700 - 0xb1000
|
||||
IOP_ORIGINAL_RETURN_ADDRESS_212 = 0x5ECD8 # 0xB35D8 + 0x5c700 - 0xb1000
|
||||
IOP_ORIGINAL_RETURN_ADDRESS_213 = 0x5E8EC # 0xB31EC + 0x5c700 - 0xb1000
|
||||
IOP_RETURN_ADDRESS_LOCATION_210 = 0x1F30AC # 0x1f62ac + 0x1F3058 - 0x1f6258
|
||||
IOP_RETURN_ADDRESS_LOCATION_212 = 0x1F30B4 # 0x1f62b4 + 0x1F3058 - 0x1f6258
|
||||
IOP_RETURN_ADDRESS_LOCATION_213 = 0x1F30B4 # 0x1F62B4 + 0x1F3058 - 0x1f6258
|
||||
|
||||
|
||||
#IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"`
|
||||
IOP_PAYLOAD_ENTRY = 0xa00fd178 # Set this manually for now.
|
||||
|
||||
IOP_PAYLOAD_ADDRESS = 0xa00fd000
|
||||
|
||||
EE_PAYLOAD_ADDRESS = 0x01fff800
|
||||
|
||||
#isoinfo -l -i dvd.iso | grep "BOOT.ELF"
|
||||
#var=`isoinfo -l -i dvd.iso | grep "BOOT.ELF" | grep -o -P "[0-9]*? -"`
|
||||
# LOAD_ELF_FROM_OFFSET =
|
||||
LOAD_ELF_FROM_OFFSET = 0x5BB000 # Set this manually for now
|
||||
|
||||
include Mainrules.mk
|
||||
290
PAYLOADS/1.00-2.13/ioppayload.iop.c
Normal file
290
PAYLOADS/1.00-2.13/ioppayload.iop.c
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
// ElReino & CTurt
|
||||
|
||||
/* Todo: seperate these settings to an include file.
|
||||
*/
|
||||
#define EE_CRT0_ADDRESS ((void*)0x21FFF800)
|
||||
#define EE_WAIT_ADDRESS ((void*)0x01FFF7F0)
|
||||
#define EE_ENTRYPOINT_ADDRESS ((void *)0x01FFF7E0)
|
||||
//#define EE_DEBUG_ADDRESS ((void *)0x01FFF7D0)
|
||||
|
||||
struct SifDmaTransfer {
|
||||
void *src,
|
||||
*dest;
|
||||
int size;
|
||||
int attr;
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
||||
#define ELF_PT_LOAD 1
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned int size_t;
|
||||
|
||||
typedef struct {
|
||||
u8 ident[16];
|
||||
u16 type;
|
||||
u16 machine;
|
||||
u32 version;
|
||||
u32 entry;
|
||||
u32 phoff;
|
||||
u32 shoff;
|
||||
u32 flags;
|
||||
u16 ehsize;
|
||||
u16 phentsize;
|
||||
u16 phnum;
|
||||
u16 shentsize;
|
||||
u16 shnum;
|
||||
u16 shstrndx;
|
||||
} elf_header_t;
|
||||
|
||||
typedef struct {
|
||||
u32 type;
|
||||
u32 offset;
|
||||
void *vaddr;
|
||||
u32 paddr;
|
||||
u32 filesz;
|
||||
u32 memsz;
|
||||
u32 flags;
|
||||
u32 align;
|
||||
} elf_pheader_t;
|
||||
|
||||
#define SECTOR_SIZE 0x800
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
int (*readSectors)(int count, int sector, void *destination);
|
||||
|
||||
//int (*sceSifSetDma)(struct SifDmaTransfer *, int num) = (void *)0x16fc8;
|
||||
//int (*sceSifDmaStat)(int trid) = (void *)0x17170;
|
||||
//void (*flushIcache)(void) = (void*)0x2f40;
|
||||
//void (*flushDcache)(void) = (void*)0x3044;
|
||||
//void (*printf)(char *, ...) = (void *)0x1ab84; // 2.10
|
||||
//void (*printf)(char *, ...) = (void *)0x155f8; // 2.12
|
||||
|
||||
int (*sceSifSetDma)(struct SifDmaTransfer *, int num);
|
||||
int (*sceSifDmaStat)(int trid);
|
||||
|
||||
static void transfer_to_ee(void *dest, void *src, unsigned int size);
|
||||
static void *memcpy(void *dest, void *src, unsigned int n);
|
||||
static void *memset(void *s, int c, unsigned int n);
|
||||
static void memset_ee(void *s, int c, unsigned int n);
|
||||
|
||||
//#include "iopresolve.h"
|
||||
|
||||
#define BD2 (*(volatile int *)0xBD000020) //msflag
|
||||
|
||||
static void readData(void *dest, unsigned int offset, size_t n) {
|
||||
//unsigned char buffer[SECTOR_SIZE];
|
||||
//unsigned char *buffer = (void *)0xfd000;
|
||||
unsigned char *buffer = (void *)0xba000; // single
|
||||
|
||||
unsigned int copied = 0;
|
||||
#define remaining (n - copied)
|
||||
|
||||
if(offset % SECTOR_SIZE) {
|
||||
readSectors(1, offset / SECTOR_SIZE, buffer);
|
||||
memcpy(dest, buffer + offset % SECTOR_SIZE, min(SECTOR_SIZE - (offset % SECTOR_SIZE), n));
|
||||
copied += min(SECTOR_SIZE - (offset % SECTOR_SIZE), n);
|
||||
}
|
||||
|
||||
if(remaining >= SECTOR_SIZE) {
|
||||
readSectors(remaining / SECTOR_SIZE, (offset + copied) / SECTOR_SIZE, dest + copied);
|
||||
copied += (remaining / SECTOR_SIZE) * SECTOR_SIZE;
|
||||
}
|
||||
|
||||
if(remaining > 0) {
|
||||
readSectors(1, (offset + copied) / SECTOR_SIZE, buffer);
|
||||
memcpy(dest + copied, buffer, remaining);
|
||||
}
|
||||
|
||||
#undef remaining
|
||||
}
|
||||
|
||||
// Read data but don't care about over/under writing to dest
|
||||
static void readDataUnsafe(void *dest, unsigned int offset, size_t n) {
|
||||
unsigned int sectorAlignedOffset = offset & ~(SECTOR_SIZE - 1);
|
||||
unsigned int underflow = offset - sectorAlignedOffset;
|
||||
|
||||
readSectors((n + underflow + SECTOR_SIZE - 1) / SECTOR_SIZE, sectorAlignedOffset / SECTOR_SIZE, dest - underflow);
|
||||
}
|
||||
|
||||
void _start(void) {
|
||||
extern unsigned char ee_crt0[];
|
||||
extern unsigned int ee_crt0_size;
|
||||
void *return_address[4] __attribute__ ((aligned (16))) = { EE_CRT0_ADDRESS, 0, 0, 0 };
|
||||
int one __attribute__ ((aligned (16))) = 1;
|
||||
int i;
|
||||
|
||||
//sceSifSetDma = resolve("sifman", 7);
|
||||
//sceSifDmaStat = resolve("sifman", 8);
|
||||
|
||||
sceSifSetDma = (void *)0x16fc8;
|
||||
sceSifDmaStat = (void *)0x17170;
|
||||
|
||||
unsigned int addiu_magic = 0x27bdffc8; // addiu $sp, $sp, -0x38
|
||||
//if(*(unsigned int *)READ_SECTORS_110 == addiu_magic) readSectors = (void *)READ_SECTORS_110;
|
||||
if(*(unsigned int *)READ_SECTORS_210 == addiu_magic) readSectors = (void *)READ_SECTORS_210;
|
||||
else if(*(unsigned int *)READ_SECTORS_212 == addiu_magic) readSectors = (void *)READ_SECTORS_212;
|
||||
else if(*(unsigned int *)READ_SECTORS_213 == addiu_magic) readSectors = (void *)READ_SECTORS_213;
|
||||
|
||||
transfer_to_ee(EE_CRT0_ADDRESS, ee_crt0, ee_crt0_size);
|
||||
|
||||
// Corrupt all known return addresses in the stack, there might be a more universal way for IOP to redirect EE...
|
||||
transfer_to_ee((void *)0x14A5FF0, &return_address, sizeof(return_address)); // 2.10E/A
|
||||
transfer_to_ee((void *)0x10007F0, &return_address, sizeof(return_address)); // 2.10J
|
||||
transfer_to_ee((void *)0x12D1C70, &return_address, sizeof(return_address)); // 2.10U
|
||||
|
||||
transfer_to_ee((void *)0x12B8CF0, &return_address, sizeof(return_address)); // 2.12U
|
||||
transfer_to_ee((void *)0x148D0F0, &return_address, sizeof(return_address)); // 2.12G
|
||||
transfer_to_ee((void *)0xFE5FF0, &return_address, sizeof(return_address)); // 2.12J
|
||||
|
||||
transfer_to_ee((void *)0x01477B80, &return_address, sizeof(return_address)); // 2.13E/A
|
||||
|
||||
// Clear bit 0 of 0x208bb710 to make EE exit loop waiting for IOP, and return to our above payload
|
||||
unsigned int loopValue = 0x010004;
|
||||
//transfer_to_ee((void *)0x208bb710, &loopValue, sizeof(loopValue)); // 2.10E
|
||||
transfer_to_ee((void *)0x2087d110, &loopValue, sizeof(loopValue)); // 2.13E
|
||||
|
||||
// We wait for EE side to be ready before sending ELF.
|
||||
while(!(SifGetMSFlag() & 1));
|
||||
SifSetMSFlag(3);
|
||||
|
||||
//unsigned char *buffer = (void *)0xfe000;
|
||||
unsigned char *buffer = (void *)0xBB800;
|
||||
size_t sizeofbuffer = 2 * SECTOR_SIZE; // todo: find a nice large space 4 sectors maybe
|
||||
|
||||
elf_header_t eh;
|
||||
readData(&eh, LOAD_ELF_FROM_OFFSET, sizeof(elf_header_t));
|
||||
|
||||
elf_pheader_t eph[eh.phnum];
|
||||
readData(&eph, LOAD_ELF_FROM_OFFSET + eh.phoff, sizeof(elf_pheader_t) * eh.phnum);
|
||||
|
||||
for (i = 0; i < eh.phnum; i++) {
|
||||
if (eph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
|
||||
// TODO: handle non-16byte aligned transfers
|
||||
|
||||
unsigned int copied = 0;
|
||||
int remaining = eph[i].filesz;
|
||||
while(remaining > 0) {
|
||||
unsigned int k = min(remaining, sizeofbuffer);
|
||||
k = (k + 0xf) & ~0xf;
|
||||
|
||||
// If offset is not aligned to a sector, start with a smaller transfer to get it aligned for future reads
|
||||
if((eph[i].offset + copied) & (SECTOR_SIZE - 1)) k = SECTOR_SIZE - (eph[i].offset + copied) & (SECTOR_SIZE - 1);
|
||||
|
||||
//readData(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + copied, k);
|
||||
readDataUnsafe(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + copied, k);
|
||||
|
||||
transfer_to_ee(eph[i].vaddr + copied, buffer, k);
|
||||
copied += k;
|
||||
remaining -= k;
|
||||
}
|
||||
|
||||
copied = 0;
|
||||
remaining = eph[i].memsz - eph[i].filesz;
|
||||
|
||||
if(remaining > 0) {
|
||||
// First transfer needs to respect if load size isn't multiple of 16 bytes and not memset 0 over the final eph[i].filesz % 16 bytes
|
||||
if(eph[i].filesz % 16) {
|
||||
readData(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + eph[i].filesz - (eph[i].filesz % 16), eph[i].filesz % 16);
|
||||
memset(buffer + (eph[i].filesz % 16), 0, 16 - (eph[i].filesz % 16));
|
||||
transfer_to_ee(eph[i].vaddr + eph[i].filesz - (eph[i].filesz % 16), buffer, 16);
|
||||
|
||||
copied += 16 - (eph[i].filesz % 16);
|
||||
remaining -= 16 - (eph[i].filesz % 16);
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeofbuffer);
|
||||
}
|
||||
while(remaining > 0) {
|
||||
unsigned int k = min(remaining, sizeofbuffer);
|
||||
k = (k + 0xf) & ~0xf;
|
||||
|
||||
transfer_to_ee(eph[i].vaddr + eph[i].filesz + copied, buffer, k);
|
||||
copied += k;
|
||||
remaining -= k;
|
||||
}
|
||||
}
|
||||
|
||||
transfer_to_ee(EE_ENTRYPOINT_ADDRESS, &eh.entry, sizeof(one));
|
||||
|
||||
// Signal EE that the ELF is loaded and ready to execute.
|
||||
transfer_to_ee(EE_WAIT_ADDRESS, &one, sizeof(one));
|
||||
|
||||
//int loopValueJ = 0;
|
||||
//transfer_to_ee((void *)0x205ea210, &loopValueJ, sizeof(loopValueJ)); // 2.10J
|
||||
}
|
||||
|
||||
/* dest and src should be aligned to 16 byte boundary
|
||||
*/
|
||||
static void transfer_to_ee(void *dest, void *src, unsigned int size)
|
||||
{
|
||||
int trid;
|
||||
|
||||
size = size & 0x3FFFFFFF;
|
||||
struct SifDmaTransfer t = { src, dest, size, 0 };
|
||||
|
||||
/* These could be sent in parallel, but is it really worth it?
|
||||
*/
|
||||
trid = sceSifSetDma(&t, 1);
|
||||
while(sceSifDmaStat(trid) > -1){};
|
||||
}
|
||||
|
||||
static void *memcpy(void *dest, void *src, unsigned int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < n; i++)
|
||||
((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void *memset(void *s, int c, unsigned int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < n; i++)
|
||||
((unsigned char *)s)[i] = c;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int SifGetMSFlag()
|
||||
{
|
||||
int a, b;
|
||||
|
||||
b = BD2;
|
||||
do {
|
||||
a=b;
|
||||
b=BD2;
|
||||
} while(a != b);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static int SifSetMSFlag(unsigned int value)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
BD2 = value;
|
||||
|
||||
b = BD2;
|
||||
do {
|
||||
a=b;
|
||||
b=BD2;
|
||||
} while(a != b);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
asm("\n\
|
||||
.global ee_crt0\n\
|
||||
ee_crt0:\n\
|
||||
.align 8\n\
|
||||
.incbin \"eepayload.ee.bin\"\n\
|
||||
ee_crt0_size: .word . - ee_crt0\n\
|
||||
");
|
||||
220
PAYLOADS/1.00-2.13/iopresolve.h
Normal file
220
PAYLOADS/1.00-2.13/iopresolve.h
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
//typedef unsigned char u8;
|
||||
//typedef unsigned short u16;
|
||||
//typedef unsigned int u32;
|
||||
|
||||
typedef void *pointer;
|
||||
|
||||
#define NULL 0
|
||||
|
||||
typedef struct _smod_mod_info {
|
||||
//struct _smod_mod_info *next;
|
||||
pointer next;
|
||||
/** A pointer to the name in IOP RAM, this must be smem_read(). */
|
||||
//char *name;
|
||||
pointer name;
|
||||
u16 version;
|
||||
/** For MODLOAD shipped with games. The old MODLOAD module from boot ROMs do not use a flags field. */
|
||||
u16 newflags;
|
||||
u16 id;
|
||||
u16 unused;
|
||||
/** _start */
|
||||
u32 entry;
|
||||
u32 gp;
|
||||
u32 text_start;
|
||||
u32 text_size;
|
||||
u32 data_size;
|
||||
u32 bss_size;
|
||||
u32 unused1;
|
||||
u32 unused2;
|
||||
} smod_mod_info_t;
|
||||
|
||||
typedef struct _slib_imp_list {
|
||||
u8 magic;
|
||||
//struct _slib_imp_list *next;
|
||||
pointer next;
|
||||
u16 version;
|
||||
u16 flags;
|
||||
u8 name[8];
|
||||
//void *imports[0];
|
||||
pointer imports[0];
|
||||
} slib_imp_list_t;
|
||||
|
||||
typedef struct _slib_exp_lib {
|
||||
//struct _slib_exp_lib *prev;
|
||||
pointer prev;
|
||||
//struct _slib_imp_list *caller;
|
||||
pointer caller;
|
||||
u16 version;
|
||||
u16 flags;
|
||||
u8 name[8];
|
||||
//void *exports[0];
|
||||
pointer exports[0];
|
||||
} slib_exp_lib_t;
|
||||
|
||||
typedef struct _slib_exp_lib_list {
|
||||
//struct _slib_exp_lib *tail;
|
||||
pointer tail;
|
||||
//struct _slib_exp_lib *head;
|
||||
pointer head;
|
||||
} slib_exp_lib_list_t;
|
||||
|
||||
#define SMEM_BUF_SIZE 0x300 //Must be large enough to accommodate all operations.
|
||||
|
||||
struct smem_buf {
|
||||
union {
|
||||
u8 bytes[SMEM_BUF_SIZE / sizeof(u8)];
|
||||
u32 words[SMEM_BUF_SIZE / sizeof(u32)];
|
||||
smod_mod_info_t mod_info;
|
||||
slib_exp_lib_t exp_lib;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
size_t strlen(const char *str) {
|
||||
const char *s;
|
||||
for (s = str; *s; ++s);
|
||||
return (s - str);
|
||||
}
|
||||
|
||||
int memcmp(const char *cs_in, const char *ct_in, size_t n) {
|
||||
size_t i;
|
||||
const unsigned char * cs = (const unsigned char*) cs_in;
|
||||
const unsigned char * ct = (const unsigned char*) ct_in;
|
||||
|
||||
for (i = 0; i < n; i++, cs++, ct++)
|
||||
{
|
||||
if (*cs < *ct)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (*cs > *ct)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
slib_exp_lib_list_t _slib_cur_exp_lib_list;
|
||||
|
||||
struct smem_buf smem_buf;
|
||||
|
||||
typedef unsigned int SifRpcReceiveData_t;
|
||||
|
||||
size_t SifRpcGetOtherData(void *a, pointer x, void *dest, size_t s, int z) {
|
||||
memcpy(dest, x, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
slib_exp_lib_list_t *slib_exp_lib_list(void) {
|
||||
SifRpcReceiveData_t RData;
|
||||
slib_exp_lib_t *core_exps;
|
||||
slib_exp_lib_list_t *exp_lib_list = NULL;
|
||||
u32 i, addr, core_end, NextMod, *exp_func;
|
||||
void *pGetLoadcoreInternalData;
|
||||
smod_mod_info_t *ModInfo;
|
||||
|
||||
/* Read the start of the global module table - this is where we will search. */
|
||||
if(SifRpcGetOtherData(&RData, (void*)0x800, &smem_buf, sizeof(smod_mod_info_t), 0)>=0){
|
||||
/* The first entry points to LOADCORE's module info. We then use the
|
||||
module info to determine the end of LOADCORE's .text segment (just
|
||||
past the export library we're trying to find. */
|
||||
NextMod = *smem_buf.words;
|
||||
if(SifRpcGetOtherData(&RData, (void*)NextMod, &smem_buf, sizeof(smod_mod_info_t), 0)>=0){
|
||||
ModInfo = &smem_buf.mod_info;
|
||||
core_end = ModInfo->text_start+ModInfo->text_size;
|
||||
|
||||
/* Back up so we position ourselves infront of where the export
|
||||
library will be. */
|
||||
if(SifRpcGetOtherData(&RData, (void*)(core_end - 512), &smem_buf, 512, 0)>=0){
|
||||
/* Search for LOADCORE's export library. */
|
||||
for (i = 0; i < 512; i += 4) {
|
||||
/* SYSMEM's export library sits at 0x830, so it should appear in
|
||||
LOADCORE's prev pointer. */
|
||||
if (smem_buf.words[i / sizeof(u32)] == 0x830) {
|
||||
if (!memcmp(smem_buf.bytes + i + 12, "loadcore", 8))
|
||||
//if(*(unsigned int *)(smem_buf.bytes + i + 12) == 0x64616f6c) // 6c 6f 61 64 == load
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= 512)
|
||||
return NULL;
|
||||
|
||||
/* Get to the start of the export table, and find the address of the
|
||||
routine that will get us the export library list info. */
|
||||
core_exps = (slib_exp_lib_t *)(smem_buf.bytes + i);
|
||||
pGetLoadcoreInternalData = core_exps->exports[3];
|
||||
|
||||
if(SifRpcGetOtherData(&RData, pGetLoadcoreInternalData, &smem_buf, 8, 0)>=0){
|
||||
exp_func = smem_buf.words;
|
||||
|
||||
/* Parse the two instructions that hold the address of the table. */
|
||||
if ((exp_func[0] & 0xffff0000) != 0x3c020000) /* lui v0, XXXX */
|
||||
return NULL;
|
||||
if ((exp_func[1] & 0xffff0000) != 0x24420000) /* addiu v0, v0, XXXX */
|
||||
return NULL;
|
||||
|
||||
addr = ((exp_func[0] & 0xffff) << 16) | (exp_func[1] & 0xffff);
|
||||
|
||||
if(SifRpcGetOtherData(&RData, (void*)addr, &smem_buf, 8, 0)>=0){
|
||||
_slib_cur_exp_lib_list.tail = (slib_exp_lib_t *)(smem_buf.words[0]);
|
||||
_slib_cur_exp_lib_list.head = (slib_exp_lib_t *)(smem_buf.words[1]);
|
||||
exp_lib_list = &_slib_cur_exp_lib_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return exp_lib_list;
|
||||
}
|
||||
|
||||
#define EXP_LIB_MAX SMEM_BUF_SIZE /* We can even handle CDVDMAN's bloat! */
|
||||
|
||||
int slib_get_exp_lib(const char *name, slib_exp_lib_t *library)
|
||||
{
|
||||
SifRpcReceiveData_t RData;
|
||||
slib_exp_lib_list_t *exp_lib_list = &_slib_cur_exp_lib_list;
|
||||
slib_exp_lib_t *exp_lib = &smem_buf.exp_lib;
|
||||
void *cur_lib;
|
||||
int len = strlen(name), count = 0;
|
||||
|
||||
if (!exp_lib_list->head && !(exp_lib_list = slib_exp_lib_list()))
|
||||
return 0;
|
||||
|
||||
/* Read the tail export library to initiate the search. */
|
||||
cur_lib = exp_lib_list->tail;
|
||||
|
||||
while (cur_lib) {
|
||||
if(SifRpcGetOtherData(&RData, cur_lib, exp_lib, EXP_LIB_MAX, 0)>=0){
|
||||
if (!memcmp(exp_lib->name, name, len)) {
|
||||
while (exp_lib->exports[count] != 0)
|
||||
count++;
|
||||
|
||||
if (library)
|
||||
memcpy(library, exp_lib, sizeof(slib_exp_lib_t) + count * 4);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
cur_lib = exp_lib->prev;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *resolve(char *name, int export) {
|
||||
slib_exp_lib_t *modload_lib = (void *)0x100;
|
||||
|
||||
memset(&_slib_cur_exp_lib_list, 0, sizeof(slib_exp_lib_list_t));
|
||||
|
||||
if (!slib_get_exp_lib(name, modload_lib)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return modload_lib->exports[export];
|
||||
}
|
||||
64
PAYLOADS/1.00-2.13/stage1_210_212.iop.S
Normal file
64
PAYLOADS/1.00-2.13/stage1_210_212.iop.S
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# ElReino & CTurt 2020
|
||||
|
||||
flushIcache = 0x00002f40
|
||||
flushDcache = 0x0003044
|
||||
|
||||
#flushDcacheWrapper = 0x0057f1c
|
||||
|
||||
iop_payload_address = 0xa00fd000
|
||||
|
||||
.section .text
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
move $fp, $sp # We need to reset $fp as it gets trashed by memcpy
|
||||
|
||||
la $v1, 0x27bdffc8 # addiu $sp, $sp, -0x38
|
||||
|
||||
check_110:
|
||||
#la $v0, READ_SECTORS_110
|
||||
#lw $t0, 0($v0)
|
||||
#beq $t0, $v1, read_iop_payload
|
||||
|
||||
check_210:
|
||||
la $v0, READ_SECTORS_210
|
||||
lw $t0, 0($v0)
|
||||
beq $t0, $v1, read_iop_payload
|
||||
|
||||
check_212:
|
||||
la $v0, READ_SECTORS_212
|
||||
|
||||
read_iop_payload:
|
||||
la $a0, (IOP_PAYLOAD_SIZE / 0x800) + 1 # count
|
||||
la $a1, 0x700000 / 0x800 # sector
|
||||
la $a2, iop_payload_address # destination
|
||||
jal $v0
|
||||
|
||||
#jal flushIcache
|
||||
#jal flushDcache
|
||||
|
||||
#jal ENTRY
|
||||
la $v0, ENTRY
|
||||
jalr $v0
|
||||
|
||||
la $v1, 0x27bdffc8 # addiu $sp, $sp, -0x38
|
||||
|
||||
check_110_again:
|
||||
|
||||
|
||||
check_210_again:
|
||||
la $v0, READ_SECTORS_210
|
||||
lw $v0, 0($v0)
|
||||
la $a0, RETURN_ADDRESS_LOCATION_210
|
||||
la $ra, ORIGINAL_RETURN_ADDRESS_210
|
||||
beq $v0, $v1, return
|
||||
|
||||
check_212_again:
|
||||
la $a0, RETURN_ADDRESS_LOCATION_212
|
||||
la $ra, ORIGINAL_RETURN_ADDRESS_212
|
||||
|
||||
return:
|
||||
# Return gracefully back to original return address
|
||||
sw $ra, 0($a0)
|
||||
la $v0, 0
|
||||
jr $ra
|
||||
38
PAYLOADS/1.00-2.13/stage1_213.iop.S
Normal file
38
PAYLOADS/1.00-2.13/stage1_213.iop.S
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# ElReino & CTurt 2020
|
||||
|
||||
flushIcache = 0x00002f40
|
||||
flushDcache = 0x0003044
|
||||
|
||||
#flushDcacheWrapper = 0x0057f1c
|
||||
|
||||
iop_payload_address = 0xa00fd000
|
||||
|
||||
.section .text
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
move $fp, $sp # We need to reset $fp as it gets trashed by memcpy
|
||||
|
||||
la $v0, READ_SECTORS_213
|
||||
|
||||
read_iop_payload:
|
||||
la $a0, (IOP_PAYLOAD_SIZE / 0x800) + 1 # count
|
||||
la $a1, 0x700000 / 0x800 # sector
|
||||
la $a2, iop_payload_address # destination
|
||||
jal $v0
|
||||
|
||||
#jal flushIcache
|
||||
#jal flushDcache
|
||||
|
||||
#jal ENTRY
|
||||
la $v0, ENTRY
|
||||
jalr $v0
|
||||
|
||||
la $a0, RETURN_ADDRESS_LOCATION_213
|
||||
la $ra, ORIGINAL_RETURN_ADDRESS_213
|
||||
|
||||
return:
|
||||
# Return gracefully back to original return address
|
||||
sw $ra, 0($a0)
|
||||
la $v0, 0
|
||||
jr $ra
|
||||
105
PAYLOADS/1.00-2.13/syscalls.ee.S
Normal file
105
PAYLOADS/1.00-2.13/syscalls.ee.S
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# ElReino and CTurt 2020
|
||||
|
||||
# Since GCC does something strange, we can't write syscall thunks directly in C
|
||||
# as GCC adds move $v1, $v0 directly after jr $ra, effectively trashing $v0.
|
||||
# I don't know why this happens, but I do know enough about GCC that this
|
||||
# approach will most probably be easier. But feel free to try fixing it.
|
||||
|
||||
.global GetThreadId
|
||||
GetThreadId:
|
||||
la $v1, 0x2f
|
||||
syscall 0x2f
|
||||
jr $ra
|
||||
|
||||
.global ChangeThreadPriority
|
||||
ChangeThreadPriority:
|
||||
la $v1, 0x29
|
||||
syscall 0x29
|
||||
jr $ra
|
||||
|
||||
.global CancelWakeupThread
|
||||
CancelWakeupThread:
|
||||
la $v1, 0x35
|
||||
syscall 0x35
|
||||
jr $ra
|
||||
|
||||
.global TerminateThread
|
||||
TerminateThread:
|
||||
la $v1, 0x25
|
||||
syscall 0x25
|
||||
jr $ra
|
||||
|
||||
.global DeleteThread
|
||||
DeleteThread:
|
||||
la $v1, 0x21
|
||||
syscall 0x21
|
||||
jr $ra
|
||||
|
||||
.global SifSetReg
|
||||
SifSetReg:
|
||||
la $v1, 0x79
|
||||
syscall 0x79
|
||||
jr $ra
|
||||
|
||||
.global SifGetReg
|
||||
SifGetReg:
|
||||
la $v1, 0x7a
|
||||
syscall 0x7a
|
||||
jr $ra
|
||||
|
||||
.global ExecPS2
|
||||
ExecPS2:
|
||||
la $v1, 0x07
|
||||
syscall 0x07 # BTW why do we put the number here also?
|
||||
|
||||
# Not a syscall, but it might as well be.
|
||||
|
||||
.global SifWriteBackDCache
|
||||
SifWriteBackDCache:
|
||||
lui $25, 0xffff
|
||||
ori $25, $25, 0xffc0
|
||||
blez $5, last
|
||||
addu $10, $4, $5
|
||||
and $8, $4, $25
|
||||
addiu $10, $10, -1
|
||||
and $9, $10, $25
|
||||
subu $10, $9, $8
|
||||
srl $11, $10, 0x6
|
||||
addiu $11, $11, 1
|
||||
andi $9, $11, 0x7
|
||||
beqz $9, eight
|
||||
srl $10, $11, 0x3
|
||||
loop1:
|
||||
sync
|
||||
cache 0x18, 0($8)
|
||||
sync
|
||||
addiu $9, $9, -1
|
||||
nop
|
||||
bgtz $9, loop1
|
||||
addiu $8, $8, 64
|
||||
eight:
|
||||
beqz $10, last
|
||||
loop8:
|
||||
addiu $10, $10, -1
|
||||
sync
|
||||
cache 0x18, 0($8)
|
||||
sync
|
||||
cache 0x18, 64($8)
|
||||
sync
|
||||
cache 0x18, 128($8)
|
||||
sync
|
||||
cache 0x18, 192($8)
|
||||
sync
|
||||
cache 0x18, 256($8)
|
||||
sync
|
||||
cache 0x18, 320($8)
|
||||
sync
|
||||
cache 0x18, 384($8)
|
||||
sync
|
||||
cache 0x18, 448($8)
|
||||
sync
|
||||
bgtz $10, loop8
|
||||
addiu $8, $8, 512
|
||||
last:
|
||||
jr $31
|
||||
nop
|
||||
50
PAYLOADS/3.03-3.11/build.sh
Normal file
50
PAYLOADS/3.03-3.11/build.sh
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
echo "Building payload"
|
||||
|
||||
ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048
|
||||
ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
ENTRY=`ee-objdump -t payload.elf | grep " _start"`
|
||||
echo $ENTRY
|
||||
|
||||
# Doesn't seem to work on MinGW toolchain, so set manually if you're using that:
|
||||
#ENTRY=0x`grep -o "^\S*" <<< $ENTRY`
|
||||
ENTRY=0x01fff99c
|
||||
|
||||
echo $ENTRY
|
||||
|
||||
echo "Building crt0 (3.03)"
|
||||
ee-gcc -Ttext=0x015FFF34 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x262360 crt0.S -o crt0_3.03.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary crt0_3.03.elf crt0_3.03.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Building crt0 (3.04M)"
|
||||
ee-gcc -Ttext=0x01800180 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x261548 crt0.S -o crt0_3.04M.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary crt0_3.04M.elf crt0_3.04M.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Building jump for 3.04J"
|
||||
ee-gcc -Ttext=0x012811E4 -DJUMP=0x01281340 jump.S -o jump.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary jump.elf jump.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Building crt0 (3.04J)"
|
||||
ee-gcc -Ttext=0x01281340 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x261560 crt0.S -o crt0_3.04J.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary crt0_3.04J.elf crt0_3.04J.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Building crt0 (3.10)"
|
||||
ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x2986a0 crt0.S -o crt0_3.10.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary crt0_3.10.elf crt0_3.10.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Building crt0 (3.11)"
|
||||
ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x2952f0 crt0.S -o crt0_3.11.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary crt0_3.11.elf crt0_3.11.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Done."
|
||||
|
||||
echo "For the All Slims image:"
|
||||
echo "Insert crt0_3.03.bin into VIDEO_TS.IFO at offset 0x0e8c"
|
||||
echo "Insert jump.bin into VIDEO_TS.IFO at offset 0x2724"
|
||||
echo "Insert crt0_3.04J.bin into VIDEO_TS.IFO at offset 0x2880"
|
||||
echo "Insert crt0_3.10.bin into VIDEO_TS.IFO at offset 0x2bb4"
|
||||
echo "Insert crt0_3.11.bin into VIDEO_TS.IFO at offset 0x2954"
|
||||
echo "Insert payload.bin into VIDEO_TS.IFO at offset 0x3000"
|
||||
|
||||
echo "For 3.04M only image:"
|
||||
echo "Insert fullpayload.bin at 0x2d00, and payload.bin at 0x3000"
|
||||
|
|
@ -2,16 +2,11 @@
|
|||
|
||||
.section .text.startup
|
||||
|
||||
.equ getBufferInternal, 0x2952f0
|
||||
.equ getBufferInternal, GETBUFFERINTERNAL
|
||||
.equ payload, (0x2000000 - 0x800) # End of RAM
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
#la $a0, 0x7f
|
||||
#la $v1, 0x01
|
||||
#syscall 0x01 # ResetEE
|
||||
|
||||
#la $a0, relo
|
||||
la $a0, load
|
||||
la $a1, 0
|
||||
la $a2, 0
|
||||
|
|
@ -28,35 +23,19 @@ load:
|
|||
la $a2, 0x3000 / 0x800 # lba offset in file
|
||||
la $a3, payload # Destination
|
||||
la $t0, 0x800 / 0x800 # Count
|
||||
la $t1, 0
|
||||
la $v0, getBufferInternal
|
||||
jalr $v0
|
||||
nop
|
||||
|
||||
#relo:
|
||||
# Relocate payload to end of RAM
|
||||
# la $a0, (0x2000000 - 1024)
|
||||
# la $a1, payload
|
||||
# la $a2, 2048
|
||||
# la $v0, memcpy
|
||||
# jalr $v0
|
||||
la $t1, 0
|
||||
|
||||
boot:
|
||||
la $v1, 0x64; la $a0, 0; syscall 0x64 # FlushCache data writeback
|
||||
la $v1, 0x64; la $a0, 2; syscall 0x64 # FlushCache instruction invalidate
|
||||
|
||||
# Point stack to end of scratchpad RAM
|
||||
la $sp, 0x70004000
|
||||
#la $sp, 0x70004000
|
||||
lui $sp, 0x7000
|
||||
|
||||
# Execute from relocated place
|
||||
la $v0, ENTRY
|
||||
j $v0
|
||||
nop
|
||||
|
||||
.space (_start + 0x2fe2 - 0x2954) - .
|
||||
fpIndex:
|
||||
.byte 0xfa
|
||||
.byte 0xdc
|
||||
|
||||
.space (_start + 0x3000 - 0x2954) - .
|
||||
.incbin "payload.bin"
|
||||
ori $sp, 0x4000
|
||||
BIN
PAYLOADS/3.03-3.11/crt0_3.03.bin
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.03.bin
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/crt0_3.03.elf
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.03.elf
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/crt0_3.04J.bin
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.04J.bin
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/crt0_3.04J.elf
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.04J.elf
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/crt0_3.04M.bin
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.04M.bin
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/crt0_3.04M.elf
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.04M.elf
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/crt0_3.10.bin
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.10.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/crt0_3.11.bin
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.11.bin
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/crt0_3.11.elf
Normal file
BIN
PAYLOADS/3.03-3.11/crt0_3.11.elf
Normal file
Binary file not shown.
8
PAYLOADS/3.03-3.11/jump.S
Normal file
8
PAYLOADS/3.03-3.11/jump.S
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.set noreorder # If we're writing assembly, why would we want this?
|
||||
|
||||
.section .text.startup
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
j JUMP
|
||||
nop
|
||||
BIN
PAYLOADS/3.03-3.11/jump.bin
Normal file
BIN
PAYLOADS/3.03-3.11/jump.bin
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/jump.elf
Normal file
BIN
PAYLOADS/3.03-3.11/jump.elf
Normal file
Binary file not shown.
BIN
PAYLOADS/3.03-3.11/payload.bin
Normal file
BIN
PAYLOADS/3.03-3.11/payload.bin
Normal file
Binary file not shown.
|
|
@ -6,26 +6,15 @@
|
|||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define pointToIFO ((void (*)(unsigned int index, unsigned int lba, unsigned int offset))0x25c880)
|
||||
#define getDiscData ((void (*)(unsigned int s, void *d))0x25c9f0)
|
||||
#define getDiscBuffer ((void (*)(void))0x25c678)
|
||||
void (*pointToIFO)(unsigned int index, unsigned int lba, unsigned int offset);
|
||||
void (*getDiscData)(unsigned int s, void *d);
|
||||
|
||||
#define sceCdSync ((void (*)(int mode))0x2a69c8)
|
||||
int (*getBufferInternal)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos);
|
||||
|
||||
typedef struct {
|
||||
unsigned int lsn;
|
||||
unsigned int size;
|
||||
char name[16];
|
||||
unsigned char date[8];
|
||||
} sceCdlFILE;
|
||||
#define sceCdSearchFile ((int (*)(sceCdlFILE *, char *, int))0x2a6488)
|
||||
|
||||
#define SifIopReset ((int (*)(char *, int))0x84fe0)
|
||||
#define SifIopSync ((int (*)(void))0x85110)
|
||||
#define SifInitRpc ((void (*)(int))0x84180)
|
||||
#define SifExitRpc ((void (*)(void))0x84310)
|
||||
|
||||
#define getBufferInternal ((int (*)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos))0x002986a0)
|
||||
int (*SifIopReset)(char *, int);
|
||||
int (*SifIopSync)(void);
|
||||
void (*SifInitRpc)(int);
|
||||
void (*SifExitRpc)(void);
|
||||
|
||||
#define ELF_PT_LOAD 1
|
||||
|
||||
|
|
@ -66,13 +55,14 @@ __attribute__((noreturn)) void ExecPS2(void *entry, void *gp, int argc, char **a
|
|||
//__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *memcpy_(void *dest, void *src, size_t n) {
|
||||
static void *memcpy_(void *dest, void *src, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n) {
|
||||
// Todo: maybe cache last sector to save 1 or 2 reads
|
||||
static void *memset(void *dest, int c, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = c;
|
||||
return dest;
|
||||
|
|
@ -102,11 +92,70 @@ static void readData(void *dest, unsigned int offset, size_t n) {
|
|||
}
|
||||
|
||||
__attribute__((noreturn)) void _start(void) {
|
||||
//Exit(0);
|
||||
//asm volatile("la $v1, 0x04; la $a0, 0; syscall 0x04");
|
||||
|
||||
int i;
|
||||
|
||||
// Identify version based on jump target location
|
||||
if((*(void **)0x928D24) == (void *)0x15ea540) {
|
||||
// 3.03
|
||||
pointToIFO = (void *)0x2432c8;
|
||||
getDiscData = (void *)0x243438;
|
||||
|
||||
getBufferInternal = (void *)0x262360;
|
||||
|
||||
SifIopReset = (void *)0x291fb8;
|
||||
SifIopSync = (void *)0x292138;
|
||||
SifInitRpc = (void *)0x2082a0;
|
||||
SifExitRpc = (void *)0x208440;
|
||||
}
|
||||
else if((*(void **)0x6D9C3C) == (void *)0x126b7e0) {
|
||||
// 3.04J
|
||||
pointToIFO = (void *)0x23dfe0;
|
||||
getDiscData = (void *)0x23e150;
|
||||
|
||||
getBufferInternal = (void *)0x261560;
|
||||
|
||||
SifIopReset = (void *)0x84fe0;
|
||||
SifIopSync = (void *)0x85110;
|
||||
SifInitRpc = (void *)0x84180;
|
||||
SifExitRpc = (void *)0x84310;
|
||||
}
|
||||
else if((*(void **)0x95CF40) == (void *)0x1800180) {
|
||||
// 3.04M
|
||||
pointToIFO = (void *)0x23dfc8;
|
||||
getDiscData = (void *)0x23e138;
|
||||
|
||||
getBufferInternal = (void *)0x261548;
|
||||
|
||||
SifIopReset = (void *)0x291358;
|
||||
SifIopSync = (void *)0x2914d8;
|
||||
SifInitRpc = (void *)0x208260;
|
||||
SifExitRpc = (void *)0x208400;
|
||||
}
|
||||
else if((*(void **)0x5f1f38) == (void *)0x1500014) {
|
||||
// 3.10
|
||||
pointToIFO = (void *)0x25c880;
|
||||
getDiscData = (void *)0x25c9f0;
|
||||
|
||||
getBufferInternal = (void *)0x002986a0;
|
||||
|
||||
SifIopReset = (void *)0x84fe0;
|
||||
SifIopSync = (void *)0x85110;
|
||||
SifInitRpc = (void *)0x84180;
|
||||
SifExitRpc = (void *)0x84310;
|
||||
}
|
||||
else if((*(void **)0x3EA438) == (void *)0x1500014) {
|
||||
// 3.11
|
||||
pointToIFO = (void *)0x258a28;
|
||||
getDiscData = (void *) 0x258b98;
|
||||
|
||||
getBufferInternal = (void *)0x2952f0;
|
||||
|
||||
SifIopReset = (void *)0x20e7d8;
|
||||
SifIopSync = (void *)0x20e958;
|
||||
SifInitRpc = (void *)0x208d80;
|
||||
SifExitRpc = (void *)0x208f20;
|
||||
}
|
||||
|
||||
#ifdef LOAD_FROM_VTS_02_0_IFO
|
||||
// point to VTS_02_0.IFO
|
||||
pointToIFO(2, 0, 0);
|
||||
|
|
@ -148,5 +197,6 @@ __attribute__((noreturn)) void _start(void) {
|
|||
SifInitRpc(0);
|
||||
SifExitRpc();
|
||||
|
||||
ExecPS2((void *)eh.entry, 0, 0, 0);
|
||||
char *argv[] = { "cdrom0:\\VIDEO_TS\\VTS_02_0.IFO" };
|
||||
ExecPS2((void *)eh.entry, 0, 1, &argv);
|
||||
}
|
||||
BIN
PAYLOADS/3.03-3.11/payload.elf
Normal file
BIN
PAYLOADS/3.03-3.11/payload.elf
Normal file
Binary file not shown.
|
|
@ -1,21 +0,0 @@
|
|||
echo "Building payload"
|
||||
|
||||
ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048
|
||||
ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
ENTRY=`ee-objdump -t payload.elf | grep " _start"`
|
||||
echo $ENTRY
|
||||
|
||||
# Doesn't seem to work on MinGW toolchain, so set manually if you're using that:
|
||||
#ENTRY=0x`grep -o "^\S*" <<< $ENTRY`
|
||||
ENTRY=0x01fff9a8
|
||||
|
||||
echo $ENTRY
|
||||
echo "Building crt0"
|
||||
|
||||
ee-gcc -Ttext=0x01800180 -DENTRY=$ENTRY crt0.S -o fullpayload.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary fullpayload.elf fullpayload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
# todo make all this hex editing automatic
|
||||
#echo "Done. Insert fullpayload.bin into VIDEO_TS.IFO at offset 0x2954"
|
||||
echo "Done. fullpayload.bin at 0x2d00, and payload.bin at 0x3000"
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
.set noreorder # If we're writing assembly, why would we want this?
|
||||
|
||||
.section .text.startup
|
||||
|
||||
.equ getBufferInternal, 0x261548
|
||||
.equ payload, (0x2000000 - 0x800) # End of RAM
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
#la $a0, 0x7f
|
||||
#la $v1, 0x01
|
||||
#syscall 0x01 # ResetEE
|
||||
|
||||
#la $a0, relo
|
||||
la $a0, load
|
||||
la $a1, 0
|
||||
la $a2, 0
|
||||
la $a3, 0
|
||||
|
||||
.global ExecPS2
|
||||
ExecPS2:
|
||||
la $v1, 7
|
||||
syscall 7 # ExecPS2
|
||||
|
||||
load:
|
||||
la $a0, 0
|
||||
la $a1, 0 # 0 = VIDEO_TS.IFO, 1 = VTS_01_0.IFO
|
||||
la $a2, 0x3000 / 0x800 # lba offset in file
|
||||
la $a3, payload # Destination
|
||||
la $t0, 0x800 / 0x800 # Count
|
||||
la $t1, 0
|
||||
la $v0, getBufferInternal
|
||||
jalr $v0
|
||||
nop
|
||||
|
||||
#relo:
|
||||
# Relocate payload to end of RAM
|
||||
# la $a0, (0x2000000 - 1024)
|
||||
# la $a1, payload
|
||||
# la $a2, 2048
|
||||
# la $v0, memcpy
|
||||
# jalr $v0
|
||||
|
||||
boot:
|
||||
la $v1, 0x64; la $a0, 0; syscall 0x64 # FlushCache data writeback
|
||||
la $v1, 0x64; la $a0, 2; syscall 0x64 # FlushCache instruction invalidate
|
||||
|
||||
# Point stack to end of scratchpad RAM
|
||||
la $sp, 0x70004000
|
||||
|
||||
# Execute from relocated place
|
||||
la $v0, ENTRY
|
||||
j $v0
|
||||
nop
|
||||
|
||||
.space (_start + 0x2faa - 0x2d00) - .
|
||||
fpIndex:
|
||||
.byte 0x96
|
||||
.byte 0x08
|
||||
|
||||
#.space (_start + 0x3000 - 0x2d00) - .
|
||||
#.incbin "payload.bin"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,141 +0,0 @@
|
|||
#include <stddef.h>
|
||||
|
||||
// Pick one
|
||||
#define LOAD_FROM_VTS_02_0_IFO
|
||||
//#define LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO (151 - 138 - 7)
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define pointToIFO ((void (*)(unsigned int index, unsigned int lba, unsigned int offset))0x23dfc8)
|
||||
#define getDiscData ((void (*)(unsigned int s, void *d))0x23e138)
|
||||
|
||||
#define SifIopReset ((int (*)(char *, int))0x291358)
|
||||
#define SifIopSync ((int (*)(void))0x2914d8)
|
||||
#define SifInitRpc ((void (*)(int))0x208260)
|
||||
#define SifExitRpc ((void (*)(void))0x208400)
|
||||
|
||||
#define getBufferInternal ((int (*)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos))0x261548)
|
||||
|
||||
#define ELF_PT_LOAD 1
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
typedef struct {
|
||||
u8 ident[16];
|
||||
u16 type;
|
||||
u16 machine;
|
||||
u32 version;
|
||||
u32 entry;
|
||||
u32 phoff;
|
||||
u32 shoff;
|
||||
u32 flags;
|
||||
u16 ehsize;
|
||||
u16 phentsize;
|
||||
u16 phnum;
|
||||
u16 shentsize;
|
||||
u16 shnum;
|
||||
u16 shstrndx;
|
||||
} elf_header_t;
|
||||
|
||||
typedef struct {
|
||||
u32 type;
|
||||
u32 offset;
|
||||
void *vaddr;
|
||||
u32 paddr;
|
||||
u32 filesz;
|
||||
u32 memsz;
|
||||
u32 flags;
|
||||
u32 align;
|
||||
} elf_pheader_t;
|
||||
|
||||
__attribute__((noreturn)) void ExecPS2(void *entry, void *gp, int argc, char **argv) {
|
||||
asm volatile("la $v1, 7; syscall 7");
|
||||
//__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *memcpy_(void *dest, void *src, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void readData(void *dest, unsigned int offset, size_t n) {
|
||||
unsigned char buffer[0x800];
|
||||
|
||||
unsigned int copied = 0;
|
||||
#define remaining (n - copied)
|
||||
|
||||
if(offset % 0x800) {
|
||||
getBufferInternal("", 1, offset / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest, buffer + offset % 0x800, min(0x800 - (offset % 0x800), n));
|
||||
copied += min(0x800 - (offset % 0x800), n);
|
||||
}
|
||||
|
||||
if(remaining >= 0x800) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, dest + copied, remaining / 0x800, 0);
|
||||
copied += (remaining / 0x800) * 0x800;
|
||||
}
|
||||
|
||||
if(remaining > 0) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest + copied, buffer, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void _start(void) {
|
||||
//Exit(0);
|
||||
//asm volatile("la $v1, 0x04; la $a0, 0; syscall 0x04");
|
||||
|
||||
int i;
|
||||
|
||||
#ifdef LOAD_FROM_VTS_02_0_IFO
|
||||
// point to VTS_02_0.IFO
|
||||
pointToIFO(2, 0, 0);
|
||||
|
||||
// Force a read from VTS_02_0.IFO
|
||||
char head[64];
|
||||
getDiscData(64, &head);
|
||||
|
||||
#define RELATIVE_SECTOR 0
|
||||
#else
|
||||
#define RELATIVE_SECTOR LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO
|
||||
#endif
|
||||
|
||||
// Based on https://github.com/AKuHAK/uLaunchELF/blob/master/loader/loader.c
|
||||
elf_header_t eh;
|
||||
readData(&eh, RELATIVE_SECTOR * 0x800, sizeof(elf_header_t));
|
||||
|
||||
elf_pheader_t eph[eh.phnum];
|
||||
readData(&eph, RELATIVE_SECTOR * 0x800 + eh.phoff, sizeof(elf_pheader_t) * eh.phnum);
|
||||
|
||||
for (i = 0; i < eh.phnum; i++) {
|
||||
if (eph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
|
||||
readData(eph[i].vaddr, RELATIVE_SECTOR * 0x800 + eph[i].offset, eph[i].filesz);
|
||||
if(eph[i].memsz > eph[i].filesz) memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
|
||||
}
|
||||
|
||||
asm volatile("la $v1, 0x64; la $a0, 0; syscall 0x64"); // FlushCache data writeback
|
||||
asm volatile("la $v1, 0x64; la $a0, 2; syscall 0x64"); // FlushCache instruction invalidate
|
||||
|
||||
//while(!SifIopReset("", 0));
|
||||
//while(!SifIopSync());
|
||||
|
||||
//while(!SifIopReset("rom0:UDNL rom0:EELOADCNF", 0));
|
||||
SifIopReset("rom0:UDNL rom0:EELOADCNF", 0);
|
||||
while(!SifIopSync());
|
||||
|
||||
SifInitRpc(0);
|
||||
SifExitRpc();
|
||||
|
||||
ExecPS2((void *)eh.entry, 0, 0, 0);
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,19 +0,0 @@
|
|||
echo "Building payload"
|
||||
|
||||
ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048
|
||||
ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
ENTRY=`ee-objdump -t payload.elf | grep " _start"`
|
||||
echo $ENTRY
|
||||
|
||||
# Doesn't seem to work on MinGW toolchain, so set manually if you're using that:
|
||||
#ENTRY=0x`grep -o "^\S*" <<< $ENTRY`
|
||||
ENTRY=0x01fff9a8
|
||||
|
||||
echo $ENTRY
|
||||
echo "Building crt0"
|
||||
|
||||
ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY crt0.S -o fullpayload.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary fullpayload.elf fullpayload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Done. Insert fullpayload.bin into VIDEO_TS.IFO at offset 0x2954"
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
# OK, so in the hybrid disc, 3.10 stage 2 is at 0x3000 as normal, but 3.11 stage 2 is modified to start at 0x38000
|
||||
# that's why we need to modify this file, just the LBA load on line 31 and the padding
|
||||
|
||||
.set noreorder # If we're writing assembly, why would we want this?
|
||||
|
||||
.section .text.startup
|
||||
|
||||
.equ getBufferInternal, 0x2986a0
|
||||
.equ payload, (0x2000000 - 0x800) # End of RAM
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
#la $a0, 0x7f
|
||||
#la $v1, 0x01
|
||||
#syscall 0x01 # ResetEE
|
||||
|
||||
#la $a0, relo
|
||||
la $a0, load
|
||||
la $a1, 0
|
||||
la $a2, 0
|
||||
la $a3, 0
|
||||
|
||||
.global ExecPS2
|
||||
ExecPS2:
|
||||
la $v1, 7
|
||||
syscall 7 # ExecPS2
|
||||
|
||||
load:
|
||||
la $a0, 0
|
||||
la $a1, 0 # 0 = VIDEO_TS.IFO, 1 = VTS_01_0.IFO
|
||||
la $a2, 0x3800 / 0x800 # lba offset in file
|
||||
la $a3, payload # Destination
|
||||
la $t0, 0x800 / 0x800 # Count
|
||||
la $t1, 0
|
||||
la $v0, getBufferInternal
|
||||
jalr $v0
|
||||
nop
|
||||
|
||||
#relo:
|
||||
# Relocate payload to end of RAM
|
||||
# la $a0, (0x2000000 - 1024)
|
||||
# la $a1, payload
|
||||
# la $a2, 2048
|
||||
# la $v0, memcpy
|
||||
# jalr $v0
|
||||
|
||||
boot:
|
||||
la $v1, 0x64; la $a0, 0; syscall 0x64 # FlushCache data writeback
|
||||
la $v1, 0x64; la $a0, 2; syscall 0x64 # FlushCache instruction invalidate
|
||||
|
||||
# Point stack to end of scratchpad RAM
|
||||
la $sp, 0x70004000
|
||||
|
||||
# Execute from relocated place
|
||||
la $v0, ENTRY
|
||||
j $v0
|
||||
nop
|
||||
|
||||
#.space (_start + 0x2fe2 - 0x2954) - .
|
||||
#fpIndex:
|
||||
# .byte 0xfa
|
||||
# .byte 0xdc
|
||||
|
||||
#.space (_start + 0x3000 - 0x2954) - .
|
||||
#.incbin "payload.bin"
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,141 +0,0 @@
|
|||
#include <stddef.h>
|
||||
|
||||
// Pick one
|
||||
#define LOAD_FROM_VTS_02_0_IFO
|
||||
//#define LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO (151 - 138 - 7)
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define pointToIFO ((void (*)(unsigned int index, unsigned int lba, unsigned int offset))0x258a28)
|
||||
#define getDiscData ((void (*)(unsigned int s, void *d))0x258b98)
|
||||
|
||||
#define SifIopReset ((int (*)(char *, int))0x20e7d8)
|
||||
#define SifIopSync ((int (*)(void))0x20e958)
|
||||
#define SifInitRpc ((void (*)(int))0x208d80)
|
||||
#define SifExitRpc ((void (*)(void))0x208f20)
|
||||
|
||||
#define getBufferInternal ((int (*)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos))0x2952f0)
|
||||
|
||||
#define ELF_PT_LOAD 1
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
typedef struct {
|
||||
u8 ident[16];
|
||||
u16 type;
|
||||
u16 machine;
|
||||
u32 version;
|
||||
u32 entry;
|
||||
u32 phoff;
|
||||
u32 shoff;
|
||||
u32 flags;
|
||||
u16 ehsize;
|
||||
u16 phentsize;
|
||||
u16 phnum;
|
||||
u16 shentsize;
|
||||
u16 shnum;
|
||||
u16 shstrndx;
|
||||
} elf_header_t;
|
||||
|
||||
typedef struct {
|
||||
u32 type;
|
||||
u32 offset;
|
||||
void *vaddr;
|
||||
u32 paddr;
|
||||
u32 filesz;
|
||||
u32 memsz;
|
||||
u32 flags;
|
||||
u32 align;
|
||||
} elf_pheader_t;
|
||||
|
||||
__attribute__((noreturn)) void ExecPS2(void *entry, void *gp, int argc, char **argv) {
|
||||
asm volatile("la $v1, 7; syscall 7");
|
||||
//__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *memcpy_(void *dest, void *src, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void readData(void *dest, unsigned int offset, size_t n) {
|
||||
unsigned char buffer[0x800];
|
||||
|
||||
unsigned int copied = 0;
|
||||
#define remaining (n - copied)
|
||||
|
||||
if(offset % 0x800) {
|
||||
getBufferInternal("", 1, offset / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest, buffer + offset % 0x800, min(0x800 - (offset % 0x800), n));
|
||||
copied += min(0x800 - (offset % 0x800), n);
|
||||
}
|
||||
|
||||
if(remaining >= 0x800) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, dest + copied, remaining / 0x800, 0);
|
||||
copied += (remaining / 0x800) * 0x800;
|
||||
}
|
||||
|
||||
if(remaining > 0) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest + copied, buffer, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void _start(void) {
|
||||
//Exit(0);
|
||||
//asm volatile("la $v1, 0x04; la $a0, 0; syscall 0x04");
|
||||
|
||||
int i;
|
||||
|
||||
#ifdef LOAD_FROM_VTS_02_0_IFO
|
||||
// point to VTS_02_0.IFO
|
||||
pointToIFO(2, 0, 0);
|
||||
|
||||
// Force a read from VTS_02_0.IFO
|
||||
char head[64];
|
||||
getDiscData(64, &head);
|
||||
|
||||
#define RELATIVE_SECTOR 0
|
||||
#else
|
||||
#define RELATIVE_SECTOR LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO
|
||||
#endif
|
||||
|
||||
// Based on https://github.com/AKuHAK/uLaunchELF/blob/master/loader/loader.c
|
||||
elf_header_t eh;
|
||||
readData(&eh, RELATIVE_SECTOR * 0x800, sizeof(elf_header_t));
|
||||
|
||||
elf_pheader_t eph[eh.phnum];
|
||||
readData(&eph, RELATIVE_SECTOR * 0x800 + eh.phoff, sizeof(elf_pheader_t) * eh.phnum);
|
||||
|
||||
for (i = 0; i < eh.phnum; i++) {
|
||||
if (eph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
|
||||
readData(eph[i].vaddr, RELATIVE_SECTOR * 0x800 + eph[i].offset, eph[i].filesz);
|
||||
if(eph[i].memsz > eph[i].filesz) memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
|
||||
}
|
||||
|
||||
asm volatile("la $v1, 0x64; la $a0, 0; syscall 0x64"); // FlushCache data writeback
|
||||
asm volatile("la $v1, 0x64; la $a0, 2; syscall 0x64"); // FlushCache instruction invalidate
|
||||
|
||||
//while(!SifIopReset("", 0));
|
||||
//while(!SifIopSync());
|
||||
|
||||
//while(!SifIopReset("rom0:UDNL rom0:EELOADCNF", 0));
|
||||
SifIopReset("rom0:UDNL rom0:EELOADCNF", 0);
|
||||
while(!SifIopSync());
|
||||
|
||||
SifInitRpc(0);
|
||||
SifExitRpc();
|
||||
|
||||
ExecPS2((void *)eh.entry, 0, 0, 0);
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,19 +0,0 @@
|
|||
echo "Building payload"
|
||||
|
||||
ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048
|
||||
ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
ENTRY=`ee-objdump -t payload.elf | grep " _start"`
|
||||
echo $ENTRY
|
||||
|
||||
# Doesn't seem to work on MinGW toolchain, so set manually if you're using that:
|
||||
ENTRY=0x`grep -o "^\S*" <<< $ENTRY`
|
||||
#ENTRY=0x01fff9a8
|
||||
|
||||
echo $ENTRY
|
||||
echo "Building crt0"
|
||||
|
||||
ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY crt0.S -o fullpayload.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary fullpayload.elf fullpayload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Done. Insert fullpayload.bin into VIDEO_TS.IFO at offset 0x2bb4"
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
.set noreorder # If we're writing assembly, why would we want this?
|
||||
|
||||
.section .text.startup
|
||||
|
||||
.equ memcpy, 0x225668
|
||||
.equ getBufferInternal, 0x2986a0
|
||||
.equ payload, (0x2000000 - 0x800) # End of RAM
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
#la $a0, 0x7f
|
||||
#la $v1, 0x01
|
||||
#syscall 0x01 # ResetEE
|
||||
|
||||
#la $a0, relo
|
||||
la $a0, load
|
||||
la $a1, 0
|
||||
la $a2, 0
|
||||
la $a3, 0
|
||||
|
||||
.global ExecPS2
|
||||
ExecPS2:
|
||||
la $v1, 7
|
||||
syscall 7 # ExecPS2
|
||||
|
||||
load:
|
||||
la $a0, 0
|
||||
la $a1, 0 # 0 = VIDEO_TS.IFO, 1 = VTS_01_0.IFO
|
||||
la $a2, 0x3000 / 0x800 # lba offset in file
|
||||
la $a3, payload # Destination
|
||||
la $t0, 0x800 / 0x800 # Count
|
||||
la $t1, 0
|
||||
la $v0, getBufferInternal
|
||||
jalr $v0
|
||||
nop
|
||||
|
||||
#relo:
|
||||
# Relocate payload to end of RAM
|
||||
# la $a0, (0x2000000 - 1024)
|
||||
# la $a1, payload
|
||||
# la $a2, 2048
|
||||
# la $v0, memcpy
|
||||
# jalr $v0
|
||||
|
||||
boot:
|
||||
la $v1, 0x64; la $a0, 0; syscall 0x64 # FlushCache data writeback
|
||||
la $v1, 0x64; la $a0, 2; syscall 0x64 # FlushCache instruction invalidate
|
||||
|
||||
# Point stack to end of scratchpad RAM
|
||||
la $sp, 0x70004000
|
||||
|
||||
# Execute from relocated place
|
||||
la $v0, ENTRY
|
||||
j $v0
|
||||
nop
|
||||
|
||||
.space (_start + 0x2faa - 0x2bb4) - .
|
||||
fpIndex:
|
||||
.byte 0x7e
|
||||
.byte 0xe0
|
||||
|
||||
.space (_start + 0x3000 - 0x2bb4) - .
|
||||
.incbin "payload.bin"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,19 +0,0 @@
|
|||
echo "Building payload"
|
||||
|
||||
ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048
|
||||
ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
ENTRY=`ee-objdump -t payload.elf | grep " _start"`
|
||||
echo $ENTRY
|
||||
|
||||
# Doesn't seem to work on MinGW toolchain, so set manually if you're using that:
|
||||
#ENTRY=0x`grep -o "^\S*" <<< $ENTRY`
|
||||
ENTRY=0x01fff9a8
|
||||
|
||||
echo $ENTRY
|
||||
echo "Building crt0"
|
||||
|
||||
ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY crt0.S -o fullpayload.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1
|
||||
ee-objcopy -O binary fullpayload.elf fullpayload.bin -Wl,-z,max-page-size=0x1
|
||||
|
||||
echo "Done. Insert fullpayload.bin into VIDEO_TS.IFO at offset 0x2954"
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,141 +0,0 @@
|
|||
#include <stddef.h>
|
||||
|
||||
// Pick one
|
||||
#define LOAD_FROM_VTS_02_0_IFO
|
||||
//#define LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO (151 - 138 - 7)
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define pointToIFO ((void (*)(unsigned int index, unsigned int lba, unsigned int offset))0x258a28)
|
||||
#define getDiscData ((void (*)(unsigned int s, void *d))0x258b98)
|
||||
|
||||
#define SifIopReset ((int (*)(char *, int))0x20e7d8)
|
||||
#define SifIopSync ((int (*)(void))0x20e958)
|
||||
#define SifInitRpc ((void (*)(int))0x208d80)
|
||||
#define SifExitRpc ((void (*)(void))0x208f20)
|
||||
|
||||
#define getBufferInternal ((int (*)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos))0x2952f0)
|
||||
|
||||
#define ELF_PT_LOAD 1
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
typedef struct {
|
||||
u8 ident[16];
|
||||
u16 type;
|
||||
u16 machine;
|
||||
u32 version;
|
||||
u32 entry;
|
||||
u32 phoff;
|
||||
u32 shoff;
|
||||
u32 flags;
|
||||
u16 ehsize;
|
||||
u16 phentsize;
|
||||
u16 phnum;
|
||||
u16 shentsize;
|
||||
u16 shnum;
|
||||
u16 shstrndx;
|
||||
} elf_header_t;
|
||||
|
||||
typedef struct {
|
||||
u32 type;
|
||||
u32 offset;
|
||||
void *vaddr;
|
||||
u32 paddr;
|
||||
u32 filesz;
|
||||
u32 memsz;
|
||||
u32 flags;
|
||||
u32 align;
|
||||
} elf_pheader_t;
|
||||
|
||||
__attribute__((noreturn)) void ExecPS2(void *entry, void *gp, int argc, char **argv) {
|
||||
asm volatile("la $v1, 7; syscall 7");
|
||||
//__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *memcpy_(void *dest, void *src, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n) {
|
||||
int i;
|
||||
for(i = 0; i < n; i++) ((unsigned char *)dest)[i] = c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void readData(void *dest, unsigned int offset, size_t n) {
|
||||
unsigned char buffer[0x800];
|
||||
|
||||
unsigned int copied = 0;
|
||||
#define remaining (n - copied)
|
||||
|
||||
if(offset % 0x800) {
|
||||
getBufferInternal("", 1, offset / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest, buffer + offset % 0x800, min(0x800 - (offset % 0x800), n));
|
||||
copied += min(0x800 - (offset % 0x800), n);
|
||||
}
|
||||
|
||||
if(remaining >= 0x800) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, dest + copied, remaining / 0x800, 0);
|
||||
copied += (remaining / 0x800) * 0x800;
|
||||
}
|
||||
|
||||
if(remaining > 0) {
|
||||
getBufferInternal("", 1, (offset + copied) / 0x800, buffer, 1, 0);
|
||||
memcpy_(dest + copied, buffer, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void _start(void) {
|
||||
//Exit(0);
|
||||
//asm volatile("la $v1, 0x04; la $a0, 0; syscall 0x04");
|
||||
|
||||
int i;
|
||||
|
||||
#ifdef LOAD_FROM_VTS_02_0_IFO
|
||||
// point to VTS_02_0.IFO
|
||||
pointToIFO(2, 0, 0);
|
||||
|
||||
// Force a read from VTS_02_0.IFO
|
||||
char head[64];
|
||||
getDiscData(64, &head);
|
||||
|
||||
#define RELATIVE_SECTOR 0
|
||||
#else
|
||||
#define RELATIVE_SECTOR LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO
|
||||
#endif
|
||||
|
||||
// Based on https://github.com/AKuHAK/uLaunchELF/blob/master/loader/loader.c
|
||||
elf_header_t eh;
|
||||
readData(&eh, RELATIVE_SECTOR * 0x800, sizeof(elf_header_t));
|
||||
|
||||
elf_pheader_t eph[eh.phnum];
|
||||
readData(&eph, RELATIVE_SECTOR * 0x800 + eh.phoff, sizeof(elf_pheader_t) * eh.phnum);
|
||||
|
||||
for (i = 0; i < eh.phnum; i++) {
|
||||
if (eph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
|
||||
readData(eph[i].vaddr, RELATIVE_SECTOR * 0x800 + eph[i].offset, eph[i].filesz);
|
||||
if(eph[i].memsz > eph[i].filesz) memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
|
||||
}
|
||||
|
||||
asm volatile("la $v1, 0x64; la $a0, 0; syscall 0x64"); // FlushCache data writeback
|
||||
asm volatile("la $v1, 0x64; la $a0, 2; syscall 0x64"); // FlushCache instruction invalidate
|
||||
|
||||
//while(!SifIopReset("", 0));
|
||||
//while(!SifIopSync());
|
||||
|
||||
//while(!SifIopReset("rom0:UDNL rom0:EELOADCNF", 0));
|
||||
SifIopReset("rom0:UDNL rom0:EELOADCNF", 0);
|
||||
while(!SifIopSync());
|
||||
|
||||
SifInitRpc(0);
|
||||
SifExitRpc();
|
||||
|
||||
ExecPS2((void *)eh.entry, 0, 0, 0);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PREBUILT ISOs/Some 2.10 models and all 2.12.iso
Normal file
BIN
PREBUILT ISOs/Some 2.10 models and all 2.12.iso
Normal file
Binary file not shown.
Binary file not shown.
135
README.md
135
README.md
|
|
@ -3,53 +3,109 @@ PlayStation 2 DVD Player Exploit. This allows you to burn your own PlayStation 2
|
|||
|
||||
For technical details please refer to my [blog post](https://cturt.github.io/freedvdboot.html).
|
||||
|
||||
## Basic setup
|
||||
Using prebuilt ISOs in this repo ([PREBUILT ISOs](https://github.com/CTurt/FreeDVDBoot/tree/master/PREBUILT%20ISOs) folder).
|
||||
Read from [here](#easy-setup-for-all-ps2-slim-consoles--bravia-tv) if you have a Slim PS2.
|
||||
|
||||
Read from [here](#phat-consoles) if you have a Phat PS2.
|
||||
|
||||
## Easy setup for all PS2 Slim consoles / Bravia TV
|
||||
All you need is:
|
||||
|
||||
- A compatible console (all PS2 Slim / Sony Bravia TV units are supported),
|
||||
- A DVD (not a CD), preferably a DVD-R as other types such as DVD+RW put more strain on the PS2 laser,
|
||||
- A computer with a built-in disc burner / external USB disc burner,
|
||||
|
||||
### Step 1: Download the ISO
|
||||
Download [`PREBUILT ISOs/All PS2 Slims - English language.iso`](https://github.com/CTurt/FreeDVDBoot/raw/master/PREBUILT%20ISOs/All%20PS2%20Slims%20-%20English%20language.iso)
|
||||
|
||||
### Step 2: Burn the ISO
|
||||
Please check following to ensure a good burn which the PS2 will be able to read:
|
||||
|
||||
- Clean off any dust from the disc,
|
||||
- Select lowest burning speed option,
|
||||
- Select finalise disc option,
|
||||
|
||||
### Step 3: Set console language to English
|
||||
Your console must be set to **English language** for the exploit to work (other languages cause memory contents to change).
|
||||
|
||||
To do this, boot without a disc inserted, press **Circle** to enter **System Configuration** and set your system language to **English**.
|
||||
|
||||
### Step 4: Boot!
|
||||
Insert the disc into your console, and wait. It should boot into **uLaunchELF** within a few seconds.
|
||||
|
||||
From **uLaunchELF**, you have the ability to run any homebrew you want over USB **mass** storage! Many people choose to run **FreeMCBoot** or **Fortuna** installer, as they find booting from a memory card more convenient.
|
||||
|
||||
If you want to add additional homebrew to your DVD / replace uLaunchELF, please read from [Custom disc setup](#custom-disc-setup).
|
||||
|
||||
## Troubleshooting - please read if the above didn't work
|
||||
| Problem | Solution |
|
||||
|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Disc doesn't spin on slim console | Press the lid down hard to ensure the sensors detect that the lid is closed. If still not working try placing some weight such as a book on the top of the console. |
|
||||
| PS2 detects the disc as "PlayStation 2 disc" instead of "DVD Video" in the browser | Your PS2 has a modchip which is incorrectly preventing the DVD player from launching. You do not need this exploit for a console with a modchip, but if you really want to try it some modchips offer the ability to temporarily disable themselves (by holding start when booting for example). |
|
||||
| PS2 displays "unable to read disc" | Please try playing a real DVD movie disc to verify that your console's DVD laser works; doing this can also recalibrate the laser which might solve the issue, as [commented here](https://github.com/CTurt/FreeDVDBoot/issues/27). Also try the following PS2 setting `Version -> Console -> Diagnosis -> On` which can assist with laser problems. |
|
||||
| PS2 freezes at black/red/green screen | If your PS2 DVD laser is really worn out, or you are using something difficult to read like a dusty DVD+RW burned on high speed, it might take some time before uLaunchELF actually starts. Please try waiting 3 minutes or so, per [this comment](https://github.com/CTurt/FreeDVDBoot/issues/3#issuecomment-651337741) |
|
||||
|
||||
Other suggestions that worked for others:
|
||||
|
||||
- Try unplugging your controller, and plugging it back in. Apparently [that solved the issue for this user](https://github.com/CTurt/FreeDVDBoot/issues/103).
|
||||
|
||||
- Try removing all memory cards. Apparently [that solved the issue for this user](https://github.com/CTurt/FreeDVDBoot/issues/3#issuecomment-651970564).
|
||||
|
||||
- Try burning with different software. Apparently [for this user](https://github.com/CTurt/FreeDVDBoot/issues/108) and [this user](https://github.com/CTurt/FreeDVDBoot/issues/124#issuecomment-661231776) ImgBurn didn't work, but CDBurnerXP with 1x speed, compatibility settings, and finalize option worked.
|
||||
|
||||
- Check that your console's language is set to English.
|
||||
|
||||
- Check the GitHub repo to see if the image has been updated recently. Download the new one if it has.
|
||||
|
||||
**Please, only open a GitHub issue if you have read and tried all of the above. If you do open an issue, please confirm that you tried a real DVD movie and it worked on your system so that we know it's not just a laser failure; also include your DVD player version, the name of the ISO you tried, the type of DVD, and what happens when you launch the disc.**
|
||||
|
||||
## Phat consoles
|
||||
Phat consoles have many different firmware version revisions, which makes them harder to add support for. It also means you will need to identify your firmware version, and burn the matching ISO file.
|
||||
|
||||
It's still early in terms of support for different versions, check back here later. Hopefully over time other developers from the scene will also contribute support for additional DVD Player versions. The new exploit for 2.10 should be possible to port to all firmwares between 1.00 - 2.13 (Sony actually patched this one in 2.14 lol).
|
||||
|
||||
### Step 1: Identify your DVD Player Version
|
||||
Boot your PlayStation 2 without any disc inserted, and press Triangle to identify which DVD Player version your console has. Still early in terms of support for different versions, check back here later for more support. Hopefully over time other developers from the scene will also contribute support for additional DVD Player versions.
|
||||
Boot your PlayStation 2 without any disc inserted, and press Triangle to identify which DVD Player version your console has.
|
||||
|
||||
**Currently only support:**
|
||||
|
||||
- 3.04 (tested only region M in emulator so far, but guess all regions EUMACDGJ will work - with English language set in settings) - please ping me and will update this page when confirmed working on hardware.
|
||||
- 3.10 (all regions EUMACDGJ - with English language set in settings) - confirmed working on hardware by CTurt, and others. [Only seems to work with English language](https://www.youtube.com/watch?v=zelVQcD7HCY).
|
||||
- 3.11 (all regions EUMACDGJ) - confirmed working on hardware by [MrMario2011](https://twitter.com/MrMario2011/status/1277586569738813440), and others. ([Only seems to work with English language](https://twitter.com/kood_infothief/status/1277600247024238592)).
|
||||
- 2.10 (certain models only? Working: SCPH-30001 R (ROMGEN 0160AC20010427), SCPH-30000 (ROMGEN 0160JC20010427), SCPH-30004 R (ROMGEN 0160EC20011004), Not working: SCPH-39004 - todo),
|
||||
|
||||
UPDATE: Experimental hybrid ISO for both 3.10 and 3.11 support merged into one now available, burn `PREBUILT ISOs/hybrid 3.10 and 3.11.iso` and set language to English. Confirmed [working on 3.11](https://twitter.com/TheWizWiki/status/1277670129355161601).
|
||||
- 2.12 (regions U, J, and G, if any other regions exist for 2.12 let me know),
|
||||
|
||||
- 3.04 (tested only region M in emulator so far, but guess most other regions EUMACDG, except for J will work - with English language set in settings),
|
||||
|
||||
### Step 2: Download the ISO
|
||||
Download the ISO that corresponds to your firmware version.
|
||||
|
||||
**Please don't bother trying on a non-supported firmware/language configuration, it won't work...**
|
||||
|
||||
### Step 2: Burn
|
||||
Pre-built ISO files for supported DVD Players containing just uLaunchELF are provided in this repository for ease of use (which can be used to boot homebrew over a USB mass storage device). For example, if your DVD Player version is 3.10E, you would want to burn `PREBUILT ISOs/3.10 only - all regions - English lang.iso`.
|
||||
For example, if your DVD Player version is 2.10J, you would want to download `PREBUILT ISOs/2.10.iso`.
|
||||
|
||||
You should use DVD-R with low burning speed (others may work, but they put more strain on PS2 laser), and make sure to finalise the disc as burning option. Otherwise, you might run into issues reading the disc.
|
||||
### Step 3, 4, 5 - Burn the ISO, set console language to English, and boot!
|
||||
These steps are the same as described for slim above.
|
||||
|
||||
## Troubleshooting - please read if the above didn't work
|
||||
Disc doesn't spin on slim console - press the lid down hard to ensure the sensors detect that the lid is closed.
|
||||
## Custom disc setup - Slim
|
||||
If you intend to make your own image containing additional homebrew / modified initial loader, please read on.
|
||||
|
||||
PS2 says "unable to read disc" - this doesn't seem to be a problem with the exploit, but just that your DVD laser might not work, or at least can't read the disc you burned. Please try a regular DVD video first, or DVD game to ensure one of those works. If that works, make sure you are finalising your disc when burning, use a low write speed, and I recommend using DVD-R instead of any other type of DVD as those put more strain on the laser.
|
||||
### Step 1: Copy your homebrew
|
||||
Once you've identified your console's DVD Player version, copy all of the homebrew you would like to include on the disc into that directory in the `Filesystems` (EG: `Filesystems/All PS2 slims (3.10 + 3.11) - English language/` is the one that supports all slim consoles).
|
||||
|
||||
PS2 enters black screen - if your PS2 DVD laser is really worn out, or you are using something difficult to read like DVD+RW burned on high speed, it might take some time before uLaunchELF actually starts. Please try waiting 3 minutes or so, per [this comment](https://github.com/CTurt/FreeDVDBoot/issues/3#issuecomment-651337741).
|
||||
### Step 2: Make an image
|
||||
Once you've placed all the homebrew files you'd like into the directory, generate a UDF (ISO9960/UDF hybrid also works) image of the directory (so `VIDEO_TS` is in the root).
|
||||
|
||||
Also try cleaning the disc to remove dust, and try verifying the burn on PC.
|
||||
On Windows, you can use a GUI like ImgBurn to make an disc image. It will give a warning that `VIDEO_TS.BUP` is missing, but just click continue anyway (PS2 doesn't require this file).
|
||||
|
||||
Try setting your console language to English, as that affects some versions of the exploit, and English language is the only one I tested.
|
||||
On Linux the easiest way is probably to use `genisoimage` as it comes pre-installed on many Linux distributions like Ubuntu. Run the following on terminal (where `exploit.iso` is the output and `Filesystem/All PS2 slims (3.10 + 3.11) - English language` is the directory containing `VIDEO_TS` and any homebrew):
|
||||
|
||||
## Custom disc setup
|
||||
If you intend to make your own image containing additional homebrew / modified initial loader, please read on. Step 1 is the same; identify your firmware version.
|
||||
genisoimage -udf -o exploit.iso "Filesystems/All PS2 slims (3.10 + 3.11) - English language"
|
||||
|
||||
### Step 2: Copy your homebrew
|
||||
Once you've identified your console's DVD Player version, copy all of the homebrew you would like to include on the disc into that directory in the `Filesystem` (EG: `Filesystem/3.10EU/`).
|
||||
|
||||
### Step 3: Make an image
|
||||
Once you've placed all the homebrew files you'd like into the directory, generate a UDF image of the directory. The easiest way is probably to install `genisoimage` (comes pre-installed on many Linux distributions like Ubuntu) or `mkisofs` and run the following (where `exploit.iso` is the output and `Filesystem/3.10` is the directory containing `VIDEO_TS` and any homebrew):
|
||||
|
||||
genisoimage -udf -o exploit.iso Filesystems/3.10
|
||||
|
||||
### Step 4: Test and burn
|
||||
### Step 3: Test and burn
|
||||
I would recommend you test in PCSX2 first, but since [PCSX2 doesn't support loading the DVD Player](https://github.com/PCSX2/pcsx2/issues/1981), you have to decrypt and repack it yourself, which is beyond the scope of this README. With that said, if you aren't touching anything in `VIDEO_TS`, there shouldn't really be any reason for the exploit to fail.
|
||||
|
||||
## OPTIONAL: Replace the initial program
|
||||
## Custom disc setup - Phat
|
||||
Instructions for building the phat exploit coming soon.
|
||||
|
||||
## Replacing the initial program - Slim
|
||||
I've included uLaunchELF recompiled with [DVD support](https://github.com/ps2dev/ps2sdk/pull/130) as the default initial program. It presents a menu which allows you to select any of the homebrew programs you chose to include on the disc (and also allows booting from USB).
|
||||
|
||||
Alternatively, if you would rather just boot into a single homebrew application, the initial program the exploit attempts to boot is located at `VIDEO_TS/VTS_02_0.IFO`, replace it with your desired `ELF` file, with the below caveat that compatibility might be lower than if you booted a program through uLaunchELF:
|
||||
|
|
@ -72,10 +128,27 @@ You can run `readelf -l` to verify your executable satisfies this requirement. F
|
|||
Segment Sections...
|
||||
00 .text .ctors .dtors .rodata .data .jcr .sdata .sbss .bss
|
||||
|
||||
## DEVELOPMENT: Replacing the loader payload
|
||||
## Replacing the initial program - Phat
|
||||
The ELF is read from `0x5bb000` in the ISO file, copy to that location with a hex editor to replace it.
|
||||
|
||||
## Loading backups
|
||||
It's possible to patch backup images of commercial games to make them bootable using this exploit. I didn't want to maintain this tool, so it's not included in this repository, but can be found by searching for something like FreeDVDBoot ESR auto patcher.
|
||||
|
||||
## DEVELOPMENT: Replacing the loader payload - Slim
|
||||
The default payload will boot `VIDEO_TS/VTS_02_0.IFO` as an ELF file, but tweaks might be desired to improve compatibility, or maybe changing the behaviour to boot `BOOT.ELF` instead for instance.
|
||||
|
||||
If you wish to update the loader payload, run `build.sh` inside `PAYLOAD` directory, and copy the output `fullpayload.bin` to `VIDEO_TS/VIDEO_TS.IFO` at offset `0x2bb4` (for 3.10E).
|
||||
If you wish to update the loader payload, run `build.sh` inside `PAYLOAD` directory, and copy the output `.bin` files into `VIDEO_TS/VIDEO_TS.IFO` at the offsets displayed by the output of the command.
|
||||
|
||||
## DEVELOPMENT: Replacing the loader payload - Phat
|
||||
Run the following to build a new `dvd.iso`:
|
||||
|
||||
`make -f hardware.mk`
|
||||
|
||||
If you want to test on PCSX2 using KrHacken's repacked DVD players, it loads `udfio` at a different base address, use the repacked Makefile to build an image for testing on the emulator:
|
||||
|
||||
`make -f emulator.mk`
|
||||
|
||||
`clean` before switching between these different Makefiles, or use `-B` flag.
|
||||
|
||||
## PORTING:
|
||||
Please read my technical writeup, to understand how the exploit works. I've also provided some notes about porting in the `porting notes.txt` file.
|
||||
Please read my technical writeup, to understand how the exploit works. I've also provided some [notes about porting](https://cturt.github.io/FreeDVDBoot/portingnotes.html) in the [`gh-pages`](https://github.com/CTurt/FreeDVDBoot/tree/gh-pages) branch.
|
||||
|
|
|
|||
|
|
@ -1,123 +0,0 @@
|
|||
OK, so turns out porting to different regions/languages is just a matter of finding new jump target, which isn't too difficult.
|
||||
|
||||
Prefer using jump targets which aren't part of the language data, so that exploit is compatible with all languages. I might go back and redo 3.10 for this reason.
|
||||
|
||||
Porting to different versions, means finding all the function addresses again, which is the time consuming bit.
|
||||
|
||||
|
||||
|
||||
porting to 3.11J (English language)
|
||||
|
||||
make memory dump for EE (PCSX2 save state, rename to zip extract, eeMemory.bin)
|
||||
search DVDVIDEO-VMG = 0x014331c8
|
||||
memory write breakpoint to find sb instruction at 0x00258BC8
|
||||
decompile that in Ghidra, you'll see getDiscData is 0x258b98, and getDiscByte is 0x258ac8
|
||||
inside getDiscByte, we can see that currentDiscBytePointer is 0x143b3e4 and endDiscBytePointer is 0x143b3e8
|
||||
xref getDiscData, 20 locations, go through them till you find the buffer overflow described in my post which copies with size (a + b + c) * 8, it's the call at 0x257564
|
||||
note destination of copy, which is 0x14351cc
|
||||
so we control range 0x14351cc - 0x15B51B4 (0x14351cc + 3 * 0xffff * 8)
|
||||
go to destination + roughly 0x6A76 and search for fpIndex (xrefs will be functions looking like setFpIndex and the OOB call as shown in my post)
|
||||
fpIndex is at 0x143bc4a
|
||||
OOB call is at 0x25ab44 (actually there are more than 1, but this one is executed first - set memory read breakpoint on fpIndex to find it)
|
||||
note the base of the function pointer array, in this case 0x003b3050
|
||||
dump the memory from base till 0x003b3050 + 4 * 0xffff = 0x3F304C, group into 4 bytes and search for jump targets that fit within overflow range
|
||||
eg: searching for "14352... " I see some results
|
||||
must also be 4 byte aligned
|
||||
3.11 is actually pretty good, there are quite a few results that should work, if not you can try switching languages and there will be different jump targets to check
|
||||
0x01522944 looks pretty good, it's at 0x3E4A74, so index would be (0x3E4A74-0x003b3050)/4 = 0xC689
|
||||
ok, we have everything we need - let's make the IFO exploit file
|
||||
the copy size should be at the same offset since that's part of the spec, so no need to change that
|
||||
now run and break at the copy (0x257564), v1 is 0xffff so we're triggering the bug :)
|
||||
set a memory write breakpoint for the byte just before currentDiscBytePointer (0x143b3e4 - 1), wait till its set by the sb instruction in getDiscData
|
||||
now note down currentDiscBytePointer's value, it's 0x0143a94c (so will be +1 by the time we are writing currentDiscBytePointer)
|
||||
goto that in the memory viewer to see where we're copying from
|
||||
we can see the "ABOVE 3" note I wrote to myself just below it (just an arbitrary marker point), so we can work out that this corresponds to offset 0x000277c in the IFO
|
||||
we write currentDiscBytePointer's same value, and then 0xffffff for endDiscBytePointer next to it
|
||||
run again and make sure it overwrites the same value it already has (easy to get off-by-one here)
|
||||
that's probably the hardest part done now, we are now overwriting fpIndex and payload space with controlled contents
|
||||
break at writing fpIndex (0x143bc4a), and see it's corrupted by getDiscData
|
||||
note down currentDiscBytePointer value, it's 0x0143b1b3
|
||||
goto that in memory view and look what it's near to, we see that the 7e e0 fpIndex for 3.10 is just above
|
||||
so we can count our offset will be at offset 0x2fe2 in the IFO
|
||||
we wanted to corrupt that to 89 c6, which should lead to jumping to 0x01522944
|
||||
run again and now break at the OOB call (0x25ab44)
|
||||
sure enough we can trace it and see jump v0 which is 0x01522944 (we got lucky and already corrupted the thing that stops resetting fpIndex)
|
||||
now we just need to run again to the copy, and break at writing 0x01522944 to find where to start our initial payload in the IFO
|
||||
currentDiscBytePointer value is 0x01521ead, which is just above where we put payload for 3.10, at offset 0x2ba4
|
||||
BOOM! We have arbitrary code execution.
|
||||
for now, I haven't reimplemented everything needed by the loader, so we need to find a few functions to use in our loader - this will be improved in future
|
||||
you need getBufferInternal (getBuffer is called inside getDiscByteInternal, 0x295518 in our case, and then getBufferInternal is called inside that, 0x2952f0 for us)
|
||||
getDiscData (we already have it, 0x258b98)
|
||||
pointToIFO (search for call to getDiscData, and it'll be near those calls - called like pointToIFO(param_1,0,0x80) and calls getDiscByteInternal inside) in our case 0x258a28
|
||||
SifIopReset (0x20e7d8), SifInitRpc (0x208d80), SifExitRpc (0x208f20) - for these, find SifIopReboot first, which is easy because of "rom0:UDNL " string (see https://github.com/ps2dev/ps2sdk/blob/8b7579979db87ace4b0aa5693a8a560d15224a96/ee/kernel/src/iopcontrol.c#L82) and look at the calls inside that match
|
||||
SifIopSync (0x20e958) - look for a call to SifIopReset and looping call just after
|
||||
edit build.sh to place correct loading address and offsets, and recompile!
|
||||
Insert fullpayload.bin into VIDEO_TS.IFO at offset 0x2ba4
|
||||
test, and see ule boot successfully in pcsx2!
|
||||
|
||||
|
||||
3.11 all (English language)
|
||||
getDiscData and getDiscByte seem the same as in 3.11J
|
||||
overflow call is also at 0x257564
|
||||
fpIndex also 0x143bc4a
|
||||
oob jump also at 0x0025A618
|
||||
it's just the jump targets that are different
|
||||
dump 0x3b3050 to 0x3b3050 + 0xffff * 4 = 0x3F304C
|
||||
we have a nice one! 01500014 will work - same as we used for 3.10EU lol :)
|
||||
that's at 0x3EA438, so index (0x3EA438-0x3b3050)/4 = 0xDCFA
|
||||
so patch the IFO, same offset as for 3.11J (0x2fe2) to fa dc
|
||||
now break at writing payload (0x1500014)
|
||||
currentDiscBytePointer points to 0x014ff57d
|
||||
nearest landmark is "ABOVE 3" string at 0x14ff41b
|
||||
so payload goes at ABOVE 3 location in IFO + (0x014ff57d - 0x14ff41b) - 1 = 0x2954
|
||||
|
||||
|
||||
|
||||
hybrid 3.10 + 3.11
|
||||
so starting with a 3.11 base VIDEO_TS.IFO
|
||||
currentDiscBytePointer offset for 3.10 is 00002744
|
||||
for 3.11 is 0000277c
|
||||
copy 3.10 currentDiscBytePointer and endDiscBytePointer corruption to its offset (8 bytes at 00002744)
|
||||
fpIndex for 3.10 is offset 00002faa, so copy those 2 bytes over
|
||||
payload needs to be modified to load stage 2 differently, I just moved it from 0x3000 to 0x38000
|
||||
payload for 3.10 is at 0x2bb4 copy that over
|
||||
|
||||
|
||||
|
||||
|
||||
3.04 (M tested only so far, but probably all regions work)
|
||||
getDiscData - 0x23e138
|
||||
getDiscByte - 0x23e068
|
||||
currentDiscBytePointer - 0x16ceee4
|
||||
endDiscBytePointer - 0x16ceee8
|
||||
|
||||
0x23cb04 is the copy we want, but I actually decided to look at different buffer overflows in case it is useful for hybrid-ing, here they all are:
|
||||
|
||||
Location Destination Max Size End
|
||||
0x23bd4c 0x16c6d60 0xffff * 0xc 0x1786D54
|
||||
0x23c48c 0x16c79d8 0xffff * 4 0x17079D4
|
||||
0x23cb04 0x16c8cd4 0xffff * 3 * 8 0x1848CBC
|
||||
0x23cc74 0x16c8cd4 0xffff * 4 0x1708CD0
|
||||
|
||||
writing currentDiscBytePointer, it's value is 0x016ce444
|
||||
offset in IFO is 0x2744 - uh on we have collision with 3.10, might not be possible to make hybrid disc with both of those
|
||||
will need more crazy tricks to do that... we'll see
|
||||
in mean time, doing 3.04 only disc
|
||||
|
||||
OOB call is at 0x23faac
|
||||
fpIndex at 0x16cf74a
|
||||
function pointer array - 0x95ace8
|
||||
select 0x95ace8 to 0x95ace8 + 0xffff * 4 = 0x99ACE4
|
||||
looking for jump targets, we have some starting with 0x018...
|
||||
01800180 at 0x95CF40, so index (0x95CF40-0x95ace8)/4 = 0x0896
|
||||
fpIndex offset in IFO is 0x2faa
|
||||
payload offset in IFO is 0x2d00
|
||||
|
||||
getBufferInternal - 0x261548
|
||||
pointToIFO - 0x23dfc8
|
||||
getDiscData - 0x23e138
|
||||
SifIopReboot - 0x291528
|
||||
SifInitRpc - 0x208260
|
||||
SifExitRpc - 0x208400
|
||||
SifIopReset - 0x291358
|
||||
SifIopSync - 0x2914d8
|
||||
Loading…
Add table
Reference in a new issue