@@ -916,6 +916,8 @@ void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
+void qemu_flush_coalesced_mmio_buffer(void);
+
/*******************************************/
/* host CPU ticks (if available) */
@@ -2424,6 +2424,12 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
kvm_uncoalesce_mmio_region(addr, size);
}
+void qemu_flush_coalesced_mmio_buffer(void)
+{
+ if (kvm_enabled())
+ kvm_flush_coalesced_mmio_buffer();
+}
+
#ifdef __linux__
#include <sys/vfs.h>
@@ -25,6 +25,9 @@
#include "hw/hw.h"
#include "gdbstub.h"
#include "kvm.h"
+#ifndef KVM_UPSTREAM
+#include "libkvm.h"
+#endif
#ifdef KVM_UPSTREAM
/* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */
@@ -385,6 +388,23 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
return ret;
}
+void kvm_flush_coalesced_mmio_buffer(void)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+ if (kvm_state->coalesced_mmio_ring) {
+ struct kvm_coalesced_mmio_ring *ring =
+ kvm_state->coalesced_mmio_ring;
+ while (ring->first != ring->last) {
+ cpu_physical_memory_rw(ring->coalesced_mmio[ring->first].phys_addr,
+ &ring->coalesced_mmio[ring->first].data[0],
+ ring->coalesced_mmio[ring->first].len, 1);
+ smp_wmb();
+ ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
+ }
+ }
+#endif
+}
+
int kvm_check_extension(KVMState *s, unsigned int extension)
{
int ret;
@@ -463,6 +463,12 @@ static void kvm_create_vcpu(CPUState *env, int id)
goto err_fd;
}
+#ifdef KVM_CAP_COALESCED_MMIO
+ if (kvm_state->coalesced_mmio && !kvm_state->coalesced_mmio_ring)
+ kvm_state->coalesced_mmio_ring = (void *) env->kvm_run +
+ kvm_state->coalesced_mmio * PAGE_SIZE;
+#endif
+
return;
err_fd:
close(env->kvm_fd);
@@ -927,8 +933,7 @@ int kvm_run(CPUState *env)
#if defined(KVM_CAP_COALESCED_MMIO)
if (kvm_state->coalesced_mmio) {
- struct kvm_coalesced_mmio_ring *ring =
- (void *) run + kvm_state->coalesced_mmio * PAGE_SIZE;
+ struct kvm_coalesced_mmio_ring *ring = kvm_state->coalesced_mmio_ring;
while (ring->first != ring->last) {
cpu_physical_memory_rw(ring->coalesced_mmio[ring->first].phys_addr,
&ring->coalesced_mmio[ring->first].data[0],
@@ -435,6 +435,7 @@ int kvm_register_coalesced_mmio(kvm_context_t kvm, uint64_t addr,
uint32_t size);
int kvm_unregister_coalesced_mmio(kvm_context_t kvm, uint64_t addr,
uint32_t size);
+void kvm_flush_coalesced_mmio_buffer(void);
/*!
* \brief Create a memory alias
@@ -1144,6 +1145,7 @@ typedef struct KVMState {
int fd;
int vmfd;
int coalesced_mmio;
+ struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
int broken_set_mem_region;
int migration_log;
int vcpu_events;
@@ -3227,6 +3227,7 @@ static void gui_update(void *opaque)
DisplayState *ds = opaque;
DisplayChangeListener *dcl = ds->listeners;
+ qemu_flush_coalesced_mmio_buffer();
dpy_refresh(ds);
while (dcl != NULL) {
@@ -3242,6 +3243,7 @@ static void nographic_update(void *opaque)
{
uint64_t interval = GUI_REFRESH_INTERVAL;
+ qemu_flush_coalesced_mmio_buffer();
qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
}