Compare commits

...
Sign in to create a new pull request.

20 commits

Author SHA1 Message Date
hax
10375322cb More 2.12 regions, WIP 2.13
Signed-off-by: hax <hax@lainlounge.xyz>
2025-02-10 20:37:40 +00:00
CTurt
ba7fa5bbda 2.13 still not working :/ 2020-09-06 19:10:55 +01:00
CTurt
55fd6db5a5 Regression, fix 2.10/2.12 2020-08-18 18:23:33 +01:00
CTurt
442167e569 More 2.12 regions, WIP 2.13 2020-08-12 21:35:44 +01:00
CTurt
6d4efb401b 2.12U 2020-08-11 23:48:10 +01:00
CTurt
4a13fcfd3c PCSX2 compatible image for debugging 2020-08-11 20:22:34 +01:00
CTurt
f5e380970b 2.10 fix 2020-08-10 19:55:49 +01:00
CTurt
cb23569e91 2.10 2020-08-10 19:17:26 +01:00
CTurt
5dbb1b8aa7 HDD only - double whoops 2020-08-09 21:14:12 +01:00
CTurt
86171f8a8c 2.10E isn't working woops 2020-08-09 21:01:05 +01:00
CTurt
a53803d59c 2.10 support, using new bug 2020-08-09 20:34:59 +01:00
CTurt
e3b92c3c55 Maybe this helps 2020-07-24 22:21:13 +01:00
CTurt
3d34b14a71 Update README.md 2020-07-22 12:02:21 +01:00
CTurt
d18e32759f Revert some stuff, people having issues 2020-07-22 11:56:00 +01:00
CTurt
fe9b8cf26d 3.04M payload back 2020-07-19 15:28:05 +01:00
CTurt
478787c9ac Move payloads to same place 2020-07-19 15:23:20 +01:00
CTurt
e13a355ba0 Fixup 2020-07-19 14:59:31 +01:00
CTurt
698d91b10e 3.04 image now supports 3.10 and 3.11 too 2020-07-19 13:54:41 +01:00
CTurt
b207971522 Shrunk crt0 and added argv 2020-07-19 12:27:02 +01:00
CTurt
824aa4a54a 3.03 language independent 2020-07-19 00:13:19 +01:00
56 changed files with 1096 additions and 831 deletions

Binary file not shown.

View 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

Binary file not shown.

View 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

View 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:
}

View 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

View 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

View 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\
");

View 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];
}

View 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

View 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

View 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

View 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"

View file

@ -23,19 +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
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
ori $sp, 0x4000

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.

View 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

Binary file not shown.

BIN
PAYLOADS/3.03-3.11/jump.elf Normal file

Binary file not shown.

Binary file not shown.

View file

@ -95,7 +95,43 @@ __attribute__((noreturn)) void _start(void) {
int i;
// Identify version based on jump target location
if((*(void **)0x5f1f38) == (void *)0x1500014) {
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;
@ -161,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);
}

Binary file not shown.

View file

@ -1,20 +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=0x015FFF34 -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. fullpayload.bin at 0x0e8c, and payload.bin at 0x3000"

View file

@ -1,54 +0,0 @@
.set noreorder # If we're writing assembly, why would we want this?
.section .text.startup
.equ getBufferInternal, 0x262360
.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

Binary file not shown.

Binary file not shown.

View file

@ -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))0x2432c8)
#define getDiscData ((void (*)(unsigned int s, void *d))0x243438)
#define SifIopReset ((int (*)(char *, int))0x291fb8)
#define SifIopSync ((int (*)(void))0x292138)
#define SifInitRpc ((void (*)(int))0x2082a0)
#define SifExitRpc ((void (*)(void))0x208440)
#define getBufferInternal ((int (*)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos))0x262360)
#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.

View file

@ -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"

View file

@ -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.

View file

@ -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.

View file

@ -1,28 +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=0x01fff99c
echo $ENTRY
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 "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"

Binary file not shown.

View file

@ -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:
@ -11,7 +15,7 @@ All you need is:
- 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)
Download [`PREBUILT ISOs/All PS2 Slims - English language.iso`](https://git.lainlounge.xyz/hax/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:
@ -37,7 +41,7 @@ If you want to add additional homebrew to your DVD / replace uLaunchELF, please
|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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). |
| 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:
@ -46,23 +50,28 @@ Other suggestions that worked for others:
- 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) ImgBurn didn't work, but CDBurnerXP with 1x speed, compatibility settings, and finalize option worked.
- 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.
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:**
- 3.03 (tested only region E in emulator as other BIOS versions aren't available to me, but guess other regions will work - with English language set in settings),
- 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),
- 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
@ -70,12 +79,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
@ -93,7 +102,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:
@ -116,13 +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
## 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
## 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.
## 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.

View file

@ -1,348 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
</style>
</head>
<body>
<h1>3.03 - 3.11</h1>
<p>
These firmware versions all have the same getDiscData 0xffff * 3 * 8 buffer overflow of immediately controllable contents.
</p>
<table>
<tr>
<th></th>
<th>3.03</th>
<th>3.04J</th>
<th>3.04M</th>
<th>3.10</th>
<th>3.11</th>
</tr>
<tr>
<th style="text-align: center" colspan="6">Symbols</th>
</tr>
<tr>
<th>getDiscData</th>
<td></td>
<td>0x23e150</td>
<td>0x23e138</td>
<td>0x25c9f0</td>
<td>0x258b98</td>
</tr>
<tr>
<th>getDiscByte</th>
<td></td>
<td></td>
<td>0x23e068</td>
<td>0x25c920</td>
<td>0x258ac8</td>
</tr>
<tr>
<th>currentDiscBytePointer</th>
<td></td>
<td></td>
<td>0x16ceee4</td>
<td>0x1411fe4</td>
<td>0x143b3e4</td>
</tr>
<tr>
<th>endDiscBytePointer</th>
<td></td>
<td></td>
<td>0x16ceee8</td>
<td>0x1411fe8</td>
<td>0x143b3e8</td>
</tr>
<tr>
<th>0xff * 3 * 8 overflow</th>
<td></td>
<td></td>
<td>0x23cb04</td>
<td>0x25b3bc</td>
<td>0x257564</td>
</tr>
<tr>
<th>fpIndex</th>
<td></td>
<td></td>
<td>0x16cf74a</td>
<td>0x141284a</td>
<td>0x143bc4a</td>
</tr>
<tr>
<th>fpArray</th>
<td></td>
<td></td>
<td>0x95ace8</td>
<td>0x5b9d40</td>
<td>0x3b3050</td>
</tr>
<tr>
<th>OOB call</th>
<td></td>
<td></td>
<td>0x23faac</td>
<td>0x25e388</td>
<td>0x25ab44</td>
</tr>
<tr>
<th>getBufferInternal</th>
<td></td>
<td></td>
<td>0x261548</td>
<td></td>
<td></td>
</tr>
<tr>
<th>pointToIFO</th>
<td></td>
<td></td>
<td>0x23dfc8</td>
<td></td>
<td></td>
</tr>
<tr>
<th>SifIopReboot</th>
<td></td>
<td></td>
<td>0x291528</td>
<td></td>
<td></td>
</tr>
<tr>
<th>SifInitRpc</th>
<td></td>
<td></td>
<td>0x208260</td>
<td></td>
<td></td>
</tr>
<tr>
<th>SifExitRpc</th>
<td></td>
<td></td>
<td>0x208400</td>
<td></td>
<td></td>
</tr>
<tr>
<th>SifIopReset</th>
<td></td>
<td></td>
<td>0x291358</td>
<td></td>
<td></td>
</tr>
<tr>
<th>SifIopSync</th>
<td></td>
<td></td>
<td>0x2914d8</td>
<td></td>
<td></td>
</tr>
<tr>
<th style="text-align: center" colspan="6">Controlled memory ranges</th>
</tr>
<tr>
<th>Destination of large copy</th>
<td></td>
<td></td>
<td>0x16c8cd4</td>
<td>0x140bdd4</td>
<td>0x14351cc</td>
</tr>
<tr>
<th>Destination + max size</th>
<td></td>
<td></td>
<td>0x1848CBC</td>
<td>0x158BDBC</td>
<td>0x15B51B4</td>
</tr>
<tr>
<th>Sector buffer (getDiscByteInternal)</th>
<td></td>
<td></td>
<td>0x16cad40</td>
<td>0x140de40</td>
<td></td>
</tr>
<tr>
<th style="text-align: center" colspan="6">Exploit values</th>
</tr>
<tr>
<th>currentDiscBytePointer value at overwrite</th>
<td></td>
<td></td>
<td>0x016ce444</td>
<td>0x01411544</td>
<td>0x0143a94c</td>
</tr>
<tr>
<th>Jump target</th>
<td></td>
<td></td>
<td>0x01800180</td>
<td>0x01500014</td>
<td>0x01500014</td>
</tr>
<tr>
<th>Address of jump target</th>
<td></td>
<td></td>
<td>0x95CF40</td>
<td>0x5f1f38</td>
<td>0x3EA438</td>
</tr>
<tr>
<th style="text-align: center" colspan="6">IFO offsets</th>
</tr>
<tr>
<th>currentDiscBytePointer</th>
<td></td>
<td></td>
<td>0x2744</td>
<td>0x2744</td>
<td>0x277c</td>
</tr>
<tr>
<th>fpIndex</th>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<th>Payload</th>
<td></td>
<td></td>
<td>0x2d00</td>
<td>0x2bb4</td>
<td>0x2954</td>
</tr>
</table>
<br>
<h2>Conflicts</h2>
<p>
In order to merge 2 exploits into a single ISO there must be either:
</p>
<ul>
<li>No conflict between offset of currentDiscBytePointer corruption value in IFO file so that the two versions can specify different addresses (3.10 and 3.11),</li>
<li>Controlled memory at a common address between the two versions so that currentDiscBytePointer can be written to controlled memory region for both (3.04J and 3.04M),</li>
</ul>
<p>
We might also be able to force a non-conflict between 2 versions by making use of 2 different buffer overflows. That would need to be experimented with. Until then, here is a table for the versions with conflicting currentDiscBytePointer IFO offsets which we would need to be common controlled memory regions for:
</p>
<table>
<tr>
<th></th>
<th>Common controlled memory</th>
</tr>
<tr>
<th>3.04 + 3.10</th>
<td>Couldn't find any</td>
</tr>
<tr>
<th>3.04J + 3.04M</th>
<td></td>
</tr>
</table>
<br>
<h1>&lt; 3.03</h1>
<p>
These firmwares don't use the same getDiscData stream reader API, instead they manually call getBuffer and then memcpy from that sectorBuffer somewhere else. They still contain the vulnerability, but as it occurs from memcpy of OOB memory into other OOB memory, it is not just immediately possible for the full memory range overflowed with to contain fully controlled contents.
</p>
<p>
Let's look at 3.02 specifically.
</p>
<pre><code>0x256668 - getBufferInternal
0x256888 - getBuffer</pre></code>
<br>
<p>
Searching calls to getBuffer, it's always a fixed number of sectors, 1 to 4, so as previously stated we can't just overflow straight into fpIndex with controlled contents as in &gt; 3.02.
</p>
<p>
But, <b>the buffer overflows definitely do still exist</b>. The function at 0x23e560 is a nice self contained one:
</p>
<pre><code>long bufferOverflow(void) {
long lVar1;
lVar1 = getBuffer(s_VIDEO_TS.IFO_0090c210,(long)(int)DAT_013c7840,sectorBuffer,1,0);
if (lVar1 == 0) {
someLengthFromIFO = (ushort)sectorBuffer[0] * 0x100 + (ushort)sectorBuffer[1];
DAT_013c7890 = ((long)(int)((uint)sectorBuffer[4] << 0x18) | (ulong)sectorBuffer[5] << 0x10) +
(ulong)sectorBuffer[6] * 0x100 + (ulong)sectorBuffer[7];
memcpy(&PTR_DAT_013c7898,sectorBuffer + 8,(uint)someLengthFromIFO * 0xc);
lVar1 = 0;
}
return lVar1;
}</code></pre>
<br>
<p>
The memcpy call can overwrite memory from 0x013c7898 to 0x148788C (0x013c7898 + 0xffff * 0xc). The buffer overflow we are triggering in all other exploits because it gives biggest size is at 0x240284:
</p>
<pre><code>
length2 = (ushort)sectorBuffer[uVar33 + 2] * 0x100 + (ushort)sectorBuffer[uVar33 + 3];
length1 = (ushort)sectorBuffer[uVar33] * 0x100 + (ushort)sectorBuffer[uVar33 + 1];
length3 = (ushort)sectorBuffer[uVar33 + 4] * 0x100 + (ushort)sectorBuffer[uVar33 + 5];
DAT_013c9a2e = (ushort)sectorBuffer[uVar33 + 6] * 0x100 + (ushort)sectorBuffer[uVar33 + 7];
memcpy(&DAT_013c9a30,sectorBuffer + uVar33 + 8,
((uint)length1 + (uint)length2 + (uint)length3) * 8);</code></pre>
<br>
<p>
fpIndex is at 0x13cfaca (leading to OOB call at 0x242f6c), and if we can set that to a controlled value we potentially have an exploit (if there's a good jump target).
</p>
<p>
fpIndex can be overwritten by either of the memcpy buffer overflows shown with a large enough size, but we're not corrupting it with data coming straight from disc; we only read at most 4 sectors (0x800 * 4) = 0x2000 into sectorBuffer, however we need to memcpy 0x609A bytes from sectorBuffer into 0x13c9a30 to overwrite fpIndex (0x13cfaca-0x13c9a30), so we'll be copying from uncontrolled OOB memory into fpIndex.
</p>
<p>
So, can we make that OOB memory contain controlled contents? Well, by making use of that buffer overflow, we can shift the question from "can we control fpIndex (0x13cfaca)", to "can we control sectorBuffer + 0x609A = 0x13D331A", since if we control that the memcpy will then copy into fpIndex from an address we can control the contents of.
</p>
<p>
Looking at all of the copies - maybe you will be lucky and find that it happens to line up that after a series of copies - some value you control ends up in fpIndex. Will need more time on it.
</p>
<br>
</body>
</html>