aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/svm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/kvm/svm.c')
-rw-r--r--drivers/kvm/svm.c113
1 files changed, 102 insertions, 11 deletions
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index fa0428735717..ccc06b1b91b5 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -235,6 +235,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
235 235
236 vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip; 236 vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip;
237 vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; 237 vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
238
239 vcpu->interrupt_window_open = 1;
238} 240}
239 241
240static int has_svm(void) 242static int has_svm(void)
@@ -495,7 +497,6 @@ static void init_vmcb(struct vmcb *vmcb)
495 /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */ 497 /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */
496 (1ULL << INTERCEPT_CPUID) | 498 (1ULL << INTERCEPT_CPUID) |
497 (1ULL << INTERCEPT_HLT) | 499 (1ULL << INTERCEPT_HLT) |
498 (1ULL << INTERCEPT_INVLPG) |
499 (1ULL << INTERCEPT_INVLPGA) | 500 (1ULL << INTERCEPT_INVLPGA) |
500 (1ULL << INTERCEPT_IOIO_PROT) | 501 (1ULL << INTERCEPT_IOIO_PROT) |
501 (1ULL << INTERCEPT_MSR_PROT) | 502 (1ULL << INTERCEPT_MSR_PROT) |
@@ -700,6 +701,10 @@ static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
700 vcpu->svm->vmcb->save.gdtr.base = dt->base ; 701 vcpu->svm->vmcb->save.gdtr.base = dt->base ;
701} 702}
702 703
704static void svm_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
705{
706}
707
703static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) 708static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
704{ 709{
705#ifdef CONFIG_X86_64 710#ifdef CONFIG_X86_64
@@ -847,6 +852,7 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
847 u64 fault_address; 852 u64 fault_address;
848 u32 error_code; 853 u32 error_code;
849 enum emulation_result er; 854 enum emulation_result er;
855 int r;
850 856
851 if (is_external_interrupt(exit_int_info)) 857 if (is_external_interrupt(exit_int_info))
852 push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); 858 push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
@@ -855,7 +861,12 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
855 861
856 fault_address = vcpu->svm->vmcb->control.exit_info_2; 862 fault_address = vcpu->svm->vmcb->control.exit_info_2;
857 error_code = vcpu->svm->vmcb->control.exit_info_1; 863 error_code = vcpu->svm->vmcb->control.exit_info_1;
858 if (!vcpu->mmu.page_fault(vcpu, fault_address, error_code)) { 864 r = kvm_mmu_page_fault(vcpu, fault_address, error_code);
865 if (r < 0) {
866 spin_unlock(&vcpu->kvm->lock);
867 return r;
868 }
869 if (!r) {
859 spin_unlock(&vcpu->kvm->lock); 870 spin_unlock(&vcpu->kvm->lock);
860 return 1; 871 return 1;
861 } 872 }
@@ -1031,10 +1042,11 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1031{ 1042{
1032 vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1; 1043 vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
1033 skip_emulated_instruction(vcpu); 1044 skip_emulated_instruction(vcpu);
1034 if (vcpu->irq_summary && (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF)) 1045 if (vcpu->irq_summary)
1035 return 1; 1046 return 1;
1036 1047
1037 kvm_run->exit_reason = KVM_EXIT_HLT; 1048 kvm_run->exit_reason = KVM_EXIT_HLT;
1049 ++kvm_stat.halt_exits;
1038 return 0; 1050 return 0;
1039} 1051}
1040 1052
@@ -1186,6 +1198,23 @@ static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1186 return rdmsr_interception(vcpu, kvm_run); 1198 return rdmsr_interception(vcpu, kvm_run);
1187} 1199}
1188 1200
1201static int interrupt_window_interception(struct kvm_vcpu *vcpu,
1202 struct kvm_run *kvm_run)
1203{
1204 /*
1205 * If the user space waits to inject interrupts, exit as soon as
1206 * possible
1207 */
1208 if (kvm_run->request_interrupt_window &&
1209 !vcpu->irq_summary) {
1210 ++kvm_stat.irq_window_exits;
1211 kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
1212 return 0;
1213 }
1214
1215 return 1;
1216}
1217
1189static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, 1218static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
1190 struct kvm_run *kvm_run) = { 1219 struct kvm_run *kvm_run) = {
1191 [SVM_EXIT_READ_CR0] = emulate_on_interception, 1220 [SVM_EXIT_READ_CR0] = emulate_on_interception,
@@ -1210,6 +1239,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
1210 [SVM_EXIT_NMI] = nop_on_interception, 1239 [SVM_EXIT_NMI] = nop_on_interception,
1211 [SVM_EXIT_SMI] = nop_on_interception, 1240 [SVM_EXIT_SMI] = nop_on_interception,
1212 [SVM_EXIT_INIT] = nop_on_interception, 1241 [SVM_EXIT_INIT] = nop_on_interception,
1242 [SVM_EXIT_VINTR] = interrupt_window_interception,
1213 /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */ 1243 /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */
1214 [SVM_EXIT_CPUID] = cpuid_interception, 1244 [SVM_EXIT_CPUID] = cpuid_interception,
1215 [SVM_EXIT_HLT] = halt_interception, 1245 [SVM_EXIT_HLT] = halt_interception,
@@ -1278,15 +1308,11 @@ static void pre_svm_run(struct kvm_vcpu *vcpu)
1278} 1308}
1279 1309
1280 1310
1281static inline void kvm_try_inject_irq(struct kvm_vcpu *vcpu) 1311static inline void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
1282{ 1312{
1283 struct vmcb_control_area *control; 1313 struct vmcb_control_area *control;
1284 1314
1285 if (!vcpu->irq_summary)
1286 return;
1287
1288 control = &vcpu->svm->vmcb->control; 1315 control = &vcpu->svm->vmcb->control;
1289
1290 control->int_vector = pop_irq(vcpu); 1316 control->int_vector = pop_irq(vcpu);
1291 control->int_ctl &= ~V_INTR_PRIO_MASK; 1317 control->int_ctl &= ~V_INTR_PRIO_MASK;
1292 control->int_ctl |= V_IRQ_MASK | 1318 control->int_ctl |= V_IRQ_MASK |
@@ -1301,6 +1327,59 @@ static void kvm_reput_irq(struct kvm_vcpu *vcpu)
1301 control->int_ctl &= ~V_IRQ_MASK; 1327 control->int_ctl &= ~V_IRQ_MASK;
1302 push_irq(vcpu, control->int_vector); 1328 push_irq(vcpu, control->int_vector);
1303 } 1329 }
1330
1331 vcpu->interrupt_window_open =
1332 !(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
1333}
1334
1335static void do_interrupt_requests(struct kvm_vcpu *vcpu,
1336 struct kvm_run *kvm_run)
1337{
1338 struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
1339
1340 vcpu->interrupt_window_open =
1341 (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
1342 (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
1343
1344 if (vcpu->interrupt_window_open && vcpu->irq_summary)
1345 /*
1346 * If interrupts enabled, and not blocked by sti or mov ss. Good.
1347 */
1348 kvm_do_inject_irq(vcpu);
1349
1350 /*
1351 * Interrupts blocked. Wait for unblock.
1352 */
1353 if (!vcpu->interrupt_window_open &&
1354 (vcpu->irq_summary || kvm_run->request_interrupt_window)) {
1355 control->intercept |= 1ULL << INTERCEPT_VINTR;
1356 } else
1357 control->intercept &= ~(1ULL << INTERCEPT_VINTR);
1358}
1359
1360static void post_kvm_run_save(struct kvm_vcpu *vcpu,
1361 struct kvm_run *kvm_run)
1362{
1363 kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
1364 vcpu->irq_summary == 0);
1365 kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0;
1366 kvm_run->cr8 = vcpu->cr8;
1367 kvm_run->apic_base = vcpu->apic_base;
1368}
1369
1370/*
1371 * Check if userspace requested an interrupt window, and that the
1372 * interrupt window is open.
1373 *
1374 * No need to exit to userspace if we already have an interrupt queued.
1375 */
1376static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
1377 struct kvm_run *kvm_run)
1378{
1379 return (!vcpu->irq_summary &&
1380 kvm_run->request_interrupt_window &&
1381 vcpu->interrupt_window_open &&
1382 (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
1304} 1383}
1305 1384
1306static void save_db_regs(unsigned long *db_regs) 1385static void save_db_regs(unsigned long *db_regs)
@@ -1324,9 +1403,10 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1324 u16 fs_selector; 1403 u16 fs_selector;
1325 u16 gs_selector; 1404 u16 gs_selector;
1326 u16 ldt_selector; 1405 u16 ldt_selector;
1406 int r;
1327 1407
1328again: 1408again:
1329 kvm_try_inject_irq(vcpu); 1409 do_interrupt_requests(vcpu, kvm_run);
1330 1410
1331 clgi(); 1411 clgi();
1332 1412
@@ -1487,18 +1567,28 @@ again:
1487 if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) { 1567 if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
1488 kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; 1568 kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
1489 kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code; 1569 kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code;
1570 post_kvm_run_save(vcpu, kvm_run);
1490 return 0; 1571 return 0;
1491 } 1572 }
1492 1573
1493 if (handle_exit(vcpu, kvm_run)) { 1574 r = handle_exit(vcpu, kvm_run);
1575 if (r > 0) {
1494 if (signal_pending(current)) { 1576 if (signal_pending(current)) {
1495 ++kvm_stat.signal_exits; 1577 ++kvm_stat.signal_exits;
1578 post_kvm_run_save(vcpu, kvm_run);
1579 return -EINTR;
1580 }
1581
1582 if (dm_request_for_irq_injection(vcpu, kvm_run)) {
1583 ++kvm_stat.request_irq_exits;
1584 post_kvm_run_save(vcpu, kvm_run);
1496 return -EINTR; 1585 return -EINTR;
1497 } 1586 }
1498 kvm_resched(vcpu); 1587 kvm_resched(vcpu);
1499 goto again; 1588 goto again;
1500 } 1589 }
1501 return 0; 1590 post_kvm_run_save(vcpu, kvm_run);
1591 return r;
1502} 1592}
1503 1593
1504static void svm_flush_tlb(struct kvm_vcpu *vcpu) 1594static void svm_flush_tlb(struct kvm_vcpu *vcpu)
@@ -1565,6 +1655,7 @@ static struct kvm_arch_ops svm_arch_ops = {
1565 .get_segment = svm_get_segment, 1655 .get_segment = svm_get_segment,
1566 .set_segment = svm_set_segment, 1656 .set_segment = svm_set_segment,
1567 .get_cs_db_l_bits = svm_get_cs_db_l_bits, 1657 .get_cs_db_l_bits = svm_get_cs_db_l_bits,
1658 .decache_cr0_cr4_guest_bits = svm_decache_cr0_cr4_guest_bits,
1568 .set_cr0 = svm_set_cr0, 1659 .set_cr0 = svm_set_cr0,
1569 .set_cr0_no_modeswitch = svm_set_cr0, 1660 .set_cr0_no_modeswitch = svm_set_cr0,
1570 .set_cr3 = svm_set_cr3, 1661 .set_cr3 = svm_set_cr3,