sysmodule: track shared module load references and unloaded status

This commit is contained in:
nmzik
2026-10-08 04:28:17 +04:00
parent 5a8808086a
commit 210d4dcd99
2 changed files with 66 additions and 1 deletions
+25 -1
View File
@@ -6,6 +6,9 @@
#include "libs/libs.h"
#include "loader/symbolDatabase.h"
#include <mutex>
#include <unordered_map>
namespace Libs {
LIB_VERSION("Sysmodule", 1, "Sysmodule", 1, 1);
@@ -17,6 +20,16 @@ int KYTY_SYSV_ABI KernelGetModuleInfoForUnwind(uint64_t addr, int flags, ModuleI
namespace Sysmodule {
constexpr int SYSMODULE_ERROR_UNLOADED = static_cast<int>(0x805a1001u);
static std::mutex g_module_mutex;
static std::unordered_map<uint16_t, uint32_t> g_module_refs;
static void LoadModule(uint16_t id) {
std::scoped_lock lock(g_module_mutex);
++g_module_refs[id];
}
static KYTY_SYSV_ABI int SysmoduleGetModuleInfoForUnwind(uint64_t addr, int flags,
LibKernel::ModuleInfoForUnwind* info) {
return LibKernel::KernelGetModuleInfoForUnwind(addr, flags, info);
@@ -27,6 +40,7 @@ static KYTY_SYSV_ABI int SysmoduleLoadModule(uint16_t id) {
LOGF("\t id = %d\n", static_cast<int>(id));
LoadModule(id);
return 0;
}
@@ -35,6 +49,14 @@ static KYTY_SYSV_ABI int SysmoduleUnloadModule(uint16_t id) {
LOGF("\t id = %d\n", static_cast<int>(id));
std::scoped_lock lock(g_module_mutex);
const auto module = g_module_refs.find(id);
if (module == g_module_refs.end()) {
return SYSMODULE_ERROR_UNLOADED;
}
if (--module->second == 0) {
g_module_refs.erase(module);
}
return 0;
}
@@ -49,6 +71,7 @@ static KYTY_SYSV_ABI int SysmoduleLoadModuleInternalWithArg(uint16_t id, int arg
EXIT_IF(arg3 != 0);
EXIT_IF(ret == nullptr);
LoadModule(id);
*ret = 0;
return 0;
@@ -59,7 +82,8 @@ static KYTY_SYSV_ABI int SysmoduleIsLoaded(uint16_t id) {
LOGF("\t id = %d\n", static_cast<int>(id));
return 0;
std::scoped_lock lock(g_module_mutex);
return g_module_refs.contains(id) ? 0 : SYSMODULE_ERROR_UNLOADED;
}
} // namespace Sysmodule
+41
View File
@@ -45,6 +45,7 @@ void InitLibKernel_1_Apr(Loader::SymbolDatabase *symbols);
namespace Libs {
void InitLibKernel_1(Loader::SymbolDatabase *symbols);
void InitSysmodule_1(Loader::SymbolDatabase *symbols);
}
namespace Libs::LibAmpr {
@@ -164,6 +165,45 @@ void TestFileDescriptorFlags() {
}
}
void TestSysmoduleReferences() {
Loader::SymbolDatabase symbols;
Libs::InitSysmodule_1(&symbols);
using ModuleCall = int (KYTY_SYSV_ABI *)(uint16_t);
const auto resolve = [&](const char* nid) {
const auto* symbol = symbols.Find(
{nid, "Sysmodule", 1, "Sysmodule", 1, 1, Loader::SymbolType::Func});
Check(symbol != nullptr, "Sysmodule export resolves");
return reinterpret_cast<ModuleCall>(symbol->vaddr);
};
const auto load = resolve("g8cM39EUZ6o");
const auto unload = resolve("eR2bZFAAU0Q");
const auto is_loaded = resolve("fMP5NHUOaMk");
constexpr int unloaded = static_cast<int>(0x805a1001u);
Check(load(0x113) == OK && is_loaded(0xb4) == unloaded,
"loading entitlement access does not mark AppContent loaded");
Check(unload(0x113) == OK, "release independent module reference");
for (const uint16_t id : {0x113, 0xb4}) {
Check(is_loaded(id) == unloaded, "unloaded module allows guest initialization");
Check(unload(id) == unloaded, "unloading an absent module reports UNLOADED");
Check(load(id) == OK && load(id) == OK && is_loaded(id) == OK,
"repeated loads retain references");
Check(unload(id) == OK && is_loaded(id) == OK,
"one unload preserves the remaining reference");
Check(unload(id) == OK && is_loaded(id) == unloaded,
"last unload restores unloaded status");
}
const auto* internal_symbol = symbols.Find(
{"hHrGoGoNf+s", "Sysmodule", 1, "Sysmodule", 1, 1, Loader::SymbolType::Func});
Check(internal_symbol != nullptr, "internal Sysmodule load export resolves");
const auto internal_load =
reinterpret_cast<int (KYTY_SYSV_ABI *)(uint16_t, int, int, int, int*)>(
internal_symbol->vaddr);
int result = -1;
Check(internal_load(0xb4, 0, 0, 0, &result) == OK && result == OK &&
is_loaded(0xb4) == OK && unload(0xb4) == OK && is_loaded(0xb4) == unloaded,
"internal and public module operations share load state");
}
void TestSaveOpenVisibility() {
constexpr char Path[] = "/savedata0/visible-save.dat";
constexpr char Payload[] = "saved progress";
@@ -1532,6 +1572,7 @@ int main(int, char**) {
TempDirectory temporary;
FileSystem::Initialize();
TestSysmoduleReferences();
TestRandomDevices();
TestFileDescriptorFlags();
CheckMountRoot(temporary.Path());