Initialize heap API and run malloc_init

Purely for testing
This commit is contained in:
Stephen Miller 2026-01-06 18:26:56 -06:00
parent 975b1d312a
commit 3949cf411f
2 changed files with 97 additions and 0 deletions

View File

@ -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<VAddr>(*addr_in_out);
if (in_addr == 0) {
in_addr = 0x880000000;
}
const auto mem_prot = static_cast<Core::MemoryProt>(prot);
const auto map_flags = static_cast<Core::MemoryMapFlags>(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<VAddr>(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);

View File

@ -69,6 +69,67 @@ void Linker::Execute(const std::vector<std::string>& 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<PS4_SYSV_ABI void (*)()>(sym.virtual_address);
}
if (sym.nid_name.compare("malloc") == 0) {
heap_api->heap_malloc =
reinterpret_cast<PS4_SYSV_ABI void* (*)(u64)>(sym.virtual_address);
}
if (sym.nid_name.compare("free") == 0) {
heap_api->heap_free =
reinterpret_cast<PS4_SYSV_ABI void (*)(void*)>(sym.virtual_address);
}
if (sym.nid_name.compare("calloc") == 0) {
heap_api->heap_calloc =
reinterpret_cast<PS4_SYSV_ABI void* (*)(u64, u64)>(sym.virtual_address);
}
if (sym.nid_name.compare("realloc") == 0) {
heap_api->heap_realloc =
reinterpret_cast<PS4_SYSV_ABI void* (*)(void*, u64)>(sym.virtual_address);
}
if (sym.nid_name.compare("memalign") == 0) {
heap_api->heap_memalign =
reinterpret_cast<PS4_SYSV_ABI void* (*)(u64, u64)>(sym.virtual_address);
}
if (sym.nid_name.compare("posix_memalign") == 0) {
heap_api->heap_posix_memalign =
reinterpret_cast<PS4_SYSV_ABI s32 (*)(void**, u64, u64)>(
sym.virtual_address);
}
if (sym.nid_name.compare("reallocalign") == 0) {
heap_api->heap_reallocalign =
reinterpret_cast<PS4_SYSV_ABI s32 (*)()>(sym.virtual_address);
}
if (sym.nid_name.compare("malloc_stats") == 0) {
heap_api->heap_malloc_stats =
reinterpret_cast<PS4_SYSV_ABI void (*)()>(sym.virtual_address);
}
if (sym.nid_name.compare("malloc_stats_fast") == 0) {
heap_api->heap_malloc_stats_fast =
reinterpret_cast<PS4_SYSV_ABI s32 (*)()>(sym.virtual_address);
}
if (sym.nid_name.compare("malloc_usable_size") == 0) {
heap_api->heap_malloc_usable_size =
reinterpret_cast<PS4_SYSV_ABI u64 (*)(void*)>(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<std::string>& 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{};