diff options
| -rw-r--r-- | arch/x86/include/asm/msr-index.h | 1 | ||||
| -rw-r--r-- | arch/x86/kvm/svm.c | 81 |
2 files changed, 82 insertions, 0 deletions
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index b49d8ca228f6..8c7ae4318629 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h | |||
| @@ -110,6 +110,7 @@ | |||
| 110 | #define MSR_AMD64_PATCH_LOADER 0xc0010020 | 110 | #define MSR_AMD64_PATCH_LOADER 0xc0010020 |
| 111 | #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 | 111 | #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 |
| 112 | #define MSR_AMD64_OSVW_STATUS 0xc0010141 | 112 | #define MSR_AMD64_OSVW_STATUS 0xc0010141 |
| 113 | #define MSR_AMD64_DC_CFG 0xc0011022 | ||
| 113 | #define MSR_AMD64_IBSFETCHCTL 0xc0011030 | 114 | #define MSR_AMD64_IBSFETCHCTL 0xc0011030 |
| 114 | #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 | 115 | #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 |
| 115 | #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 | 116 | #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 5e1ed033cd7e..ce438e0fdd26 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/ftrace_event.h> | 28 | #include <linux/ftrace_event.h> |
| 29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 30 | 30 | ||
| 31 | #include <asm/tlbflush.h> | ||
| 31 | #include <asm/desc.h> | 32 | #include <asm/desc.h> |
| 32 | 33 | ||
| 33 | #include <asm/virtext.h> | 34 | #include <asm/virtext.h> |
| @@ -56,6 +57,8 @@ MODULE_LICENSE("GPL"); | |||
| 56 | 57 | ||
| 57 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) | 58 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) |
| 58 | 59 | ||
| 60 | static bool erratum_383_found __read_mostly; | ||
| 61 | |||
| 59 | static const u32 host_save_user_msrs[] = { | 62 | static const u32 host_save_user_msrs[] = { |
| 60 | #ifdef CONFIG_X86_64 | 63 | #ifdef CONFIG_X86_64 |
| 61 | MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE, | 64 | MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE, |
| @@ -374,6 +377,31 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, | |||
| 374 | svm->vmcb->control.event_inj_err = error_code; | 377 | svm->vmcb->control.event_inj_err = error_code; |
| 375 | } | 378 | } |
| 376 | 379 | ||
| 380 | static void svm_init_erratum_383(void) | ||
| 381 | { | ||
| 382 | u32 low, high; | ||
| 383 | int err; | ||
| 384 | u64 val; | ||
| 385 | |||
| 386 | /* Only Fam10h is affected */ | ||
| 387 | if (boot_cpu_data.x86 != 0x10) | ||
| 388 | return; | ||
| 389 | |||
| 390 | /* Use _safe variants to not break nested virtualization */ | ||
| 391 | val = native_read_msr_safe(MSR_AMD64_DC_CFG, &err); | ||
| 392 | if (err) | ||
| 393 | return; | ||
| 394 | |||
| 395 | val |= (1ULL << 47); | ||
| 396 | |||
| 397 | low = lower_32_bits(val); | ||
| 398 | high = upper_32_bits(val); | ||
| 399 | |||
| 400 | native_write_msr_safe(MSR_AMD64_DC_CFG, low, high); | ||
| 401 | |||
| 402 | erratum_383_found = true; | ||
| 403 | } | ||
| 404 | |||
| 377 | static int has_svm(void) | 405 | static int has_svm(void) |
| 378 | { | 406 | { |
| 379 | const char *msg; | 407 | const char *msg; |
| @@ -429,6 +457,8 @@ static int svm_hardware_enable(void *garbage) | |||
| 429 | 457 | ||
| 430 | wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT); | 458 | wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT); |
| 431 | 459 | ||
| 460 | svm_init_erratum_383(); | ||
| 461 | |||
| 432 | return 0; | 462 | return 0; |
| 433 | } | 463 | } |
| 434 | 464 | ||
| @@ -1410,8 +1440,59 @@ static int nm_interception(struct vcpu_svm *svm) | |||
| 1410 | return 1; | 1440 | return 1; |
| 1411 | } | 1441 | } |
| 1412 | 1442 | ||
| 1443 | static bool is_erratum_383(void) | ||
| 1444 | { | ||
| 1445 | int err, i; | ||
| 1446 | u64 value; | ||
| 1447 | |||
| 1448 | if (!erratum_383_found) | ||
| 1449 | return false; | ||
| 1450 | |||
| 1451 | value = native_read_msr_safe(MSR_IA32_MC0_STATUS, &err); | ||
| 1452 | if (err) | ||
| 1453 | return false; | ||
| 1454 | |||
| 1455 | /* Bit 62 may or may not be set for this mce */ | ||
| 1456 | value &= ~(1ULL << 62); | ||
| 1457 | |||
| 1458 | if (value != 0xb600000000010015ULL) | ||
| 1459 | return false; | ||
| 1460 | |||
| 1461 | /* Clear MCi_STATUS registers */ | ||
| 1462 | for (i = 0; i < 6; ++i) | ||
| 1463 | native_write_msr_safe(MSR_IA32_MCx_STATUS(i), 0, 0); | ||
| 1464 | |||
| 1465 | value = native_read_msr_safe(MSR_IA32_MCG_STATUS, &err); | ||
| 1466 | if (!err) { | ||
| 1467 | u32 low, high; | ||
| 1468 | |||
| 1469 | value &= ~(1ULL << 2); | ||
| 1470 | low = lower_32_bits(value); | ||
| 1471 | high = upper_32_bits(value); | ||
| 1472 | |||
| 1473 | native_write_msr_safe(MSR_IA32_MCG_STATUS, low, high); | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | /* Flush tlb to evict multi-match entries */ | ||
| 1477 | __flush_tlb_all(); | ||
| 1478 | |||
| 1479 | return true; | ||
| 1480 | } | ||
| 1481 | |||
| 1413 | static void svm_handle_mce(struct vcpu_svm *svm) | 1482 | static void svm_handle_mce(struct vcpu_svm *svm) |
| 1414 | { | 1483 | { |
| 1484 | if (is_erratum_383()) { | ||
| 1485 | /* | ||
| 1486 | * Erratum 383 triggered. Guest state is corrupt so kill the | ||
| 1487 | * guest. | ||
| 1488 | */ | ||
| 1489 | pr_err("KVM: Guest triggered AMD Erratum 383\n"); | ||
| 1490 | |||
| 1491 | set_bit(KVM_REQ_TRIPLE_FAULT, &svm->vcpu.requests); | ||
| 1492 | |||
| 1493 | return; | ||
| 1494 | } | ||
| 1495 | |||
| 1415 | /* | 1496 | /* |
| 1416 | * On an #MC intercept the MCE handler is not called automatically in | 1497 | * On an #MC intercept the MCE handler is not called automatically in |
| 1417 | * the host. So do it by hand here. | 1498 | * the host. So do it by hand here. |
