diff --git a/externals/Vulkan-Utility-Libraries b/externals/Vulkan-Utility-Libraries index bc3a4d9fd..0d5b49b80 160000 --- a/externals/Vulkan-Utility-Libraries +++ b/externals/Vulkan-Utility-Libraries @@ -1 +1 @@ -Subproject commit bc3a4d9fd9b46729651a3cec4f5226f6272b8684 +Subproject commit 0d5b49b80f17bca25e7f9321ad4e671a56f70887 diff --git a/externals/VulkanMemoryAllocator b/externals/VulkanMemoryAllocator index 29b35ea42..89d3a6a5e 160000 --- a/externals/VulkanMemoryAllocator +++ b/externals/VulkanMemoryAllocator @@ -1 +1 @@ -Subproject commit 29b35ea4232688c0f42cdff0c10848290760a417 +Subproject commit 89d3a6a5ea35d140fe865ed493c89bde777c6a07 diff --git a/externals/vcpkg b/externals/vcpkg index a7d06b3a7..64f3d3d62 160000 --- a/externals/vcpkg +++ b/externals/vcpkg @@ -1 +1 @@ -Subproject commit a7d06b3a72d5ec48353bacb84152bd027ee9999b +Subproject commit 64f3d3d6201d9cea01d15ea6e793daf0bbcd47c7 diff --git a/src/core/memory.cpp b/src/core/memory.cpp index c598edbc2..b92698945 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-FileCopyrightText: 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: 2025 Citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -909,7 +910,9 @@ struct Memory::Impl { #endif }; -Memory::Memory(Core::System& system_) : system{system_} { +Memory::Memory(Core::System& system_) : system(system_), impl(std::make_unique(system_)), gen(rd()) { + // Initialize the random number distribution + dis = std::uniform_int_distribution(0, std::numeric_limits::max()); Reset(); } @@ -1151,4 +1154,48 @@ bool Memory::InvalidateSeparateHeap(void* fault_address) { #endif } +Common::ProcessAddress Memory::GenerateRandomBaseAddress() { + u64 random_bits = dis(gen); + return Common::ProcessAddress((random_bits & ~NRO_BASE_ADDRESS_RANDOMIZATION_MASK) | + (random_bits & NRO_BASE_ADDRESS_RANDOMIZATION_MASK)); +} + +Memory::MemoryRegion* Memory::FindRegion(Common::ProcessAddress address) { + for (auto& entry : memory_regions) { + if (address >= entry.second.start_address && + address < entry.second.start_address + entry.second.size) { + return &entry.second; + } + } + return nullptr; +} + +void Memory::MapMemoryRegion(Common::ProcessAddress start_address, u64 size, MemoryRegionType type, + bool exec, bool write) { + if (start_address + size > EMULATED_MEMORY_SIZE) { + LOG_ERROR(HW_Memory, "Memory mapping exceeds emulated memory boundaries at address {:016X}", + GetInteger(start_address)); + return; + } + + // Create the memory region + memory_regions[start_address] = MemoryRegion(start_address, size, type, exec, write); + + // Map the region in the page table + Common::MemoryPermission perms{}; + if (exec) perms |= Common::MemoryPermission::Execute; + if (write) perms |= Common::MemoryPermission::Write; + perms |= Common::MemoryPermission::Read; + + // Using the MapMemoryRegion method defined in the Impl struct + impl->MapMemoryRegion(*impl->current_page_table, start_address, size, + Common::PhysicalAddress(GetInteger(start_address)), perms, false); +} + +Common::ProcessAddress Memory::MapBinary(u64 size) { + Common::ProcessAddress base_address = GenerateRandomBaseAddress(); + MapMemoryRegion(base_address, size, MemoryRegionType::BinaryMemory, true, true); + return base_address; +} + } // namespace Core::Memory diff --git a/src/core/memory.h b/src/core/memory.h index 3f315ff7a..45189c426 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: 2014 Citra Emulator Project +// SPDX-FileCopyrightText: 2025 Citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -9,6 +10,8 @@ #include #include #include +#include +#include #include "common/scratch_buffer.h" #include "common/typed_address.h" @@ -43,6 +46,9 @@ constexpr std::size_t CITRON_PAGEBITS = 12; constexpr u64 CITRON_PAGESIZE = 1ULL << CITRON_PAGEBITS; constexpr u64 CITRON_PAGEMASK = CITRON_PAGESIZE - 1; +/// Emulated memory size (4GB) +constexpr u64 EMULATED_MEMORY_SIZE = 4ULL * 1024 * 1024 * 1024; + /// Virtual user-space memory regions enum : u64 { /// TLS (Thread-Local Storage) related. @@ -50,6 +56,18 @@ enum : u64 { /// Application stack DEFAULT_STACK_SIZE = 0x100000, + + /// Mask to randomize bits 37-12 for NRO base address + NRO_BASE_ADDRESS_RANDOMIZATION_MASK = 0xFFFFFFFFFFFFF000, +}; + +/// Types of memory regions in the system +enum class MemoryRegionType { + SystemMemory, + GraphicsMemory, + IOMemory, + BinaryMemory, + Undefined }; /// Central class that handles all memory operations and state. @@ -64,6 +82,55 @@ public: Memory(Memory&&) = default; Memory& operator=(Memory&&) = delete; + /** + * Structure representing a memory region with its properties + */ + struct MemoryRegion { + Common::ProcessAddress start_address; + u64 size; + std::unique_ptr data; + bool is_mapped; + MemoryRegionType type; + bool is_executable; + bool is_writable; + + // Default constructor needed for STL containers + MemoryRegion() : start_address(0), size(0), data(nullptr), is_mapped(false), + type(MemoryRegionType::Undefined), is_executable(false), is_writable(false) {} + + MemoryRegion(Common::ProcessAddress start, u64 sz, MemoryRegionType t, bool exec = false, bool write = false) + : start_address(start), size(sz), data(std::make_unique(sz)), is_mapped(false), + type(t), is_executable(exec), is_writable(write) {} + }; + + /** + * Maps a memory region with the specified properties + * + * @param start_address The starting address of the region + * @param size The size of the region in bytes + * @param type The type of memory region + * @param exec Whether the region is executable + * @param write Whether the region is writable + */ + void MapMemoryRegion(Common::ProcessAddress start_address, u64 size, MemoryRegionType type, + bool exec = false, bool write = false); + + /** + * Maps a binary with a randomized base address + * + * @param size The size of the binary in bytes + * @returns The base address where the binary was mapped + */ + Common::ProcessAddress MapBinary(u64 size); + + /** + * Finds a memory region containing the specified address + * + * @param address The address to search for + * @returns Pointer to the memory region if found, nullptr otherwise + */ + MemoryRegion* FindRegion(Common::ProcessAddress address); + /** * Resets the state of the Memory system. */ @@ -497,6 +564,13 @@ private: struct Impl; std::unique_ptr impl; + + std::unordered_map memory_regions; + std::random_device rd; + std::mt19937 gen; + std::uniform_int_distribution dis; + + Common::ProcessAddress GenerateRandomBaseAddress(); }; template