[D3D12] Experimental write watch implementation for shared memory
This commit is contained in:
@@ -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, ®ion_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
|
||||
|
||||
Reference in New Issue
Block a user