]>
Commit | Line | Data |
---|---|---|
7d777456 GKH |
1 | From a61279422bc32ecbf85e3a6a9349287c7df0b0b1 Mon Sep 17 00:00:00 2001 |
2 | From: Joerg Roedel <joerg.roedel@amd.com> | |
3 | Date: Mon, 17 May 2010 14:43:35 +0200 | |
4 | Subject: KVM: SVM: Implement workaround for Erratum 383 | |
5 | ||
6 | This patch implements a workaround for AMD erratum 383 into | |
7 | KVM. Without this erratum fix it is possible for a guest to | |
8 | kill the host machine. This patch implements the suggested | |
9 | workaround for hypervisors which will be published by the | |
10 | next revision guide update. | |
11 | ||
12 | [jan: fix overflow warning on i386] | |
13 | [xiao: fix unused variable warning] | |
14 | ||
15 | Cc: stable@kernel.org | |
16 | Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> | |
17 | Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> | |
18 | Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> | |
19 | Signed-off-by: Avi Kivity <avi@redhat.com> | |
20 | (cherry picked from commit 67ec66077799f2fef84b21a643912b179c422281) | |
21 | --- | |
22 | arch/x86/include/asm/msr-index.h | 1 | |
23 | arch/x86/kvm/svm.c | 84 ++++++++++++++++++++++++++++++++++++++- | |
24 | 2 files changed, 84 insertions(+), 1 deletion(-) | |
25 | ||
26 | --- a/arch/x86/include/asm/msr-index.h | |
27 | +++ b/arch/x86/include/asm/msr-index.h | |
28 | @@ -106,6 +106,7 @@ | |
29 | #define MSR_AMD64_PATCH_LOADER 0xc0010020 | |
30 | #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 | |
31 | #define MSR_AMD64_OSVW_STATUS 0xc0010141 | |
32 | +#define MSR_AMD64_DC_CFG 0xc0011022 | |
33 | #define MSR_AMD64_IBSFETCHCTL 0xc0011030 | |
34 | #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 | |
35 | #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 | |
36 | --- a/arch/x86/kvm/svm.c | |
37 | +++ b/arch/x86/kvm/svm.c | |
38 | @@ -27,6 +27,7 @@ | |
39 | #include <linux/sched.h> | |
40 | #include <linux/ftrace_event.h> | |
41 | ||
42 | +#include <asm/tlbflush.h> | |
43 | #include <asm/desc.h> | |
44 | ||
45 | #include <asm/virtext.h> | |
46 | @@ -62,6 +63,8 @@ MODULE_LICENSE("GPL"); | |
47 | #define nsvm_printk(fmt, args...) do {} while(0) | |
48 | #endif | |
49 | ||
50 | +static bool erratum_383_found __read_mostly; | |
51 | + | |
52 | static const u32 host_save_user_msrs[] = { | |
53 | #ifdef CONFIG_X86_64 | |
54 | MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE, | |
55 | @@ -299,6 +302,31 @@ static void skip_emulated_instruction(st | |
56 | svm_set_interrupt_shadow(vcpu, 0); | |
57 | } | |
58 | ||
59 | +static void svm_init_erratum_383(void) | |
60 | +{ | |
61 | + u32 low, high; | |
62 | + int err; | |
63 | + u64 val; | |
64 | + | |
65 | + /* Only Fam10h is affected */ | |
66 | + if (boot_cpu_data.x86 != 0x10) | |
67 | + return; | |
68 | + | |
69 | + /* Use _safe variants to not break nested virtualization */ | |
70 | + val = native_read_msr_safe(MSR_AMD64_DC_CFG, &err); | |
71 | + if (err) | |
72 | + return; | |
73 | + | |
74 | + val |= (1ULL << 47); | |
75 | + | |
76 | + low = lower_32_bits(val); | |
77 | + high = upper_32_bits(val); | |
78 | + | |
79 | + native_write_msr_safe(MSR_AMD64_DC_CFG, low, high); | |
80 | + | |
81 | + erratum_383_found = true; | |
82 | +} | |
83 | + | |
84 | static int has_svm(void) | |
85 | { | |
86 | const char *msg; | |
87 | @@ -318,7 +346,6 @@ static void svm_hardware_disable(void *g | |
88 | ||
89 | static void svm_hardware_enable(void *garbage) | |
90 | { | |
91 | - | |
92 | struct svm_cpu_data *svm_data; | |
93 | uint64_t efer; | |
94 | struct descriptor_table gdt_descr; | |
95 | @@ -350,6 +377,10 @@ static void svm_hardware_enable(void *ga | |
96 | ||
97 | wrmsrl(MSR_VM_HSAVE_PA, | |
98 | page_to_pfn(svm_data->save_area) << PAGE_SHIFT); | |
99 | + | |
100 | + svm_init_erratum_383(); | |
101 | + | |
102 | + return; | |
103 | } | |
104 | ||
105 | static void svm_cpu_uninit(int cpu) | |
106 | @@ -1257,8 +1288,59 @@ static int nm_interception(struct vcpu_s | |
107 | return 1; | |
108 | } | |
109 | ||
110 | +static bool is_erratum_383(void) | |
111 | +{ | |
112 | + int err, i; | |
113 | + u64 value; | |
114 | + | |
115 | + if (!erratum_383_found) | |
116 | + return false; | |
117 | + | |
118 | + value = native_read_msr_safe(MSR_IA32_MC0_STATUS, &err); | |
119 | + if (err) | |
120 | + return false; | |
121 | + | |
122 | + /* Bit 62 may or may not be set for this mce */ | |
123 | + value &= ~(1ULL << 62); | |
124 | + | |
125 | + if (value != 0xb600000000010015ULL) | |
126 | + return false; | |
127 | + | |
128 | + /* Clear MCi_STATUS registers */ | |
129 | + for (i = 0; i < 6; ++i) | |
130 | + native_write_msr_safe(MSR_IA32_MCx_STATUS(i), 0, 0); | |
131 | + | |
132 | + value = native_read_msr_safe(MSR_IA32_MCG_STATUS, &err); | |
133 | + if (!err) { | |
134 | + u32 low, high; | |
135 | + | |
136 | + value &= ~(1ULL << 2); | |
137 | + low = lower_32_bits(value); | |
138 | + high = upper_32_bits(value); | |
139 | + | |
140 | + native_write_msr_safe(MSR_IA32_MCG_STATUS, low, high); | |
141 | + } | |
142 | + | |
143 | + /* Flush tlb to evict multi-match entries */ | |
144 | + __flush_tlb_all(); | |
145 | + | |
146 | + return true; | |
147 | +} | |
148 | + | |
149 | static void svm_handle_mce(struct vcpu_svm *svm) | |
150 | { | |
151 | + if (is_erratum_383()) { | |
152 | + /* | |
153 | + * Erratum 383 triggered. Guest state is corrupt so kill the | |
154 | + * guest. | |
155 | + */ | |
156 | + pr_err("KVM: Guest triggered AMD Erratum 383\n"); | |
157 | + | |
158 | + set_bit(KVM_REQ_TRIPLE_FAULT, &svm->vcpu.requests); | |
159 | + | |
160 | + return; | |
161 | + } | |
162 | + | |
163 | /* | |
164 | * On an #MC intercept the MCE handler is not called automatically in | |
165 | * the host. So do it by hand here. |