mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-07-16 02:01:02 +00:00
Core: Proper module memory mappings (#4273)
* Early memory regions setup Needed to enable flexible allocations before mapping the eboot * Improved accuracy of module mappings To keep our current logic intact, reserve the full memory space, then perform fixed mappings for trampoline and segments. Segment mappings use type flexible, so they properly count toward flexible usage, while trampoline mappings use type code to bypass this. * Asserts for failed offset finding Always check before you leap. * Hex logging for segment sizes * Only map game modules to flex mem. * Revert "Asserts for failed offset finding" This reverts commit38083f8cbb. * Revert "Early memory regions setup" This reverts commitda1552d4ac. * Initialize memory regions in MemoryManager constructor Much simpler approach to enabling the necessary flexible mappings on startup.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -75,7 +75,7 @@ void Linker::Execute(const std::vector<std::string>& 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<std::string>& 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<void**>(&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<void*>(base_virtual_addr + aligned_base_size);
|
||||
VAddr trampoline_vaddr = base_virtual_addr + aligned_base_size;
|
||||
void* trampoline_addr = std::bit_cast<void*>(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<void*>(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]);
|
||||
|
||||
Reference in New Issue
Block a user