diff --git a/Core/HLE/HLE.cpp b/Core/HLE/HLE.cpp index 01b0e44468..304165e946 100644 --- a/Core/HLE/HLE.cpp +++ b/Core/HLE/HLE.cpp @@ -58,8 +58,6 @@ typedef std::vector SyscallVector; typedef std::map SyscallVectorByModule; static std::vector moduleDB; -static SyscallVectorByModule unresolvedSyscalls; -static SyscallVectorByModule exportedCalls; static int delayedResultEvent = -1; static int hleAfterSyscall = HLE_AFTER_NOTHING; static const char *hleAfterSyscallReschedReason; @@ -87,8 +85,6 @@ void HLEInit() void HLEDoState(PointerWrap &p) { - p.Do(unresolvedSyscalls); - p.Do(exportedCalls); p.Do(delayedResultEvent); CoreTiming::RestoreRegisterEvent(delayedResultEvent, "HLEDelayedResult", hleDelayResultFinish); p.DoMarker("HLE"); @@ -98,8 +94,6 @@ void HLEShutdown() { hleAfterSyscall = HLE_AFTER_NOTHING; moduleDB.clear(); - unresolvedSyscalls.clear(); - exportedCalls.clear(); } void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable) @@ -159,33 +153,19 @@ const char *GetFuncName(const char *moduleName, u32 nib) if (func) return func->name; - SyscallModuleName searchModuleName = {0}; - strncpy(searchModuleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH); - searchModuleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; - - // Was this function exported previously? static char temp[256]; - const auto exported = exportedCalls.find(searchModuleName); - if (exported != exportedCalls.end()) - { - const SyscallVector &syscalls = exported->second; - for (auto it = syscalls.begin(), end = syscalls.end(); it != end; ++it) - { - if (it->nid == nib) - { - sprintf(temp, "[EXP: 0x%08x]", nib); - return temp; - } - } - } - - // No good, we can't find it. sprintf(temp,"[UNK: 0x%08x]", nib); return temp; } u32 GetSyscallOp(const char *moduleName, u32 nib) { + // Special case to hook up bad imports. + if (moduleName == NULL) + { + return (0x03FFFFCC); // invalid syscall + } + int modindex = GetModuleIndex(moduleName); if (modindex != -1) { @@ -208,78 +188,47 @@ u32 GetSyscallOp(const char *moduleName, u32 nib) } } -void WriteSyscall(const char *moduleName, u32 nib, u32 address) +bool FuncImportIsSyscall(const char *module, u32 nib) +{ + return GetFunc(module, nib) != NULL; +} + +void WriteFuncStub(u32 stubAddr, u32 symAddr) +{ + // Note that this should be J not JAL, as otherwise control will return to the stub.. + Memory::Write_U32(MIPS_MAKE_J(symAddr), stubAddr); + // Note: doing that, we can't trace external module calls, so maybe something else should be done to debug more efficiently + // Perhaps a syscall here (and verify support in jit), marking the module by uid (debugIdentifier)? + Memory::Write_U32(MIPS_MAKE_NOP(), stubAddr + 4); +} + +void WriteFuncMissingStub(u32 stubAddr, u32 nid) +{ + // Write a trap so we notice this func if it's called before resolving. + Memory::Write_U32(MIPS_MAKE_JR_RA(), stubAddr); // jr ra + Memory::Write_U32(GetSyscallOp(NULL, nid), stubAddr + 4); +} + +bool WriteSyscall(const char *moduleName, u32 nib, u32 address) { if (nib == 0) { + WARN_LOG_REPORT(HLE, "Wrote patched out nid=0 syscall (%s)", moduleName); Memory::Write_U32(MIPS_MAKE_JR_RA(), address); //patched out? Memory::Write_U32(MIPS_MAKE_NOP(), address+4); //patched out? - return; + return true; } int modindex = GetModuleIndex(moduleName); if (modindex != -1) { Memory::Write_U32(MIPS_MAKE_JR_RA(), address); // jr ra Memory::Write_U32(GetSyscallOp(moduleName, nib), address + 4); + return true; } else { - Syscall sysc = {"", address, nib}; - strncpy(sysc.moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH); - sysc.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; - - // Did another module export this already? - const auto exported = exportedCalls.find(sysc.moduleName); - if (exported != exportedCalls.end()) - { - const SyscallVector &syscalls = exported->second; - for (auto it = syscalls.begin(), end = syscalls.end(); it != end; ++it) - { - if (it->nid == nib) - { - Memory::Write_U32(MIPS_MAKE_J(it->symAddr), address); // j symAddr - Memory::Write_U32(MIPS_MAKE_NOP(), address + 4); // nop (delay slot) - return; - } - } - } - - // Module inexistent.. for now; let's store the syscall for it to be resolved later - INFO_LOG(HLE,"Syscall (%s,%08x) unresolved, storing for later resolving", moduleName, nib); - unresolvedSyscalls[sysc.moduleName].push_back(sysc); - - // Write a trap so we notice this func if it's called before resolving. - Memory::Write_U32(MIPS_MAKE_JR_RA(), address); // jr ra - Memory::Write_U32(GetSyscallOp("(invalid syscall)", nib), address + 4); - } -} - -void ResolveSyscall(const char *moduleName, u32 nib, u32 address) -{ - _dbg_assert_msg_(HLE, moduleName != NULL, "Invalid module name."); - - Syscall ex = {"", address, nib}; - strncpy(ex.moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH); - ex.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0'; - exportedCalls[ex.moduleName].push_back(ex); - - const auto unresolved = unresolvedSyscalls.find(ex.moduleName); - if (unresolved != unresolvedSyscalls.end()) - { - const SyscallVector &syscalls = unresolved->second; - for (size_t i = 0; i < syscalls.size(); i++) - { - const Syscall *sysc = &syscalls[i]; - if (sysc->nid == nib) - { - INFO_LOG(HLE, "Resolving function symbol %s/%08x", moduleName, nib); - // Note that this should be J not JAL, as otherwise control will return to the stub.. - Memory::Write_U32(MIPS_MAKE_J(address), sysc->symAddr); - // Note: doing that, we can't trace external module calls, so maybe something else should be done to debug more efficiently - // Perhaps a syscall here (and verify support in jit), marking the module by uid? - Memory::Write_U32(MIPS_MAKE_NOP(), sysc->symAddr + 4); - } - } + ERROR_LOG_REPORT(HLE, "Unable to write unknown syscall: %s/%08x", moduleName, nib); + return false; } } diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index de34f7f9fc..abed955750 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -113,7 +113,9 @@ void HLEDoState(PointerWrap &p); void HLEShutdown(); u32 GetNibByName(const char *module, const char *function); u32 GetSyscallOp(const char *module, u32 nib); -void WriteSyscall(const char *module, u32 nib, u32 address); +bool FuncImportIsSyscall(const char *module, u32 nib); +bool WriteSyscall(const char *module, u32 nib, u32 address); void CallSyscall(MIPSOpcode op); void ResolveSyscall(const char *moduleName, u32 nib, u32 address); - +void WriteFuncStub(u32 stubAddr, u32 symAddr); +void WriteFuncMissingStub(u32 stubAddr, u32 nid); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index f529153657..0aaa4829bf 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -128,6 +128,10 @@ void ImportVarSymbol(const VarSymbolImport &var); void ExportVarSymbol(const VarSymbolExport &var); void UnexportVarSymbol(const VarSymbolExport &var); +void ImportFuncSymbol(const FuncSymbolImport &func); +void ExportFuncSymbol(const FuncSymbolExport &func); +void UnexportFuncSymbol(const FuncSymbolExport &func); + struct NativeModule { u32_le next; u16_le attribute; @@ -198,6 +202,9 @@ public: for (auto it = exportedVars.begin(), end = exportedVars.end(); it != end; ++it) { UnexportVarSymbol(*it); } + for (auto it = exportedFuncs.begin(), end = exportedFuncs.end(); it != end; ++it) { + UnexportFuncSymbol(*it); + } if (memoryBlockAddr) { userMemory.Free(memoryBlockAddr); } @@ -254,7 +261,7 @@ public: // Keep track and actually hook it up if possible. importedFuncs.push_back(func); impExpModuleNames.insert(func.moduleName); - WriteSyscall(func.moduleName, func.nid, func.stubAddr); + ImportFuncSymbol(func); } void ImportVar(const VarSymbolImport &var) { @@ -267,7 +274,7 @@ public: void ExportFunc(const FuncSymbolExport &func) { exportedFuncs.push_back(func); impExpModuleNames.insert(func.moduleName); - ResolveSyscall(func.moduleName, func.nid, func.symAddr); + ExportFuncSymbol(func); } void ExportVar(const VarSymbolExport &var) { @@ -541,7 +548,7 @@ void ExportVarSymbol(const VarSymbolExport &var) { // Look for imports currently loaded modules already have, hook it up right away. for (auto it = module->importedVars.begin(), end = module->importedVars.end(); it != end; ++it) { if (var.Matches(*it)) { - INFO_LOG(HLE, "Resolving var %s/%08x", var.moduleName, var.nid); + INFO_LOG(LOADER, "Resolving var %s/%08x", var.moduleName, var.nid); WriteVarSymbol(var.symAddr, it->stubAddr, it->type); } } @@ -556,16 +563,96 @@ void UnexportVarSymbol(const VarSymbolExport &var) { continue; } - // Look for imports currently loaded modules already have, hook it up right away. + // Look for imports modules that are *still* loaded have, and reverse them. for (auto it = module->importedVars.begin(), end = module->importedVars.end(); it != end; ++it) { if (var.Matches(*it)) { - INFO_LOG(HLE, "Unresolving var %s/%08x", var.moduleName, var.nid); + INFO_LOG(LOADER, "Unresolving var %s/%08x", var.moduleName, var.nid); WriteVarSymbol(var.symAddr, it->stubAddr, it->type, true); } } } } +void ImportFuncSymbol(const FuncSymbolImport &func) { + // Prioritize HLE implementations. + // TODO: Or not? + if (FuncImportIsSyscall(func.moduleName, func.nid)) { + WriteSyscall(func.moduleName, func.nid, func.stubAddr); + return; + } + + u32 error; + for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) { + Module *module = kernelObjects.Get(*mod, error); + if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) { + continue; + } + + // Look for exports currently loaded modules already have. Maybe it's available? + for (auto it = module->exportedFuncs.begin(), end = module->exportedFuncs.end(); it != end; ++it) { + if (it->Matches(func)) { + WriteFuncStub(func.stubAddr, it->symAddr); + return; + } + } + } + + // It hasn't been exported yet, but hopefully it will later. + if (GetModuleIndex(func.moduleName) != -1) { + WARN_LOG_REPORT(LOADER, "Unknown syscall (%s,%08x) imported", func.moduleName, func.nid); + } else { + INFO_LOG(LOADER, "Function (%s,%08x) unresolved, storing for later resolving", func.moduleName, func.nid); + } + WriteFuncMissingStub(func.stubAddr, func.nid); +} + +void ExportFuncSymbol(const FuncSymbolExport &func) { + if (FuncImportIsSyscall(func.moduleName, func.nid)) { + // Oops, HLE covers this. + WARN_LOG_REPORT(LOADER, "Ignoring func export %s/%08x, already implemented in HLE.", func.moduleName, func.nid); + return; + } + + u32 error; + for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) { + Module *module = kernelObjects.Get(*mod, error); + if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) { + continue; + } + + // Look for imports currently loaded modules already have, hook it up right away. + for (auto it = module->importedFuncs.begin(), end = module->importedFuncs.end(); it != end; ++it) { + if (func.Matches(*it)) { + INFO_LOG(LOADER, "Resolving function %s/%08x", func.moduleName, func.nid); + WriteFuncStub(it->stubAddr, func.symAddr); + } + } + } +} + +void UnexportFuncSymbol(const FuncSymbolExport &func) { + if (FuncImportIsSyscall(func.moduleName, func.nid)) { + // Oops, HLE covers this. + return; + } + + u32 error; + for (auto mod = loadedModules.begin(), modend = loadedModules.end(); mod != modend; ++mod) { + Module *module = kernelObjects.Get(*mod, error); + if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) { + continue; + } + + // Look for imports modules that are *still* loaded have, and write back stubs. + for (auto it = module->importedFuncs.begin(), end = module->importedFuncs.end(); it != end; ++it) { + if (func.Matches(*it)) { + INFO_LOG(LOADER, "Unresolving function %s/%08x", func.moduleName, func.nid); + WriteFuncMissingStub(it->stubAddr, it->nid); + } + } + } +} + Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *error_string, u32 *magic) { Module *module = new Module; kernelObjects.Create(module);