diff options
author | Sheng Yang <sheng@linux.intel.com> | 2008-10-09 04:01:55 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2008-12-31 09:51:44 -0500 |
commit | 468d472f3f65100d5fb88c8d45043c85b874c294 (patch) | |
tree | 6b82d3f738879827a2836aba8c54391e7a743588 | |
parent | 0bed3b568b68e5835ef5da888a372b9beabf7544 (diff) |
KVM: VMX: Add PAT support for EPT
GUEST_PAT support is a new feature introduced by Intel Core i7 architecture.
With this, cpu would save/load guest and host PAT automatically, for EPT memory
type in guest depends on MSR_IA32_CR_PAT.
Also add save/restore for MSR_IA32_CR_PAT.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/kvm/vmx.c | 29 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.h | 7 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 2 |
3 files changed, 34 insertions, 4 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 2180109d794c..b4c95a501cca 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -962,6 +962,13 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) | |||
962 | pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", msr_index, data); | 962 | pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", msr_index, data); |
963 | 963 | ||
964 | break; | 964 | break; |
965 | case MSR_IA32_CR_PAT: | ||
966 | if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) { | ||
967 | vmcs_write64(GUEST_IA32_PAT, data); | ||
968 | vcpu->arch.pat = data; | ||
969 | break; | ||
970 | } | ||
971 | /* Otherwise falls through to kvm_set_msr_common */ | ||
965 | default: | 972 | default: |
966 | vmx_load_host_state(vmx); | 973 | vmx_load_host_state(vmx); |
967 | msr = find_msr_entry(vmx, msr_index); | 974 | msr = find_msr_entry(vmx, msr_index); |
@@ -1181,12 +1188,13 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) | |||
1181 | #ifdef CONFIG_X86_64 | 1188 | #ifdef CONFIG_X86_64 |
1182 | min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; | 1189 | min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; |
1183 | #endif | 1190 | #endif |
1184 | opt = 0; | 1191 | opt = VM_EXIT_SAVE_IA32_PAT | VM_EXIT_LOAD_IA32_PAT; |
1185 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, | 1192 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, |
1186 | &_vmexit_control) < 0) | 1193 | &_vmexit_control) < 0) |
1187 | return -EIO; | 1194 | return -EIO; |
1188 | 1195 | ||
1189 | min = opt = 0; | 1196 | min = 0; |
1197 | opt = VM_ENTRY_LOAD_IA32_PAT; | ||
1190 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, | 1198 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, |
1191 | &_vmentry_control) < 0) | 1199 | &_vmentry_control) < 0) |
1192 | return -EIO; | 1200 | return -EIO; |
@@ -2092,8 +2100,9 @@ static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr) | |||
2092 | */ | 2100 | */ |
2093 | static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | 2101 | static int vmx_vcpu_setup(struct vcpu_vmx *vmx) |
2094 | { | 2102 | { |
2095 | u32 host_sysenter_cs; | 2103 | u32 host_sysenter_cs, msr_low, msr_high; |
2096 | u32 junk; | 2104 | u32 junk; |
2105 | u64 host_pat; | ||
2097 | unsigned long a; | 2106 | unsigned long a; |
2098 | struct descriptor_table dt; | 2107 | struct descriptor_table dt; |
2099 | int i; | 2108 | int i; |
@@ -2181,6 +2190,20 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | |||
2181 | rdmsrl(MSR_IA32_SYSENTER_EIP, a); | 2190 | rdmsrl(MSR_IA32_SYSENTER_EIP, a); |
2182 | vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */ | 2191 | vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */ |
2183 | 2192 | ||
2193 | if (vmcs_config.vmexit_ctrl & VM_EXIT_LOAD_IA32_PAT) { | ||
2194 | rdmsr(MSR_IA32_CR_PAT, msr_low, msr_high); | ||
2195 | host_pat = msr_low | ((u64) msr_high << 32); | ||
2196 | vmcs_write64(HOST_IA32_PAT, host_pat); | ||
2197 | } | ||
2198 | if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) { | ||
2199 | rdmsr(MSR_IA32_CR_PAT, msr_low, msr_high); | ||
2200 | host_pat = msr_low | ((u64) msr_high << 32); | ||
2201 | /* Write the default value follow host pat */ | ||
2202 | vmcs_write64(GUEST_IA32_PAT, host_pat); | ||
2203 | /* Keep arch.pat sync with GUEST_IA32_PAT */ | ||
2204 | vmx->vcpu.arch.pat = host_pat; | ||
2205 | } | ||
2206 | |||
2184 | for (i = 0; i < NR_VMX_MSR; ++i) { | 2207 | for (i = 0; i < NR_VMX_MSR; ++i) { |
2185 | u32 index = vmx_msr_index[i]; | 2208 | u32 index = vmx_msr_index[i]; |
2186 | u32 data_low, data_high; | 2209 | u32 data_low, data_high; |
diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h index ec5edc339da6..18598afe52eb 100644 --- a/arch/x86/kvm/vmx.h +++ b/arch/x86/kvm/vmx.h | |||
@@ -63,10 +63,13 @@ | |||
63 | 63 | ||
64 | #define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 | 64 | #define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 |
65 | #define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 | 65 | #define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 |
66 | #define VM_EXIT_SAVE_IA32_PAT 0x00040000 | ||
67 | #define VM_EXIT_LOAD_IA32_PAT 0x00080000 | ||
66 | 68 | ||
67 | #define VM_ENTRY_IA32E_MODE 0x00000200 | 69 | #define VM_ENTRY_IA32E_MODE 0x00000200 |
68 | #define VM_ENTRY_SMM 0x00000400 | 70 | #define VM_ENTRY_SMM 0x00000400 |
69 | #define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 | 71 | #define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 |
72 | #define VM_ENTRY_LOAD_IA32_PAT 0x00004000 | ||
70 | 73 | ||
71 | /* VMCS Encodings */ | 74 | /* VMCS Encodings */ |
72 | enum vmcs_field { | 75 | enum vmcs_field { |
@@ -112,6 +115,8 @@ enum vmcs_field { | |||
112 | VMCS_LINK_POINTER_HIGH = 0x00002801, | 115 | VMCS_LINK_POINTER_HIGH = 0x00002801, |
113 | GUEST_IA32_DEBUGCTL = 0x00002802, | 116 | GUEST_IA32_DEBUGCTL = 0x00002802, |
114 | GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, | 117 | GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, |
118 | GUEST_IA32_PAT = 0x00002804, | ||
119 | GUEST_IA32_PAT_HIGH = 0x00002805, | ||
115 | GUEST_PDPTR0 = 0x0000280a, | 120 | GUEST_PDPTR0 = 0x0000280a, |
116 | GUEST_PDPTR0_HIGH = 0x0000280b, | 121 | GUEST_PDPTR0_HIGH = 0x0000280b, |
117 | GUEST_PDPTR1 = 0x0000280c, | 122 | GUEST_PDPTR1 = 0x0000280c, |
@@ -120,6 +125,8 @@ enum vmcs_field { | |||
120 | GUEST_PDPTR2_HIGH = 0x0000280f, | 125 | GUEST_PDPTR2_HIGH = 0x0000280f, |
121 | GUEST_PDPTR3 = 0x00002810, | 126 | GUEST_PDPTR3 = 0x00002810, |
122 | GUEST_PDPTR3_HIGH = 0x00002811, | 127 | GUEST_PDPTR3_HIGH = 0x00002811, |
128 | HOST_IA32_PAT = 0x00002c00, | ||
129 | HOST_IA32_PAT_HIGH = 0x00002c01, | ||
123 | PIN_BASED_VM_EXEC_CONTROL = 0x00004000, | 130 | PIN_BASED_VM_EXEC_CONTROL = 0x00004000, |
124 | CPU_BASED_VM_EXEC_CONTROL = 0x00004002, | 131 | CPU_BASED_VM_EXEC_CONTROL = 0x00004002, |
125 | EXCEPTION_BITMAP = 0x00004004, | 132 | EXCEPTION_BITMAP = 0x00004004, |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f5b2334c6bda..0edf75339f3a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -452,7 +452,7 @@ static u32 msrs_to_save[] = { | |||
452 | MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, | 452 | MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, |
453 | #endif | 453 | #endif |
454 | MSR_IA32_TIME_STAMP_COUNTER, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, | 454 | MSR_IA32_TIME_STAMP_COUNTER, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, |
455 | MSR_IA32_PERF_STATUS, | 455 | MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT |
456 | }; | 456 | }; |
457 | 457 | ||
458 | static unsigned num_msrs_to_save; | 458 | static unsigned num_msrs_to_save; |