diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 46759c4fd9..3cb7eac601 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -629,6 +629,12 @@ template void WrapI_CUUUUU(MIPSState *mips) { RETURN(retval); } +template void WrapU_CCU(MIPSState *mips) { + u32 retval = HLECall(mips, Memory::GetCharPointer(PARAM(0)), + Memory::GetCharPointer(PARAM(1)), PARAM(2)); + RETURN(retval); +} + template void WrapU_CU(MIPSState *mips) { u32 retval = HLECall(mips, Memory::GetCharPointer(PARAM(0)), PARAM(1)); RETURN((u32) retval); diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 64e3cf9419..2d031b2bfd 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -353,6 +353,7 @@ void RegisterAllModules() { Register_SystemCtrlForKernel(); Register_sceGe_driver(); Register_sceMePower_driver(); + Register_SystemCtrlForUser(); // Not ready to enable this due to apparent softlocks in Patapon 3. // Register_sceNpMatching2(); diff --git a/Core/HLE/KUBridge.cpp b/Core/HLE/KUBridge.cpp index 81342b604d..fdf2db1688 100644 --- a/Core/HLE/KUBridge.cpp +++ b/Core/HLE/KUBridge.cpp @@ -19,12 +19,56 @@ // providing the ability to call some kernel-only functions from user mode. // A few homebrew applications use this. We only simulate a small subset of the functionality for now. +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/KUBridge.h" #include "Core/HLE/sceKernelModule.h" +#include "Core/HLE/sceKernelThread.h" +#include "Core/MemMap.h" +#include "Core/MIPS/MIPS.h" #include "Core/Config.h" +// kuKernelCall's arguments and results: struct KernelCallArg { u32 arg1..arg12, ret1, ret2; }. +static const u32 KERNEL_CALL_ARGS = 12; +static const u32 KERNEL_CALL_RET1 = 0x30; +static const u32 KERNEL_CALL_RET2 = 0x34; + +static int actionKernelCallDone = -1; + +// Copies the called function's v0 and v1 to ret1 and ret2. +class KernelCallDone : public PSPAction { +public: + static PSPAction *Create() { return new KernelCallDone(); } + void SetArgs(u32 argsAddr) { argsAddr_ = argsAddr; } + void run(MipsCall &call) override { + Memory::WriteUnchecked_U32(currentMIPS->r[MIPS_REG_V0], argsAddr_ + KERNEL_CALL_RET1); + Memory::WriteUnchecked_U32(currentMIPS->r[MIPS_REG_V1], argsAddr_ + KERNEL_CALL_RET2); + } + void DoState(PointerWrap &p) override { + auto s = p.Section("KernelCallDone", 1); + if (!s) + return; + Do(p, argsAddr_); + } + +private: + u32 argsAddr_ = 0; +}; + +void __KUBridgeInit() { + actionKernelCallDone = __KernelRegisterActionType(KernelCallDone::Create); +} + +void __KUBridgeDoState(PointerWrap &p) { + auto s = p.Section("KUBridge", 0, 1); + if (!s) + return; + Do(p, actionKernelCallDone); + __KernelRestoreActionType(actionKernelCallDone, KernelCallDone::Create); +} + static int kuKernelLoadModule(MIPSState *mips, const char *path, uint32_t flags, uint32_t lmOptionAddr) { INFO_LOG(Log::sceKernel, "kuKernelLoadModule - forwarding to sceKernelLoadModule"); // Simply forward the call, like JPSCP does. @@ -36,10 +80,29 @@ static int kuKernelGetModel() { return g_Config.iPSPModel; } +// Runs a function of the caller in kernel mode, which for us is any mode. The first eight arguments +// go in registers, which is all we pass. +static int kuKernelCall(u32 func, u32 argsAddr) { + if (!Memory::IsValidRange(argsAddr, KERNEL_CALL_RET2 + 4) || !Memory::IsValid4AlignedAddress(func)) { + return hleLogError(Log::sceKernel, -1, "bad function or arguments"); + } + u32 args[8]; + for (int i = 0; i < 8; ++i) + args[i] = Memory::ReadUnchecked_U32(argsAddr + i * 4); + if (Memory::ReadUnchecked_U32(argsAddr + 8 * 4) || Memory::ReadUnchecked_U32(argsAddr + 9 * 4) || Memory::ReadUnchecked_U32(argsAddr + 10 * 4) || Memory::ReadUnchecked_U32(argsAddr + 11 * 4)) { + WARN_LOG(Log::sceKernel, "kuKernelCall: arguments 9-%d not passed", KERNEL_CALL_ARGS); + } + KernelCallDone *done = (KernelCallDone *)__KernelCreateAction(actionKernelCallDone); + done->SetArgs(argsAddr); + hleEnqueueCall(func, 8, args, done); + return hleLogDebug(Log::sceKernel, 0); +} + const HLEFunction KUBridge[] = { { 0x4C25EA72, &WrapI_CUU, "kuKernelLoadModule", 'i', "sxx" }, { 0x24331850, &WrapI_V, "kuKernelGetModel", 'i', "" }, + { 0x9060F69D, &WrapI_UU, "kuKernelCall", 'i', "xx" }, }; void Register_KUBridge() { diff --git a/Core/HLE/KUBridge.h b/Core/HLE/KUBridge.h index d9337cb45e..9197f29dc5 100644 --- a/Core/HLE/KUBridge.h +++ b/Core/HLE/KUBridge.h @@ -17,4 +17,8 @@ #pragma once +class PointerWrap; + void Register_KUBridge(); +void __KUBridgeInit(); +void __KUBridgeDoState(PointerWrap &p); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 2b7eda22f7..133aa66cb8 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -26,6 +26,7 @@ #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/ErrorCodes.h" +#include "Core/HLE/KUBridge.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/Interpreter.h" @@ -158,6 +159,7 @@ void __KernelInit() __NetAdhocMatchingInit(); __VaudioInit(); __CheatInit(); + __KUBridgeInit(); __HeapInit(); __DmacInit(); __AudioCodecInit(); @@ -296,6 +298,7 @@ void __KernelDoState(PointerWrap &p) __MpegDoState(p); __MpegBaseDoState(p); __VideocodecDoState(p); + __KUBridgeDoState(p); __NetDoState(p); __NetAdhocDoState(p); __PowerDoState(p); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 5506d0a0df..1d9673b30b 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -2922,6 +2922,24 @@ static u32 sctrlHENFindDriver(const char *drvname) { return hleLogInfo(Log::sceModule, 0, "driver %s", drvname ? drvname : "(null)"); } +// The custom firmware's lookup of a loaded module's export, by module and library name (either may +// be left out) and NID. Only modules loaded as code have exports to find. +static u32 sctrlHENFindFunction(const char *moduleName, const char *libraryName, u32 nid) { + u32 error; + for (SceUID moduleId : loadedModules) { + PSPModule *module = kernelObjects.Get(moduleId, error); + if (!module || (moduleName && strcmp(module->GetName(), moduleName) != 0)) { + continue; + } + for (const FuncSymbolExport &func : module->exportedFuncs) { + if (func.nid == nid && (!libraryName || strcmp(func.moduleName, libraryName) == 0)) { + return hleLogDebug(Log::sceModule, func.symAddr); + } + } + } + return hleLogWarning(Log::sceModule, 0, "not found"); +} + int __KernelStartModule(SceUID moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, SceKernelSMOption *smoption, bool *needsWait) { if (needsWait) { *needsWait = false; @@ -3716,8 +3734,17 @@ void Register_ModuleMgrForKernel() { static const HLEFunction SystemCtrlForKernel[] = { {0x1C90BECB, &WrapU_U, "sctrlHENSetStartModuleHandler", 'x', "x", HLE_KERNEL_SYSCALL}, {0x78E46415, &WrapU_C, "sctrlHENFindDriver", 'x', "s", HLE_KERNEL_SYSCALL}, + {0x159AF5CC, &WrapU_CCU, "sctrlHENFindFunction", 'x', "ssx", HLE_KERNEL_SYSCALL}, +}; + +static const HLEFunction SystemCtrlForUser[] = { + {0x159AF5CC, &WrapU_CCU, "sctrlHENFindFunction", 'x', "ssx"}, }; void Register_SystemCtrlForKernel() { RegisterHLEModule("SystemCtrlForKernel", ARRAY_SIZE(SystemCtrlForKernel), SystemCtrlForKernel); } + +void Register_SystemCtrlForUser() { + RegisterHLEModule("SystemCtrlForUser", ARRAY_SIZE(SystemCtrlForUser), SystemCtrlForUser); +} diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 758445be05..812e85f7d5 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -274,6 +274,7 @@ u32 sceKernelFindModuleByUID(u32 uid); void Register_ModuleMgrForUser(); void Register_ModuleMgrForKernel(); void Register_SystemCtrlForKernel(); +void Register_SystemCtrlForUser(); // Expose for use by KUBridge. u32 sceKernelLoadModule(MIPSState *mips, const char *name, u32 flags, u32 optionAddr);