[Vulkan/D3D12] Validate upload range bounds before vastcpy

The D3D12 backend's existing check only validated the last page of the
range. The Vulkan backend had no check at all and did not respect the
gpu_allow_invalid_upload_range cvar. Both now verify start and
end pages are mapped before copying, preventing access violations when
games reference unmapped guest physical memory during transitions.
This commit is contained in:
Herman S.
2026-01-29 15:43:43 +09:00
parent 3e1b0c715a
commit a092551735
2 changed files with 40 additions and 7 deletions

View File

@@ -422,17 +422,24 @@ bool D3D12SharedMemory::UploadRanges(
upload_range_length << page_size_log2());
if (upload_range_length > 0 && !cvars::gpu_allow_invalid_upload_range) {
// Check both start and end of the range for unmapped memory.
const uint32_t range_start_addr = upload_range_start << page_size_log2();
const uint32_t upload_range_last_page =
upload_range_start + upload_range_length - 1;
const uint32_t range_end_addr = upload_range_last_page
<< page_size_log2();
const memory::PageAccess page_access =
memory().GetPhysicalHeap()->QueryRangeAccess(
upload_range_last_page << page_size_log2(),
upload_range_last_page
<< page_size_log2()); // Check only last page
const memory::PageAccess start_access =
memory().GetPhysicalHeap()->QueryRangeAccess(range_start_addr,
range_start_addr);
const memory::PageAccess end_access =
memory().GetPhysicalHeap()->QueryRangeAccess(range_end_addr,
range_end_addr);
if (page_access == xe::memory::PageAccess::kNoAccess) {
XELOGE("Invalid upload range for GPU: {:08X}", upload_range_start);
if (start_access == xe::memory::PageAccess::kNoAccess ||
end_access == xe::memory::PageAccess::kNoAccess) {
XELOGE("Invalid upload range for GPU: {:08X} length {:08X}",
upload_range_start, upload_range_length);
return false;
}
}

View File

@@ -19,6 +19,8 @@
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
#include "xenia/ui/vulkan/vulkan_util.h"
DECLARE_bool(gpu_allow_invalid_upload_range);
DEFINE_bool(vulkan_sparse_shared_memory, true,
"Enable sparse binding for shared memory emulation. Disabling it "
"increases video memory usage - a 512 MB buffer is created - but "
@@ -405,6 +407,30 @@ bool VulkanSharedMemory::UploadRanges(
uint32_t upload_range_length = upload_page_ranges[i].second;
trace_writer_.WriteMemoryRead(upload_range_start << page_size_log2(),
upload_range_length << page_size_log2());
if (upload_range_length > 0 && !cvars::gpu_allow_invalid_upload_range) {
const uint32_t range_start_addr = upload_range_start << page_size_log2();
const uint32_t upload_range_last_page =
upload_range_start + upload_range_length - 1;
const uint32_t range_end_addr = upload_range_last_page
<< page_size_log2();
const memory::PageAccess start_access =
memory().GetPhysicalHeap()->QueryRangeAccess(range_start_addr,
range_start_addr);
const memory::PageAccess end_access =
memory().GetPhysicalHeap()->QueryRangeAccess(range_end_addr,
range_end_addr);
if (start_access == xe::memory::PageAccess::kNoAccess ||
end_access == xe::memory::PageAccess::kNoAccess) {
XELOGE(
"Vulkan shared memory: Invalid upload range {:08X} length {:08X}",
upload_range_start, upload_range_length);
successful = false;
break;
}
}
while (upload_range_length) {
VkBuffer upload_buffer;
VkDeviceSize upload_buffer_offset, upload_buffer_size;