summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZephyron <zephyron@citron-emu.org>2025-02-09 15:40:24 +1000
committerZephyron <zephyron@citron-emu.org>2025-02-09 15:40:24 +1000
commit5af4803e42f206d6332e812997e5db45ea01d0b5 (patch)
treeb775c0ec01cc43e34842376943095c66f9763e49 /src
parentbecaf850ab7b21456b7799fbaa31c65e20be0a92 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/common/host_memory.cpp94
-rw-r--r--src/common/host_memory.h7
2 files changed, 100 insertions, 1 deletions
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 0678efa50..551d2838a 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -41,7 +41,23 @@ namespace Common {
constexpr size_t PageAlignment = 0x1000;
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
@@ -763,6 +779,8 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
return;
}
+ LogMemoryOperation("Map", virtual_offset, host_offset, length);
+
ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0);
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;
}
+ // 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);
}
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(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size);
+
if (length == 0 || !virtual_base || !impl) {
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
diff --git a/src/common/host_memory.h b/src/common/host_memory.h
index 7d4a94123..438edd659 100644
--- a/src/common/host_memory.h
+++ b/src/common/host_memory.h
@@ -52,6 +52,13 @@ public:
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 {
return backing_base;
}