diff mbox

[11/14] hvf: implement vga dirty page tracking

Message ID 20170828015654.2530-12-Sergio.G.DelReal@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

This commit implements setting the tracking of dirty pages, using hvf's
interface to protect guest memory. It uses the MemoryListener callback
mechanism through .log_start/stop/sync

Signed-off-by: Sergio Andres Gomez Del Real <Sergio.G.DelReal@gmail.com>
---
 include/sysemu/hvf.h  |  5 ++++
 target/i386/hvf-all.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 70 insertions(+), 7 deletions(-)
diff mbox

Patch

diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h
index 5b92769b16..90e9ec174e 100644
--- a/include/sysemu/hvf.h
+++ b/include/sysemu/hvf.h
@@ -27,11 +27,16 @@ 
 #include <Hypervisor/hv_error.h>
 #endif
 
+/* hvf_slot flags */
+#define HVF_SLOT_LOG (1 << 0)
+
 typedef struct hvf_slot {
     uint64_t start;
     uint64_t size;
     uint8_t *mem;
     int slot_id;
+    uint32_t flags;
+    MemoryRegion *region;
 } hvf_slot;
 
 struct hvf_vcpu_caps {
diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c
index 11d20671f7..20c796089d 100644
--- a/target/i386/hvf-all.c
+++ b/target/i386/hvf-all.c
@@ -172,6 +172,7 @@  void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
     mem->size = int128_get64(section->size);
     mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
     mem->start = section->offset_within_address_space;
+    mem->region = area;
 
     if (do_hvf_set_memory(mem)) {
         fprintf(stderr, "Error registering new memory slot\n");
@@ -441,8 +442,7 @@  void hvf_cpu_synchronize_post_init(CPUState *cpu_state)
     run_on_cpu(cpu_state, _hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
 }
 
-/* TODO: ept fault handlig */
-static bool ept_emulation_fault(uint64_t ept_qual)
+static bool ept_emulation_fault(hvf_slot *slot, addr_t gpa, uint64_t ept_qual)
 {
     int read, write;
 
@@ -458,6 +458,14 @@  static bool ept_emulation_fault(uint64_t ept_qual)
         return false;
     }
 
+    if (write && slot) {
+        if (slot->flags & HVF_SLOT_LOG) {
+            memory_region_set_dirty(slot->region, gpa - slot->start, 1);
+            hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size,
+                          HV_MEMORY_READ | HV_MEMORY_WRITE);
+        }
+    }
+
     /*
      * The EPT violation must have been caused by accessing a
      * guest-physical address that is a translation of a guest-linear
@@ -468,7 +476,57 @@  static bool ept_emulation_fault(uint64_t ept_qual)
         return false;
     }
 
-    return true;
+    return !slot;
+}
+
+static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
+{
+    struct mac_slot *macslot;
+    hvf_slot *slot;
+
+    slot = hvf_find_overlap_slot(
+            section->offset_within_address_space,
+            section->offset_within_address_space + int128_get64(section->size));
+
+    /* protect region against writes; begin tracking it */
+    if (on) {
+        slot->flags |= HVF_SLOT_LOG;
+        hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size,
+                      HV_MEMORY_READ);
+    /* stop tracking region*/
+    } else {
+        slot->flags &= ~HVF_SLOT_LOG;
+        hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size,
+                      HV_MEMORY_READ | HV_MEMORY_WRITE);
+    }
+}
+
+static void hvf_log_start(MemoryListener *listener,
+                          MemoryRegionSection *section, int old, int new)
+{
+    if (old != 0)
+        return;
+
+    hvf_set_dirty_tracking(section, 1);
+}
+
+static void hvf_log_stop(MemoryListener *listener,
+                         MemoryRegionSection *section, int old, int new)
+{
+    if (new != 0)
+        return;
+
+    hvf_set_dirty_tracking(section, 0);
+}
+
+static void hvf_log_sync(MemoryListener *listener,
+                         MemoryRegionSection *section)
+{
+    /*
+     * sync of dirty pages is handled elsewhere; just make sure we keep
+     * tracking the region.
+     */
+    hvf_set_dirty_tracking(section, 1);
 }
 
 static void hvf_region_add(MemoryListener *listener,
@@ -487,6 +545,9 @@  static MemoryListener hvf_memory_listener = {
     .priority = 10,
     .region_add = hvf_region_add,
     .region_del = hvf_region_del,
+    .log_start = hvf_log_start,
+    .log_stop = hvf_log_stop,
+    .log_sync = hvf_log_sync,
 };
 
 void vmx_reset_vcpu(CPUState *cpu) {
@@ -763,7 +824,7 @@  int hvf_vcpu_exec(CPUState *cpu)
 
             slot = hvf_find_overlap_slot(gpa, gpa);
             /* mmio */
-            if (ept_emulation_fault(exit_qual) && !slot) {
+            if (ept_emulation_fault(slot, gpa, exit_qual)) {
                 struct x86_decode decode;
 
                 load_regs(cpu);
@@ -774,9 +835,6 @@  int hvf_vcpu_exec(CPUState *cpu)
                 store_regs(cpu);
                 break;
             }
-#ifdef DIRTY_VGA_TRACKING
-            /* TODO: handle dirty page tracking */
-#endif
             break;
         }
         case EXIT_REASON_INOUT: