diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index 378064e44..5d94735ae 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -318,6 +318,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); @@ -833,6 +865,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 ac5133d16..a5a2846a9 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -69,6 +69,68 @@ 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)() = nullptr; + + 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; @@ -110,6 +172,13 @@ void Linker::Execute(const std::vector& args) { ipc.WaitForStart(); } + LoadLibcInternal(); + + if (malloc_init != nullptr) { + // Call _malloc_init + malloc_init(); + } + LoadSharedLibraries(); // Simulate libSceGnmDriver initialization, which maps a chunk of direct memory. diff --git a/src/core/linker.h b/src/core/linker.h index 8ffcd9d45..e2efccbb0 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*; @@ -125,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); } }