#include "qemu-common.h"
#include "sysemu.h"
+#include "hw/hw.h"
#include "gdbstub.h"
#include "kvm.h"
KVMSlot slots[32];
int fd;
int vmfd;
+ int regs_modified;
int coalesced_mmio;
int broken_set_mem_region;
int migration_log;
#ifdef KVM_CAP_SET_GUEST_DEBUG
struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
#endif
+ int irqchip_in_kernel;
+ int pit_in_kernel;
};
static KVMState *kvm_state;
return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
}
+static void kvm_reset_vcpu(void *opaque)
+{
+ CPUState *env = opaque;
+
+ if (kvm_arch_put_registers(env)) {
+ fprintf(stderr, "Fatal: kvm vcpu reset failed\n");
+ abort();
+ }
+}
+
+int kvm_irqchip_in_kernel(void)
+{
+ return kvm_state->irqchip_in_kernel;
+}
+
+int kvm_pit_in_kernel(void)
+{
+ return kvm_state->pit_in_kernel;
+}
+
int kvm_init_vcpu(CPUState *env)
{
}
ret = kvm_arch_init_vcpu(env);
-
+ if (ret == 0) {
+ qemu_register_reset(kvm_reset_vcpu, env);
+ ret = kvm_arch_put_registers(env);
+ }
err:
return ret;
}
-int kvm_sync_vcpus(void)
+int kvm_put_mp_state(CPUState *env)
{
- CPUState *env;
+ struct kvm_mp_state mp_state = { .mp_state = env->mp_state };
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- int ret;
+ return kvm_vcpu_ioctl(env, KVM_SET_MP_STATE, &mp_state);
+}
- ret = kvm_arch_put_registers(env);
- if (ret)
- return ret;
- }
+int kvm_get_mp_state(CPUState *env)
+{
+ struct kvm_mp_state mp_state;
+ int ret;
+ ret = kvm_vcpu_ioctl(env, KVM_GET_MP_STATE, &mp_state);
+ if (ret < 0) {
+ return ret;
+ }
+ env->mp_state = mp_state.mp_state;
return 0;
}
if (mem == NULL) {
fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
TARGET_FMT_plx "\n", __func__, phys_addr,
- phys_addr + size - 1);
+ (target_phys_addr_t)(phys_addr + size - 1));
return -EINVAL;
}
return 0;
}
+static int test_le_bit(unsigned long nr, unsigned char *addr)
+{
+ return (addr[nr >> 3] >> (nr & 7)) & 1;
+}
+
/**
* kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
* This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty().
for (phys_addr = mem->start_addr, addr = mem->phys_offset;
phys_addr < mem->start_addr + mem->memory_size;
phys_addr += TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
- unsigned long *bitmap = (unsigned long *)d.dirty_bitmap;
+ unsigned char *bitmap = (unsigned char *)d.dirty_bitmap;
unsigned nr = (phys_addr - mem->start_addr) >> TARGET_PAGE_BITS;
- unsigned word = nr / (sizeof(*bitmap) * 8);
- unsigned bit = nr % (sizeof(*bitmap) * 8);
- if ((bitmap[word] >> bit) & 1) {
+ if (test_le_bit(nr, bitmap)) {
cpu_physical_memory_set_dirty(addr);
}
}
int kvm_init(int smp_cpus)
{
+ static const char upgrade_note[] =
+ "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
+ "(see http://sourceforge.net/projects/kvm).\n";
KVMState *s;
int ret;
int i;
*/
if (!kvm_check_extension(s, KVM_CAP_USER_MEMORY)) {
ret = -EINVAL;
- fprintf(stderr, "kvm does not support KVM_CAP_USER_MEMORY\n");
+ fprintf(stderr, "kvm does not support KVM_CAP_USER_MEMORY\n%s",
+ upgrade_note);
goto err;
}
ret = -EINVAL;
fprintf(stderr,
- "KVM kernel module broken (DESTROY_MEMORY_REGION)\n"
- "Please upgrade to at least kvm-81.\n");
+ "KVM kernel module broken (DESTROY_MEMORY_REGION).\n%s",
+ upgrade_note);
goto err;
}
#endif
}
+void kvm_cpu_synchronize_state(CPUState *env)
+{
+ if (!env->kvm_state->regs_modified) {
+ kvm_arch_get_registers(env);
+ env->kvm_state->regs_modified = 1;
+ }
+}
+
int kvm_cpu_exec(CPUState *env)
{
struct kvm_run *run = env->kvm_run;
dprintf("kvm_cpu_exec()\n");
do {
- kvm_arch_pre_run(env, run);
-
if (env->exit_request) {
dprintf("interrupt exit requested\n");
ret = 0;
break;
}
+ if (env->kvm_state->regs_modified) {
+ kvm_arch_put_registers(env);
+ env->kvm_state->regs_modified = 0;
+ }
+
+ kvm_arch_pre_run(env, run);
ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
kvm_arch_post_run(env, run);
}
#ifdef KVM_CAP_SET_GUEST_DEBUG
+static void on_vcpu(CPUState *env, void (*func)(void *data), void *data)
+{
+ if (env == cpu_single_env) {
+ func(data);
+ return;
+ }
+ abort();
+}
+
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
target_ulong pc)
{
return !TAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints);
}
+struct kvm_set_guest_debug_data {
+ struct kvm_guest_debug dbg;
+ CPUState *env;
+ int err;
+};
+
+static void kvm_invoke_set_guest_debug(void *data)
+{
+ struct kvm_set_guest_debug_data *dbg_data = data;
+ dbg_data->err = kvm_vcpu_ioctl(dbg_data->env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg);
+}
+
int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
{
- struct kvm_guest_debug dbg;
+ struct kvm_set_guest_debug_data data;
- dbg.control = 0;
+ data.dbg.control = 0;
if (env->singlestep_enabled)
- dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+ data.dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
- kvm_arch_update_guest_debug(env, &dbg);
- dbg.control |= reinject_trap;
+ kvm_arch_update_guest_debug(env, &data.dbg);
+ data.dbg.control |= reinject_trap;
+ data.env = env;
- return kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg);
+ on_vcpu(env, kvm_invoke_set_guest_debug, &data);
+ return data.err;
}
int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,