IOP: Convert most IOP memory access in the IRX HLE and debugging module to

safe access through iopMem* functions.
This commit is contained in:
Pseudonym 2016-11-08 10:12:38 +00:00 committed by sudonim1
parent d3a748ce3a
commit b3b1f3ac68
7 changed files with 192 additions and 119 deletions

View File

@ -91,10 +91,42 @@ namespace R3000A {
#define ra (psxRegs.GPR.n.ra)
#define pc (psxRegs.pc)
#define Ra0 (iopVirtMemR<char>(a0))
#define Ra1 (iopVirtMemR<char>(a1))
#define Ra2 (iopVirtMemR<char>(a2))
#define Ra3 (iopVirtMemR<char>(a3))
#define Ra0 (iopMemReadString(a0))
#define Ra1 (iopMemReadString(a1))
#define Ra2 (iopMemReadString(a2))
#define Ra3 (iopMemReadString(a3))
static std::string host_path(const std::string path)
{
// WIP code. Works well on win32, not so sure on unixes
// TODO: get rid of dependency on CWD/PWD
#if USE_HOST_REWRITE
// we want filenames to be relative to pcs2dir / host
std::string pathMod;
// partial "rooting",
// it will NOT avoid a path like "../../x" from escaping the pcsx2 folder!
const std::string _local_root = "/usr/local/";
if (HOST_REWRITE_USR_LOCAL && 0 == path.compare(0, _local_root.size(), _local_root.data())) {
return HostRoot + path.substr(_local_root.size());
} else if ((path[0] == '/') || (path[0] == '\\') || (isalpha(path[0]) && (path[1] == ':'))) // absolute NATIVE path (X:\blah)
{
// TODO: allow some way to use native paths in non-windows platforms
// maybe hack it so linux prefixes the path with "X:"? ;P
// or have all platforms use a common prefix for native paths
// FIXME: Why the hell would we allow this?
return path;
} else // relative paths
return HostRoot + path;
return pathMod;
#else
return path;
#endif
}
// TODO: sandbox option, other permissions
class HostFile : public IOManFile
@ -128,49 +160,14 @@ public:
}
}
static int open(IOManFile **file, const char *name, s32 flags, u16 mode)
static int open(IOManFile **file, const std::string &full_path, s32 flags, u16 mode)
{
const char *path = strchr(name, ':') + 1;
const std::string path = full_path.substr(full_path.rfind(':') + 1);
// host: actually DOES let you write!
//if (flags != IOP_O_RDONLY)
// return -IOP_EROFS;
// WIP code. Works well on win32, not so sure on unixes
// TODO: get rid of dependency on CWD/PWD
#if USE_HOST_REWRITE
// we want filenames to be relative to pcs2dir / host
static char pathMod[1024];
// partial "rooting",
// it will NOT avoid a path like "../../x" from escaping the pcsx2 folder!
#if HOST_REWRITE_USR_LOCAL
const char *_local_root = "/usr/local/";
if(strncmp(path,_local_root,strlen(_local_root))==0)
{
strcpy(pathMod,HostRoot);
strcat(pathMod,path+strlen(_local_root));
}
else
#endif
if((path[0] == '/') || (path[0] == '\\') || (isalpha(path[0]) && (path[1] == ':'))) // absolute NATIVE path (X:\blah)
{
// TODO: allow some way to use native paths in non-windows platforms
// maybe hack it so linux prefixes the path with "X:"? ;P
// or have all platforms use a common prefix for native paths
strcpy(pathMod,path);
}
else // relative paths
{
strcpy(pathMod,HostRoot);
strcat(pathMod,path);
}
#else
const char* pathMod = path;
#endif
int native_flags = O_BINARY; // necessary in Windows.
switch(flags&IOP_O_RDWR)
@ -184,7 +181,7 @@ public:
if(flags&IOP_O_CREAT) native_flags |= O_CREAT;
if(flags&IOP_O_TRUNC) native_flags |= O_TRUNC;
int hostfd = ::open(pathMod, native_flags);
int hostfd = ::open(host_path(path).data(), native_flags);
if (hostfd < 0)
return translate_error(hostfd);
@ -328,15 +325,21 @@ namespace ioman {
fds[i].close();
}
bool is_host(const std::string path)
{
if ((!g_GameStarted || EmuConfig.HostFs) && 0 == path.compare(0, 4, "host") && path[path.find_first_not_of("0123456789", 4)] == ':')
return true;
return false;
}
int open_HLE()
{
IOManFile *file = NULL;
const char *name = Ra0;
const std::string path = Ra0;
s32 flags = a1;
u16 mode = a2;
if ((!g_GameStarted || EmuConfig.HostFs)
&& !strncmp(name, "host", 4) && name[4 + strspn(name + 4, "0123456789")] == ':')
if (is_host(path))
{
if (!freefdcount())
{
@ -345,7 +348,7 @@ namespace ioman {
return 1;
}
int err = HostFile::open(&file, name, flags, mode);
int err = HostFile::open(&file, path, flags, mode);
if (err != 0 || !file)
{
@ -403,15 +406,26 @@ namespace ioman {
int read_HLE()
{
s32 fd = a0;
u32 buf = a1;
u32 data = a1;
u32 count = a2;
if (IOManFile *file = getfd<IOManFile>(fd))
{
if (!iopVirtMemR<void>(buf))
return 0;
v0 = file->read(iopVirtMemW<void>(buf), count);
char *buf;
try {
buf = new char[count];
v0 = file->read(buf, count);
}
catch (const std::bad_alloc &) {
v0 = -IOP_ENOMEM;
}
catch (...) {
delete[] buf;
throw;
}
for (s32 i = 0; i < (s32)v0; i++)
iopMemWrite8(data + i, buf[i]);
delete[] buf;
pc = ra;
return 1;
}
@ -422,22 +436,32 @@ namespace ioman {
int write_HLE()
{
s32 fd = a0;
u32 buf = a1;
u32 data = a1;
u32 count = a2;
if (fd == 1) // stdout
{
iopConLog(ShiftJIS_ConvertString(Ra1, a2));
const std::string s = Ra1;
iopConLog(ShiftJIS_ConvertString(s.data(), a2));
pc = ra;
v0 = a2;
return 1;
}
else if (IOManFile *file = getfd<IOManFile>(fd))
{
if (!iopVirtMemR<void>(buf))
return 0;
v0 = file->write(iopVirtMemW<void>(buf), count);
char *buf = NULL;
try {
buf = new char[count];
for (u32 i = 0; i < count; i++)
buf[i] = iopMemRead8(data + i);
v0 = file->write(buf, count);
} catch (const std::bad_alloc &) {
v0 = -IOP_ENOMEM;
} catch (...) {
delete[] buf;
throw;
}
delete[] buf;
pc = ra;
return 1;
}
@ -456,6 +480,7 @@ namespace sysmem {
iopMemWrite32(sp + 12, a3);
pc = ra;
const std::string fmt = Ra0;
// From here we're intercepting the Kprintf and piping it to our console, complete with
// printf-style formatting processing. This part can be skipped if the user has the
@ -467,33 +492,33 @@ namespace sysmem {
char *ptmp = tmp;
int n=1, i=0, j = 0;
while (Ra0[i])
while (fmt[i])
{
switch (Ra0[i])
switch (fmt[i])
{
case '%':
j = 0;
tmp2[j++] = '%';
_start:
switch (Ra0[++i])
switch (fmt[++i])
{
case '.':
case 'l':
tmp2[j++] = Ra0[i];
tmp2[j++] = fmt[i];
goto _start;
default:
if (Ra0[i] >= '0' && Ra0[i] <= '9')
if (fmt[i] >= '0' && fmt[i] <= '9')
{
tmp2[j++] = Ra0[i];
tmp2[j++] = fmt[i];
goto _start;
}
break;
}
tmp2[j++] = Ra0[i];
tmp2[j++] = fmt[i];
tmp2[j] = 0;
switch (Ra0[i])
switch (fmt[i])
{
case 'f': case 'F':
ptmp+= sprintf(ptmp, tmp2, (float)iopMemRead32(sp + n * 4));
@ -522,12 +547,15 @@ _start:
break;
case 's':
ptmp+= sprintf(ptmp, tmp2, iopVirtMemR<char>(iopMemRead32(sp + n * 4)));
n++;
{
std::string s = iopMemReadString(iopMemRead32(sp + n * 4));
ptmp += sprintf(ptmp, tmp2, s.data());
n++;
}
break;
case '%':
*ptmp++ = Ra0[i];
*ptmp++ = fmt[i];
break;
default:
@ -537,7 +565,7 @@ _start:
break;
default:
*ptmp++ = Ra0[i++];
*ptmp++ = fmt[i++];
break;
}
}
@ -551,7 +579,8 @@ _start:
namespace loadcore {
void RegisterLibraryEntries_DEBUG()
{
DevCon.WriteLn(Color_Gray, "RegisterLibraryEntries: %8.8s", iopVirtMemR<char>(a0 + 12));
const std::string modname = iopMemReadString(a0 + 12);
DevCon.WriteLn(Color_Gray, "RegisterLibraryEntries: %8.8s version %x.%02x", modname.data(), (unsigned)iopMemRead8(a0 + 9), (unsigned)iopMemRead8(a0 + 8));
}
}
@ -589,18 +618,21 @@ namespace sifcmd {
}
}
const char* irxImportLibname(u32 entrypc)
const u32 irxImportTableAddr(u32 entrypc)
{
u32 i;
i = entrypc;
while (iopMemRead32(i -= 4) != 0x41e00000) // documented magic number
;
i = entrypc - 0x18;
while (entrypc - i < 0x2000) {
if (iopMemRead32(i) == 0x41e00000)
return i;
i -= 4;
}
return iopVirtMemR<char>(i + 12);
return 0;
}
const char* irxImportFuncname(const char libname[8], u16 index)
const char* irxImportFuncname(const std::string &libname, u16 index)
{
#include "IopModuleNames.cpp"
@ -614,12 +646,12 @@ const char* irxImportFuncname(const char libname[8], u16 index)
return 0;
}
#define MODULE(n) if (!strncmp(libname, #n, 8)) { using namespace n; switch (index) {
#define MODULE(n) if (#n == libname) { using namespace n; switch (index) {
#define END_MODULE }}
#define EXPORT_D(i, n) case (i): return n ## _DEBUG;
#define EXPORT_H(i, n) case (i): return n ## _HLE;
irxHLE irxImportHLE(const char libname[8], u16 index)
irxHLE irxImportHLE(const std::string &libname, u16 index)
{
// debugging output
MODULE(sysmem)
@ -637,7 +669,7 @@ irxHLE irxImportHLE(const char libname[8], u16 index)
return 0;
}
irxDEBUG irxImportDebug(const char libname[8], u16 index)
irxDEBUG irxImportDebug(const std::string &libname, u16 index)
{
MODULE(loadcore)
EXPORT_D( 6, RegisterLibraryEntries)
@ -657,15 +689,24 @@ irxDEBUG irxImportDebug(const char libname[8], u16 index)
#undef EXPORT_D
#undef EXPORT_H
void __fastcall irxImportLog(const char libname[8], u16 index, const char *funcname)
void irxImportLog(const std::string &libname, u16 index, const char *funcname)
{
PSXBIOS_LOG("%8.8s.%03d: %s (%x, %x, %x, %x)",
libname, index, funcname ? funcname : "unknown",
libname.data(), index, funcname ? funcname : "unknown",
a0, a1, a2, a3);
}
int __fastcall irxImportExec(const char libname[8], u16 index)
void __fastcall irxImportLog_rec(u32 import_table, u16 index, const char *funcname)
{
irxImportLog(iopMemReadString(import_table + 12, 8), index, funcname);
}
int irxImportExec(u32 import_table, u16 index)
{
if (!import_table)
return 0;
std::string libname = iopMemReadString(import_table + 12, 8);
const char *funcname = irxImportFuncname(libname, index);
irxHLE hle = irxImportHLE(libname, index);
irxDEBUG debug = irxImportDebug(libname, index);

View File

@ -20,6 +20,7 @@
#define IOP_EIO 5
#define IOP_ENOMEM 12
#define IOP_EACCES 13
#define IOP_ENODEV 19
#define IOP_EISDIR 21
#define IOP_EMFILE 24
#define IOP_EROFS 30
@ -38,7 +39,10 @@
class IOManFile {
public:
// int open(IOManFile **file, char *name, s32 flags, u16 mode);
static int open(IOManFile **file, const std::string &path, s32 flags, u16 mode)
{
return -IOP_ENODEV;
}
virtual void close() = 0;
@ -59,12 +63,13 @@ typedef void (*irxDEBUG)();
namespace R3000A
{
const char* irxImportLibname(u32 entrypc);
const char* irxImportFuncname(const char libname[8], u16 index);
irxHLE irxImportHLE(const char libname[8], u16 index);
irxDEBUG irxImportDebug(const char libname[8], u16 index);
void __fastcall irxImportLog(const char libname[8], u16 index, const char *funcname);
int __fastcall irxImportExec(const char libname[8], u16 index);
const u32 irxImportTableAddr(u32 entrypc);
const char* irxImportFuncname(const std::string &libname, u16 index);
irxHLE irxImportHLE(const std::string &libnam, u16 index);
irxDEBUG irxImportDebug(const std::string & libname, u16 index);
void irxImportLog(const std::string &libnameptr, u16 index, const char *funcname);
void __fastcall irxImportLog_rec(u32 import_table, u16 index, const char *funcname);
int irxImportExec(u32 import_table, u16 index);
namespace ioman
{

View File

@ -490,3 +490,14 @@ void __fastcall iopMemWrite32(u32 mem, u32 value)
}
}
}
std::string iopMemReadString(u32 mem, int maxlen)
{
std::string ret;
char c;
while ((c = iopMemRead8(mem++)) && maxlen--)
ret.push_back(c);
return ret;
}

View File

@ -83,6 +83,8 @@ extern void __fastcall iopMemWrite8 (u32 mem, u8 value);
extern void __fastcall iopMemWrite16(u32 mem, u16 value);
extern void __fastcall iopMemWrite32(u32 mem, u32 value);
std::string iopMemReadString(u32 mem, int maxlen = 65536);
namespace IopMemory
{
// Sif functions not made yet (will for future Iop improvements):

View File

@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#define MODULE(n) if (!strncmp(libname, #n, 8)) switch (index) {
#define MODULE(n) if (#n == libname) switch (index) {
#define END_MODULE }
#define EXPORT(i, n) case (i): return #n;

View File

@ -93,7 +93,7 @@ void psxJ()
{
// check for iop module import table magic
u32 delayslot = iopMemRead32(psxRegs.pc);
if (delayslot >> 16 == 0x2400 && irxImportExec(irxImportLibname(psxRegs.pc), delayslot & 0xffff))
if (delayslot >> 16 == 0x2400 && irxImportExec(irxImportTableAddr(psxRegs.pc), delayslot & 0xffff))
return;
doBranch(_JumpTarget_);

View File

@ -498,39 +498,53 @@ void psxRecompileCodeConst0(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode,
PSX_DEL_CONST(_Rd_);
}
static void psxRecompileIrxImport()
{
u32 import_table = irxImportTableAddr(psxpc - 4);
u16 index = psxRegs.code & 0xffff;
if (!import_table)
return;
const std::string libname = iopMemReadString(import_table + 12, 8);
irxHLE hle = irxImportHLE(libname, index);
irxDEBUG debug = 0;
const char *funcname = 0;
#ifdef PCSX2_DEVBUILD
funcname = irxImportFuncname(libname, index);
debug = irxImportDebug(libname, index);
#endif
if (!hle && !debug && (!SysTraceActive(IOP.Bios) || !funcname))
return;
xMOV(ptr32[&psxRegs.code], psxRegs.code);
xMOV(ptr32[&psxRegs.pc], psxpc);
_psxFlushCall(FLUSH_NODESTROY);
if (SysTraceActive(IOP.Bios)) {
xPUSH((uptr)funcname);
xFastCall((void *)irxImportLog_rec, import_table, index);
}
if (debug)
xFastCall((void *)debug);
if (hle) {
xFastCall((void *)hle);
xTEST(eax, eax);
xJNZ(iopDispatcherReg);
}
}
// rt = rs op imm16
void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode)
{
if ( ! _Rt_ ) {
// check for iop module import table magic
if (psxRegs.code >> 16 == 0x2400) {
xMOV(ptr32[&psxRegs.code], psxRegs.code );
xMOV(ptr32[&psxRegs.pc], psxpc );
_psxFlushCall(FLUSH_NODESTROY);
const char *libname = irxImportLibname(psxpc);
u16 index = psxRegs.code & 0xffff;
#ifdef PCSX2_DEVBUILD
const char *funcname = irxImportFuncname(libname, index);
irxDEBUG debug = irxImportDebug(libname, index);
if (SysTraceActive(IOP.Bios)) {
xMOV(ecx, (uptr)libname);
xMOV(edx, index);
xPUSH((uptr)funcname);
xCALL((void*)irxImportLog);
}
if (debug)
xFastCall((void*)debug);
#endif
irxHLE hle = irxImportHLE(libname, index);
if (hle) {
xFastCall((void*)hle);
xCMP(eax, 0);
xJNE(iopDispatcherReg);
}
}
if (psxRegs.code >> 16 == 0x2400)
psxRecompileIrxImport();
return;
}