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 ra (psxRegs.GPR.n.ra)
#define pc (psxRegs.pc) #define pc (psxRegs.pc)
#define Ra0 (iopVirtMemR<char>(a0)) #define Ra0 (iopMemReadString(a0))
#define Ra1 (iopVirtMemR<char>(a1)) #define Ra1 (iopMemReadString(a1))
#define Ra2 (iopVirtMemR<char>(a2)) #define Ra2 (iopMemReadString(a2))
#define Ra3 (iopVirtMemR<char>(a3)) #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 // TODO: sandbox option, other permissions
class HostFile : public IOManFile 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! // host: actually DOES let you write!
//if (flags != IOP_O_RDONLY) //if (flags != IOP_O_RDONLY)
// return -IOP_EROFS; // 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. int native_flags = O_BINARY; // necessary in Windows.
switch(flags&IOP_O_RDWR) switch(flags&IOP_O_RDWR)
@ -184,7 +181,7 @@ public:
if(flags&IOP_O_CREAT) native_flags |= O_CREAT; if(flags&IOP_O_CREAT) native_flags |= O_CREAT;
if(flags&IOP_O_TRUNC) native_flags |= O_TRUNC; 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) if (hostfd < 0)
return translate_error(hostfd); return translate_error(hostfd);
@ -328,15 +325,21 @@ namespace ioman {
fds[i].close(); 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() int open_HLE()
{ {
IOManFile *file = NULL; IOManFile *file = NULL;
const char *name = Ra0; const std::string path = Ra0;
s32 flags = a1; s32 flags = a1;
u16 mode = a2; u16 mode = a2;
if ((!g_GameStarted || EmuConfig.HostFs) if (is_host(path))
&& !strncmp(name, "host", 4) && name[4 + strspn(name + 4, "0123456789")] == ':')
{ {
if (!freefdcount()) if (!freefdcount())
{ {
@ -345,7 +348,7 @@ namespace ioman {
return 1; return 1;
} }
int err = HostFile::open(&file, name, flags, mode); int err = HostFile::open(&file, path, flags, mode);
if (err != 0 || !file) if (err != 0 || !file)
{ {
@ -403,15 +406,26 @@ namespace ioman {
int read_HLE() int read_HLE()
{ {
s32 fd = a0; s32 fd = a0;
u32 buf = a1; u32 data = a1;
u32 count = a2; u32 count = a2;
if (IOManFile *file = getfd<IOManFile>(fd)) if (IOManFile *file = getfd<IOManFile>(fd))
{ {
if (!iopVirtMemR<void>(buf)) char *buf;
return 0; try {
buf = new char[count];
v0 = file->read(iopVirtMemW<void>(buf), 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; pc = ra;
return 1; return 1;
} }
@ -422,22 +436,32 @@ namespace ioman {
int write_HLE() int write_HLE()
{ {
s32 fd = a0; s32 fd = a0;
u32 buf = a1; u32 data = a1;
u32 count = a2; u32 count = a2;
if (fd == 1) // stdout if (fd == 1) // stdout
{ {
iopConLog(ShiftJIS_ConvertString(Ra1, a2)); const std::string s = Ra1;
iopConLog(ShiftJIS_ConvertString(s.data(), a2));
pc = ra; pc = ra;
v0 = a2; v0 = a2;
return 1; return 1;
} }
else if (IOManFile *file = getfd<IOManFile>(fd)) else if (IOManFile *file = getfd<IOManFile>(fd))
{ {
if (!iopVirtMemR<void>(buf)) char *buf = NULL;
return 0; try {
buf = new char[count];
v0 = file->write(iopVirtMemW<void>(buf), 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; pc = ra;
return 1; return 1;
} }
@ -456,6 +480,7 @@ namespace sysmem {
iopMemWrite32(sp + 12, a3); iopMemWrite32(sp + 12, a3);
pc = ra; pc = ra;
const std::string fmt = Ra0;
// From here we're intercepting the Kprintf and piping it to our console, complete with // 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 // printf-style formatting processing. This part can be skipped if the user has the
@ -467,33 +492,33 @@ namespace sysmem {
char *ptmp = tmp; char *ptmp = tmp;
int n=1, i=0, j = 0; int n=1, i=0, j = 0;
while (Ra0[i]) while (fmt[i])
{ {
switch (Ra0[i]) switch (fmt[i])
{ {
case '%': case '%':
j = 0; j = 0;
tmp2[j++] = '%'; tmp2[j++] = '%';
_start: _start:
switch (Ra0[++i]) switch (fmt[++i])
{ {
case '.': case '.':
case 'l': case 'l':
tmp2[j++] = Ra0[i]; tmp2[j++] = fmt[i];
goto _start; goto _start;
default: 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; goto _start;
} }
break; break;
} }
tmp2[j++] = Ra0[i]; tmp2[j++] = fmt[i];
tmp2[j] = 0; tmp2[j] = 0;
switch (Ra0[i]) switch (fmt[i])
{ {
case 'f': case 'F': case 'f': case 'F':
ptmp+= sprintf(ptmp, tmp2, (float)iopMemRead32(sp + n * 4)); ptmp+= sprintf(ptmp, tmp2, (float)iopMemRead32(sp + n * 4));
@ -522,12 +547,15 @@ _start:
break; break;
case 's': 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; break;
case '%': case '%':
*ptmp++ = Ra0[i]; *ptmp++ = fmt[i];
break; break;
default: default:
@ -537,7 +565,7 @@ _start:
break; break;
default: default:
*ptmp++ = Ra0[i++]; *ptmp++ = fmt[i++];
break; break;
} }
} }
@ -551,7 +579,8 @@ _start:
namespace loadcore { namespace loadcore {
void RegisterLibraryEntries_DEBUG() 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; u32 i;
i = entrypc; i = entrypc - 0x18;
while (iopMemRead32(i -= 4) != 0x41e00000) // documented magic number 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" #include "IopModuleNames.cpp"
@ -614,12 +646,12 @@ const char* irxImportFuncname(const char libname[8], u16 index)
return 0; 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 END_MODULE }}
#define EXPORT_D(i, n) case (i): return n ## _DEBUG; #define EXPORT_D(i, n) case (i): return n ## _DEBUG;
#define EXPORT_H(i, n) case (i): return n ## _HLE; #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 // debugging output
MODULE(sysmem) MODULE(sysmem)
@ -637,7 +669,7 @@ irxHLE irxImportHLE(const char libname[8], u16 index)
return 0; return 0;
} }
irxDEBUG irxImportDebug(const char libname[8], u16 index) irxDEBUG irxImportDebug(const std::string &libname, u16 index)
{ {
MODULE(loadcore) MODULE(loadcore)
EXPORT_D( 6, RegisterLibraryEntries) EXPORT_D( 6, RegisterLibraryEntries)
@ -657,15 +689,24 @@ irxDEBUG irxImportDebug(const char libname[8], u16 index)
#undef EXPORT_D #undef EXPORT_D
#undef EXPORT_H #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)", 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); 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); const char *funcname = irxImportFuncname(libname, index);
irxHLE hle = irxImportHLE(libname, index); irxHLE hle = irxImportHLE(libname, index);
irxDEBUG debug = irxImportDebug(libname, index); irxDEBUG debug = irxImportDebug(libname, index);

View File

@ -20,6 +20,7 @@
#define IOP_EIO 5 #define IOP_EIO 5
#define IOP_ENOMEM 12 #define IOP_ENOMEM 12
#define IOP_EACCES 13 #define IOP_EACCES 13
#define IOP_ENODEV 19
#define IOP_EISDIR 21 #define IOP_EISDIR 21
#define IOP_EMFILE 24 #define IOP_EMFILE 24
#define IOP_EROFS 30 #define IOP_EROFS 30
@ -38,7 +39,10 @@
class IOManFile { class IOManFile {
public: 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; virtual void close() = 0;
@ -59,12 +63,13 @@ typedef void (*irxDEBUG)();
namespace R3000A namespace R3000A
{ {
const char* irxImportLibname(u32 entrypc); const u32 irxImportTableAddr(u32 entrypc);
const char* irxImportFuncname(const char libname[8], u16 index); const char* irxImportFuncname(const std::string &libname, u16 index);
irxHLE irxImportHLE(const char libname[8], u16 index); irxHLE irxImportHLE(const std::string &libnam, u16 index);
irxDEBUG irxImportDebug(const char libname[8], u16 index); irxDEBUG irxImportDebug(const std::string & libname, u16 index);
void __fastcall irxImportLog(const char libname[8], u16 index, const char *funcname); void irxImportLog(const std::string &libnameptr, u16 index, const char *funcname);
int __fastcall irxImportExec(const char libname[8], u16 index); void __fastcall irxImportLog_rec(u32 import_table, u16 index, const char *funcname);
int irxImportExec(u32 import_table, u16 index);
namespace ioman 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 iopMemWrite16(u32 mem, u16 value);
extern void __fastcall iopMemWrite32(u32 mem, u32 value); extern void __fastcall iopMemWrite32(u32 mem, u32 value);
std::string iopMemReadString(u32 mem, int maxlen = 65536);
namespace IopMemory namespace IopMemory
{ {
// Sif functions not made yet (will for future Iop improvements): // Sif functions not made yet (will for future Iop improvements):

View File

@ -13,7 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>. * 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 END_MODULE }
#define EXPORT(i, n) case (i): return #n; #define EXPORT(i, n) case (i): return #n;

View File

@ -93,7 +93,7 @@ void psxJ()
{ {
// check for iop module import table magic // check for iop module import table magic
u32 delayslot = iopMemRead32(psxRegs.pc); 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; return;
doBranch(_JumpTarget_); doBranch(_JumpTarget_);

View File

@ -498,39 +498,53 @@ void psxRecompileCodeConst0(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode,
PSX_DEL_CONST(_Rd_); 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 // rt = rs op imm16
void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode) void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode)
{ {
if ( ! _Rt_ ) { if ( ! _Rt_ ) {
// check for iop module import table magic // check for iop module import table magic
if (psxRegs.code >> 16 == 0x2400) { if (psxRegs.code >> 16 == 0x2400)
xMOV(ptr32[&psxRegs.code], psxRegs.code ); psxRecompileIrxImport();
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);
}
}
return; return;
} }