diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp index 4830f65a5..47ed6a48f 100644 --- a/src/core/address_space.cpp +++ b/src/core/address_space.cpp @@ -55,7 +55,7 @@ static constexpr u64 SystemReservedSize = SYSTEM_RESERVED_MAX - SYSTEM_RESERVED_ static constexpr u64 UserSize = USER_MAX - USER_MIN + 1; // Required backing file size for mapping physical address space. -static u64 BackingSize = ORBIS_KERNEL_TOTAL_MEM_DEV_PRO; +static u64 BackingSize = ORBIS_KERNEL_TOTAL_MEM_DEV_PRO + ORBIS_KERNEL_FLEXIBLE_MEMORY_SIZE; #ifdef _WIN32 diff --git a/src/core/libraries/kernel/memory.h b/src/core/libraries/kernel/memory.h index 9f78eb84f..7134f98b0 100644 --- a/src/core/libraries/kernel/memory.h +++ b/src/core/libraries/kernel/memory.h @@ -12,8 +12,8 @@ constexpr u64 ORBIS_KERNEL_TOTAL_MEM_DEV = 6656_MB; // TODO: This value needs confirmation constexpr u64 ORBIS_KERNEL_TOTAL_MEM_DEV_PRO = 7936_MB; -constexpr u64 ORBIS_FLEXIBLE_MEMORY_BASE = 64_MB; -constexpr u64 ORBIS_FLEXIBLE_MEMORY_SIZE = 512_MB; +constexpr u64 ORBIS_KERNEL_FLEXIBLE_MEMORY_BASE = 64_MB; +constexpr u64 ORBIS_KERNEL_FLEXIBLE_MEMORY_SIZE = 512_MB; namespace Core::Loader { class SymbolsResolver; diff --git a/src/core/linker.cpp b/src/core/linker.cpp index 2db41375b..0897b63f7 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -75,7 +75,7 @@ void Linker::Execute(const std::vector& args) { } // Configure the direct and flexible memory regions. - u64 fmem_size = ORBIS_FLEXIBLE_MEMORY_SIZE; + u64 fmem_size = ORBIS_KERNEL_FLEXIBLE_MEMORY_SIZE; bool use_extended_mem1 = true, use_extended_mem2 = true; const auto* proc_param = GetProcParam(); @@ -88,7 +88,7 @@ void Linker::Execute(const std::vector& args) { 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; + fmem_size = *flexible_size + ORBIS_KERNEL_FLEXIBLE_MEMORY_BASE; } } } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index a340c3643..442937a5a 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -27,6 +27,21 @@ MemoryManager::MemoryManager() { LOG_INFO(Kernel_Vmm, "{:#x} - {:#x}", region.lower(), region.upper()); } + // Pre-initialize direct backing + auto total_size = ORBIS_KERNEL_TOTAL_MEM_DEV_PRO; + s32 extra_dmem = EmulatorSettings.GetExtraDmemInMBytes(); + if (extra_dmem != 0) { + total_size += extra_dmem * 1_MB; + } + total_direct_size = total_size; + dmem_map.clear(); + dmem_map.emplace(0, PhysicalMemoryArea{0, total_direct_size}); + + // Pre-initialize flexible backing + total_flexible_size = ORBIS_KERNEL_FLEXIBLE_MEMORY_SIZE; + fmem_map.clear(); + fmem_map.emplace(total_size, PhysicalMemoryArea{total_size, total_flexible_size}); + ASSERT_MSG(Libraries::Kernel::sceKernelGetCompiledSdkVersion(&sdk_version) == 0, "Failed to get compiled SDK version"); } @@ -35,6 +50,7 @@ MemoryManager::~MemoryManager() = default; void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1, bool use_extended_mem2) { + // Calculate actual direct and flexible memory sizes 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,20 +69,19 @@ 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; + + // Update stored totals + total_flexible_size = flexible_size - ORBIS_KERNEL_FLEXIBLE_MEMORY_BASE; + ASSERT_MSG(total_flexible_size >= flexible_usage, "Unable to shrink flexible memory size"); + u64 old_direct_size = total_direct_size; total_direct_size = total_size - flexible_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. - dmem_map.clear(); - dmem_map.emplace(0, PhysicalMemoryArea{0, total_direct_size}); - - // Insert an area that covers the flexible memory physical address block. - // Note that this should never be called after flexible memory allocations have been made. - const auto remaining_physical_space = total_size - total_direct_size; - fmem_map.clear(); - fmem_map.emplace(total_direct_size, - PhysicalMemoryArea{total_direct_size, remaining_physical_space}); + // Limit direct memory space to match actual limit + auto last_dmem_area = FindDmemArea(total_direct_size); + ASSERT_MSG(last_dmem_area->second.dma_type == PhysicalMemoryType::Free && + last_dmem_area->second.size >= old_direct_size - total_direct_size, + "Unable to shrink dmem map"); + last_dmem_area->second.size -= (old_direct_size - total_direct_size); LOG_INFO(Kernel_Vmm, "Configured memory regions: flexible size = {:#x}, direct size = {:#x}", total_flexible_size, total_direct_size); diff --git a/src/core/module.cpp b/src/core/module.cpp index 7e9d74a09..074c8d62e 100644 --- a/src/core/module.cpp +++ b/src/core/module.cpp @@ -110,16 +110,19 @@ void Module::LoadModuleToMemory(u32& max_tls_index) { const u64 base_size = CalculateBaseSize(elf_header, elf_pheader); aligned_base_size = Common::AlignUp(base_size, BlockAlign); - // Map module segments (and possible TLS trampolines) + // Reserve memory area for module void** out_addr = reinterpret_cast(&base_virtual_addr); memory->MapMemory(out_addr, ModuleLoadBase, aligned_base_size + TrampolineSize, - MemoryProt::CpuReadWrite | MemoryProt::CpuExec, MemoryMapFlags::NoFlags, - VMAType::Code, name); + MemoryProt::NoAccess, MemoryMapFlags::NoFlags, VMAType::Reserved, name); LOG_INFO(Core_Linker, "Loading module {} to {}", name, fmt::ptr(*out_addr)); #ifdef ARCH_X86_64 // Initialize trampoline generator. - void* trampoline_addr = std::bit_cast(base_virtual_addr + aligned_base_size); + VAddr trampoline_vaddr = base_virtual_addr + aligned_base_size; + void* trampoline_addr = std::bit_cast(trampoline_vaddr); + memory->MapMemory(&trampoline_addr, trampoline_vaddr, TrampolineSize, + MemoryProt::CpuReadWrite | MemoryProt::CpuExec, MemoryMapFlags::Fixed, + VMAType::Code, name); RegisterPatchModule(*out_addr, aligned_base_size, trampoline_addr, TrampolineSize); #endif @@ -129,15 +132,32 @@ void Module::LoadModuleToMemory(u32& max_tls_index) { LOG_INFO(Core_Linker, "aligned_base_size ......: {:#018x}", aligned_base_size); const auto add_segment = [this](const elf_program_header& phdr, bool do_map = true) { - const VAddr segment_addr = base_virtual_addr + phdr.p_vaddr; + const VAddr segment_vaddr = base_virtual_addr + phdr.p_vaddr; + void* segment_addr = std::bit_cast(segment_vaddr); + const u64 segment_size = GetAlignedSize(phdr); if (do_map) { - elf.LoadSegment(segment_addr, phdr.p_offset, phdr.p_filesz); + // Convert ELF flags to memory prot. + auto segment_prot = MemoryProt::NoAccess; + if ((phdr.p_flags & PF_READ) != 0) { + segment_prot |= MemoryProt::CpuRead; + } + if ((phdr.p_flags & PF_WRITE) != 0) { + segment_prot |= MemoryProt::CpuWrite; + } + if ((phdr.p_flags & PF_EXEC) != 0) { + segment_prot |= MemoryProt::CpuExec; + } + // Map module segments + const auto memory_type = IsSystemLib() ? VMAType::Code : VMAType::Flexible; + memory->MapMemory(&segment_addr, segment_vaddr, segment_size, segment_prot, + MemoryMapFlags::Fixed, memory_type, name); + elf.LoadSegment(segment_vaddr, phdr.p_offset, phdr.p_filesz); } if (info.num_segments < 4) { auto& segment = info.segments[info.num_segments++]; - segment.address = segment_addr; + segment.address = segment_vaddr; segment.prot = phdr.p_flags; - segment.size = GetAlignedSize(phdr); + segment.size = segment_size; } else { LOG_ERROR(Core_Linker, "Attempting to add too many segments!"); } @@ -159,8 +179,8 @@ void Module::LoadModuleToMemory(u32& max_tls_index) { const auto segment_mode = elf.ElfPheaderFlagsStr(elf_pheader[i].p_flags); LOG_INFO(Core_Linker, "program header = [{}] type = {}", i, header_type); LOG_INFO(Core_Linker, "segment_addr ..........: {:#018x}", segment_addr); - LOG_INFO(Core_Linker, "segment_file_size .....: {}", segment_file_size); - LOG_INFO(Core_Linker, "segment_memory_size ...: {}", segment_memory_size); + LOG_INFO(Core_Linker, "segment_file_size .....: {:#018x}", segment_file_size); + LOG_INFO(Core_Linker, "segment_memory_size ...: {:#018x}", segment_memory_size); LOG_INFO(Core_Linker, "segment_mode ..........: {}", segment_mode); add_segment(elf_pheader[i]);