[D3D12] Experimental write watch implementation for shared memory

This commit is contained in:
Triang3l
2018-09-24 23:18:16 +03:00
parent 005e590c92
commit 6e36101b42
7 changed files with 424 additions and 187 deletions

View File

@@ -412,22 +412,21 @@ void Memory::CancelAccessWatch(uintptr_t watch_handle) {
mmio_handler_->CancelAccessWatch(watch_handle);
}
void Memory::SetGlobalPhysicalAccessWatch(
cpu::GlobalAccessWatchCallback callback, void* callback_context) {
mmio_handler_->SetGlobalPhysicalAccessWatch(callback, callback_context);
void* Memory::RegisterPhysicalWriteWatch(
cpu::PhysicalWriteWatchCallback callback, void* callback_context) {
return mmio_handler_->RegisterPhysicalWriteWatch(callback, callback_context);
}
void Memory::ProtectPhysicalMemory(uint32_t physical_address, uint32_t length,
cpu::MMIOHandler::WatchType type,
bool protect_host_access) {
mmio_handler_->ProtectPhysicalMemory(physical_address, length, type,
protect_host_access);
void Memory::UnregisterPhysicalWriteWatch(void* watch_handle) {
mmio_handler_->UnregisterPhysicalWriteWatch(watch_handle);
}
void Memory::UnprotectPhysicalMemory(uint32_t physical_address, uint32_t length,
bool unprotect_host_access) {
mmio_handler_->UnprotectPhysicalMemory(physical_address, length,
unprotect_host_access);
void Memory::WatchPhysicalMemoryWrite(uint32_t physical_address,
uint32_t length) {
// Watch independently in all three mappings.
heaps_.vA0000000.WatchWrite(physical_address, length, mmio_handler_.get());
heaps_.vC0000000.WatchWrite(physical_address, length, mmio_handler_.get());
heaps_.vE0000000.WatchWrite(physical_address, length, mmio_handler_.get());
}
uint32_t Memory::SystemHeapAlloc(uint32_t size, uint32_t alignment,
@@ -1363,8 +1362,8 @@ bool PhysicalHeap::Release(uint32_t base_address, uint32_t* out_region_size) {
uint32_t parent_base_address = GetPhysicalAddress(base_address);
uint32_t region_size = 0;
if (QuerySize(base_address, &region_size)) {
cpu::MMIOHandler::global_handler()->InvalidateRange(parent_base_address,
region_size);
cpu::MMIOHandler::global_handler()->InvalidateRange(
base_address, region_size, !FLAGS_protect_on_release);
}
if (!parent_heap_->Release(parent_base_address, out_region_size)) {
@@ -1378,10 +1377,11 @@ bool PhysicalHeap::Release(uint32_t base_address, uint32_t* out_region_size) {
bool PhysicalHeap::Protect(uint32_t address, uint32_t size, uint32_t protect,
uint32_t* old_protect) {
auto global_lock = global_critical_region_.Acquire();
uint32_t parent_address = GetPhysicalAddress(address);
cpu::MMIOHandler::global_handler()->InvalidateRange(parent_address, size);
if (!parent_heap_->Protect(parent_address, size, protect, old_protect)) {
cpu::MMIOHandler::global_handler()->InvalidateRange(address, size, false);
if (!parent_heap_->Protect(GetPhysicalAddress(address), size, protect,
old_protect)) {
XELOGE("PhysicalHeap::Protect failed due to parent heap failure");
return false;
}
@@ -1389,4 +1389,47 @@ bool PhysicalHeap::Protect(uint32_t address, uint32_t size, uint32_t protect,
return BaseHeap::Protect(address, size, protect);
}
void PhysicalHeap::WatchWrite(uint32_t address, uint32_t size,
cpu::MMIOHandler* mmio_handler) {
address &= 0x1FFFFFFF;
if (address >= heap_size_) {
// E0000000 is not exactly 512 MB long.
return;
}
size = std::min(size, heap_size_ - address);
if (size == 0) {
return;
}
uint32_t system_page_size = uint32_t(xe::memory::page_size());
uint32_t system_page_first = address / system_page_size;
uint32_t system_page_last = (address + size - 1) / system_page_size;
auto global_lock = global_critical_region_.Acquire();
// Watch all writable pages of the system page size within the requested
// range.
uint32_t range_start = UINT32_MAX;
for (uint32_t i = system_page_first; i <= system_page_last; ++i) {
if (page_table_[i * system_page_size / page_size_].current_protect &
kMemoryProtectWrite) {
if (range_start == UINT32_MAX) {
range_start = i;
}
} else {
if (range_start != UINT32_MAX) {
mmio_handler->ProtectAndWatchPhysicalMemory(
heap_base_ + range_start * system_page_size,
(i - range_start) * system_page_size);
range_start = UINT32_MAX;
}
}
}
if (range_start != UINT32_MAX) {
mmio_handler->ProtectAndWatchPhysicalMemory(
heap_base_ + range_start * system_page_size,
(system_page_last - range_start + 1) * system_page_size);
}
}
} // namespace xe