diff --git a/Filesystems/2.10/BOOT.ELF b/Filesystems/2.10/BOOT.ELF new file mode 100644 index 0000000..d9f7983 Binary files /dev/null and b/Filesystems/2.10/BOOT.ELF differ diff --git a/Filesystems/2.10/VIDEO_TS/VIDEO_TS.IFO b/Filesystems/2.10/VIDEO_TS/VIDEO_TS.IFO new file mode 100644 index 0000000..3722fa8 Binary files /dev/null and b/Filesystems/2.10/VIDEO_TS/VIDEO_TS.IFO differ diff --git a/Filesystems/2.10/VIDEO_TS/VTS_01_0.IFO b/Filesystems/2.10/VIDEO_TS/VTS_01_0.IFO new file mode 100644 index 0000000..8d78ffe Binary files /dev/null and b/Filesystems/2.10/VIDEO_TS/VTS_01_0.IFO differ diff --git a/PAYLOADS/2.10/Makefile b/PAYLOADS/2.10/Makefile new file mode 100644 index 0000000..69cfe15 --- /dev/null +++ b/PAYLOADS/2.10/Makefile @@ -0,0 +1,81 @@ +#STAGE1_LOAD_ADDRESS = 0x1f62b0 +#STAGE1_LOAD_ADDRESS = 0xa01f62b0 # repacked +#STAGE1_LOAD_ADDRESS = 0xA01F30B0 # (0xa0000000 + 0x01f62b0 + 0x1F3058 - 0x1f6258) # hardware + +# (0xb7548 + 0x5c700 - 0xb1000) = 0x62C48 +STAGE1_LOAD_ADDRESS = 0xa0062C48 # hardware + +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_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -g + +EE_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 + +#IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"` +#IOP_PAYLOAD_ENTRY = 0xa0460178 # Set this manually for now. +IOP_PAYLOAD_ENTRY = 0xa00fd178 # Set this manually for now. + +IOP_STAGE1_SIZE = `stat -c '%s' stage1.iop.bin` +IOP_PAYLOAD_SIZE = `stat -c '%s' ioppayload.iop.bin` +#IOP_PAYLOAD_ADDRESS = 0x460000 +#IOP_PAYLOAD_ADDRESS = 0xa0460000 +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 + +all: dvd.iso + +dvd.iso: dvd.base.iso stage1.iop.bin ioppayload.iop.bin + cp dvd.base.iso dvd.iso + + #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 + + # bs=4096 iflag=skip_bytes,count_bytes + + # 0x820f8 = 532728 + dd if=stage1.iop.bin of=dvd.iso bs=1 seek=532728 count=$(IOP_STAGE1_SIZE) 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.iop.elf: stage1.iop.S ioppayload.iop.bin + $(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start" + $(IOP_CC) -Ttext=$(STAGE1_LOAD_ADDRESS) $< -DENTRY=$(IOP_PAYLOAD_ENTRY) -DIOP_PAYLOAD_SIZE=$(IOP_PAYLOAD_SIZE) $(IOP_CFLAGS) -o $@ + +ioppayload.iop.elf: ioppayload.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 diff --git a/PAYLOADS/2.10/dvd.base.iso b/PAYLOADS/2.10/dvd.base.iso new file mode 100644 index 0000000..8fbce33 Binary files /dev/null and b/PAYLOADS/2.10/dvd.base.iso differ diff --git a/PAYLOADS/2.10/eecrt0.ee.S b/PAYLOADS/2.10/eecrt0.ee.S new file mode 100644 index 0000000..3da509f --- /dev/null +++ b/PAYLOADS/2.10/eecrt0.ee.S @@ -0,0 +1,27 @@ +# ElReino & CTurt 2020 + +.section .text.startup + +.global _start +_start: + # Point stack to end of scratchpad RAM + #la $sp, 0x70004000 + + la $v0, 0x01FFF7D0 + sw $v0, 0($v0) + +.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 + +#ExecPS2: + #la $v1, 0x07 + #syscall 0x07 # ExecPS2 diff --git a/PAYLOADS/2.10/eecrt0.ee.o b/PAYLOADS/2.10/eecrt0.ee.o new file mode 100644 index 0000000..6358bfd Binary files /dev/null and b/PAYLOADS/2.10/eecrt0.ee.o differ diff --git a/PAYLOADS/2.10/eepayload.ee.bin b/PAYLOADS/2.10/eepayload.ee.bin new file mode 100644 index 0000000..e62d369 Binary files /dev/null and b/PAYLOADS/2.10/eepayload.ee.bin differ diff --git a/PAYLOADS/2.10/eepayload.ee.c b/PAYLOADS/2.10/eepayload.ee.c new file mode 100644 index 0000000..9a96d2d --- /dev/null +++ b/PAYLOADS/2.10/eepayload.ee.c @@ -0,0 +1,37 @@ +// 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 main(void) { + volatile int *waitAddress = (void *)0x21FFF7F0; + while(!*waitAddress); + + flush(); + + SifInitRpc(0); + SifExitRpc(); + while(!SifIopReset("", 0)); + while(!SifIopSync()){}; + + //SifInitRpc(0); + + volatile void **entry_point_address = (void *)0x01FFF7E0; + ExecPS2(*entry_point_address, 0, 0, 0); +} diff --git a/PAYLOADS/2.10/eepayload.ee.elf b/PAYLOADS/2.10/eepayload.ee.elf new file mode 100644 index 0000000..dc180e8 Binary files /dev/null and b/PAYLOADS/2.10/eepayload.ee.elf differ diff --git a/PAYLOADS/2.10/ioppayload.iop.bin b/PAYLOADS/2.10/ioppayload.iop.bin new file mode 100644 index 0000000..78ff2b6 Binary files /dev/null and b/PAYLOADS/2.10/ioppayload.iop.bin differ diff --git a/PAYLOADS/2.10/ioppayload.iop.c b/PAYLOADS/2.10/ioppayload.iop.c new file mode 100644 index 0000000..c773023 --- /dev/null +++ b/PAYLOADS/2.10/ioppayload.iop.c @@ -0,0 +1,247 @@ +// 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)) + +/* All of these could be reimplemented here, but I'm lazy so we will use whatever + * the IOP has already loaded. The addresses are hardcoded but should be easy + * enough to extract from IOP memory by looking for their module names and magic + * number 0x41C00000. + */ + +//int (*readSectors)(int count, int sector, void *destination) = (void *)0xb260c; // repacked ELF +int (*readSectors)(int count, int sector, void *destination) = (void *)(0xb260c + 0x5c700 - 0xb1000); // real hardware + +int (*sceSifSetDma)(struct SifDmaTransfer *, int num) = (void *)0x16fc8; +int (*sceSifDmaStat)(int trid) = (void *)0x17170; +void (*flushIcache)(void) = (void*)0x2f40; +void (*flushDcache)(void) = (void*)0x3148; +void (*printf)(char *, ...) = (void *)0x1ab84; + +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); + +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 = EE_CRT0_ADDRESS; + int one = 1; + int i; + + transfer_to_ee(EE_CRT0_ADDRESS, ee_crt0, ee_crt0_size); + + /* Corrupt all known return addresses in the stack. + */ + 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 */ + + + // 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 + + + //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; + } + + //unsigned char x[] = { 0x08, 0x00, 0xE0, 0x03, 0x01, 0x00, 0x42, 0x30, 0x01 }; + //memcpy(buffer, &x, sizeof(x)); + //memset(buffer + sizeof(x), 0, sizeofbuffer - sizeof(x)); + //transfer_to_ee(eph[i].vaddr + (eph[i].filesz & ~(0x10 - 1)), buffer, (remaining + 0xf) & ~(0x10 - 1)); + } + + 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; +} + +asm("\n\ +.global ee_crt0\n\ +ee_crt0:\n\ +.align 8\n\ +.incbin \"eepayload.ee.bin\"\n\ +ee_crt0_size: .word . - ee_crt0\n\ +"); diff --git a/PAYLOADS/2.10/ioppayload.iop.elf b/PAYLOADS/2.10/ioppayload.iop.elf new file mode 100644 index 0000000..ffcb352 Binary files /dev/null and b/PAYLOADS/2.10/ioppayload.iop.elf differ diff --git a/PAYLOADS/2.10/stage1.iop.S b/PAYLOADS/2.10/stage1.iop.S new file mode 100644 index 0000000..a223d97 --- /dev/null +++ b/PAYLOADS/2.10/stage1.iop.S @@ -0,0 +1,48 @@ +# ElReino & CTurt 2020 + +# entry 0xb7548 # repacked +# entry (0xb7548 + 0x5c700 - 0xb1000) = 0x62C48 (0xa0062C48) # hardware + + +#readSector = 0xb260c # repacked +readSector = (0xb260c + 0x5c700 - 0xb1000) # real hardware + +flushIcache = 0x00002f40 +flushDcache = 0x0003044 + +flushDcacheWrapper = 0x0057f1c + +#iop_payload_address = 0x460000 +#iop_payload_address = 0xa0460000 +iop_payload_address = 0xa00fd000 + +.section .text + +.global _start +_start: + move $fp, $sp # We need to reset $fp as it gets trashed by memcpy + + la $a0, (IOP_PAYLOAD_SIZE / 0x800) + 1 # count + la $a1, 0x700000 / 0x800 # sector + la $a2, iop_payload_address # destination + jal readSector + + #jal flushIcache + #jal flushDcache + + #jal ENTRY + la $v0, ENTRY + jalr $v0 + + # Return gracefully back to original return address + #la $a0, 0x1f62ac # repacked + la $a0, (0x1f62ac + 0x1F3058 - 0x1f6258) # hardware + + #la $ra, 0xb3630 # repacked + la $ra, (0xb3630 + 0x5c700 - 0xb1000) # hardware + + sw $ra, 0($a0) + + la $v0, 0 + + jr $ra diff --git a/PAYLOADS/2.10/stage1.iop.bin b/PAYLOADS/2.10/stage1.iop.bin new file mode 100644 index 0000000..d345213 Binary files /dev/null and b/PAYLOADS/2.10/stage1.iop.bin differ diff --git a/PAYLOADS/2.10/stage1.iop.elf b/PAYLOADS/2.10/stage1.iop.elf new file mode 100644 index 0000000..8e59a21 Binary files /dev/null and b/PAYLOADS/2.10/stage1.iop.elf differ diff --git a/PAYLOADS/2.10/syscalls.ee.S b/PAYLOADS/2.10/syscalls.ee.S new file mode 100644 index 0000000..0da0655 --- /dev/null +++ b/PAYLOADS/2.10/syscalls.ee.S @@ -0,0 +1,69 @@ +# ElReino 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 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 diff --git a/PAYLOADS/2.10/syscalls.ee.o b/PAYLOADS/2.10/syscalls.ee.o new file mode 100644 index 0000000..1392f5c Binary files /dev/null and b/PAYLOADS/2.10/syscalls.ee.o differ diff --git a/PREBUILT ISOs/2.10.iso b/PREBUILT ISOs/2.10.iso new file mode 100644 index 0000000..8fbce33 Binary files /dev/null and b/PREBUILT ISOs/2.10.iso differ diff --git a/README.md b/README.md index 9afd0ac..c2e35b9 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ 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). +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: @@ -57,13 +61,15 @@ Other suggestions that worked for others: ## 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. +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. **Currently only support:** +- 2.10 (tested on U and J regions on real hardware, any language works), + - 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 @@ -71,12 +77,12 @@ 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...** -For example, if your DVD Player version is 3.04M, you would want to burn `PREBUILT ISOs/3.04 only - M+maybe other regions except J - English language.iso`. +For example, if your DVD Player version is 2.10J, you would want to download `PREBUILT ISOs/2.10.iso`. ### Step 3, 4, 5 - Burn the ISO, set console language to English, and boot! These steps are the same as described for slim above. -## Custom disc setup +## Custom disc setup - Slim If you intend to make your own image containing additional homebrew / modified initial loader, please read on. ### Step 1: Copy your homebrew @@ -94,7 +100,10 @@ On Linux the easiest way is probably to use `genisoimage` as it comes pre-instal ### 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. -## Replacing 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: @@ -117,10 +126,13 @@ 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 +## Replacing the initial program - Phat +The ELF is read from `0x5bb000` in the ISO file. + ## 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 +## 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 `.bin` files into `VIDEO_TS/VIDEO_TS.IFO` at the offsets displayed by the output of the command.