1dfb4dd993
Today, when notifying a VM state change with vm_state_notify(), we pass a VMSTOP macro as the 'reason' argument. This is not ideal because the VMSTOP macros tell why qemu stopped and not exactly what the current VM state is. One example to demonstrate this problem is that vm_start() calls vm_state_notify() with reason=0, which turns out to be VMSTOP_USER. This commit fixes that by replacing the VMSTOP macros with a proper state type called RunState. Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
119 lines
2.8 KiB
C
119 lines
2.8 KiB
C
/*
|
|
* QEMU KVM support, paravirtual clock device
|
|
*
|
|
* Copyright (C) 2011 Siemens AG
|
|
*
|
|
* Authors:
|
|
* Jan Kiszka <jan.kiszka@siemens.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL version 2.
|
|
* See the COPYING file in the top-level directory.
|
|
*
|
|
*/
|
|
|
|
#include "qemu-common.h"
|
|
#include "sysemu.h"
|
|
#include "sysbus.h"
|
|
#include "kvm.h"
|
|
#include "kvmclock.h"
|
|
|
|
#include <linux/kvm.h>
|
|
#include <linux/kvm_para.h>
|
|
|
|
typedef struct KVMClockState {
|
|
SysBusDevice busdev;
|
|
uint64_t clock;
|
|
bool clock_valid;
|
|
} KVMClockState;
|
|
|
|
static void kvmclock_pre_save(void *opaque)
|
|
{
|
|
KVMClockState *s = opaque;
|
|
struct kvm_clock_data data;
|
|
int ret;
|
|
|
|
if (s->clock_valid) {
|
|
return;
|
|
}
|
|
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
|
|
if (ret < 0) {
|
|
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
|
|
data.clock = 0;
|
|
}
|
|
s->clock = data.clock;
|
|
/*
|
|
* If the VM is stopped, declare the clock state valid to avoid re-reading
|
|
* it on next vmsave (which would return a different value). Will be reset
|
|
* when the VM is continued.
|
|
*/
|
|
s->clock_valid = !vm_running;
|
|
}
|
|
|
|
static int kvmclock_post_load(void *opaque, int version_id)
|
|
{
|
|
KVMClockState *s = opaque;
|
|
struct kvm_clock_data data;
|
|
|
|
data.clock = s->clock;
|
|
data.flags = 0;
|
|
return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
|
|
}
|
|
|
|
static void kvmclock_vm_state_change(void *opaque, int running,
|
|
RunState state)
|
|
{
|
|
KVMClockState *s = opaque;
|
|
|
|
if (running) {
|
|
s->clock_valid = false;
|
|
}
|
|
}
|
|
|
|
static int kvmclock_init(SysBusDevice *dev)
|
|
{
|
|
KVMClockState *s = FROM_SYSBUS(KVMClockState, dev);
|
|
|
|
qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
|
|
return 0;
|
|
}
|
|
|
|
static const VMStateDescription kvmclock_vmsd = {
|
|
.name = "kvmclock",
|
|
.version_id = 1,
|
|
.minimum_version_id = 1,
|
|
.minimum_version_id_old = 1,
|
|
.pre_save = kvmclock_pre_save,
|
|
.post_load = kvmclock_post_load,
|
|
.fields = (VMStateField[]) {
|
|
VMSTATE_UINT64(clock, KVMClockState),
|
|
VMSTATE_END_OF_LIST()
|
|
}
|
|
};
|
|
|
|
static SysBusDeviceInfo kvmclock_info = {
|
|
.qdev.name = "kvmclock",
|
|
.qdev.size = sizeof(KVMClockState),
|
|
.qdev.vmsd = &kvmclock_vmsd,
|
|
.qdev.no_user = 1,
|
|
.init = kvmclock_init,
|
|
};
|
|
|
|
/* Note: Must be called after VCPU initialization. */
|
|
void kvmclock_create(void)
|
|
{
|
|
if (kvm_enabled() &&
|
|
first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
|
|
(1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
|
|
sysbus_create_simple("kvmclock", -1, NULL);
|
|
}
|
|
}
|
|
|
|
static void kvmclock_register_device(void)
|
|
{
|
|
if (kvm_enabled()) {
|
|
sysbus_register_withprop(&kvmclock_info);
|
|
}
|
|
}
|
|
|
|
device_init(kvmclock_register_device);
|