diff options
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r-- | arch/x86/kvm/vmx.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 4ff0ab9bc3c8..32eb58866292 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/highmem.h> | 27 | #include <linux/highmem.h> |
28 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
29 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
30 | #include <linux/mod_devicetable.h> | ||
30 | #include <linux/ftrace_event.h> | 31 | #include <linux/ftrace_event.h> |
31 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
32 | #include <linux/tboot.h> | 33 | #include <linux/tboot.h> |
@@ -51,6 +52,12 @@ | |||
51 | MODULE_AUTHOR("Qumranet"); | 52 | MODULE_AUTHOR("Qumranet"); |
52 | MODULE_LICENSE("GPL"); | 53 | MODULE_LICENSE("GPL"); |
53 | 54 | ||
55 | static const struct x86_cpu_id vmx_cpu_id[] = { | ||
56 | X86_FEATURE_MATCH(X86_FEATURE_VMX), | ||
57 | {} | ||
58 | }; | ||
59 | MODULE_DEVICE_TABLE(x86cpu, vmx_cpu_id); | ||
60 | |||
54 | static bool __read_mostly enable_vpid = 1; | 61 | static bool __read_mostly enable_vpid = 1; |
55 | module_param_named(vpid, enable_vpid, bool, 0444); | 62 | module_param_named(vpid, enable_vpid, bool, 0444); |
56 | 63 | ||
@@ -386,6 +393,9 @@ struct vcpu_vmx { | |||
386 | struct { | 393 | struct { |
387 | int loaded; | 394 | int loaded; |
388 | u16 fs_sel, gs_sel, ldt_sel; | 395 | u16 fs_sel, gs_sel, ldt_sel; |
396 | #ifdef CONFIG_X86_64 | ||
397 | u16 ds_sel, es_sel; | ||
398 | #endif | ||
389 | int gs_ldt_reload_needed; | 399 | int gs_ldt_reload_needed; |
390 | int fs_reload_needed; | 400 | int fs_reload_needed; |
391 | } host_state; | 401 | } host_state; |
@@ -1411,6 +1421,11 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu) | |||
1411 | } | 1421 | } |
1412 | 1422 | ||
1413 | #ifdef CONFIG_X86_64 | 1423 | #ifdef CONFIG_X86_64 |
1424 | savesegment(ds, vmx->host_state.ds_sel); | ||
1425 | savesegment(es, vmx->host_state.es_sel); | ||
1426 | #endif | ||
1427 | |||
1428 | #ifdef CONFIG_X86_64 | ||
1414 | vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE)); | 1429 | vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE)); |
1415 | vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE)); | 1430 | vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE)); |
1416 | #else | 1431 | #else |
@@ -1450,6 +1465,19 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) | |||
1450 | } | 1465 | } |
1451 | if (vmx->host_state.fs_reload_needed) | 1466 | if (vmx->host_state.fs_reload_needed) |
1452 | loadsegment(fs, vmx->host_state.fs_sel); | 1467 | loadsegment(fs, vmx->host_state.fs_sel); |
1468 | #ifdef CONFIG_X86_64 | ||
1469 | if (unlikely(vmx->host_state.ds_sel | vmx->host_state.es_sel)) { | ||
1470 | loadsegment(ds, vmx->host_state.ds_sel); | ||
1471 | loadsegment(es, vmx->host_state.es_sel); | ||
1472 | } | ||
1473 | #else | ||
1474 | /* | ||
1475 | * The sysexit path does not restore ds/es, so we must set them to | ||
1476 | * a reasonable value ourselves. | ||
1477 | */ | ||
1478 | loadsegment(ds, __USER_DS); | ||
1479 | loadsegment(es, __USER_DS); | ||
1480 | #endif | ||
1453 | reload_tss(); | 1481 | reload_tss(); |
1454 | #ifdef CONFIG_X86_64 | 1482 | #ifdef CONFIG_X86_64 |
1455 | wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); | 1483 | wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); |
@@ -3633,8 +3661,18 @@ static void vmx_set_constant_host_state(void) | |||
3633 | vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ | 3661 | vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ |
3634 | 3662 | ||
3635 | vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ | 3663 | vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ |
3664 | #ifdef CONFIG_X86_64 | ||
3665 | /* | ||
3666 | * Load null selectors, so we can avoid reloading them in | ||
3667 | * __vmx_load_host_state(), in case userspace uses the null selectors | ||
3668 | * too (the expected case). | ||
3669 | */ | ||
3670 | vmcs_write16(HOST_DS_SELECTOR, 0); | ||
3671 | vmcs_write16(HOST_ES_SELECTOR, 0); | ||
3672 | #else | ||
3636 | vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ | 3673 | vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ |
3637 | vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ | 3674 | vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ |
3675 | #endif | ||
3638 | vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ | 3676 | vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ |
3639 | vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */ | 3677 | vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */ |
3640 | 3678 | ||
@@ -6256,7 +6294,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) | |||
6256 | } | 6294 | } |
6257 | } | 6295 | } |
6258 | 6296 | ||
6259 | asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); | ||
6260 | vmx->loaded_vmcs->launched = 1; | 6297 | vmx->loaded_vmcs->launched = 1; |
6261 | 6298 | ||
6262 | vmx->exit_reason = vmcs_read32(VM_EXIT_REASON); | 6299 | vmx->exit_reason = vmcs_read32(VM_EXIT_REASON); |
@@ -6343,7 +6380,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) | |||
6343 | return &vmx->vcpu; | 6380 | return &vmx->vcpu; |
6344 | 6381 | ||
6345 | free_vmcs: | 6382 | free_vmcs: |
6346 | free_vmcs(vmx->loaded_vmcs->vmcs); | 6383 | free_loaded_vmcs(vmx->loaded_vmcs); |
6347 | free_msrs: | 6384 | free_msrs: |
6348 | kfree(vmx->guest_msrs); | 6385 | kfree(vmx->guest_msrs); |
6349 | uninit_vcpu: | 6386 | uninit_vcpu: |