mirror of
https://git.citron-emu.org/Citron/Citron.git
synced 2025-03-15 05:34:49 +00:00
common: Enhance memory mapping safety and debugging
- Reduce max_memory_size from 512GB to 1GB for safer allocation limits - Add memory operation logging for debugging purposes - Implement MapMemory() with additional safety checks and large allocation handling - Add validation checks for memory mappings - Introduce chunked allocation strategy for large memory requests - Add detailed error logging for memory operations
This commit is contained in:
parent
becaf850ab
commit
5af4803e42
2 changed files with 100 additions and 1 deletions
|
@ -41,7 +41,23 @@ namespace Common {
|
||||||
|
|
||||||
constexpr size_t PageAlignment = 0x1000;
|
constexpr size_t PageAlignment = 0x1000;
|
||||||
constexpr size_t HugePageSize = 0x200000;
|
constexpr size_t HugePageSize = 0x200000;
|
||||||
constexpr size_t max_memory_size = 0x8000000000; // 512 GB max memory size
|
constexpr size_t max_memory_size = 0x40000000; // 1GB max memory size
|
||||||
|
constexpr bool ENABLE_MEMORY_DEBUG = true;
|
||||||
|
|
||||||
|
// Move LogMemoryOperation declaration to the top, before any usage
|
||||||
|
static void LogMemoryOperation(const char* operation, size_t virtual_offset, size_t host_offset,
|
||||||
|
size_t length, const char* result = nullptr) {
|
||||||
|
if (!ENABLE_MEMORY_DEBUG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
LOG_DEBUG(Common_Memory, "{}: virtual=0x{:x}, host=0x{:x}, length=0x{:x} ({})",
|
||||||
|
operation, virtual_offset, host_offset, length, result);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(Common_Memory, "{}: virtual=0x{:x}, host=0x{:x}, length=0x{:x}",
|
||||||
|
operation, virtual_offset, host_offset, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
@ -763,6 +779,8 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogMemoryOperation("Map", virtual_offset, host_offset, length);
|
||||||
|
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
|
@ -771,13 +789,24 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if mapping is valid
|
||||||
|
if (!impl->IsValidMapping(host_offset, length)) {
|
||||||
|
LOG_WARNING(Common_Memory,
|
||||||
|
"Memory validation failed: virtual=0x{:x}, host=0x{:x}, length=0x{:x}",
|
||||||
|
virtual_offset, host_offset, length);
|
||||||
|
// Continue anyway - the mapping may still work
|
||||||
|
}
|
||||||
|
|
||||||
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
|
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
|
||||||
|
LogMemoryOperation("Unmap", virtual_offset, 0, length);
|
||||||
|
|
||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
|
|
||||||
if (length == 0 || !virtual_base || !impl) {
|
if (length == 0 || !virtual_base || !impl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -819,4 +848,67 @@ void HostMemory::EnableDirectMappedAddress() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HostMemory::MapMemory(uint64_t virtual_offset, uint64_t host_offset, uint64_t length) {
|
||||||
|
static constexpr uint64_t MAX_SAFE_ALLOCATION = 0x40000000; // 1GB max allocation
|
||||||
|
|
||||||
|
if (!impl || !impl->IsValidMapping(host_offset, length)) {
|
||||||
|
// For very large allocations, try splitting into smaller chunks
|
||||||
|
if (length > MAX_SAFE_ALLOCATION) {
|
||||||
|
LOG_WARNING(Common_Memory,
|
||||||
|
"Large mapping requested: virtual=0x{:x}, host=0x{:x}, size=0x{:x}. Attempting split allocation.",
|
||||||
|
virtual_offset, host_offset, length);
|
||||||
|
|
||||||
|
// Try mapping in smaller chunks
|
||||||
|
uint64_t remaining = length;
|
||||||
|
uint64_t current_virtual = virtual_offset;
|
||||||
|
uint64_t current_host = host_offset;
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
uint64_t chunk_size = std::min(remaining, MAX_SAFE_ALLOCATION);
|
||||||
|
if (!MapMemory(current_virtual, current_host, chunk_size)) {
|
||||||
|
LOG_ERROR(Common_Memory,
|
||||||
|
"Failed to map memory chunk: virtual=0x{:x}, host=0x{:x}, size=0x{:x}",
|
||||||
|
current_virtual, current_host, chunk_size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
remaining -= chunk_size;
|
||||||
|
current_virtual += chunk_size;
|
||||||
|
current_host += chunk_size;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERROR(Common_Memory,
|
||||||
|
"Failed to verify memory mapping: virtual_offset=0x{:x}, host_offset=0x{:x}, length=0x{:x}",
|
||||||
|
virtual_offset, host_offset, length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure addresses are page-aligned
|
||||||
|
if ((virtual_offset & (PageAlignment - 1)) || (host_offset & (PageAlignment - 1))) {
|
||||||
|
LOG_ERROR(Common_Memory,
|
||||||
|
"Unaligned memory mapping: virtual=0x{:x}, host=0x{:x}",
|
||||||
|
virtual_offset, host_offset);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Add the missing separate_heap parameter
|
||||||
|
Map(virtual_offset, host_offset, length, MemoryPermission::ReadWrite, false);
|
||||||
|
|
||||||
|
if (ENABLE_MEMORY_DEBUG) {
|
||||||
|
LOG_DEBUG(Common_Memory,
|
||||||
|
"Successfully mapped memory: virtual=0x{:x}, host=0x{:x}, length=0x{:x}",
|
||||||
|
virtual_offset, host_offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR(Common_Memory,
|
||||||
|
"Failed to map memory: virtual=0x{:x}, host=0x{:x}, length=0x{:x}, error: {}",
|
||||||
|
virtual_offset, host_offset, length, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
|
@ -52,6 +52,13 @@ public:
|
||||||
|
|
||||||
void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value);
|
void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value);
|
||||||
|
|
||||||
|
/// Attempts to map memory with additional safety checks and chunking for large allocations
|
||||||
|
/// @param virtual_offset The virtual memory address to map to
|
||||||
|
/// @param host_offset The physical memory address to map from
|
||||||
|
/// @param length The size of the mapping in bytes
|
||||||
|
/// @return true if mapping succeeded, false if it failed
|
||||||
|
bool MapMemory(uint64_t virtual_offset, uint64_t host_offset, uint64_t length);
|
||||||
|
|
||||||
[[nodiscard]] u8* BackingBasePointer() noexcept {
|
[[nodiscard]] u8* BackingBasePointer() noexcept {
|
||||||
return backing_base;
|
return backing_base;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue