diff options
author | Avi Kivity <avi@qumranet.com> | 2007-11-22 04:42:59 -0500 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:53:01 -0500 |
commit | 9c8cba3761d4741cfd53ecc40604fac01f52128a (patch) | |
tree | 40d65ea2a0f000ebff9ce803bc2515c814bf1750 /drivers/kvm/vmx.c | |
parent | 1155f76a8166ae6fc88e7d73eb6817eb9012d476 (diff) |
KVM: Fix faults during injection of real-mode interrupts
If vmx fails to inject a real-mode interrupt while fetching the interrupt
redirection table, it fails to record this in the vectoring information
field. So we detect this condition and do it ourselves.
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/vmx.c')
-rw-r--r-- | drivers/kvm/vmx.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index f045f4005eaa..26719aa9701e 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -65,7 +65,13 @@ struct vcpu_vmx { | |||
65 | int fs_reload_needed; | 65 | int fs_reload_needed; |
66 | int guest_efer_loaded; | 66 | int guest_efer_loaded; |
67 | } host_state; | 67 | } host_state; |
68 | 68 | struct { | |
69 | struct { | ||
70 | bool pending; | ||
71 | u8 vector; | ||
72 | unsigned rip; | ||
73 | } irq; | ||
74 | } rmode; | ||
69 | }; | 75 | }; |
70 | 76 | ||
71 | static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) | 77 | static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) |
@@ -1713,11 +1719,16 @@ out: | |||
1713 | 1719 | ||
1714 | static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) | 1720 | static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) |
1715 | { | 1721 | { |
1722 | struct vcpu_vmx *vmx = to_vmx(vcpu); | ||
1723 | |||
1716 | if (vcpu->rmode.active) { | 1724 | if (vcpu->rmode.active) { |
1725 | vmx->rmode.irq.pending = true; | ||
1726 | vmx->rmode.irq.vector = irq; | ||
1727 | vmx->rmode.irq.rip = vmcs_readl(GUEST_RIP); | ||
1717 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, | 1728 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, |
1718 | irq | INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK); | 1729 | irq | INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK); |
1719 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1); | 1730 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1); |
1720 | vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP) - 1); | 1731 | vmcs_writel(GUEST_RIP, vmx->rmode.irq.rip - 1); |
1721 | return; | 1732 | return; |
1722 | } | 1733 | } |
1723 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, | 1734 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, |
@@ -2251,6 +2262,17 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) | |||
2251 | return; | 2262 | return; |
2252 | } | 2263 | } |
2253 | if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { | 2264 | if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { |
2265 | if ((idtv_info_field & VECTORING_INFO_TYPE_MASK) | ||
2266 | == INTR_TYPE_EXT_INTR | ||
2267 | && vcpu->rmode.active) { | ||
2268 | u8 vect = idtv_info_field & VECTORING_INFO_VECTOR_MASK; | ||
2269 | |||
2270 | vmx_inject_irq(vcpu, vect); | ||
2271 | if (unlikely(has_ext_irq)) | ||
2272 | enable_irq_window(vcpu); | ||
2273 | return; | ||
2274 | } | ||
2275 | |||
2254 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); | 2276 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); |
2255 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, | 2277 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, |
2256 | vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); | 2278 | vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); |
@@ -2275,6 +2297,29 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) | |||
2275 | enable_irq_window(vcpu); | 2297 | enable_irq_window(vcpu); |
2276 | } | 2298 | } |
2277 | 2299 | ||
2300 | /* | ||
2301 | * Failure to inject an interrupt should give us the information | ||
2302 | * in IDT_VECTORING_INFO_FIELD. However, if the failure occurs | ||
2303 | * when fetching the interrupt redirection bitmap in the real-mode | ||
2304 | * tss, this doesn't happen. So we do it ourselves. | ||
2305 | */ | ||
2306 | static void fixup_rmode_irq(struct vcpu_vmx *vmx) | ||
2307 | { | ||
2308 | vmx->rmode.irq.pending = 0; | ||
2309 | if (vmcs_readl(GUEST_RIP) + 1 != vmx->rmode.irq.rip) | ||
2310 | return; | ||
2311 | vmcs_writel(GUEST_RIP, vmx->rmode.irq.rip); | ||
2312 | if (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) { | ||
2313 | vmx->idt_vectoring_info &= ~VECTORING_INFO_TYPE_MASK; | ||
2314 | vmx->idt_vectoring_info |= INTR_TYPE_EXT_INTR; | ||
2315 | return; | ||
2316 | } | ||
2317 | vmx->idt_vectoring_info = | ||
2318 | VECTORING_INFO_VALID_MASK | ||
2319 | | INTR_TYPE_EXT_INTR | ||
2320 | | vmx->rmode.irq.vector; | ||
2321 | } | ||
2322 | |||
2278 | static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 2323 | static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
2279 | { | 2324 | { |
2280 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 2325 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
@@ -2401,6 +2446,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2401 | ); | 2446 | ); |
2402 | 2447 | ||
2403 | vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); | 2448 | vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); |
2449 | if (vmx->rmode.irq.pending) | ||
2450 | fixup_rmode_irq(vmx); | ||
2404 | 2451 | ||
2405 | vcpu->interrupt_window_open = | 2452 | vcpu->interrupt_window_open = |
2406 | (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; | 2453 | (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; |