diff options
Diffstat (limited to 'arch/x86/kvm/svm.c')
-rw-r--r-- | arch/x86/kvm/svm.c | 48 |
1 files changed, 29 insertions, 19 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 9c4ce657d963..1452851ae258 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -28,6 +28,8 @@ | |||
28 | 28 | ||
29 | #include <asm/desc.h> | 29 | #include <asm/desc.h> |
30 | 30 | ||
31 | #include <asm/virtext.h> | ||
32 | |||
31 | #define __ex(x) __kvm_handle_fault_on_reboot(x) | 33 | #define __ex(x) __kvm_handle_fault_on_reboot(x) |
32 | 34 | ||
33 | MODULE_AUTHOR("Qumranet"); | 35 | MODULE_AUTHOR("Qumranet"); |
@@ -245,34 +247,19 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) | |||
245 | 247 | ||
246 | static int has_svm(void) | 248 | static int has_svm(void) |
247 | { | 249 | { |
248 | uint32_t eax, ebx, ecx, edx; | 250 | const char *msg; |
249 | |||
250 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { | ||
251 | printk(KERN_INFO "has_svm: not amd\n"); | ||
252 | return 0; | ||
253 | } | ||
254 | 251 | ||
255 | cpuid(0x80000000, &eax, &ebx, &ecx, &edx); | 252 | if (!cpu_has_svm(&msg)) { |
256 | if (eax < SVM_CPUID_FUNC) { | 253 | printk(KERN_INFO "has_svn: %s\n", msg); |
257 | printk(KERN_INFO "has_svm: can't execute cpuid_8000000a\n"); | ||
258 | return 0; | 254 | return 0; |
259 | } | 255 | } |
260 | 256 | ||
261 | cpuid(0x80000001, &eax, &ebx, &ecx, &edx); | ||
262 | if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) { | ||
263 | printk(KERN_DEBUG "has_svm: svm not available\n"); | ||
264 | return 0; | ||
265 | } | ||
266 | return 1; | 257 | return 1; |
267 | } | 258 | } |
268 | 259 | ||
269 | static void svm_hardware_disable(void *garbage) | 260 | static void svm_hardware_disable(void *garbage) |
270 | { | 261 | { |
271 | uint64_t efer; | 262 | cpu_svm_disable(); |
272 | |||
273 | wrmsrl(MSR_VM_HSAVE_PA, 0); | ||
274 | rdmsrl(MSR_EFER, efer); | ||
275 | wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); | ||
276 | } | 263 | } |
277 | 264 | ||
278 | static void svm_hardware_enable(void *garbage) | 265 | static void svm_hardware_enable(void *garbage) |
@@ -772,6 +759,22 @@ static void svm_get_segment(struct kvm_vcpu *vcpu, | |||
772 | var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; | 759 | var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; |
773 | var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; | 760 | var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; |
774 | var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1; | 761 | var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1; |
762 | |||
763 | /* | ||
764 | * SVM always stores 0 for the 'G' bit in the CS selector in | ||
765 | * the VMCB on a VMEXIT. This hurts cross-vendor migration: | ||
766 | * Intel's VMENTRY has a check on the 'G' bit. | ||
767 | */ | ||
768 | if (seg == VCPU_SREG_CS) | ||
769 | var->g = s->limit > 0xfffff; | ||
770 | |||
771 | /* | ||
772 | * Work around a bug where the busy flag in the tr selector | ||
773 | * isn't exposed | ||
774 | */ | ||
775 | if (seg == VCPU_SREG_TR) | ||
776 | var->type |= 0x2; | ||
777 | |||
775 | var->unusable = !var->present; | 778 | var->unusable = !var->present; |
776 | } | 779 | } |
777 | 780 | ||
@@ -1099,6 +1102,7 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1099 | rep = (io_info & SVM_IOIO_REP_MASK) != 0; | 1102 | rep = (io_info & SVM_IOIO_REP_MASK) != 0; |
1100 | down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; | 1103 | down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; |
1101 | 1104 | ||
1105 | skip_emulated_instruction(&svm->vcpu); | ||
1102 | return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); | 1106 | return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); |
1103 | } | 1107 | } |
1104 | 1108 | ||
@@ -1912,6 +1916,11 @@ static int get_npt_level(void) | |||
1912 | #endif | 1916 | #endif |
1913 | } | 1917 | } |
1914 | 1918 | ||
1919 | static int svm_get_mt_mask_shift(void) | ||
1920 | { | ||
1921 | return 0; | ||
1922 | } | ||
1923 | |||
1915 | static struct kvm_x86_ops svm_x86_ops = { | 1924 | static struct kvm_x86_ops svm_x86_ops = { |
1916 | .cpu_has_kvm_support = has_svm, | 1925 | .cpu_has_kvm_support = has_svm, |
1917 | .disabled_by_bios = is_disabled, | 1926 | .disabled_by_bios = is_disabled, |
@@ -1967,6 +1976,7 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
1967 | 1976 | ||
1968 | .set_tss_addr = svm_set_tss_addr, | 1977 | .set_tss_addr = svm_set_tss_addr, |
1969 | .get_tdp_level = get_npt_level, | 1978 | .get_tdp_level = get_npt_level, |
1979 | .get_mt_mask_shift = svm_get_mt_mask_shift, | ||
1970 | }; | 1980 | }; |
1971 | 1981 | ||
1972 | static int __init svm_init(void) | 1982 | static int __init svm_init(void) |