diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/svm.c | 80 |
1 files changed, 50 insertions, 30 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 53376f144d70..be28a38db918 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -47,6 +47,10 @@ MODULE_LICENSE("GPL"); | |||
47 | #define SVM_FEATURE_LBRV (1 << 1) | 47 | #define SVM_FEATURE_LBRV (1 << 1) |
48 | #define SVM_FEATURE_SVML (1 << 2) | 48 | #define SVM_FEATURE_SVML (1 << 2) |
49 | 49 | ||
50 | #define NESTED_EXIT_HOST 0 /* Exit handled on host level */ | ||
51 | #define NESTED_EXIT_DONE 1 /* Exit caused nested vmexit */ | ||
52 | #define NESTED_EXIT_CONTINUE 2 /* Further checks needed */ | ||
53 | |||
50 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) | 54 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) |
51 | 55 | ||
52 | /* Turn on to get debugging output*/ | 56 | /* Turn on to get debugging output*/ |
@@ -126,7 +130,7 @@ module_param(nested, int, S_IRUGO); | |||
126 | static void svm_flush_tlb(struct kvm_vcpu *vcpu); | 130 | static void svm_flush_tlb(struct kvm_vcpu *vcpu); |
127 | static void svm_complete_interrupts(struct vcpu_svm *svm); | 131 | static void svm_complete_interrupts(struct vcpu_svm *svm); |
128 | 132 | ||
129 | static int nested_svm_exit_handled(struct vcpu_svm *svm, bool kvm_override); | 133 | static int nested_svm_exit_handled(struct vcpu_svm *svm); |
130 | static int nested_svm_vmexit(struct vcpu_svm *svm); | 134 | static int nested_svm_vmexit(struct vcpu_svm *svm); |
131 | static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr, | 135 | static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr, |
132 | bool has_error_code, u32 error_code); | 136 | bool has_error_code, u32 error_code); |
@@ -1365,7 +1369,7 @@ static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr, | |||
1365 | svm->vmcb->control.exit_info_1 = error_code; | 1369 | svm->vmcb->control.exit_info_1 = error_code; |
1366 | svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2; | 1370 | svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2; |
1367 | 1371 | ||
1368 | return nested_svm_exit_handled(svm, false); | 1372 | return nested_svm_exit_handled(svm); |
1369 | } | 1373 | } |
1370 | 1374 | ||
1371 | static inline int nested_svm_intr(struct vcpu_svm *svm) | 1375 | static inline int nested_svm_intr(struct vcpu_svm *svm) |
@@ -1379,7 +1383,7 @@ static inline int nested_svm_intr(struct vcpu_svm *svm) | |||
1379 | 1383 | ||
1380 | svm->vmcb->control.exit_code = SVM_EXIT_INTR; | 1384 | svm->vmcb->control.exit_code = SVM_EXIT_INTR; |
1381 | 1385 | ||
1382 | if (nested_svm_exit_handled(svm, false)) { | 1386 | if (nested_svm_exit_handled(svm)) { |
1383 | nsvm_printk("VMexit -> INTR\n"); | 1387 | nsvm_printk("VMexit -> INTR\n"); |
1384 | return 1; | 1388 | return 1; |
1385 | } | 1389 | } |
@@ -1465,31 +1469,39 @@ out: | |||
1465 | return ret; | 1469 | return ret; |
1466 | } | 1470 | } |
1467 | 1471 | ||
1468 | static int nested_svm_exit_handled(struct vcpu_svm *svm, bool kvm_override) | 1472 | static int nested_svm_exit_special(struct vcpu_svm *svm) |
1469 | { | 1473 | { |
1470 | u32 exit_code = svm->vmcb->control.exit_code; | 1474 | u32 exit_code = svm->vmcb->control.exit_code; |
1471 | bool vmexit = false; | ||
1472 | 1475 | ||
1473 | if (kvm_override) { | 1476 | switch (exit_code) { |
1474 | switch (exit_code) { | 1477 | case SVM_EXIT_INTR: |
1475 | case SVM_EXIT_INTR: | 1478 | case SVM_EXIT_NMI: |
1476 | case SVM_EXIT_NMI: | 1479 | return NESTED_EXIT_HOST; |
1477 | return 0; | ||
1478 | /* For now we are always handling NPFs when using them */ | 1480 | /* For now we are always handling NPFs when using them */ |
1479 | case SVM_EXIT_NPF: | 1481 | case SVM_EXIT_NPF: |
1480 | if (npt_enabled) | 1482 | if (npt_enabled) |
1481 | return 0; | 1483 | return NESTED_EXIT_HOST; |
1482 | break; | 1484 | break; |
1483 | /* When we're shadowing, trap PFs */ | 1485 | /* When we're shadowing, trap PFs */ |
1484 | case SVM_EXIT_EXCP_BASE + PF_VECTOR: | 1486 | case SVM_EXIT_EXCP_BASE + PF_VECTOR: |
1485 | if (!npt_enabled) | 1487 | if (!npt_enabled) |
1486 | return 0; | 1488 | return NESTED_EXIT_HOST; |
1487 | break; | 1489 | break; |
1488 | default: | 1490 | default: |
1489 | break; | 1491 | break; |
1490 | } | ||
1491 | } | 1492 | } |
1492 | 1493 | ||
1494 | return NESTED_EXIT_CONTINUE; | ||
1495 | } | ||
1496 | |||
1497 | /* | ||
1498 | * If this function returns true, this #vmexit was already handled | ||
1499 | */ | ||
1500 | static int nested_svm_exit_handled(struct vcpu_svm *svm) | ||
1501 | { | ||
1502 | u32 exit_code = svm->vmcb->control.exit_code; | ||
1503 | int vmexit = NESTED_EXIT_HOST; | ||
1504 | |||
1493 | switch (exit_code) { | 1505 | switch (exit_code) { |
1494 | case SVM_EXIT_MSR: | 1506 | case SVM_EXIT_MSR: |
1495 | vmexit = nested_svm_exit_handled_msr(svm); | 1507 | vmexit = nested_svm_exit_handled_msr(svm); |
@@ -1497,42 +1509,42 @@ static int nested_svm_exit_handled(struct vcpu_svm *svm, bool kvm_override) | |||
1497 | case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR8: { | 1509 | case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR8: { |
1498 | u32 cr_bits = 1 << (exit_code - SVM_EXIT_READ_CR0); | 1510 | u32 cr_bits = 1 << (exit_code - SVM_EXIT_READ_CR0); |
1499 | if (svm->nested.intercept_cr_read & cr_bits) | 1511 | if (svm->nested.intercept_cr_read & cr_bits) |
1500 | vmexit = true; | 1512 | vmexit = NESTED_EXIT_DONE; |
1501 | break; | 1513 | break; |
1502 | } | 1514 | } |
1503 | case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR8: { | 1515 | case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR8: { |
1504 | u32 cr_bits = 1 << (exit_code - SVM_EXIT_WRITE_CR0); | 1516 | u32 cr_bits = 1 << (exit_code - SVM_EXIT_WRITE_CR0); |
1505 | if (svm->nested.intercept_cr_write & cr_bits) | 1517 | if (svm->nested.intercept_cr_write & cr_bits) |
1506 | vmexit = true; | 1518 | vmexit = NESTED_EXIT_DONE; |
1507 | break; | 1519 | break; |
1508 | } | 1520 | } |
1509 | case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR7: { | 1521 | case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR7: { |
1510 | u32 dr_bits = 1 << (exit_code - SVM_EXIT_READ_DR0); | 1522 | u32 dr_bits = 1 << (exit_code - SVM_EXIT_READ_DR0); |
1511 | if (svm->nested.intercept_dr_read & dr_bits) | 1523 | if (svm->nested.intercept_dr_read & dr_bits) |
1512 | vmexit = true; | 1524 | vmexit = NESTED_EXIT_DONE; |
1513 | break; | 1525 | break; |
1514 | } | 1526 | } |
1515 | case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR7: { | 1527 | case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR7: { |
1516 | u32 dr_bits = 1 << (exit_code - SVM_EXIT_WRITE_DR0); | 1528 | u32 dr_bits = 1 << (exit_code - SVM_EXIT_WRITE_DR0); |
1517 | if (svm->nested.intercept_dr_write & dr_bits) | 1529 | if (svm->nested.intercept_dr_write & dr_bits) |
1518 | vmexit = true; | 1530 | vmexit = NESTED_EXIT_DONE; |
1519 | break; | 1531 | break; |
1520 | } | 1532 | } |
1521 | case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: { | 1533 | case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: { |
1522 | u32 excp_bits = 1 << (exit_code - SVM_EXIT_EXCP_BASE); | 1534 | u32 excp_bits = 1 << (exit_code - SVM_EXIT_EXCP_BASE); |
1523 | if (svm->nested.intercept_exceptions & excp_bits) | 1535 | if (svm->nested.intercept_exceptions & excp_bits) |
1524 | vmexit = true; | 1536 | vmexit = NESTED_EXIT_DONE; |
1525 | break; | 1537 | break; |
1526 | } | 1538 | } |
1527 | default: { | 1539 | default: { |
1528 | u64 exit_bits = 1ULL << (exit_code - SVM_EXIT_INTR); | 1540 | u64 exit_bits = 1ULL << (exit_code - SVM_EXIT_INTR); |
1529 | nsvm_printk("exit code: 0x%x\n", exit_code); | 1541 | nsvm_printk("exit code: 0x%x\n", exit_code); |
1530 | if (svm->nested.intercept & exit_bits) | 1542 | if (svm->nested.intercept & exit_bits) |
1531 | vmexit = true; | 1543 | vmexit = NESTED_EXIT_DONE; |
1532 | } | 1544 | } |
1533 | } | 1545 | } |
1534 | 1546 | ||
1535 | if (vmexit) { | 1547 | if (vmexit == NESTED_EXIT_DONE) { |
1536 | nsvm_printk("#VMEXIT reason=%04x\n", exit_code); | 1548 | nsvm_printk("#VMEXIT reason=%04x\n", exit_code); |
1537 | nested_svm_vmexit(svm); | 1549 | nested_svm_vmexit(svm); |
1538 | } | 1550 | } |
@@ -2312,10 +2324,18 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
2312 | trace_kvm_exit(exit_code, svm->vmcb->save.rip); | 2324 | trace_kvm_exit(exit_code, svm->vmcb->save.rip); |
2313 | 2325 | ||
2314 | if (is_nested(svm)) { | 2326 | if (is_nested(svm)) { |
2327 | int vmexit; | ||
2328 | |||
2315 | nsvm_printk("nested handle_exit: 0x%x | 0x%lx | 0x%lx | 0x%lx\n", | 2329 | nsvm_printk("nested handle_exit: 0x%x | 0x%lx | 0x%lx | 0x%lx\n", |
2316 | exit_code, svm->vmcb->control.exit_info_1, | 2330 | exit_code, svm->vmcb->control.exit_info_1, |
2317 | svm->vmcb->control.exit_info_2, svm->vmcb->save.rip); | 2331 | svm->vmcb->control.exit_info_2, svm->vmcb->save.rip); |
2318 | if (nested_svm_exit_handled(svm, true)) | 2332 | |
2333 | vmexit = nested_svm_exit_special(svm); | ||
2334 | |||
2335 | if (vmexit == NESTED_EXIT_CONTINUE) | ||
2336 | vmexit = nested_svm_exit_handled(svm); | ||
2337 | |||
2338 | if (vmexit == NESTED_EXIT_DONE) | ||
2319 | return 1; | 2339 | return 1; |
2320 | } | 2340 | } |
2321 | 2341 | ||