mirror of https://git.citron-emu.org/citron/emu
memory: Implement enhanced memory management system
Add a flexible memory region management system that provides: - Memory region type classification (System, Graphics, IO, Binary) - Memory region permission management (executable, writable) - Binary base address randomization for ASLR - Dynamic memory mapping capabilities Credit: boss.smc@citron-emu.org Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
parent
1fd5fefcb1
commit
ebfc9d8347
|
@ -1 +1 @@
|
|||
Subproject commit bc3a4d9fd9b46729651a3cec4f5226f6272b8684
|
||||
Subproject commit 0d5b49b80f17bca25e7f9321ad4e671a56f70887
|
|
@ -1 +1 @@
|
|||
Subproject commit 29b35ea4232688c0f42cdff0c10848290760a417
|
||||
Subproject commit 89d3a6a5ea35d140fe865ed493c89bde777c6a07
|
|
@ -1 +1 @@
|
|||
Subproject commit a7d06b3a72d5ec48353bacb84152bd027ee9999b
|
||||
Subproject commit 64f3d3d6201d9cea01d15ea6e793daf0bbcd47c7
|
|
@ -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 <algorithm>
|
||||
|
@ -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<Impl>(system_)), gen(rd()) {
|
||||
// Initialize the random number distribution
|
||||
dis = std::uniform_int_distribution<u64>(0, std::numeric_limits<u64>::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
|
||||
|
|
|
@ -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 <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <random>
|
||||
|
||||
#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<u8[]> 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<u8[]>(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> impl;
|
||||
|
||||
std::unordered_map<Common::ProcessAddress, MemoryRegion> memory_regions;
|
||||
std::random_device rd;
|
||||
std::mt19937 gen;
|
||||
std::uniform_int_distribution<u64> dis;
|
||||
|
||||
Common::ProcessAddress GenerateRandomBaseAddress();
|
||||
};
|
||||
|
||||
template <typename T, GuestMemoryFlags FLAGS>
|
||||
|
|
Loading…
Reference in New Issue