aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/vmx.c
diff options
context:
space:
mode:
authorDor Laor <dor.laor@qumranet.com>2007-01-05 19:36:24 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2007-01-06 02:55:22 -0500
commitc1150d8cf9e9d2b356fab52d79f2366985e5511b (patch)
treedbd50c3e064c22dcab7ce4acc7236370c6750923 /drivers/kvm/vmx.c
parente097f35ce58eb8d687f3a300247cf1a978fcea39 (diff)
[PATCH] KVM: Improve interrupt response
The current interrupt injection mechanism might delay an interrupt under the following circumstances: - if injection fails because the guest is not interruptible (rflags.IF clear, or after a 'mov ss' or 'sti' instruction). Userspace can check rflags, but the other cases or not testable under the current API. - if injection fails because of a fault during delivery. This probably never happens under normal guests. - if injection fails due to a physical interrupt causing a vmexit so that it can be handled by the host. In all cases the guest proceeds without processing the interrupt, reducing the interactive feel and interrupt throughput of the guest. This patch fixes the situation by allowing userspace to request an exit when the 'interrupt window' opens, so that it can re-inject the interrupt at the right time. Guest interactivity is very visibly improved. Signed-off-by: Dor Laor <dor.laor@qumranet.com> Signed-off-by: Avi Kivity <avi@qumranet.com> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/kvm/vmx.c')
-rw-r--r--drivers/kvm/vmx.c88
1 files changed, 72 insertions, 16 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 2d204fd45972..c55635ddf426 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -263,6 +263,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
263 if (interruptibility & 3) 263 if (interruptibility & 3)
264 vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 264 vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
265 interruptibility & ~3); 265 interruptibility & ~3);
266 vcpu->interrupt_window_open = 1;
266} 267}
267 268
268static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) 269static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
@@ -1214,21 +1215,34 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
1214 irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); 1215 irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
1215} 1216}
1216 1217
1217static void kvm_try_inject_irq(struct kvm_vcpu *vcpu) 1218
1219static void do_interrupt_requests(struct kvm_vcpu *vcpu,
1220 struct kvm_run *kvm_run)
1218{ 1221{
1219 if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) 1222 u32 cpu_based_vm_exec_control;
1220 && (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0) 1223
1224 vcpu->interrupt_window_open =
1225 ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
1226 (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
1227
1228 if (vcpu->interrupt_window_open &&
1229 vcpu->irq_summary &&
1230 !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK))
1221 /* 1231 /*
1222 * Interrupts enabled, and not blocked by sti or mov ss. Good. 1232 * If interrupts enabled, and not blocked by sti or mov ss. Good.
1223 */ 1233 */
1224 kvm_do_inject_irq(vcpu); 1234 kvm_do_inject_irq(vcpu);
1225 else 1235
1236 cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
1237 if (!vcpu->interrupt_window_open &&
1238 (vcpu->irq_summary || kvm_run->request_interrupt_window))
1226 /* 1239 /*
1227 * Interrupts blocked. Wait for unblock. 1240 * Interrupts blocked. Wait for unblock.
1228 */ 1241 */
1229 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, 1242 cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
1230 vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) 1243 else
1231 | CPU_BASED_VIRTUAL_INTR_PENDING); 1244 cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
1245 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
1232} 1246}
1233 1247
1234static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu) 1248static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu)
@@ -1565,23 +1579,41 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1565 return 1; 1579 return 1;
1566} 1580}
1567 1581
1582static void post_kvm_run_save(struct kvm_vcpu *vcpu,
1583 struct kvm_run *kvm_run)
1584{
1585 kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0;
1586 kvm_run->cr8 = vcpu->cr8;
1587 kvm_run->apic_base = vcpu->apic_base;
1588 kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
1589 vcpu->irq_summary == 0);
1590}
1591
1568static int handle_interrupt_window(struct kvm_vcpu *vcpu, 1592static int handle_interrupt_window(struct kvm_vcpu *vcpu,
1569 struct kvm_run *kvm_run) 1593 struct kvm_run *kvm_run)
1570{ 1594{
1571 /* Turn off interrupt window reporting. */ 1595 /*
1572 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, 1596 * If the user space waits to inject interrupts, exit as soon as
1573 vmcs_read32(CPU_BASED_VM_EXEC_CONTROL) 1597 * possible
1574 & ~CPU_BASED_VIRTUAL_INTR_PENDING); 1598 */
1599 if (kvm_run->request_interrupt_window &&
1600 !vcpu->irq_summary &&
1601 (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)) {
1602 kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
1603 ++kvm_stat.irq_window_exits;
1604 return 0;
1605 }
1575 return 1; 1606 return 1;
1576} 1607}
1577 1608
1578static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 1609static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1579{ 1610{
1580 skip_emulated_instruction(vcpu); 1611 skip_emulated_instruction(vcpu);
1581 if (vcpu->irq_summary && (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)) 1612 if (vcpu->irq_summary)
1582 return 1; 1613 return 1;
1583 1614
1584 kvm_run->exit_reason = KVM_EXIT_HLT; 1615 kvm_run->exit_reason = KVM_EXIT_HLT;
1616 ++kvm_stat.halt_exits;
1585 return 0; 1617 return 0;
1586} 1618}
1587 1619
@@ -1632,6 +1664,21 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
1632 return 0; 1664 return 0;
1633} 1665}
1634 1666
1667/*
1668 * Check if userspace requested an interrupt window, and that the
1669 * interrupt window is open.
1670 *
1671 * No need to exit to userspace if we already have an interrupt queued.
1672 */
1673static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
1674 struct kvm_run *kvm_run)
1675{
1676 return (!vcpu->irq_summary &&
1677 kvm_run->request_interrupt_window &&
1678 vcpu->interrupt_window_open &&
1679 (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
1680}
1681
1635static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 1682static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1636{ 1683{
1637 u8 fail; 1684 u8 fail;
@@ -1663,9 +1710,7 @@ again:
1663 vmcs_writel(HOST_GS_BASE, segment_base(gs_sel)); 1710 vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
1664#endif 1711#endif
1665 1712
1666 if (vcpu->irq_summary && 1713 do_interrupt_requests(vcpu, kvm_run);
1667 !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK))
1668 kvm_try_inject_irq(vcpu);
1669 1714
1670 if (vcpu->guest_debug.enabled) 1715 if (vcpu->guest_debug.enabled)
1671 kvm_guest_debug_pre(vcpu); 1716 kvm_guest_debug_pre(vcpu);
@@ -1802,6 +1847,7 @@ again:
1802 1847
1803 fx_save(vcpu->guest_fx_image); 1848 fx_save(vcpu->guest_fx_image);
1804 fx_restore(vcpu->host_fx_image); 1849 fx_restore(vcpu->host_fx_image);
1850 vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
1805 1851
1806#ifndef CONFIG_X86_64 1852#ifndef CONFIG_X86_64
1807 asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); 1853 asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
@@ -1834,12 +1880,22 @@ again:
1834 /* Give scheduler a change to reschedule. */ 1880 /* Give scheduler a change to reschedule. */
1835 if (signal_pending(current)) { 1881 if (signal_pending(current)) {
1836 ++kvm_stat.signal_exits; 1882 ++kvm_stat.signal_exits;
1883 post_kvm_run_save(vcpu, kvm_run);
1884 return -EINTR;
1885 }
1886
1887 if (dm_request_for_irq_injection(vcpu, kvm_run)) {
1888 ++kvm_stat.request_irq_exits;
1889 post_kvm_run_save(vcpu, kvm_run);
1837 return -EINTR; 1890 return -EINTR;
1838 } 1891 }
1892
1839 kvm_resched(vcpu); 1893 kvm_resched(vcpu);
1840 goto again; 1894 goto again;
1841 } 1895 }
1842 } 1896 }
1897
1898 post_kvm_run_save(vcpu, kvm_run);
1843 return 0; 1899 return 0;
1844} 1900}
1845 1901