qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 3/4] kvm: Introduce kvm logging interface.


From: Glauber Costa
Subject: [Qemu-devel] [PATCH 3/4] kvm: Introduce kvm logging interface.
Date: Mon, 24 Nov 2008 16:17:47 -0200

Introduce functions to control logging of memory regions.
We select regions based on its start address, a
guest_physical_addr (target_phys_addr_t, in qemu nomenclature).

The main user of this interface right now is VGA optimization
(a way of reducing the number of mmio exits).

Signed-off-by: Glauber Costa <address@hidden>
---
 kvm-all.c |  122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 kvm.h     |    4 ++
 2 files changed, 113 insertions(+), 13 deletions(-)

diff --git a/kvm-all.c b/kvm-all.c
index e44f296..39f826b 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -2,9 +2,11 @@
  * QEMU KVM support
  *
  * Copyright IBM, Corp. 2008
+ *           Red Hat, Inc. 2008
  *
  * Authors:
  *  Anthony Liguori   <address@hidden>
+ *  Glauber Costa     <address@hidden>
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
@@ -41,6 +43,8 @@ typedef struct KVMSlot
     int flags;
 } KVMSlot;
 
+typedef struct kvm_dirty_log KVMDirtyLog;
+
 int kvm_allowed = 0;
 
 struct KVMState
@@ -82,6 +86,20 @@ static KVMSlot *kvm_lookup_slot(KVMState *s, 
target_phys_addr_t start_addr)
     return NULL;
 }
 
+static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
+{
+    struct kvm_userspace_memory_region mem;
+
+    mem.slot = slot->slot;
+    mem.guest_phys_addr = slot->start_addr;
+    mem.memory_size = slot->memory_size;
+    mem.userspace_addr = (unsigned long)phys_ram_base + slot->phys_offset;
+    mem.flags = slot->flags;
+
+    return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
+}
+
+
 int kvm_init_vcpu(CPUState *env)
 {
     KVMState *s = kvm_state;
@@ -119,6 +137,97 @@ err:
     return ret;
 }
 
+/*
+ * dirty pages logging control
+ */
+static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, 
target_phys_addr_t end_addr,
+                                      unsigned flags,
+                                      unsigned mask)
+{
+    KVMState *s = kvm_state;
+    KVMSlot *mem = kvm_lookup_slot(s, phys_addr);
+    if (mem == NULL)  {
+            dprintf("invalid parameters %llx-%llx\n", phys_addr, end_addr);
+            return -EINVAL;
+    }
+
+    flags = (mem->flags & ~mask) | flags;
+    /* Nothing changed, no need to issue ioctl */
+    if (flags == mem->flags)
+            return 0;
+
+    mem->flags = flags;
+
+    return kvm_set_user_memory_region(s, mem);
+}
+
+int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t end_addr)
+{
+        return kvm_dirty_pages_log_change(phys_addr, end_addr,
+                                          KVM_MEM_LOG_DIRTY_PAGES,
+                                          KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t end_addr)
+{
+        return kvm_dirty_pages_log_change(phys_addr, end_addr,
+                                          0,
+                                          KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+/**
+ * kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
+ * This function updates qemu's dirty bitmap using 
cpu_physical_memory_set_dirty().
+ * This means all bits are set to dirty.
+ *
+ * @start_add: start of logged region. This is what we use to search the 
memslot
+ * @end_addr: end of logged region.
+ */
+void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, 
target_phys_addr_t end_addr)
+{
+    KVMState *s = kvm_state;
+    KVMDirtyLog d;
+    KVMSlot *mem = kvm_lookup_slot(s, start_addr);
+    unsigned long alloc_size;
+    ram_addr_t addr;
+    target_phys_addr_t phys_addr = start_addr;
+
+    dprintf("sync addr: %llx into %lx\n", start_addr, mem->phys_offset);
+    if (mem == NULL) {
+            fprintf(stderr, "BUG: %s: invalid parameters\n", __func__);
+            return;
+    }
+
+    alloc_size = mem->memory_size >> TARGET_PAGE_BITS / sizeof(d.dirty_bitmap);
+    d.dirty_bitmap = qemu_mallocz(alloc_size);
+
+    if (d.dirty_bitmap == NULL) {
+        dprintf("Could not allocate dirty bitmap\n");
+        return;
+    }
+
+    d.slot = mem->slot;
+    dprintf("slot %d, phys_addr %llx, uaddr: %llx\n",
+            d.slot, mem->start_addr, mem->phys_offset);
+
+    if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
+        dprintf("ioctl failed %d\n", errno);
+        goto out;
+    }
+
+    phys_addr = start_addr;
+    for (addr = mem->phys_offset; phys_addr < end_addr; phys_addr+= 
TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
+        unsigned long *bitmap = (unsigned long *)d.dirty_bitmap;
+        unsigned nr = (phys_addr - start_addr) >> TARGET_PAGE_BITS;
+        unsigned word = nr / (sizeof(*bitmap) * 8);
+        unsigned bit = nr % (sizeof(*bitmap) * 8);
+        if ((bitmap[word] >> bit) & 1)
+            cpu_physical_memory_set_dirty(addr);
+    }
+out:
+    qemu_free(d.dirty_bitmap);
+}
+
 int kvm_init(int smp_cpus)
 {
     KVMState *s;
@@ -316,19 +425,6 @@ int kvm_cpu_exec(CPUState *env)
     return ret;
 }
 
-static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
-{
-    struct kvm_userspace_memory_region mem;
-
-    mem.slot = slot->slot;
-    mem.guest_phys_addr = slot->start_addr;
-    mem.memory_size = slot->memory_size;
-    mem.userspace_addr = (unsigned long)phys_ram_base + slot->phys_offset;
-    mem.flags = slot->flags;
-
-    return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
-}
-
 void kvm_set_phys_mem(target_phys_addr_t start_addr,
                       ram_addr_t size,
                       ram_addr_t phys_offset)
diff --git a/kvm.h b/kvm.h
index 304de27..fb952a3 100644
--- a/kvm.h
+++ b/kvm.h
@@ -38,6 +38,10 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
                       ram_addr_t size,
                       ram_addr_t phys_offset);
 
+void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, 
target_phys_addr_t end_addr);
+
+int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t len);
+int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t len);
 /* internal API */
 
 struct KVMState;
-- 
1.5.6.5





reply via email to

[Prev in Thread] Current Thread [Next in Thread]