diff options
author | Yang, Sheng <sheng.yang@intel.com> | 2007-07-29 04:07:42 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:20 -0400 |
commit | 1c3d14fe0ab75337a3f6c06b6bc18bcbc2b3d0bc (patch) | |
tree | f3d2533b5250e8405af14f99c2810bb3ead1a06c /drivers/kvm | |
parent | fb3f0f51d92d1496f9628ca6f0fb06a48dc9ed2a (diff) |
KVM: VMX: Improve the method of writing vmcs control
Put cpu feature detecting part in hardware_setup, and stored the vmcs
condition in global variable for further check.
[glommer: fix for some i386-only machines not supporting CR8 load/store
exiting]
Signed-off-by: Sheng Yang <sheng.yang@intel.com>
Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/vmx.c | 147 |
1 files changed, 102 insertions, 45 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index df5787823309..18f9b0b3fb1f 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -71,18 +71,17 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs); | |||
71 | static struct page *vmx_io_bitmap_a; | 71 | static struct page *vmx_io_bitmap_a; |
72 | static struct page *vmx_io_bitmap_b; | 72 | static struct page *vmx_io_bitmap_b; |
73 | 73 | ||
74 | #ifdef CONFIG_X86_64 | ||
75 | #define HOST_IS_64 1 | ||
76 | #else | ||
77 | #define HOST_IS_64 0 | ||
78 | #endif | ||
79 | #define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE) | 74 | #define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE) |
80 | 75 | ||
81 | static struct vmcs_descriptor { | 76 | static struct vmcs_config { |
82 | int size; | 77 | int size; |
83 | int order; | 78 | int order; |
84 | u32 revision_id; | 79 | u32 revision_id; |
85 | } vmcs_descriptor; | 80 | u32 pin_based_exec_ctrl; |
81 | u32 cpu_based_exec_ctrl; | ||
82 | u32 vmexit_ctrl; | ||
83 | u32 vmentry_ctrl; | ||
84 | } vmcs_config; | ||
86 | 85 | ||
87 | #define VMX_SEGMENT_FIELD(seg) \ | 86 | #define VMX_SEGMENT_FIELD(seg) \ |
88 | [VCPU_SREG_##seg] = { \ | 87 | [VCPU_SREG_##seg] = { \ |
@@ -839,14 +838,93 @@ static void hardware_disable(void *garbage) | |||
839 | asm volatile (ASM_VMX_VMXOFF : : : "cc"); | 838 | asm volatile (ASM_VMX_VMXOFF : : : "cc"); |
840 | } | 839 | } |
841 | 840 | ||
842 | static __init void setup_vmcs_descriptor(void) | 841 | static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, |
842 | u32 msr, u32* result) | ||
843 | { | ||
844 | u32 vmx_msr_low, vmx_msr_high; | ||
845 | u32 ctl = ctl_min | ctl_opt; | ||
846 | |||
847 | rdmsr(msr, vmx_msr_low, vmx_msr_high); | ||
848 | |||
849 | ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */ | ||
850 | ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */ | ||
851 | |||
852 | /* Ensure minimum (required) set of control bits are supported. */ | ||
853 | if (ctl_min & ~ctl) | ||
854 | return -1; | ||
855 | |||
856 | *result = ctl; | ||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static __init int setup_vmcs_config(void) | ||
843 | { | 861 | { |
844 | u32 vmx_msr_low, vmx_msr_high; | 862 | u32 vmx_msr_low, vmx_msr_high; |
863 | u32 min, opt; | ||
864 | u32 _pin_based_exec_control = 0; | ||
865 | u32 _cpu_based_exec_control = 0; | ||
866 | u32 _vmexit_control = 0; | ||
867 | u32 _vmentry_control = 0; | ||
868 | |||
869 | min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; | ||
870 | opt = 0; | ||
871 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, | ||
872 | &_pin_based_exec_control) < 0) | ||
873 | return -1; | ||
874 | |||
875 | min = CPU_BASED_HLT_EXITING | | ||
876 | #ifdef CONFIG_X86_64 | ||
877 | CPU_BASED_CR8_LOAD_EXITING | | ||
878 | CPU_BASED_CR8_STORE_EXITING | | ||
879 | #endif | ||
880 | CPU_BASED_USE_IO_BITMAPS | | ||
881 | CPU_BASED_MOV_DR_EXITING | | ||
882 | CPU_BASED_USE_TSC_OFFSETING; | ||
883 | opt = 0; | ||
884 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, | ||
885 | &_cpu_based_exec_control) < 0) | ||
886 | return -1; | ||
887 | |||
888 | min = 0; | ||
889 | #ifdef CONFIG_X86_64 | ||
890 | min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; | ||
891 | #endif | ||
892 | opt = 0; | ||
893 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, | ||
894 | &_vmexit_control) < 0) | ||
895 | return -1; | ||
896 | |||
897 | min = opt = 0; | ||
898 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, | ||
899 | &_vmentry_control) < 0) | ||
900 | return -1; | ||
845 | 901 | ||
846 | rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); | 902 | rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); |
847 | vmcs_descriptor.size = vmx_msr_high & 0x1fff; | 903 | |
848 | vmcs_descriptor.order = get_order(vmcs_descriptor.size); | 904 | /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ |
849 | vmcs_descriptor.revision_id = vmx_msr_low; | 905 | if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) |
906 | return -1; | ||
907 | |||
908 | #ifdef CONFIG_X86_64 | ||
909 | /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ | ||
910 | if (vmx_msr_high & (1u<<16)) | ||
911 | return -1; | ||
912 | #endif | ||
913 | |||
914 | /* Require Write-Back (WB) memory type for VMCS accesses. */ | ||
915 | if (((vmx_msr_high >> 18) & 15) != 6) | ||
916 | return -1; | ||
917 | |||
918 | vmcs_config.size = vmx_msr_high & 0x1fff; | ||
919 | vmcs_config.order = get_order(vmcs_config.size); | ||
920 | vmcs_config.revision_id = vmx_msr_low; | ||
921 | |||
922 | vmcs_config.pin_based_exec_ctrl = _pin_based_exec_control; | ||
923 | vmcs_config.cpu_based_exec_ctrl = _cpu_based_exec_control; | ||
924 | vmcs_config.vmexit_ctrl = _vmexit_control; | ||
925 | vmcs_config.vmentry_ctrl = _vmentry_control; | ||
926 | |||
927 | return 0; | ||
850 | } | 928 | } |
851 | 929 | ||
852 | static struct vmcs *alloc_vmcs_cpu(int cpu) | 930 | static struct vmcs *alloc_vmcs_cpu(int cpu) |
@@ -855,12 +933,12 @@ static struct vmcs *alloc_vmcs_cpu(int cpu) | |||
855 | struct page *pages; | 933 | struct page *pages; |
856 | struct vmcs *vmcs; | 934 | struct vmcs *vmcs; |
857 | 935 | ||
858 | pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order); | 936 | pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order); |
859 | if (!pages) | 937 | if (!pages) |
860 | return NULL; | 938 | return NULL; |
861 | vmcs = page_address(pages); | 939 | vmcs = page_address(pages); |
862 | memset(vmcs, 0, vmcs_descriptor.size); | 940 | memset(vmcs, 0, vmcs_config.size); |
863 | vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */ | 941 | vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */ |
864 | return vmcs; | 942 | return vmcs; |
865 | } | 943 | } |
866 | 944 | ||
@@ -871,7 +949,7 @@ static struct vmcs *alloc_vmcs(void) | |||
871 | 949 | ||
872 | static void free_vmcs(struct vmcs *vmcs) | 950 | static void free_vmcs(struct vmcs *vmcs) |
873 | { | 951 | { |
874 | free_pages((unsigned long)vmcs, vmcs_descriptor.order); | 952 | free_pages((unsigned long)vmcs, vmcs_config.order); |
875 | } | 953 | } |
876 | 954 | ||
877 | static void free_kvm_area(void) | 955 | static void free_kvm_area(void) |
@@ -904,7 +982,8 @@ static __init int alloc_kvm_area(void) | |||
904 | 982 | ||
905 | static __init int hardware_setup(void) | 983 | static __init int hardware_setup(void) |
906 | { | 984 | { |
907 | setup_vmcs_descriptor(); | 985 | if (setup_vmcs_config() < 0) |
986 | return -1; | ||
908 | return alloc_kvm_area(); | 987 | return alloc_kvm_area(); |
909 | } | 988 | } |
910 | 989 | ||
@@ -1275,17 +1354,6 @@ static int init_rmode_tss(struct kvm* kvm) | |||
1275 | return 1; | 1354 | return 1; |
1276 | } | 1355 | } |
1277 | 1356 | ||
1278 | static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val) | ||
1279 | { | ||
1280 | u32 msr_high, msr_low; | ||
1281 | |||
1282 | rdmsr(msr, msr_low, msr_high); | ||
1283 | |||
1284 | val &= msr_high; | ||
1285 | val |= msr_low; | ||
1286 | vmcs_write32(vmcs_field, val); | ||
1287 | } | ||
1288 | |||
1289 | static void seg_setup(int seg) | 1357 | static void seg_setup(int seg) |
1290 | { | 1358 | { |
1291 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; | 1359 | struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; |
@@ -1382,20 +1450,10 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) | |||
1382 | vmcs_write64(GUEST_IA32_DEBUGCTL, 0); | 1450 | vmcs_write64(GUEST_IA32_DEBUGCTL, 0); |
1383 | 1451 | ||
1384 | /* Control */ | 1452 | /* Control */ |
1385 | vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS, | 1453 | vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, |
1386 | PIN_BASED_VM_EXEC_CONTROL, | 1454 | vmcs_config.pin_based_exec_ctrl); |
1387 | PIN_BASED_EXT_INTR_MASK /* 20.6.1 */ | 1455 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, |
1388 | | PIN_BASED_NMI_EXITING /* 20.6.1 */ | 1456 | vmcs_config.cpu_based_exec_ctrl); |
1389 | ); | ||
1390 | vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS, | ||
1391 | CPU_BASED_VM_EXEC_CONTROL, | ||
1392 | CPU_BASED_HLT_EXITING /* 20.6.2 */ | ||
1393 | | CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */ | ||
1394 | | CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */ | ||
1395 | | CPU_BASED_USE_IO_BITMAPS /* 20.6.2 */ | ||
1396 | | CPU_BASED_MOV_DR_EXITING | ||
1397 | | CPU_BASED_USE_TSC_OFFSETING /* 21.3 */ | ||
1398 | ); | ||
1399 | 1457 | ||
1400 | vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); | 1458 | vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); |
1401 | vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); | 1459 | vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); |
@@ -1459,12 +1517,11 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) | |||
1459 | 1517 | ||
1460 | setup_msrs(vcpu); | 1518 | setup_msrs(vcpu); |
1461 | 1519 | ||
1462 | vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS, | 1520 | vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl); |
1463 | (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */ | ||
1464 | 1521 | ||
1465 | /* 22.2.1, 20.8.1 */ | 1522 | /* 22.2.1, 20.8.1 */ |
1466 | vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS, | 1523 | vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl); |
1467 | VM_ENTRY_CONTROLS, 0); | 1524 | |
1468 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ | 1525 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ |
1469 | 1526 | ||
1470 | #ifdef CONFIG_X86_64 | 1527 | #ifdef CONFIG_X86_64 |