[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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user