diff mbox

[v4,12/14] hvf: implement vga dirty page tracking

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

Commit Message

This patch implements setting the tracking of dirty vga 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 | 74 ++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 72 insertions(+), 7 deletions(-)
diff mbox

Patch

diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h
index 9230c13851..f54e043955 100644
--- a/include/sysemu/hvf.h
+++ b/include/sysemu/hvf.h
@@ -34,11 +34,16 @@  uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
 #define hvf_get_supported_cpuid(func, idx, reg) 0
 #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;
 
 typedef struct hvf_vcpu_caps {
diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c
index 97f4ded673..e8466e6f47 100644
--- a/target/i386/hvf-all.c
+++ b/target/i386/hvf-all.c
@@ -195,6 +195,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)) {
         error_report("Error registering new memory slot\n");
@@ -291,8 +292,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;
 
@@ -308,6 +308,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
@@ -318,7 +326,59 @@  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,
@@ -337,6 +397,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 hvf_reset_vcpu(CPUState *cpu) {
@@ -609,7 +672,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);
@@ -620,9 +683,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: