aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/vmx.c
diff options
context:
space:
mode:
authorEddie Dong <eddie.dong@intel.com>2007-07-06 05:20:49 -0400
committerAvi Kivity <avi@qumranet.com>2007-10-13 04:18:24 -0400
commit85f455f7ddbed403b34b4d54b1eaf0e14126a126 (patch)
tree1dba7aa8fee3c8f756e12049c496dee5baae752c /drivers/kvm/vmx.c
parent152d3f2f246ce3c2a0cf2fc6c2214663cd99aa83 (diff)
KVM: Add support for in-kernel PIC emulation
Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/vmx.c')
-rw-r--r--drivers/kvm/vmx.c80
1 files changed, 71 insertions, 9 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index d63e82e5dbf8..f1e80a95b69d 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -17,6 +17,7 @@
17 17
18#include "kvm.h" 18#include "kvm.h"
19#include "x86_emulate.h" 19#include "x86_emulate.h"
20#include "irq.h"
20#include "vmx.h" 21#include "vmx.h"
21#include "segment_descriptor.h" 22#include "segment_descriptor.h"
22 23
@@ -1582,6 +1583,16 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
1582 vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6)); 1583 vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
1583} 1584}
1584 1585
1586static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
1587{
1588 if (vcpu->rmode.active) {
1589 inject_rmode_irq(vcpu, irq);
1590 return;
1591 }
1592 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
1593 irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
1594}
1595
1585static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) 1596static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
1586{ 1597{
1587 int word_index = __ffs(vcpu->irq_summary); 1598 int word_index = __ffs(vcpu->irq_summary);
@@ -1591,13 +1602,7 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
1591 clear_bit(bit_index, &vcpu->irq_pending[word_index]); 1602 clear_bit(bit_index, &vcpu->irq_pending[word_index]);
1592 if (!vcpu->irq_pending[word_index]) 1603 if (!vcpu->irq_pending[word_index])
1593 clear_bit(word_index, &vcpu->irq_summary); 1604 clear_bit(word_index, &vcpu->irq_summary);
1594 1605 vmx_inject_irq(vcpu, irq);
1595 if (vcpu->rmode.active) {
1596 inject_rmode_irq(vcpu, irq);
1597 return;
1598 }
1599 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
1600 irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
1601} 1606}
1602 1607
1603 1608
@@ -1681,7 +1686,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1681 "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); 1686 "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
1682 } 1687 }
1683 1688
1684 if (is_external_interrupt(vect_info)) { 1689 if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
1685 int irq = vect_info & VECTORING_INFO_VECTOR_MASK; 1690 int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
1686 set_bit(irq, vcpu->irq_pending); 1691 set_bit(irq, vcpu->irq_pending);
1687 set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); 1692 set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
@@ -1961,6 +1966,12 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu,
1961static int handle_interrupt_window(struct kvm_vcpu *vcpu, 1966static int handle_interrupt_window(struct kvm_vcpu *vcpu,
1962 struct kvm_run *kvm_run) 1967 struct kvm_run *kvm_run)
1963{ 1968{
1969 u32 cpu_based_vm_exec_control;
1970
1971 /* clear pending irq */
1972 cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
1973 cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
1974 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
1964 /* 1975 /*
1965 * If the user space waits to inject interrupts, exit as soon as 1976 * If the user space waits to inject interrupts, exit as soon as
1966 * possible 1977 * possible
@@ -2052,6 +2063,55 @@ static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
2052{ 2063{
2053} 2064}
2054 2065
2066static void enable_irq_window(struct kvm_vcpu *vcpu)
2067{
2068 u32 cpu_based_vm_exec_control;
2069
2070 cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
2071 cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
2072 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
2073}
2074
2075static void vmx_intr_assist(struct kvm_vcpu *vcpu)
2076{
2077 u32 idtv_info_field, intr_info_field;
2078 int has_ext_irq, interrupt_window_open;
2079
2080 has_ext_irq = kvm_cpu_has_interrupt(vcpu);
2081 intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
2082 idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
2083 if (intr_info_field & INTR_INFO_VALID_MASK) {
2084 if (idtv_info_field & INTR_INFO_VALID_MASK) {
2085 /* TODO: fault when IDT_Vectoring */
2086 printk(KERN_ERR "Fault when IDT_Vectoring\n");
2087 }
2088 if (has_ext_irq)
2089 enable_irq_window(vcpu);
2090 return;
2091 }
2092 if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
2093 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
2094 vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
2095 vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
2096
2097 if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK))
2098 vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
2099 vmcs_read32(IDT_VECTORING_ERROR_CODE));
2100 if (unlikely(has_ext_irq))
2101 enable_irq_window(vcpu);
2102 return;
2103 }
2104 if (!has_ext_irq)
2105 return;
2106 interrupt_window_open =
2107 ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
2108 (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
2109 if (interrupt_window_open)
2110 vmx_inject_irq(vcpu, kvm_cpu_get_interrupt(vcpu));
2111 else
2112 enable_irq_window(vcpu);
2113}
2114
2055static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 2115static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
2056{ 2116{
2057 struct vcpu_vmx *vmx = to_vmx(vcpu); 2117 struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -2088,7 +2148,9 @@ again:
2088 goto out; 2148 goto out;
2089 } 2149 }
2090 2150
2091 if (!vcpu->mmio_read_completed) 2151 if (irqchip_in_kernel(vcpu->kvm))
2152 vmx_intr_assist(vcpu);
2153 else if (!vcpu->mmio_read_completed)
2092 do_interrupt_requests(vcpu, kvm_run); 2154 do_interrupt_requests(vcpu, kvm_run);
2093 2155
2094 vcpu->guest_mode = 1; 2156 vcpu->guest_mode = 1;