aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/vmx.c
diff options
context:
space:
mode:
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