Merge pull request #22259 from hrydgard/firmware-modules-load-high

Firmware modules: Load to high memory
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-09-08 13:44:14 -06:00
commit 2845de3a4d
5 files changed
+48 -8

No files matched your search

+37 -4
View File
@@ -203,14 +203,23 @@ DisableHLEFlags AlwaysDisableHLEFlags() {
return DisableHLEFlags::scePsmf | DisableHLEFlags::scePsmfPlayer | DisableHLEFlags::sceCcc;
}
// Process compat flags.
// Which modules we're HLE-ing is part of the machine's state, not a live setting: it's decided
// when each module is loaded, and the syscall stubs written into memory then are what a savestate
// captures. So latch it on the first use after boot, save it in the state, and restore it on load
// - otherwise a state made on one side of the boundary gets its imports re-resolved against the
// other, and every call into the module lands on an unresolved stub. Changing the setting takes
// effect on the next boot, which is the only point it could have taken effect anyway.
static DisableHLEFlags g_effectiveDisableHLE;
static bool g_disableHLELatched;
// Flags the user asked for that we can't honour this boot, because the firmware modules they
// need aren't in the NAND directory. Subtracted in GetDisableHLEFlags so that a missing dump
// need aren't in the NAND directory. Subtracted in ComputeDisableHLEFlags so that a missing dump
// leaves the HLE in place rather than handing the game unresolved imports, which is much worse
// than our stubs. Recomputed per boot, since the dump can appear between runs.
static DisableHLEFlags g_unavailableDisableFlags = (DisableHLEFlags)0;
static DisableHLEFlags GetDisableHLEFlags() {
// Process compat flags.
static DisableHLEFlags ComputeDisableHLEFlags() {
DisableHLEFlags flags = (DisableHLEFlags)g_Config.iDisableHLE | AlwaysDisableHLEFlags();
if (PSP_CoreParameter().compat.flags().DisableHLESceFont) {
flags |= DisableHLEFlags::sceFont;
@@ -225,6 +234,18 @@ static DisableHLEFlags GetDisableHLEFlags() {
return flags;
}
static DisableHLEFlags GetDisableHLEFlags() {
if (!g_disableHLELatched) {
g_effectiveDisableHLE = ComputeDisableHLEFlags();
g_disableHLELatched = true;
}
return g_effectiveDisableHLE;
}
DisableHLEFlags GetEffectiveDisableHLEFlags() {
return GetDisableHLEFlags();
}
// Note: name is the modname from prx, not the export module name!
bool ShouldHLEModule(std::string_view modname, bool *wasDisabledManually) {
if (wasDisabledManually) {
@@ -296,16 +317,28 @@ static void CheckDisableHLEAvailability() {
void HLEInit() {
CheckDisableHLEAvailability();
RegisterAllModules();
// Latched lazily rather than here: the compat flags this depends on aren't loaded yet.
g_disableHLELatched = false;
g_stackSize = 0;
delayedResultEvent = CoreTiming::RegisterEvent("HLEDelayedResult", hleDelayResultFinish);
g_idleOp = GetSyscallOp("FakeSysCalls", NID_IDLE);
}
void HLEDoState(PointerWrap &p) {
auto s = p.Section("HLE", 1, 2);
auto s = p.Section("HLE", 1, 3);
if (!s)
return;
if (s >= 3) {
int disableHLE = (int)GetDisableHLEFlags();
Do(p, disableHLE);
if (p.mode == p.MODE_READ) {
// Whatever the config says now, this state's modules were loaded under these flags.
g_effectiveDisableHLE = (DisableHLEFlags)disableHLE;
g_disableHLELatched = true;
}
}
// Can't be inside a syscall when saving state, reset this so errors aren't misleading.
if (g_stackSize) {
ERROR_LOG(Log::HLE, "Can't save state while in a HLE syscall");
+3
View File
@@ -127,6 +127,9 @@ void RegisterHLEModule(std::string_view name, int numFunctions, const HLEFunctio
int GetNumRegisteredHLEModules();
const HLEModule *GetHLEModuleByIndex(int index);
DisableHLEFlags AlwaysDisableHLEFlags();
// The flags actually in effect for this boot - latched at the first module load and restored from
// savestates, so it can differ from what g_Config says if the setting changed since.
DisableHLEFlags GetEffectiveDisableHLEFlags();
// Run the current thread's callbacks after the syscall finishes.
void hleCheckCurrentCallbacks();
+2 -2
View File
@@ -1927,14 +1927,14 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load
return module;
}
SceUID KernelLoadModule(const std::string &filename, std::string *error_string) {
SceUID KernelLoadModule(const std::string &filename, std::string *error_string, bool fromTop) {
std::vector<uint8_t> buffer;
if (pspFileSystem.ReadEntireFile(filename, buffer) < 0)
return SCE_KERNEL_ERROR_NOFILE;
u32 error = SCE_KERNEL_ERROR_ILLEGAL_OBJECT;
u32 magic;
PSPModule *module = __KernelLoadELFFromPtr(&buffer[0], buffer.size(), 0, false, error_string, &magic, filename, error);
PSPModule *module = __KernelLoadELFFromPtr(&buffer[0], buffer.size(), 0, fromTop, error_string, &magic, filename, error);
if (module == nullptr)
return error;
+5 -1
View File
@@ -247,7 +247,11 @@ bool KernelFindImportByStubAddr(u32 stubAddr, std::string *importModuleName, u32
bool DescribeModuleAddress(u32 address, char *buffer, size_t bufferSize);
int __KernelGPUReplay();
void __KernelReturnFromModuleFunc();
SceUID KernelLoadModule(const std::string &filename, std::string *error_string);
// fromTop puts the module at the top of the user partition instead of the bottom. Use it for
// firmware modules we inject before the game loads - taking the bottom pushes the game's own ELF
// up, which shifts every address in it and invalidates cheats and achievements, and outright
// fails for a game like Tekken 6 whose EBOOT must load at a fixed low address.
SceUID KernelLoadModule(const std::string &filename, std::string *error_string, bool fromTop = false);
int __KernelStartModule(SceUID moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, SceKernelSMOption *smoption, bool *needsWait);
u32 __KernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, u32 argp, u32 statusAddr, u32 optionAddr, bool WithStatus);
u32 sceKernelFindModuleByUID(u32 uid);
+1 -1
View File
@@ -108,7 +108,7 @@ static void NotifyLoadStatusMp4(int state, u32 loadAddr, u32 totalSize) {
continue;
}
std::string error;
SceUID id = KernelLoadModule(paths[i], &error);
SceUID id = KernelLoadModule(paths[i], &error, true);
if (id < 0) {
ERROR_LOG(Log::sceUtility, "sceMp4 HLE is disabled, but %s wouldn't load (%s) - "
"the game will get unresolved imports", paths[i], error.c_str());