Commit 5832d1f2f51e1a1991c53ea98c535a619cf03001
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,9 +2,11 @@ | ||
2 | * QEMU KVM support | 2 | * QEMU KVM support |
3 | * | 3 | * |
4 | * Copyright IBM, Corp. 2008 | 4 | * Copyright IBM, Corp. 2008 |
5 | + * Red Hat, Inc. 2008 | ||
5 | * | 6 | * |
6 | * Authors: | 7 | * Authors: |
7 | * Anthony Liguori <aliguori@us.ibm.com> | 8 | * Anthony Liguori <aliguori@us.ibm.com> |
9 | + * Glauber Costa <gcosta@redhat.com> | ||
8 | * | 10 | * |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | 11 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
10 | * See the COPYING file in the top-level directory. | 12 | * See the COPYING file in the top-level directory. |
@@ -41,6 +43,8 @@ typedef struct KVMSlot | @@ -41,6 +43,8 @@ typedef struct KVMSlot | ||
41 | int flags; | 43 | int flags; |
42 | } KVMSlot; | 44 | } KVMSlot; |
43 | 45 | ||
46 | +typedef struct kvm_dirty_log KVMDirtyLog; | ||
47 | + | ||
44 | int kvm_allowed = 0; | 48 | int kvm_allowed = 0; |
45 | 49 | ||
46 | struct KVMState | 50 | struct KVMState |
@@ -82,6 +86,20 @@ static KVMSlot *kvm_lookup_slot(KVMState *s, target_phys_addr_t start_addr) | @@ -82,6 +86,20 @@ static KVMSlot *kvm_lookup_slot(KVMState *s, target_phys_addr_t start_addr) | ||
82 | return NULL; | 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 | int kvm_init_vcpu(CPUState *env) | 103 | int kvm_init_vcpu(CPUState *env) |
86 | { | 104 | { |
87 | KVMState *s = kvm_state; | 105 | KVMState *s = kvm_state; |
@@ -119,6 +137,97 @@ err: | @@ -119,6 +137,97 @@ err: | ||
119 | return ret; | 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 | int kvm_init(int smp_cpus) | 231 | int kvm_init(int smp_cpus) |
123 | { | 232 | { |
124 | KVMState *s; | 233 | KVMState *s; |
@@ -316,19 +425,6 @@ int kvm_cpu_exec(CPUState *env) | @@ -316,19 +425,6 @@ int kvm_cpu_exec(CPUState *env) | ||
316 | return ret; | 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 | void kvm_set_phys_mem(target_phys_addr_t start_addr, | 428 | void kvm_set_phys_mem(target_phys_addr_t start_addr, |
333 | ram_addr_t size, | 429 | ram_addr_t size, |
334 | ram_addr_t phys_offset) | 430 | ram_addr_t phys_offset) |
kvm.h
@@ -38,6 +38,10 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr, | @@ -38,6 +38,10 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr, | ||
38 | ram_addr_t size, | 38 | ram_addr_t size, |
39 | ram_addr_t phys_offset); | 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 | /* internal API */ | 45 | /* internal API */ |
42 | 46 | ||
43 | struct KVMState; | 47 | struct KVMState; |