diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index c8a4179be0..d5a7818884 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -301,11 +301,16 @@ static const HLENidAlias hleNidAliases[] = { { "sceSysreg_driver", 0xD1999F94, 0x4634C9DC }, // sceSysreg_driver_4634C9DC { "sceSysreg_driver", 0xD74D9041, 0x38527743 }, // sceSysregMeBusClockEnable660 { "sceSysreg_driver", 0xE2606FCB, 0x48F1C4AD }, // sceSysregMeResetDisable660 - // 6.20, from popsman.prx. + // 6.20, from popsman.prx (the clock one is 4.05's too). { "InitForKernel", 0x977A0F90, 0x9D33A110 }, // InitForKernel_9D33A110 { "LoadExecForKernel", 0x29413885, 0xC3474C2A }, // sceKernelExitVSHKernel { "ModuleMgrForKernel", 0xDF8FFFAB, 0x3FF74DF1 }, // sceKernelStartModule { "ModuleMgrForKernel", 0xE3CCC6EA, 0x939E4270 }, // sceKernelLoadModuleForKernel + { "SysMemForKernel", 0x02AEA33F, 0x310802A9 }, // SysMemForKernel_310802A9 + { "SysMemForKernel", 0xA4AC3934, 0xFDC97D28 }, + { "SysMemForKernel", 0xB9796F69, 0xB4F00CB5 }, // sceKernelGetCompiledSdkVersion + { "SysMemForKernel", 0xF5780DAA, 0xC90B0992 }, // sceKernelGetUIDcontrolBlock + { "SysMemForKernel", 0xFEB5C72B, 0xF12A62F7 }, { "sceClockgen_driver", 0xACC30ECE, 0xDAB6E612 }, { "sceCodec_driver", 0x794EE731, 0x376399B6 }, { "sceCtrl_driver", 0x7A6436DE, 0x6C86AF22 }, @@ -327,6 +332,7 @@ static const HLENidAlias hleNidAliases[] = { { "scePadSvc_driver", 0x1971BAE0, 0x7CAB5A3D }, { "scePadSvc_driver", 0x3B0567D6, 0x0B3E6FD3 }, { "scePadSvc_driver", 0x79B60777, 0x05C9C803 }, + { "scePower_driver", 0xEBD177D6, 0x469989AD }, // scePowerSetClockFrequency630 { "sceRtc_driver", 0x2F20DAF0, 0x4E267E02 }, { "sceRtc_driver", 0x43F38ED8, 0xE7B3ABF4 }, { "sceSyscon_driver", 0xB757C11D, 0x48448373 }, @@ -343,11 +349,6 @@ static const HLENidAlias hleNidAliases[] = { { "sceSysreg_driver", 0x9EBB3C43, 0xC36775AD }, // sceSysreg_driver_C36775AD { "sceSysreg_driver", 0xB733A263, 0xB1751B06 }, // sceSysreg_driver_B1751B06 { "sceSysreg_driver", 0xE7849809, 0x8B1DD83A }, // sceSysreg_driver_8B1DD83A - { "SysMemForKernel", 0x02AEA33F, 0x310802A9 }, // SysMemForKernel_310802A9 - { "SysMemForKernel", 0xA4AC3934, 0xFDC97D28 }, - { "SysMemForKernel", 0xB9796F69, 0xB4F00CB5 }, // sceKernelGetCompiledSdkVersion - { "SysMemForKernel", 0xF5780DAA, 0xC90B0992 }, // sceKernelGetUIDcontrolBlock - { "SysMemForKernel", 0xFEB5C72B, 0xF12A62F7 }, // 5.55, from popsman.prx, whose code changed too much to match every import: only the ones used here, // each checked by its call site. { "LoadExecForKernel", 0x9C9BB2D8, 0xC3474C2A }, // sceKernelExitVSHKernel @@ -370,6 +371,29 @@ static const HLENidAlias hleNidAliases[] = { { "sceSysreg_driver", 0x923509A1, 0xC36775AD }, // sceSysreg_driver_C36775AD { "sceSysreg_driver", 0xC7FC7669, 0x8B1DD83A }, // sceSysreg_driver_8B1DD83A { "sceSysreg_driver", 0xE46A0890, 0x4B4CCE80 }, // sceSysreg_driver_4B4CCE80 + // 4.05, from popsman.prx, the same way as 5.55 (the sysreg ones by what they do to the registers). + { "LoadExecForKernel", 0x63D88393, 0xC3474C2A }, // sceKernelExitVSHKernel + { "ModuleMgrForKernel", 0x24C5ABC2, 0x939E4270 }, // sceKernelLoadModuleForKernel + { "ModuleMgrForKernel", 0x63A3CAFB, 0x3FF74DF1 }, // sceKernelStartModule + { "SysMemForKernel", 0x12720EDA, 0xB4F00CB5 }, // sceKernelGetCompiledSdkVersion + { "SysMemForKernel", 0x5136926D, 0xF12A62F7 }, + { "SysMemForKernel", 0x523E300A, 0xC90B0992 }, // sceKernelGetUIDcontrolBlock + { "sceGe_driver", 0x1DDA69CE, 0xD8633888 }, // sceGeEdramSetSize + { "sceImpose_driver", 0x6F502C0A, 0x4B02F047 }, // sceImposeGetParam + { "sceImpose_driver", 0x869EB4A8, 0x5557F4E2 }, // sceImposeGetBatteryIconStatus + { "sceImpose_driver", 0xCD1291FD, 0x0BBCA0BF }, // sceImposeChanges + { "sceSysreg_driver", 0x15574362, 0xC36775AD }, // sceSysreg_driver_C36775AD + { "sceSysreg_driver", 0x21797DCF, 0x4B4CCE80 }, // sceSysreg_driver_4B4CCE80 + { "sceSysreg_driver", 0x643169E5, 0x8B1DD83A }, // sceSysreg_driver_8B1DD83A + { "sceSysreg_driver", 0x67583EF1, 0xB1751B06 }, // sceSysreg_driver_B1751B06 + { "sceSysreg_driver", 0x8E6586AD, 0x48F1C4AD }, // sceSysregMeResetDisable660 + { "sceSysreg_driver", 0xA36C4E9E, 0x457FEBA9 }, // sceSysregMeResetEnable660 + { "sceSysreg_driver", 0xB60FBA15, 0x38527743 }, // sceSysregMeBusClockEnable660 + { "sceSysreg_driver", 0xC4B60AB3, 0x41B0337B }, // sceSysreg_driver_41B0337B + { "sceSysreg_driver", 0xD80E8AAF, 0x0AE8E549 }, // sceSysregAvcResetEnable660 + { "sceSysreg_driver", 0xD83733C9, 0x0143E8A8 }, // sceSysregSemaTryLock660 + { "sceSysreg_driver", 0xE08034E0, 0x4634C9DC }, // sceSysreg_driver_4634C9DC + { "sceSysreg_driver", 0xE65B0490, 0xDB97C70E }, // sceSysregSemaUnlock660 }; u32 GetHLENidAlias(std::string_view moduleName, u32 nid) { diff --git a/Core/HLE/PopsBoot.cpp b/Core/HLE/PopsBoot.cpp index fba86b42d8..59b848dc3a 100644 --- a/Core/HLE/PopsBoot.cpp +++ b/Core/HLE/PopsBoot.cpp @@ -32,6 +32,7 @@ #include "Core/CoreTiming.h" #include "Core/Debugger/MemBlockInfo.h" #include "Core/ELF/PBPReader.h" +#include "Core/ELF/PrxDecrypter.h" #include "Core/FileSystems/MetaFileSystem.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/HLE.h" @@ -91,6 +92,7 @@ static const PopsManLayout POPSMAN_LAYOUTS[] = { { 0x155C, 0x130, 0, 0x3550, 0x3570, 0x3578, 0x0500, 0x058C, 0x0144 }, // 5.55 { 0x1538, 0x130, 0, 0x34D0, 0x34F0, 0x34F8, 0x0500, 0x058C, 0x0144 }, // 5.50 { 0x1538, 0x020, 0, 0x33D0, 0x33F0, 0x33F8, 0x0500, 0x058C, 0x0144, 1 }, // 5.00-5.05 + { 0x150C, 0x030, 0, 0x3510, 0x3530, 0x3538, 0x0538, 0x05C4, 0x0138, 1 }, // 4.05 }; static int g_popsManLayout = 0; @@ -305,22 +307,61 @@ static void PatchCall(u32 addr, const char *func) { Memory::WriteUnchecked_U32(MIPS_MAKE_SYSCALL("PopsBootCalls", func), addr); } -// The user modules the 6.60 POPS boot configuration (pspbtcnf) starts after the manager. -void __PopsBootLoadModules() { - static const char *const paths[] = { - "flash0:/vsh/module/libfont_hv.prx", - "flash0:/vsh/module/pafmini.prx", - "flash0:/vsh/module/libpspvmc.prx", +// The user modules the firmware's POPS boot configuration (flash0:/kd/pspbtcnf.bin) starts after the +// manager: those in its POPS mode under /vsh/module/. They differ by version (4.05 adds heaparea2.prx). +static std::vector PopsUserModules() { + std::vector file; + if (pspFileSystem.ReadEntireFile("flash0:/kd/pspbtcnf.bin", file, true) < 0 || file.size() < 0x150) { + return {}; + } + std::vector plain(file.size()); + const int size = pspDecryptPRX(file.data(), plain.data(), (u32)file.size()); + auto word = [&](u32 offset) -> u32 { + return offset + 4 <= (u32)size ? plain[offset] | (plain[offset + 1] << 8) | (plain[offset + 2] << 16) | ((u32)plain[offset + 3] << 24) : 0; }; - for (const char *path : paths) { + if (size <= 0 || word(0) != 0x0F803001) { + return {}; + } + // Header: modules at 0x20 (offset, count), names at 0x30. A module is 32 bytes: name offset, then + // at +8 its mode flags (POPS is 8). + const u32 modules = word(0x20), count = word(0x24), names = word(0x30); + std::vector paths; + bool afterManager = false; + for (u32 i = 0; i < count && modules + i * 32 + 12 <= (u32)size; i++) { + const u32 nameOffset = names + word(modules + i * 32); + if (nameOffset >= (u32)size || !(word(modules + i * 32 + 8) & 8)) { + continue; + } + const std::string name((const char *)&plain[nameOffset], strnlen((const char *)&plain[nameOffset], size - nameOffset)); + if (name == "/kd/popsman.prx") { + afterManager = true; + } else if (afterManager && startsWith(name, "/vsh/module/")) { + paths.push_back("flash0:" + name); + } + } + return paths; +} + +void __PopsBootLoadModules() { + std::vector paths = PopsUserModules(); + if (paths.empty()) { + WARN_LOG(Log::sceKernel, "POPS: couldn't read the boot configuration, starting 6.60's modules"); + paths = { + "flash0:/vsh/module/libfont_hv.prx", + "flash0:/vsh/module/pafmini.prx", + "flash0:/vsh/module/common_util.prx", + "flash0:/vsh/module/libpspvmc.prx", + }; + } + for (const std::string &path : paths) { std::string error; const SceUID moduleId = KernelLoadModule(path, &error); if (moduleId < 0) { - WARN_LOG(Log::sceKernel, "POPS: failed to load %s: %s", path, error.c_str()); + WARN_LOG(Log::sceKernel, "POPS: failed to load %s: %s", path.c_str(), error.c_str()); continue; } if (__KernelStartModule(moduleId, 0, 0, 0, nullptr, nullptr) < 0) { - WARN_LOG(Log::sceKernel, "POPS: failed to start %s", path); + WARN_LOG(Log::sceKernel, "POPS: failed to start %s", path.c_str()); } } } @@ -441,13 +482,19 @@ static bool IsUsableIcon0(FileLoader *loader) { bool __PopsBootStartInit(FileLoader *pbp, const std::string &gamePath, std::string *error) { if (!FindPopsManLayout(IsConvertedPBP(pbp))) { auto er = GetI18NCategory(I18NCat::ERRORS); - *error = er->T("PS1FirmwareVersion", "So far, PS1 games only run with firmware 6.00 to 6.61 (converted ones also with 5.01 to 5.55), and a different version is installed. Install one of those from an official PSP update file in Settings > Tools > PSP Firmware."); + *error = er->T("PS1FirmwareVersion", "So far, PS1 games only run with firmware 6.00 to 6.61 (converted ones also with 4.05 to 5.55), and a different version is installed. Install one of those from an official PSP update file in Settings > Tools > PSP Firmware."); return false; } const u32 base = PopsManBase(); g_popsPBPPath = pbp->GetPath(); g_popsConvertedPBP = IsConvertedPBP(pbp); g_popsIcon0Usable = IsUsableIcon0(pbp); + // 4.05's manager allocates from a pool with the kernel's sceKernelAllocateFpl, which isn't resolved for + // kernel modules (see ThreadManForKernel): only its import gets the user one. + if (u32 stub = KernelFindModuleImport("scePops_Manager", "ThreadManForKernel", 0xD979E9BF)) { + WriteHLESyscall("ThreadManForUser", 0xD979E9BF, stub); + currentMIPS->InvalidateICacheRangeDeferred(stub, 8); + } const u32 loadModule = base + PopsMan().loadModule; if (PopsMan().keyProbe != 0) { PatchReturn(base + PopsMan().keyProbe, MIPS_MAKE_SYSCALL("PopsBootCalls", "__PopsGetVersionKey")); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index ed534f6590..c55a59e229 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -521,6 +521,22 @@ u32 KernelFindModuleExport(const char *libraryName, u32 nid) { return 0; } +u32 KernelFindModuleImport(const char *moduleName, const char *libraryName, u32 nid) { + u32 error; + for (SceUID moduleId : loadedModules) { + PSPModule *module = kernelObjects.Get(moduleId, error); + if (!module || strcmp(module->GetName(), moduleName) != 0) { + continue; + } + for (const FuncSymbolImport &func : module->importedFuncs) { + if (func.nid == nid && !strncmp(func.moduleName, libraryName, KERNELOBJECT_MAX_NAME_LENGTH)) { + return func.stubAddr; + } + } + } + return 0; +} + // Set once we've seen a PSP_MODULE_VSH_MODE module load (i.e. we're booting the VSH rather // than a game), and reset on the next __KernelLoadExec. See ShouldHLEModuleForLoad below. static bool g_runningVSH = false; diff --git a/Core/HLE/sceKernelModule.h b/Core/HLE/sceKernelModule.h index 1e649941cc..c50c92ca6e 100644 --- a/Core/HLE/sceKernelModule.h +++ b/Core/HLE/sceKernelModule.h @@ -283,3 +283,5 @@ u32 sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValue // Address of a function a loaded module exports, or 0. u32 KernelFindModuleExport(const char *libraryName, u32 nid); +// The stub through which a loaded module imports a function. 0 if it doesn't. +u32 KernelFindModuleImport(const char *moduleName, const char *libraryName, u32 nid); diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index d96daf902b..93943e71c9 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -719,6 +719,7 @@ static int scePowerSetWakeupCondition(u32 condition) { const HLEFunction scePower_driver[] = { {0X5F5006D2, &WrapI_V, "scePower_driver_5F5006D2", 'i', "" }, {0XBA566CD0, &WrapI_U, "scePowerSetWakeupCondition", 'i', "x" }, + {0X469989AD, &WrapU_UUU, "scePowerSetClockFrequency630", 'x', "xxx"}, }; void Register_scePower_driver() {