From 529227e4e65cb8f070f5d5d3a3cd1ef5a22431aa Mon Sep 17 00:00:00 2001
From: "Dr. Chat" <arkolbed@gmail.com>
Date: Sun, 8 Nov 2015 18:18:28 -0600
Subject: [PATCH 1/2] MMIOHandler::InvalidateRange

---
 src/xenia/cpu/mmio_handler.cc | 27 ++++++++++++++++++++++++---
 src/xenia/cpu/mmio_handler.h  |  3 ++-
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/xenia/cpu/mmio_handler.cc b/src/xenia/cpu/mmio_handler.cc
index 980ff12f1..e5412d8e7 100644
--- a/src/xenia/cpu/mmio_handler.cc
+++ b/src/xenia/cpu/mmio_handler.cc
@@ -156,8 +156,29 @@ void MMIOHandler::CancelWriteWatch(uintptr_t watch_handle) {
   delete entry;
 }
 
-bool MMIOHandler::CheckWriteWatch(X64Context* thread_context,
-                                  uint64_t fault_address) {
+void MMIOHandler::InvalidateRange(uint32_t physical_address, size_t length) {
+  auto lock = global_critical_region_.Acquire();
+
+  for (auto it = write_watches_.begin(); it != write_watches_.end();) {
+    auto entry = *it;
+    if ((entry->address <= physical_address &&
+         entry->address + entry->length > physical_address) ||
+        (entry->address >= physical_address &&
+         entry->address < physical_address + length)) {
+      // This watch lies within the range. End it.
+      ClearWriteWatch(entry);
+      entry->callback(entry->callback_context, entry->callback_data,
+                      entry->address);
+
+      it = write_watches_.erase(it);
+      continue;
+    }
+
+    ++it;
+  }
+}
+
+bool MMIOHandler::CheckWriteWatch(uint64_t fault_address) {
   uint32_t physical_address = uint32_t(fault_address);
   if (physical_address > 0x1FFFFFFF) {
     physical_address &= 0x1FFFFFFF;
@@ -395,7 +416,7 @@ bool MMIOHandler::ExceptionCallback(Exception* ex) {
   if (!range) {
     // Access is not found within any range, so fail and let the caller handle
     // it (likely by aborting).
-    return CheckWriteWatch(ex->thread_context(), ex->fault_address());
+    return CheckWriteWatch(ex->fault_address());
   }
 
   auto rip = ex->pc();
diff --git a/src/xenia/cpu/mmio_handler.h b/src/xenia/cpu/mmio_handler.h
index 4151da5bb..70d89ac02 100644
--- a/src/xenia/cpu/mmio_handler.h
+++ b/src/xenia/cpu/mmio_handler.h
@@ -63,6 +63,7 @@ class MMIOHandler {
                                   WriteWatchCallback callback,
                                   void* callback_context, void* callback_data);
   void CancelWriteWatch(uintptr_t watch_handle);
+  void InvalidateRange(uint32_t physical_address, size_t length);
 
  protected:
   struct WriteWatchEntry {
@@ -83,7 +84,7 @@ class MMIOHandler {
   bool ExceptionCallback(Exception* ex);
 
   void ClearWriteWatch(WriteWatchEntry* entry);
-  bool CheckWriteWatch(X64Context* thread_context, uint64_t fault_address);
+  bool CheckWriteWatch(uint64_t fault_address);
 
   uint8_t* virtual_membase_;
   uint8_t* physical_membase_;

From c98d10545e3236dc466215cf0bad471e92247680 Mon Sep 17 00:00:00 2001
From: "Dr. Chat" <arkolbed@gmail.com>
Date: Sun, 8 Nov 2015 19:14:06 -0600
Subject: [PATCH 2/2] Invalidate MMIO Ranges when memory is released or access
 protections are changed.

---
 src/xenia/memory.cc | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/src/xenia/memory.cc b/src/xenia/memory.cc
index 7485ece77..6b13ecee6 100644
--- a/src/xenia/memory.cc
+++ b/src/xenia/memory.cc
@@ -1128,21 +1128,30 @@ 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, &region_size)) {
+    cpu::MMIOHandler::global_handler()->InvalidateRange(parent_base_address,
+                                                        region_size);
+  }
+
   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);
 }
 
 bool PhysicalHeap::Protect(uint32_t address, uint32_t size, uint32_t protect) {
   auto global_lock = global_critical_region_.Acquire();
   uint32_t parent_address = GetPhysicalAddress(address);
-  bool parent_result = parent_heap_->Protect(parent_address, size, protect);
-  if (!parent_result) {
+  cpu::MMIOHandler::global_handler()->InvalidateRange(parent_address, size);
+
+  if (!parent_heap_->Protect(parent_address, size, protect)) {
     XELOGE("PhysicalHeap::Protect failed due to parent heap failure");
     return false;
   }
+
   return BaseHeap::Protect(address, size, protect);
 }