/* * qemu/kvm integration, x86 specific code * * Copyright (C) 2006-2008 Qumranet Technologies * * Licensed under the terms of the GNU GPL version 2 or higher. */ #include "config.h" #include "config-host.h" #include #include "hw/hw.h" #include "gdbstub.h" #include #include "qemu-kvm.h" #include #include #include #include #include "kvm.h" #include "hw/apic.h" int kvm_reinject_control(KVMState *s, int pit_reinject) { #ifdef KVM_CAP_REINJECT_CONTROL int r; struct kvm_reinject_control control; control.pit_reinject = pit_reinject; r = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_REINJECT_CONTROL); if (r > 0) { return kvm_vm_ioctl(s, KVM_REINJECT_CONTROL, &control); } #endif return -ENOSYS; } static int kvm_create_pit(KVMState *s) { int r; if (kvm_pit) { r = kvm_vm_ioctl(s, KVM_CREATE_PIT); if (r < 0) { fprintf(stderr, "Create kernel PIC irqchip failed\n"); return r; } if (!kvm_pit_reinject) { r = kvm_reinject_control(s, 0); if (r < 0) { fprintf(stderr, "failure to disable in-kernel PIT reinjection\n"); return r; } } } return 0; } int kvm_handle_tpr_access(CPUState *env) { struct kvm_run *run = env->kvm_run; kvm_tpr_access_report(env, run->tpr_access.rip, run->tpr_access.is_write); return 1; } int kvm_enable_vapic(CPUState *env, uint64_t vapic) { struct kvm_vapic_addr va = { .vapic_addr = vapic, }; return kvm_vcpu_ioctl(env, KVM_SET_VAPIC_ADDR, &va); } int kvm_get_lapic(CPUState *env, struct kvm_lapic_state *s) { int r = 0; if (!kvm_irqchip_in_kernel()) { return r; } r = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, s); if (r < 0) { fprintf(stderr, "KVM_GET_LAPIC failed\n"); } return r; } int kvm_set_lapic(CPUState *env, struct kvm_lapic_state *s) { int r = 0; if (!kvm_irqchip_in_kernel()) { return 0; } r = kvm_vcpu_ioctl(env, KVM_SET_LAPIC, s); if (r < 0) { fprintf(stderr, "KVM_SET_LAPIC failed\n"); } return r; } int kvm_get_pit(KVMState *s, struct kvm_pit_state *pit_state) { if (!kvm_pit_in_kernel()) { return 0; } return kvm_vm_ioctl(s, KVM_GET_PIT, pit_state); } int kvm_set_pit(KVMState *s, struct kvm_pit_state *pit_state) { if (!kvm_pit_in_kernel()) { return 0; } return kvm_vm_ioctl(s, KVM_SET_PIT, pit_state); } int kvm_get_pit2(KVMState *s, struct kvm_pit_state2 *ps2) { if (!kvm_pit_in_kernel()) { return 0; } return kvm_vm_ioctl(s, KVM_GET_PIT2, ps2); } int kvm_set_pit2(KVMState *s, struct kvm_pit_state2 *ps2) { if (!kvm_pit_in_kernel()) { return 0; } return kvm_vm_ioctl(s, KVM_SET_PIT2, ps2); } static int kvm_enable_tpr_access_reporting(CPUState *env) { int r; struct kvm_tpr_access_ctl tac = { .enabled = 1 }; r = kvm_ioctl(env->kvm_state, KVM_CHECK_EXTENSION, KVM_CAP_VAPIC); if (r <= 0) { return -ENOSYS; } return kvm_vcpu_ioctl(env, KVM_TPR_ACCESS_REPORTING, &tac); } static int _kvm_arch_init_vcpu(CPUState *env) { kvm_arch_reset_vcpu(env); kvm_enable_tpr_access_reporting(env); return kvm_update_ioport_access(env); } #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT int kvm_arch_set_ioport_access(unsigned long start, unsigned long size, bool enable) { if (ioperm(start, size, enable) < 0) { return -errno; } return 0; } #endif /* * Setup x86 specific IRQ routing */ int kvm_arch_init_irq_routing(void) { int i, r; if (kvm_has_gsi_routing()) { kvm_clear_gsi_routes(); for (i = 0; i < 8; ++i) { if (i == 2) { continue; } r = kvm_add_irq_route(i, KVM_IRQCHIP_PIC_MASTER, i); if (r < 0) { return r; } } for (i = 8; i < 16; ++i) { r = kvm_add_irq_route(i, KVM_IRQCHIP_PIC_SLAVE, i - 8); if (r < 0) { return r; } } for (i = 0; i < 24; ++i) { if (i == 0) { r = kvm_add_irq_route(i, KVM_IRQCHIP_IOAPIC, 2); } else if (i != 2) { r = kvm_add_irq_route(i, KVM_IRQCHIP_IOAPIC, i); } if (r < 0) { return r; } } kvm_commit_irq_routes(); if (!kvm_has_pit_state2()) { no_hpet = 1; } } else { /* If kernel can't do irq routing, interrupt source * override 0->2 can not be set up as required by HPET. * so we have to disable it. */ no_hpet = 1; } return 0; }