Commit 5832d1f2f51e1a1991c53ea98c535a619cf03001

Authored by aliguori
1 parent b4fbd879

kvm: Introduce kvm logging interface (Glauber Costa)

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 <glommer@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5792 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 113 additions and 13 deletions
kvm-all.c
... ... @@ -2,9 +2,11 @@
2 2 * QEMU KVM support
3 3 *
4 4 * Copyright IBM, Corp. 2008
  5 + * Red Hat, Inc. 2008
5 6 *
6 7 * Authors:
7 8 * Anthony Liguori <aliguori@us.ibm.com>
  9 + * Glauber Costa <gcosta@redhat.com>
8 10 *
9 11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 12 * See the COPYING file in the top-level directory.
... ... @@ -41,6 +43,8 @@ typedef struct KVMSlot
41 43 int flags;
42 44 } KVMSlot;
43 45  
  46 +typedef struct kvm_dirty_log KVMDirtyLog;
  47 +
44 48 int kvm_allowed = 0;
45 49  
46 50 struct KVMState
... ... @@ -82,6 +86,20 @@ static KVMSlot *kvm_lookup_slot(KVMState *s, target_phys_addr_t start_addr)
82 86 return NULL;
83 87 }
84 88  
  89 +static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
  90 +{
  91 + struct kvm_userspace_memory_region mem;
  92 +
  93 + mem.slot = slot->slot;
  94 + mem.guest_phys_addr = slot->start_addr;
  95 + mem.memory_size = slot->memory_size;
  96 + mem.userspace_addr = (unsigned long)phys_ram_base + slot->phys_offset;
  97 + mem.flags = slot->flags;
  98 +
  99 + return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
  100 +}
  101 +
  102 +
85 103 int kvm_init_vcpu(CPUState *env)
86 104 {
87 105 KVMState *s = kvm_state;
... ... @@ -119,6 +137,97 @@ err:
119 137 return ret;
120 138 }
121 139  
  140 +/*
  141 + * dirty pages logging control
  142 + */
  143 +static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, target_phys_addr_t end_addr,
  144 + unsigned flags,
  145 + unsigned mask)
  146 +{
  147 + KVMState *s = kvm_state;
  148 + KVMSlot *mem = kvm_lookup_slot(s, phys_addr);
  149 + if (mem == NULL) {
  150 + dprintf("invalid parameters %llx-%llx\n", phys_addr, end_addr);
  151 + return -EINVAL;
  152 + }
  153 +
  154 + flags = (mem->flags & ~mask) | flags;
  155 + /* Nothing changed, no need to issue ioctl */
  156 + if (flags == mem->flags)
  157 + return 0;
  158 +
  159 + mem->flags = flags;
  160 +
  161 + return kvm_set_user_memory_region(s, mem);
  162 +}
  163 +
  164 +int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t end_addr)
  165 +{
  166 + return kvm_dirty_pages_log_change(phys_addr, end_addr,
  167 + KVM_MEM_LOG_DIRTY_PAGES,
  168 + KVM_MEM_LOG_DIRTY_PAGES);
  169 +}
  170 +
  171 +int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t end_addr)
  172 +{
  173 + return kvm_dirty_pages_log_change(phys_addr, end_addr,
  174 + 0,
  175 + KVM_MEM_LOG_DIRTY_PAGES);
  176 +}
  177 +
  178 +/**
  179 + * kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
  180 + * This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty().
  181 + * This means all bits are set to dirty.
  182 + *
  183 + * @start_add: start of logged region. This is what we use to search the memslot
  184 + * @end_addr: end of logged region.
  185 + */
  186 +void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr)
  187 +{
  188 + KVMState *s = kvm_state;
  189 + KVMDirtyLog d;
  190 + KVMSlot *mem = kvm_lookup_slot(s, start_addr);
  191 + unsigned long alloc_size;
  192 + ram_addr_t addr;
  193 + target_phys_addr_t phys_addr = start_addr;
  194 +
  195 + dprintf("sync addr: %llx into %lx\n", start_addr, mem->phys_offset);
  196 + if (mem == NULL) {
  197 + fprintf(stderr, "BUG: %s: invalid parameters\n", __func__);
  198 + return;
  199 + }
  200 +
  201 + alloc_size = mem->memory_size >> TARGET_PAGE_BITS / sizeof(d.dirty_bitmap);
  202 + d.dirty_bitmap = qemu_mallocz(alloc_size);
  203 +
  204 + if (d.dirty_bitmap == NULL) {
  205 + dprintf("Could not allocate dirty bitmap\n");
  206 + return;
  207 + }
  208 +
  209 + d.slot = mem->slot;
  210 + dprintf("slot %d, phys_addr %llx, uaddr: %llx\n",
  211 + d.slot, mem->start_addr, mem->phys_offset);
  212 +
  213 + if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
  214 + dprintf("ioctl failed %d\n", errno);
  215 + goto out;
  216 + }
  217 +
  218 + phys_addr = start_addr;
  219 + for (addr = mem->phys_offset; phys_addr < end_addr; phys_addr+= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
  220 + unsigned long *bitmap = (unsigned long *)d.dirty_bitmap;
  221 + unsigned nr = (phys_addr - start_addr) >> TARGET_PAGE_BITS;
  222 + unsigned word = nr / (sizeof(*bitmap) * 8);
  223 + unsigned bit = nr % (sizeof(*bitmap) * 8);
  224 + if ((bitmap[word] >> bit) & 1)
  225 + cpu_physical_memory_set_dirty(addr);
  226 + }
  227 +out:
  228 + qemu_free(d.dirty_bitmap);
  229 +}
  230 +
122 231 int kvm_init(int smp_cpus)
123 232 {
124 233 KVMState *s;
... ... @@ -316,19 +425,6 @@ int kvm_cpu_exec(CPUState *env)
316 425 return ret;
317 426 }
318 427  
319   -static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
320   -{
321   - struct kvm_userspace_memory_region mem;
322   -
323   - mem.slot = slot->slot;
324   - mem.guest_phys_addr = slot->start_addr;
325   - mem.memory_size = slot->memory_size;
326   - mem.userspace_addr = (unsigned long)phys_ram_base + slot->phys_offset;
327   - mem.flags = slot->flags;
328   -
329   - return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
330   -}
331   -
332 428 void kvm_set_phys_mem(target_phys_addr_t start_addr,
333 429 ram_addr_t size,
334 430 ram_addr_t phys_offset)
... ...
... ... @@ -38,6 +38,10 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
38 38 ram_addr_t size,
39 39 ram_addr_t phys_offset);
40 40  
  41 +void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr);
  42 +
  43 +int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t len);
  44 +int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t len);
41 45 /* internal API */
42 46  
43 47 struct KVMState;
... ...