diff --git a/src/core/linker.cpp b/src/core/linker.cpp index 15b939737..173de87cc 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -74,41 +74,6 @@ void Linker::Execute(const std::vector& args) { Relocate(m.get()); } - // Configure the direct and flexible memory regions. - u64 fmem_size = ORBIS_FLEXIBLE_MEMORY_SIZE; - bool use_extended_mem1 = true, use_extended_mem2 = true; - - const auto* proc_param = GetProcParam(); - ASSERT(proc_param); - - Core::OrbisKernelMemParam mem_param{}; - if (proc_param->size >= offsetof(OrbisProcParam, mem_param) + sizeof(OrbisKernelMemParam*)) { - if (proc_param->mem_param) { - mem_param = *proc_param->mem_param; - if (mem_param.size >= - offsetof(OrbisKernelMemParam, flexible_memory_size) + sizeof(u64*)) { - if (const auto* flexible_size = mem_param.flexible_memory_size) { - fmem_size = *flexible_size + ORBIS_FLEXIBLE_MEMORY_BASE; - } - } - } - } - - if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_1) + sizeof(u64*)) { - mem_param.extended_memory_1 = nullptr; - } - if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_2) + sizeof(u64*)) { - mem_param.extended_memory_2 = nullptr; - } - - const u64 sdk_ver = proc_param->sdk_version; - if (sdk_ver < Common::ElfInfo::FW_50) { - use_extended_mem1 = mem_param.extended_memory_1 ? *mem_param.extended_memory_1 : false; - use_extended_mem2 = mem_param.extended_memory_2 ? *mem_param.extended_memory_2 : false; - } - - memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2); - main_thread.Run([this, module, &args](std::stop_token) { Common::SetCurrentThreadName("Game:Main"); #ifndef _WIN32 // Clear any existing signal mask for game threads. diff --git a/src/core/memory.cpp b/src/core/memory.cpp index a340c3643..9110e8858 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -33,8 +33,23 @@ MemoryManager::MemoryManager() { MemoryManager::~MemoryManager() = default; -void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1, - bool use_extended_mem2) { +void MemoryManager::SetupMemoryRegions(u64* flexible_size, u8* extended_memory_1, + u8* extended_memory_2) { + u64 fmem_size = ORBIS_FLEXIBLE_MEMORY_SIZE; + bool use_extended_mem1 = true, use_extended_mem2 = true; + + if (flexible_size) { + fmem_size = *flexible_size + ORBIS_FLEXIBLE_MEMORY_BASE; + } + + s32 sdk_ver; + ASSERT_MSG(::Libraries::Kernel::sceKernelGetCompiledSdkVersion(&sdk_ver) == ORBIS_OK, + "Failed to get SDK version"); + if (sdk_ver < Common::ElfInfo::FW_50) { + use_extended_mem1 = extended_memory_1 ? *extended_memory_1 : false; + use_extended_mem2 = extended_memory_2 ? *extended_memory_2 : false; + } + const bool is_neo = ::Libraries::Kernel::sceKernelIsNeoMode(); auto total_size = is_neo ? ORBIS_KERNEL_TOTAL_MEM_PRO : ORBIS_KERNEL_TOTAL_MEM; if (EmulatorSettings.IsDevKit()) { @@ -53,8 +68,8 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1 if (!use_extended_mem2 && !is_neo) { total_size -= 128_MB; } - total_flexible_size = flexible_size - ORBIS_FLEXIBLE_MEMORY_BASE; - total_direct_size = total_size - flexible_size; + total_flexible_size = fmem_size - ORBIS_FLEXIBLE_MEMORY_BASE; + total_direct_size = total_size - fmem_size; // Insert an area that covers the direct memory physical address block. // Note that this should never be called after direct memory allocations have been made. diff --git a/src/core/memory.h b/src/core/memory.h index 2588fbd6a..06d7c3d91 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -240,7 +240,7 @@ public: bool TryWriteBacking(void* address, const void* data, u64 size); - void SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1, bool use_extended_mem2); + void SetupMemoryRegions(u64* flexible_size, u8* extended_memory_1, u8* extended_memory_2); PAddr PoolExpand(PAddr search_start, PAddr search_end, u64 size, u64 alignment); diff --git a/src/emulator.cpp b/src/emulator.cpp index ac21c9759..e541798e7 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -92,6 +92,106 @@ s32 ReadCompiledSdkVersion(const std::filesystem::path& file) { return 0; } +void InitializeMemoryRegions(const std::filesystem::path& file) { + Core::Loader::Elf elf; + elf.Open(file); + if (!elf.IsElfFile()) { + return; + } + const auto elf_pheader = elf.GetProgramHeader(); + auto i_procparam = std::find_if(elf_pheader.begin(), elf_pheader.end(), [](const auto& entry) { + return entry.p_type == PT_SCE_PROCPARAM; + }); + + if (i_procparam != elf_pheader.end()) { + Core::OrbisProcParam param{}; + elf.LoadSegment(std::bit_cast(¶m), i_procparam->p_offset, i_procparam->p_filesz); + + // We need to convert virtual addresses to their physical file offset. + // To do this, search through program headers and calculate the offset for + // the block the address is in. + const auto get_offset = [](std::span phdr, void* offset) { + s64 virtual_offset = std::bit_cast(offset); + auto block = + std::find_if(phdr.begin(), phdr.end(), [virtual_offset](const auto& entry) { + return (entry.p_type == PT_SCE_RELRO || entry.p_type == PT_LOAD) && + entry.p_vaddr <= virtual_offset && + entry.p_vaddr + entry.p_memsz > virtual_offset; + }); + if (block != phdr.end()) { + return virtual_offset + block->p_offset - block->p_vaddr; + } + return static_cast(0); + }; + + // Read raw memory parameter data + Core::OrbisKernelMemParam* mem_param = new Core::OrbisKernelMemParam(); + if (param.mem_param) { + u64 offset = get_offset(elf_pheader, param.mem_param); + u64 vaddr = std::bit_cast(mem_param); + elf.LoadSegment(vaddr, offset, sizeof(*mem_param)); + } else { + delete (mem_param); + mem_param = nullptr; + } + + // Read flexible memory size + u64* flexible_memory_size = new u64(); + if (mem_param && mem_param->flexible_memory_size) { + u64 offset = get_offset(elf_pheader, mem_param->flexible_memory_size); + u64 vaddr = std::bit_cast(flexible_memory_size); + elf.LoadSegment(vaddr, offset, sizeof(*flexible_memory_size)); + } else { + delete (flexible_memory_size); + flexible_memory_size = nullptr; + } + + // Read the extended memory parameters + u8* extended_memory_1 = new u8(); + if (mem_param && mem_param->extended_memory_1) { + u64 offset = get_offset(elf_pheader, mem_param->extended_memory_1); + u64 vaddr = std::bit_cast(extended_memory_1); + elf.LoadSegment(vaddr, offset, sizeof(*extended_memory_1)); + } else { + delete (extended_memory_1); + extended_memory_1 = nullptr; + } + u8* extended_memory_2 = new u8(); + if (mem_param && mem_param->extended_memory_2) { + u64 offset = get_offset(elf_pheader, mem_param->extended_memory_2); + u64 vaddr = std::bit_cast(extended_memory_2); + elf.LoadSegment(vaddr, offset, sizeof(*extended_memory_2)); + } else { + delete (extended_memory_2); + extended_memory_2 = nullptr; + } + + // Run memory initialization with these parameters. + auto* memory = Core::Memory::Instance(); + memory->SetupMemoryRegions(flexible_memory_size, extended_memory_1, extended_memory_2); + + // Clean up + if (mem_param) { + delete (mem_param); + mem_param = nullptr; + } + if (flexible_memory_size) { + delete (flexible_memory_size); + flexible_memory_size = nullptr; + } + if (extended_memory_1) { + delete (extended_memory_1); + extended_memory_1 = nullptr; + } + if (extended_memory_2) { + delete (extended_memory_2); + extended_memory_2 = nullptr; + } + return; + } + return; +} + void Emulator::Run(std::filesystem::path file, std::vector args, std::optional p_game_folder) { Common::SetCurrentThreadName("shadPS4:Main"); @@ -450,6 +550,9 @@ void Emulator::Run(std::filesystem::path file, std::vector args, LOG_WARNING(Loader, "No dumped system fonts, expect missing text or instability"); } + // Initialize memory regions + InitializeMemoryRegions(eboot_path); + // Initialize kernel and library facilities. Libraries::InitHLELibs(&linker->GetHLESymbols());