2010-04-24 21:37:39 +00:00
|
|
|
/*********************************************************************
|
|
|
|
* Copyright (C) 2003 Tord Lindstrom (pukko@home.se)
|
|
|
|
* Copyright (C) 2004 adresd (adresd_ps2dev@yahoo.com)
|
|
|
|
* This file is subject to the terms and conditions of the PS2Link License.
|
|
|
|
* See the file LICENSE in the main directory of this distribution for more
|
|
|
|
* details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "stdio.h"
|
|
|
|
#include <tamtypes.h>
|
|
|
|
#include <kernel.h>
|
|
|
|
#include <sifrpc.h>
|
|
|
|
#include <loadfile.h>
|
|
|
|
#include <iopcontrol.h>
|
|
|
|
#include <fileio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "debug.h"
|
|
|
|
#include "excepHandler.h"
|
|
|
|
|
|
|
|
#include "byteorder.h"
|
|
|
|
#include "ps2regs.h"
|
|
|
|
#include "hostlink.h"
|
|
|
|
|
|
|
|
//#define scr_printf(args...) printf(args)
|
|
|
|
//#define init_scr() do { } while(0)
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define dbgprintf(args...) printf(args)
|
|
|
|
#else
|
|
|
|
#define dbgprintf(args...) do { } while(0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if HOOK_THREADS
|
|
|
|
extern void KillActiveThreads(void);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Prototypes
|
|
|
|
static int cmdThread(void);
|
|
|
|
static int pkoStopVU(pko_pkt_stop_vu *);
|
|
|
|
static int pkoStartVU(pko_pkt_start_vu *);
|
|
|
|
static int pkoDumpMem(pko_pkt_mem_io *);
|
|
|
|
static int pkoDumpReg(pko_pkt_dump_regs *);
|
|
|
|
void pkoReset(void);
|
|
|
|
static int pkoLoadElf(char *path);
|
|
|
|
static int pkoGSExec(pko_pkt_gsexec_req *);
|
|
|
|
static int pkoWriteMem(pko_pkt_mem_io *);
|
|
|
|
|
|
|
|
|
|
|
|
// Flags for which type of boot (oh crap, make a header file dammit)
|
|
|
|
#define B_CD 1
|
|
|
|
#define B_MC 2
|
|
|
|
#define B_HOST 3
|
|
|
|
#define B_CC 4
|
|
|
|
#define B_UNKN 5
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Globals
|
|
|
|
extern u32 _start;
|
|
|
|
extern int _gp;
|
|
|
|
extern int boot;
|
|
|
|
extern char elfName[];
|
|
|
|
|
|
|
|
int userThreadID = 0;
|
|
|
|
static int cmdThreadID = 0;
|
|
|
|
static char userThreadStack[16*1024] __attribute__((aligned(16)));
|
|
|
|
static char cmdThreadStack[16*1024] __attribute__((aligned(64)));
|
|
|
|
static char dataBuffer[16384] __attribute__((aligned(16)));
|
|
|
|
|
|
|
|
// The 'global' argv string area
|
|
|
|
static char argvStrings[PKO_MAX_PATH];
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// How about that header file again?
|
|
|
|
#define MAX_ARGS 16
|
|
|
|
#define MAX_ARGLEN 256
|
|
|
|
|
|
|
|
struct argData
|
|
|
|
{
|
|
|
|
int flag; // Contains thread id atm
|
|
|
|
int argc;
|
|
|
|
char *argv[MAX_ARGS];
|
|
|
|
} __attribute__((packed)) userArgs;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
int sifCmdSema;
|
|
|
|
int sif0HandlerId = 0;
|
|
|
|
// XXX: Hardcoded address atm.. Should be configurable!!
|
|
|
|
unsigned int *sifDmaDataPtr =(unsigned int*)(0x20100000-2048);
|
|
|
|
int excepscrdump = 1;
|
|
|
|
|
|
|
|
extern int pkoExecEE(pko_pkt_execee_req *cmd);
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Create the argument struct to send to the user thread
|
|
|
|
int
|
|
|
|
makeArgs(int cmdargc, char *cmdargv, struct argData *arg_data)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int t;
|
|
|
|
int argc;
|
|
|
|
|
|
|
|
argc = 0;
|
|
|
|
|
|
|
|
if (cmdargc > MAX_ARGS)
|
|
|
|
cmdargc = MAX_ARGS;
|
|
|
|
cmdargv[PKO_MAX_PATH-1] = '\0';
|
|
|
|
|
|
|
|
memcpy(argvStrings, cmdargv, PKO_MAX_PATH);
|
|
|
|
|
|
|
|
dbgprintf("cmd->argc %d, argv[0]: %s\n", cmdargc, cmdargv);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
t = 0;
|
|
|
|
do {
|
|
|
|
arg_data->argv[i] = &argvStrings[t];
|
|
|
|
dbgprintf("arg_data[%d]=%s\n", i, arg_data->argv[i]);
|
|
|
|
dbgprintf("argvStrings[%d]=%s\n", t, &argvStrings[t]);
|
|
|
|
t += strlen(&argvStrings[t]);
|
|
|
|
t++;
|
|
|
|
i++;
|
|
|
|
} while ((i < cmdargc) && (t < PKO_MAX_PATH));
|
|
|
|
|
|
|
|
arg_data->argc = i;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Load the actual elf, and create a thread for it
|
|
|
|
// Return the thread id
|
|
|
|
static int
|
|
|
|
pkoLoadElf(char *path)
|
|
|
|
{
|
|
|
|
ee_thread_t th_attr;
|
|
|
|
t_ExecData elfdata;
|
|
|
|
int ret;
|
|
|
|
int pid;
|
|
|
|
|
|
|
|
ret = SifLoadElf(path, &elfdata);
|
|
|
|
|
|
|
|
FlushCache(0);
|
|
|
|
FlushCache(2);
|
|
|
|
|
|
|
|
dbgprintf("EE: LoadElf returned %d\n", ret);
|
|
|
|
|
2010-04-25 00:31:27 +00:00
|
|
|
dbgprintf("EE: Creating user thread (ent: %x, gp: %x, st: %x)\n",
|
2010-04-24 21:37:39 +00:00
|
|
|
elfdata.epc, elfdata.gp, elfdata.sp);
|
|
|
|
|
|
|
|
if (elfdata.epc == 0) {
|
|
|
|
dbgprintf("EE: Could not load file\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
th_attr.func = (void *)elfdata.epc;
|
|
|
|
th_attr.stack = userThreadStack;
|
|
|
|
th_attr.stack_size = sizeof(userThreadStack);
|
|
|
|
th_attr.gp_reg = (void *)elfdata.gp;
|
|
|
|
th_attr.initial_priority = 64;
|
|
|
|
|
|
|
|
pid = CreateThread(&th_attr);
|
|
|
|
if (pid < 0) {
|
|
|
|
printf("EE: Create user thread failed %d\n", pid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dbgprintf("EE: Created user thread: %d\n", pid);
|
|
|
|
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Load and start the requested elf
|
|
|
|
extern int pkoExecEE(pko_pkt_execee_req *cmd)
|
|
|
|
{
|
|
|
|
char path[PKO_MAX_PATH];
|
|
|
|
int ret;
|
|
|
|
int pid;
|
|
|
|
|
|
|
|
if (userThreadID) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dbgprintf("EE: Executing file %s...\n", cmd->argv);
|
|
|
|
memcpy(path, cmd->argv, PKO_MAX_PATH);
|
|
|
|
|
|
|
|
scr_printf("Executing file %s...\n", path);
|
|
|
|
|
|
|
|
pid = pkoLoadElf(path);
|
|
|
|
if (pid < 0) {
|
|
|
|
scr_printf("Could not execute file %s\n", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
FlushCache(0);
|
|
|
|
FlushCache(2);
|
|
|
|
|
|
|
|
userThreadID = pid;
|
|
|
|
|
|
|
|
makeArgs(ntohl(cmd->argc), path, &userArgs);
|
|
|
|
|
|
|
|
// Hack away..
|
|
|
|
userArgs.flag = (int)&userThreadID;
|
|
|
|
|
|
|
|
ret = StartThread(userThreadID, &userArgs);
|
|
|
|
if (ret < 0) {
|
|
|
|
printf("EE: Start user thread failed %d\n", ret);
|
|
|
|
cmdThreadID = 0;
|
|
|
|
DeleteThread(userThreadID);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// takes cmd->data and sends it to GIF via path1
|
|
|
|
static int
|
|
|
|
pkoGSExec(pko_pkt_gsexec_req *cmd) {
|
|
|
|
int fd;
|
|
|
|
int len;
|
|
|
|
fd = fioOpen(cmd->file, O_RDONLY);
|
|
|
|
if ( fd < 0 ) {
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
len = fioRead(fd, dataBuffer, 128);
|
|
|
|
fioClose(fd);
|
|
|
|
// stop/reset dma02
|
|
|
|
|
|
|
|
// dmasend via GIF channel
|
|
|
|
asm __volatile__(
|
|
|
|
"move $10, %0;"
|
|
|
|
"move $11, %1;"
|
|
|
|
"lui $8, 0x1001;"
|
|
|
|
"sw $11, -24544($8);"
|
|
|
|
"sw $10, -24560($8);"
|
|
|
|
"ori $9, $0, 0x101;"
|
|
|
|
"sw $9, -24576($8);"
|
|
|
|
:: "r" (dataBuffer), "r" ((ntohs(cmd->size))/16) );
|
|
|
|
|
|
|
|
// dmawait for GIF channel
|
|
|
|
asm __volatile__(
|
|
|
|
"lui $8, 0x1001;"
|
|
|
|
"dmawait:"
|
|
|
|
"lw $9, -24576($8);"
|
|
|
|
"nop;"
|
|
|
|
"andi $9, $9, 0x100;"
|
|
|
|
"nop;"
|
|
|
|
"bnez $9, dmawait;"
|
|
|
|
"nop;"
|
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// command to dump cmd->size bytes of memory from cmd->offset
|
2010-04-25 00:31:27 +00:00
|
|
|
static int
|
2010-04-24 21:37:39 +00:00
|
|
|
pkoDumpMem(pko_pkt_mem_io *cmd) {
|
|
|
|
int fd;
|
|
|
|
int total, len;
|
|
|
|
unsigned int offset;
|
|
|
|
unsigned int size;
|
|
|
|
char path[PKO_MAX_PATH];
|
|
|
|
int ret = 0;
|
|
|
|
size = ntohl(cmd->size);
|
|
|
|
offset = ntohl(cmd->offset);
|
2010-04-25 00:31:27 +00:00
|
|
|
scr_printf("dump mem from 0x%x, size %d\n",
|
2010-04-24 21:37:39 +00:00
|
|
|
ntohl(cmd->offset), ntohl(cmd->size)
|
|
|
|
);
|
|
|
|
memcpy(path, cmd->argv, PKO_MAX_PATH);
|
|
|
|
fd = fioOpen(path, O_WRONLY|O_CREAT);
|
|
|
|
total = 0;
|
|
|
|
len = 16*1024;
|
|
|
|
if ( fd > 0 ) {
|
|
|
|
while(total < size) {
|
|
|
|
if ( size < len) {
|
|
|
|
len = size;
|
|
|
|
} else if ((size - total) < len) {
|
|
|
|
len = size - total;
|
|
|
|
}
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2010-04-24 21:37:39 +00:00
|
|
|
memcpy(dataBuffer, (void *)offset, len);
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2010-04-24 21:37:39 +00:00
|
|
|
if ((ret = fioWrite(fd, (void *)dataBuffer, len)) > 0) {
|
|
|
|
} else {
|
|
|
|
printf("EE: pkoDumpMem() fioWrite failed\n");
|
|
|
|
return fd;
|
2010-04-25 00:31:27 +00:00
|
|
|
}
|
|
|
|
offset = offset + len;
|
2010-04-24 21:37:39 +00:00
|
|
|
total += len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fioClose(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
pkoWriteMem(pko_pkt_mem_io *cmd) {
|
|
|
|
int fd, len, total;
|
|
|
|
unsigned int offset;
|
|
|
|
unsigned int size;
|
|
|
|
char path[PKO_MAX_PATH];
|
|
|
|
int ret = 0;
|
|
|
|
size = ntohl(cmd->size);
|
|
|
|
offset = ntohl(cmd->offset);
|
2010-04-25 00:31:27 +00:00
|
|
|
scr_printf("write mem to 0x%x, size %d\n",
|
2010-04-24 21:37:39 +00:00
|
|
|
ntohl(cmd->offset), ntohl(cmd->size)
|
|
|
|
);
|
|
|
|
memcpy(path, cmd->argv, PKO_MAX_PATH);
|
|
|
|
fd = fioOpen(path, O_RDONLY);
|
|
|
|
total = 0;
|
|
|
|
len = 16*1024;
|
|
|
|
if( fd > 0) {
|
|
|
|
while(total < size) {
|
|
|
|
if ( size < len) {
|
|
|
|
len = size;
|
|
|
|
} else if ((size - total) < len) {
|
|
|
|
len = size - total;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = fioRead(fd, (void *)dataBuffer, len)) > 0) {
|
|
|
|
} else {
|
|
|
|
printf("EE: pkoDumpMem() fioWrite failed\n");
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy((void *)offset, dataBuffer, len);
|
|
|
|
offset = offset + len;
|
|
|
|
total += len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fioClose(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// command to stop VU0/1 and VIF0/1
|
|
|
|
static int
|
|
|
|
pkoStopVU(pko_pkt_stop_vu *cmd) {
|
|
|
|
if ( ntohs(cmd->vpu) == 0 ) {
|
|
|
|
asm(
|
|
|
|
"ori $25, $0, 0x1;"
|
|
|
|
"ctc2 $25, $28;"
|
|
|
|
"sync.p;"
|
|
|
|
"vnop;"
|
|
|
|
);
|
|
|
|
VIF0_FBRST = 0x2;
|
|
|
|
} else if ( ntohs(cmd->vpu) == 1 ) {
|
|
|
|
asm(
|
|
|
|
"ori $25, $0, 0x100;"
|
|
|
|
"ctc2 $25, $28;"
|
|
|
|
"sync.p;"
|
|
|
|
"vnop;"
|
|
|
|
);
|
|
|
|
VIF1_FBRST = 0x2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// command to reset VU0/1 VIF0/1
|
|
|
|
static int
|
|
|
|
pkoStartVU(pko_pkt_start_vu *cmd) {
|
|
|
|
if ( ntohs(cmd->vpu) == 0 ) {
|
|
|
|
asm(
|
|
|
|
"ori $25, $0, 0x2;"
|
|
|
|
"ctc2 $25, $28;"
|
|
|
|
"sync.p;"
|
|
|
|
"vnop;"
|
|
|
|
);
|
|
|
|
VIF0_FBRST = 0x8;
|
|
|
|
} else if ( ntohs(cmd->vpu) == 1 ) {
|
|
|
|
asm(
|
|
|
|
"ori $25, $0, 0x200;"
|
|
|
|
"ctc2 $25, $28;"
|
|
|
|
"sync.p;"
|
|
|
|
"vnop;"
|
|
|
|
);
|
|
|
|
VIF1_FBRST = 0x8;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
|
|
pkoReset(void)
|
|
|
|
{
|
|
|
|
char *argv[1];
|
|
|
|
// Check if user thread is running, if so kill it
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
|
|
|
#if HOOK_THREADS
|
|
|
|
KillActiveThreads();
|
|
|
|
#else
|
|
|
|
if (userThreadID) {
|
|
|
|
TerminateThread(userThreadID);
|
|
|
|
DeleteThread(userThreadID);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
userThreadID = 0;
|
|
|
|
|
|
|
|
RemoveDmacHandler(5, sif0HandlerId);
|
|
|
|
sif0HandlerId = 0;
|
|
|
|
|
|
|
|
SifInitRpc(0);
|
|
|
|
//cdvdInit(CDVD_INIT_NOWAIT);
|
|
|
|
//cdvdInit(CDVD_EXIT);
|
|
|
|
SifIopReset(NULL, 0);
|
|
|
|
SifExitRpc();
|
|
|
|
while(SifIopSync());
|
|
|
|
#if 1
|
|
|
|
SifInitRpc(0);
|
|
|
|
//cdvdExit();
|
|
|
|
SifExitRpc();
|
|
|
|
#endif
|
|
|
|
FlushCache(0);
|
|
|
|
|
|
|
|
#ifdef USE_CACHED_CFG
|
|
|
|
argv[0] = elfName;
|
|
|
|
SifLoadFileExit();
|
|
|
|
ExecPS2(&_start, 0, 1, argv);
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ((boot == B_MC) || (boot == B_HOST) || (boot == B_UNKN) || (boot == B_CC)) {
|
|
|
|
argv[0] = elfName;
|
|
|
|
SifLoadFileExit();
|
|
|
|
ExecPS2(&_start, 0, 1, argv);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LoadExecPS2(elfName, 0, NULL);
|
|
|
|
}
|
|
|
|
}
|