diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc index ece9a8cfd..4352c7be9 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc @@ -170,8 +170,8 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle, if (XSUCCEEDED(result)) { if (true || file->is_synchronous()) { // some games NtReadFile() directly into texture memory - // TODO(rick): better checking of physical address - if (buffer.guest_address() >= 0xA0000000) { + auto heap = kernel_memory()->LookupHeap(buffer.guest_address()); + if (heap && heap->IsGuestPhysicalHeap()) { kernel_memory()->TriggerWatches(buffer.guest_address(), buffer_length, true, true); } diff --git a/src/xenia/memory.cc b/src/xenia/memory.cc index cec4da18b..bd6d58f44 100644 --- a/src/xenia/memory.cc +++ b/src/xenia/memory.cc @@ -1355,6 +1355,11 @@ bool PhysicalHeap::Alloc(uint32_t size, uint32_t alignment, // TODO(benvanik): don't leak parent memory. return false; } + + if (protect & kMemoryProtectWrite) { + TriggerWatches(address, size, true, true, false); + } + *out_address = address; return true; } @@ -1392,6 +1397,10 @@ bool PhysicalHeap::AllocFixed(uint32_t base_address, uint32_t size, return false; } + if (protect & kMemoryProtectWrite) { + TriggerWatches(address, size, true, true, false); + } + return true; } @@ -1432,6 +1441,11 @@ bool PhysicalHeap::AllocRange(uint32_t low_address, uint32_t high_address, // TODO(benvanik): don't leak parent memory. return false; } + + if (protect & kMemoryProtectWrite) { + TriggerWatches(address, size, true, true, false); + } + *out_address = address; return true; } @@ -1449,17 +1463,10 @@ bool PhysicalHeap::Decommit(uint32_t address, uint32_t size) { bool PhysicalHeap::Release(uint32_t base_address, uint32_t* out_region_size) { auto global_lock = global_critical_region_.Acquire(); uint32_t parent_base_address = GetPhysicalAddress(base_address); - uint32_t region_size = 0; - if (QuerySize(base_address, ®ion_size)) { - TriggerWatches(base_address, region_size, true, true, - !cvars::protect_on_release); - } - if (!parent_heap_->Release(parent_base_address, out_region_size)) { XELOGE("PhysicalHeap::Release failed due to parent heap failure"); return false; } - return BaseHeap::Release(base_address, out_region_size); } @@ -1467,7 +1474,11 @@ bool PhysicalHeap::Protect(uint32_t address, uint32_t size, uint32_t protect, uint32_t* old_protect) { auto global_lock = global_critical_region_.Acquire(); - TriggerWatches(address, size, true, true, false); + // Only invalidate if making writable again, for simplicity - not when simply + // marking some range as immutable, for instance. + if (protect & kMemoryProtectWrite) { + TriggerWatches(address, size, true, true, false); + } if (!parent_heap_->Protect(GetPhysicalAddress(address), size, protect, old_protect)) { diff --git a/src/xenia/memory.h b/src/xenia/memory.h index 570f98e1f..8250b1787 100644 --- a/src/xenia/memory.h +++ b/src/xenia/memory.h @@ -363,15 +363,15 @@ class Memory { // triggered multiple times for a single range, and for any watched page every // registered callbacks is triggered. This is a very simple one-shot method // for use primarily for cache invalidation - there may be spurious firing, - // for example, if the game only changes the protection level without writing - // anything. + // for example, if the game only makes the pages writable without actually + // writing anything (done for simplicity). // // A range of pages can be watched at any time, but pages are only unwatched // when watches are triggered (since multiple subscribers can depend on the // same memory, and one subscriber shouldn't interfere with another). // // Callbacks can be triggered for one page (if the guest just stores words) or - // for multiple pages (for file reading, protection level changes). + // for multiple pages (for file reading, making pages writable). // // Only guest physical memory mappings are watched - the host-only mapping is // not protected so it can be used to bypass the write protection (for file @@ -392,11 +392,12 @@ class Memory { // Enables watching of the specified memory range, snapped to system page // boundaries. When something is written to a watched range (or when the - // protection of it changes), the registered watch callbacks are triggered for - // the page (or pages, for file reads and protection changes) where something - // has been written to. This protects physical memory only under - // virtual_membase_, so writing to physical_membase_ can be done to bypass the - // protection placed by the watches. + // protection of it changes in a a way that it becomes writable), the + // registered watch callbacks are triggered for the page (or pages, for file + // reads and protection changes) where something has been written to. This + // protects physical memory only under virtual_membase_, so writing to + // physical_membase_ can be done to bypass the protection placed by the + // watches. void WatchPhysicalMemoryWrite(uint32_t physical_address, uint32_t length); // Forces triggering of watch callbacks for a virtual address range if pages