diff options
author | Eddie Dong <eddie.dong@intel.com> | 2007-07-06 05:20:49 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:24 -0400 |
commit | 85f455f7ddbed403b34b4d54b1eaf0e14126a126 (patch) | |
tree | 1dba7aa8fee3c8f756e12049c496dee5baae752c /drivers/kvm/vmx.c | |
parent | 152d3f2f246ce3c2a0cf2fc6c2214663cd99aa83 (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.c | 80 |
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 | ||
1586 | static 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 | |||
1585 | static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) | 1596 | static 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, | |||
1961 | static int handle_interrupt_window(struct kvm_vcpu *vcpu, | 1966 | static 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 | ||
2066 | static 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 | |||
2075 | static 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 | |||
2055 | static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 2115 | static 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; |