From 3949cf411f380fefa512041cd4fd7504dc11f7ad Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:26:56 -0600 Subject: [PATCH 1/4] Initialize heap API and run malloc_init Purely for testing --- src/core/libraries/kernel/memory.cpp | 33 ++++++++++++++ src/core/linker.cpp | 64 ++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index 62903ff72..c5732b294 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -308,6 +308,38 @@ s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, u64 len, s32 pro return sceKernelMapNamedFlexibleMemory(addr_in_out, len, prot, flags, "anon"); } +s32 PS4_SYSV_ABI sceKernelMapNamedSystemFlexibleMemory(void** addr_in_out, u64 len, s32 prot, + s32 flags, const char* name) { + LOG_INFO(Kernel_Vmm, "in_addr = {}, len = {:#x}, prot = {:#x}, flags = {:#x}, name = '{}'", + fmt::ptr(*addr_in_out), len, prot, flags, name); + if (len == 0 || !Common::Is16KBAligned(len)) { + LOG_ERROR(Kernel_Vmm, "len is 0 or not 16kb multiple"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + if (name == nullptr) { + LOG_ERROR(Kernel_Vmm, "name is invalid!"); + return ORBIS_KERNEL_ERROR_EFAULT; + } + + if (std::strlen(name) >= ORBIS_KERNEL_MAXIMUM_NAME_LENGTH) { + LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!"); + return ORBIS_KERNEL_ERROR_ENAMETOOLONG; + } + + VAddr in_addr = reinterpret_cast(*addr_in_out); + if (in_addr == 0) { + in_addr = 0x880000000; + } + const auto mem_prot = static_cast(prot); + const auto map_flags = static_cast(flags); + auto* memory = Core::Memory::Instance(); + const auto ret = memory->MapMemory(addr_in_out, in_addr, len, mem_prot, map_flags, + Core::VMAType::Stack, name); + LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr_in_out)); + return ret; +} + s32 PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot) { auto* memory = Core::Memory::Instance(); return memory->QueryProtection(std::bit_cast(addr), start, end, prot); @@ -823,6 +855,7 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("PGhQHd-dzv8", "libkernel", 1, "libkernel", sceKernelMmap); LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", sceKernelMunmap); LIB_FUNCTION("mL8NDH86iQI", "libkernel", 1, "libkernel", sceKernelMapNamedFlexibleMemory); + LIB_FUNCTION("kc+LEEIYakc", "libkernel", 1, "libkernel", sceKernelMapNamedSystemFlexibleMemory); LIB_FUNCTION("aNz11fnnzi4", "libkernel", 1, "libkernel", sceKernelAvailableFlexibleMemorySize); LIB_FUNCTION("aNz11fnnzi4", "libkernel_avlfmem", 1, "libkernel", sceKernelAvailableFlexibleMemorySize); diff --git a/src/core/linker.cpp b/src/core/linker.cpp index 8d7f9207e..d8153e535 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -69,6 +69,67 @@ void Linker::Execute(const std::vector& args) { Relocate(m.get()); } + // Before we can run guest code, we need to properly initialize the heap API and + // libSceLibcInternal. libSceLibcInternal's _malloc_init serves as an additional initialization + // function called by libkernel. + heap_api = new HeapAPI{}; + static PS4_SYSV_ABI void (*malloc_init)(); + + for (const auto& m : m_modules) { + const auto& mod = m.get(); + if (mod->name.contains("libSceLibcInternal.sprx")) { + // Found libSceLibcInternal, now search through function exports. + // Looking for _malloc_init to init libSceLibcInternal properly + // and for all the memory allocating functions, so we can initialize our heap API + for (const auto& sym : mod->export_sym.GetSymbols()) { + if (sym.nid_name.compare("_malloc_init") == 0) { + malloc_init = reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("malloc") == 0) { + heap_api->heap_malloc = + reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("free") == 0) { + heap_api->heap_free = + reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("calloc") == 0) { + heap_api->heap_calloc = + reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("realloc") == 0) { + heap_api->heap_realloc = + reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("memalign") == 0) { + heap_api->heap_memalign = + reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("posix_memalign") == 0) { + heap_api->heap_posix_memalign = + reinterpret_cast( + sym.virtual_address); + } + if (sym.nid_name.compare("reallocalign") == 0) { + heap_api->heap_reallocalign = + reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("malloc_stats") == 0) { + heap_api->heap_malloc_stats = + reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("malloc_stats_fast") == 0) { + heap_api->heap_malloc_stats_fast = + reinterpret_cast(sym.virtual_address); + } + if (sym.nid_name.compare("malloc_usable_size") == 0) { + heap_api->heap_malloc_usable_size = + reinterpret_cast(sym.virtual_address); + } + } + } + } + // Configure the direct and flexible memory regions. u64 fmem_size = ORBIS_FLEXIBLE_MEMORY_SIZE; bool use_extended_mem1 = true, use_extended_mem2 = true; @@ -112,6 +173,9 @@ void Linker::Execute(const std::vector& args) { LoadSharedLibraries(); + // Call _malloc_init + malloc_init(); + // Simulate libSceGnmDriver initialization, which maps a chunk of direct memory. // Some games fail without accurately emulating this behavior. s64 phys_addr{}; From f2f2d8359a4d6aad7f85049346e48822eeffa4dc Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:29:57 -0600 Subject: [PATCH 2/4] Update linker.cpp --- src/core/linker.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/linker.cpp b/src/core/linker.cpp index d8153e535..de08f54eb 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -73,7 +73,7 @@ void Linker::Execute(const std::vector& args) { // libSceLibcInternal. libSceLibcInternal's _malloc_init serves as an additional initialization // function called by libkernel. heap_api = new HeapAPI{}; - static PS4_SYSV_ABI void (*malloc_init)(); + static PS4_SYSV_ABI void (*malloc_init)() = nullptr; for (const auto& m : m_modules) { const auto& mod = m.get(); @@ -173,8 +173,10 @@ void Linker::Execute(const std::vector& args) { LoadSharedLibraries(); - // Call _malloc_init - malloc_init(); + if (malloc_init != nullptr) { + // Call _malloc_init + malloc_init(); + } // Simulate libSceGnmDriver initialization, which maps a chunk of direct memory. // Some games fail without accurately emulating this behavior. From 8539328ff8802353b34fadd1e90746745a198416 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Tue, 6 Jan 2026 19:11:37 -0600 Subject: [PATCH 3/4] Fix heap function definitions --- src/core/linker.cpp | 7 ++++--- src/core/linker.h | 19 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/core/linker.cpp b/src/core/linker.cpp index de08f54eb..cb6b1192e 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -112,15 +112,16 @@ void Linker::Execute(const std::vector& args) { } if (sym.nid_name.compare("reallocalign") == 0) { heap_api->heap_reallocalign = - reinterpret_cast(sym.virtual_address); + reinterpret_cast( + sym.virtual_address); } if (sym.nid_name.compare("malloc_stats") == 0) { heap_api->heap_malloc_stats = - reinterpret_cast(sym.virtual_address); + reinterpret_cast(sym.virtual_address); } if (sym.nid_name.compare("malloc_stats_fast") == 0) { heap_api->heap_malloc_stats_fast = - reinterpret_cast(sym.virtual_address); + reinterpret_cast(sym.virtual_address); } if (sym.nid_name.compare("malloc_usable_size") == 0) { heap_api->heap_malloc_usable_size = diff --git a/src/core/linker.h b/src/core/linker.h index 8ffcd9d45..b4a26ae39 100644 --- a/src/core/linker.h +++ b/src/core/linker.h @@ -54,17 +54,16 @@ struct EntryParams { }; struct HeapAPI { - PS4_SYSV_ABI void* (*heap_malloc)(size_t); + PS4_SYSV_ABI void* (*heap_malloc)(u64); PS4_SYSV_ABI void (*heap_free)(void*); - PS4_SYSV_ABI void* (*heap_calloc)(size_t, size_t); - PS4_SYSV_ABI void* (*heap_realloc)(void*, size_t); - PS4_SYSV_ABI void* (*heap_memalign)(size_t, size_t); - PS4_SYSV_ABI int (*heap_posix_memalign)(void**, size_t, size_t); - // NOTE: Fields below may be inaccurate - PS4_SYSV_ABI int (*heap_reallocalign)(void); - PS4_SYSV_ABI void (*heap_malloc_stats)(void); - PS4_SYSV_ABI int (*heap_malloc_stats_fast)(void); - PS4_SYSV_ABI size_t (*heap_malloc_usable_size)(void*); + PS4_SYSV_ABI void* (*heap_calloc)(u64, u64); + PS4_SYSV_ABI void* (*heap_realloc)(void*, u64); + PS4_SYSV_ABI void* (*heap_memalign)(u64, u64); + PS4_SYSV_ABI s32 (*heap_posix_memalign)(void**, u64, u64); + PS4_SYSV_ABI s32 (*heap_reallocalign)(void*, u64, u64); + PS4_SYSV_ABI s32 (*heap_malloc_stats)(void*); + PS4_SYSV_ABI s32 (*heap_malloc_stats_fast)(void*); + PS4_SYSV_ABI u64 (*heap_malloc_usable_size)(void*); }; using AppHeapAPI = HeapAPI*; From dcb5d4dd38ca239005526d7e02aaf9d6e9e28f30 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Sun, 1 Mar 2026 11:20:23 -0600 Subject: [PATCH 4/4] Run malloc_init before initializing libs Allows LLE libSceMoveTracker. --- src/core/linker.cpp | 4 +++- src/core/linker.h | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/core/linker.cpp b/src/core/linker.cpp index ef7bc0d45..10b73f023 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -172,13 +172,15 @@ void Linker::Execute(const std::vector& args) { ipc.WaitForStart(); } - LoadSharedLibraries(); + LoadLibcInternal(); if (malloc_init != nullptr) { // Call _malloc_init malloc_init(); } + LoadSharedLibraries(); + // Simulate libSceGnmDriver initialization, which maps a chunk of direct memory. // Some games fail without accurately emulating this behavior. s64 phys_addr{}; diff --git a/src/core/linker.h b/src/core/linker.h index b4a26ae39..e2efccbb0 100644 --- a/src/core/linker.h +++ b/src/core/linker.h @@ -124,9 +124,17 @@ public: } } + void LoadLibcInternal() { + for (auto& module : m_modules) { + if (module->name.contains("libSceLibcInternal")) { + module->Start(0, nullptr, nullptr); + } + } + } + void LoadSharedLibraries() { for (auto& module : m_modules) { - if (module->IsSharedLib()) { + if (module->IsSharedLib() && !module->name.contains("libSceLibcInternal")) { module->Start(0, nullptr, nullptr); } }