KVM: nVMX: Validate EFER values for VM_ENTRY/EXIT_LOAD_IA32_EFER
PATCH 1/2 KVM: nVMX: Validate EFER values for VM_ENTRY/EXIT_LOAD_IA32_EFER
From: Jan Kiszka <[email protected]>
As we may emulate the loading of EFER on VM-entry and VM-exit, implement the checks that VMX performs on the guest and host values on vmlaunch/ vmresume. Factor out kvm_valid_efer for this purpose which checks for set reserved bits.
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx.c | 38 ++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 29 +++++++++++++++++++---------- 3 files changed, 58 insertions(+), 10 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -805,6 +805,7 @@ static inline int emulate_instruction(struct kvm_vcpu *vcpu, }void kvm_enable_efer_bits (u64 ); +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer);int kvm_get_msr (struct kvm_vcpu *vcpu,u32 msr_index,u64 *data);int kvm_set_msr (struct kvm_vcpu *vcpu,struct msr_data *msr);
arch/x86/kvm/vmx.c +38 -0
@@ -7257,6 +7257,44 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) }/* +* If the “load IA32_EFER” VM-entry control is 1, the following checks +* are performed on the field for the IA32_EFER MSR: +* - Bits reserved in the IA32_EFER MSR must be 0. +* - Bit 10 (corresponding to IA32_EFER.LMA) must equal the value of +* the IA-32e mode guest VM-exit control. It must also be identical +* to bit 8 (LME) if bit 31 in the CR0 field (corresponding to +* CR0.PG) is 1.1 +*/ +if (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_IA32_EFER && + (!kvm_valid_efer (vcpu, vmcs12->guest_ia32_efer) || + !!(vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) != + !!(vmcs12->guest_ia32_efer &EFER_LMA ) || + (vmcs12->guest_cr0 &X86_CR0_PG && + !!(vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) != + !!(vmcs12->guest_ia32_efer &EFER_LME )))) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + } + +/* +* If the load IA32_EFER VM-exit control is 1, bits reserved in the +* IA32_EFER MSR must be 0 in the field for that register. In addition, +* the values of the LMA and LME bits in the field must each be that of +* the host address-space size VM-exit control. +*/ +if (vmcs12->vm_exit_controls &VM_EXIT_LOAD_IA32_EFER && + (!kvm_valid_efer (vcpu, vmcs12->host_ia32_efer) || + !!(vmcs12->vm_exit_controls &VM_EXIT_HOST_ADDR_SPACE_SIZE ) != + !!(vmcs12->host_ia32_efer &EFER_LMA ) || + !!(vmcs12->vm_exit_controls &VM_EXIT_HOST_ADDR_SPACE_SIZE ) != + !!(vmcs12->host_ia32_efer &EFER_LME ))) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + } + +/* * We're finally done with prerequisite checking, and can start with * the nested entry. */
arch/x86/kvm/x86.c +19 -10
@@ -845,23 +845,17 @@ static const u32 emulated_msrs[] = { MSR_IA32_MCG_CTL, }; -static int set_efer (struct kvm_vcpu *vcpu,u64 efer) +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer) { -u64 old_efer = vcpu->arch.efer; -if (efer & efer_reserved_bits) -return 1 ; - -if (is_paging (vcpu) - && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) -return 1 ; +return false;if (efer &EFER_FFXSR ) {struct kvm_cpuid_entry2 *feat; feat =kvm_find_cpuid_entry (vcpu,0x80000001 ,0 );if (!feat || !(feat->edx &bit (X86_FEATURE_FXSR_OPT ))) -return 1 ; +return false; }if (efer &EFER_SVME ) {
@@ -869,9 +863,24 @@ static int set_efer(struct kvm_vcpu *vcpu, u64 efer) feat =kvm_find_cpuid_entry (vcpu,0x80000001 ,0 );if (!feat || !(feat->ecx &bit (X86_FEATURE_SVM ))) -return 1 ; +return false; } +return true; +} +EXPORT_SYMBOL_GPL (kvm_valid_efer); + +static int set_efer (struct kvm_vcpu *vcpu,u64 efer) +{ +u64 old_efer = vcpu->arch.efer; + +if (!kvm_valid_efer (vcpu, efer)) +return 1 ; + +if (is_paging (vcpu) + && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) +return 1 ; + efer &= ~EFER_LMA ; efer |= vcpu->arch.efer &EFER_LMA ;
Signature · 1 line
1.7.3.4
PATCH 2/2 KVM: nVMX: VM_ENTRY/EXIT_LOAD_IA32_EFER overrides EFER.LMA settings
From: Jan Kiszka <[email protected]>
If we load the complete EFER MSR on entry or exit, EFER.LMA (and LME) loading is skipped. Their consistency is already checked now before starting the transition.
--- arch/x86/kvm/vmx.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx.c +2 -2
@@ -7135,7 +7135,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)if (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_IA32_EFER ) vcpu->arch.efer = vmcs12->guest_ia32_efer; -if (vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) +else if (vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) vcpu->arch.efer |= (EFER_LMA |EFER_LME );else vcpu->arch.efer &= ~(EFER_LMA |EFER_LME );
@@ -7536,7 +7536,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, {if (vmcs12->vm_exit_controls &VM_EXIT_LOAD_IA32_EFER ) vcpu->arch.efer = vmcs12->host_ia32_efer; -if (vmcs12->vm_exit_controls &VM_EXIT_HOST_ADDR_SPACE_SIZE ) +else if (vmcs12->vm_exit_controls &VM_EXIT_HOST_ADDR_SPACE_SIZE ) vcpu->arch.efer |= (EFER_LMA |EFER_LME );else vcpu->arch.efer &= ~(EFER_LMA |EFER_LME );
Signature · 1 line
1.7.3.4
Re: [PATCH 2/2] KVM: nVMX: VM_ENTRY/EXIT_LOAD_IA32_EFER overrides EFER.LMA settings
Il 14/04/2013 12:44, Jan Kiszka ha scritto:
Quoted 26 lines
From: Jan Kiszka <[email protected]>
If we load the complete EFER MSR on entry or exit, EFER.LMA (and LME) loading is skipped. Their consistency is already checked now before starting the transition.
Signed-off-by Jan Kiszka <[email protected]>--- arch/x86/kvm/vmx.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)arch/x86/kvm/vmx.c +1
-1@@ -7135,7 +7135,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)if (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_IA32_EFER ) vcpu->arch.efer = vmcs12->guest_ia32_efer; -if (vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) +else if (vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) vcpu->arch.efer |= (EFER_LMA |EFER_LME );else vcpu->arch.efer &= ~(EFER_LMA |EFER_LME );
arch/x86/kvm/vmx.c static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, · line 7542
Quoted 8 lines
arch/x86/kvm/vmx.c +1
-1@@ -7536,7 +7536,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, {if (vmcs12->vm_exit_controls &VM_EXIT_LOAD_IA32_EFER ) vcpu->arch.efer = vmcs12->host_ia32_efer; -if (vmcs12->vm_exit_controls &VM_EXIT_HOST_ADDR_SPACE_SIZE ) +else if (vmcs12->vm_exit_controls &VM_EXIT_HOST_ADDR_SPACE_SIZE ) vcpu->arch.efer |= (EFER_LMA |EFER_LME );else vcpu->arch.efer &= ~(EFER_LMA |EFER_LME );
Paolo Bonzini
maintainerIl 14/04/2013 12:44, Jan Kiszka ha scritto:
arch/x86/kvm/vmx.c static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) · line 7278
Quoted 11 lines
arch/x86/kvm/vmx.c +11
-0+if (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_IA32_EFER && + (!kvm_valid_efer (vcpu, vmcs12->guest_ia32_efer) || + !!(vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) != + !!(vmcs12->guest_ia32_efer &EFER_LMA ) || + (vmcs12->guest_cr0 &X86_CR0_PG && + !!(vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) != + !!(vmcs12->guest_ia32_efer &EFER_LME )))) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + }
if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER) {
bool ia32e = (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) != 0;
if (...) {
}
}Also please put parentheses around the & operator.
The exit tests can similarly extract the host address space size bit to a bool.
Paolo
Quoted 31 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
As we may emulate the loading of EFER on VM-entry and VM-exit, implement the checks that VMX performs on the guest and host values on vmlaunch/ vmresume. Factor out
kvm_valid_eferfor this purpose which checks for set reserved bits.Signed-off-by Jan Kiszka <[email protected]>--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx.c | 38 ++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 29 +++++++++++++++++++---------- 3 files changed, 58 insertions(+), 10 deletions(-)arch/x86/include/asm/kvm_host.h +1
-0@@ -805,6 +805,7 @@ static inline int emulate_instruction(struct kvm_vcpu *vcpu, }void kvm_enable_efer_bits (u64 ); +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer);int kvm_get_msr (struct kvm_vcpu *vcpu,u32 msr_index,u64 *data);int kvm_set_msr (struct kvm_vcpu *vcpu,struct msr_data *msr);arch/x86/kvm/vmx.c +0
-0
arch/x86/kvm/vmx.c static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) · line 7266
Quoted 10 lines
arch/x86/kvm/vmx.c +7
-0@@ -7257,6 +7257,44 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) }/* +* If the “load IA32_EFER” VM-entry control is 1, the following checks +* are performed on the field for the IA32_EFER MSR: +* - Bits reserved in the IA32_EFER MSR must be 0. +* - Bit 10 (corresponding to IA32_EFER.LMA) must equal the value of +* the IA-32e mode guest VM-exit control. It must also be identical +* to bit 8 (LME) if bit 31 in the CR0 field (corresponding to +* CR0.PG) is 1.1
^^^
Typo?
PATCH v2 1/2 KVM: nVMX: Validate EFER values for VM_ENTRY/EXIT_LOAD_IA32_EFER
In reply to Jan KiszkaAs we may emulate the loading of EFER on VM-entry and VM-exit, implement the checks that VMX performs on the guest and host values on vmlaunch/ vmresume. Factor out kvm_valid_efer for this purpose which checks for set reserved bits.
---
Changes in v2:
- refactored if clauses as requested by Paolo
- fixed typo in comment found my Marcelo
arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx.c | 40 +++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 29 ++++++++++++++++++--------- 3 files changed, 60 insertions(+), 10 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -809,6 +809,7 @@ static inline int emulate_instruction(struct kvm_vcpu *vcpu, }void kvm_enable_efer_bits (u64 ); +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer);int kvm_get_msr (struct kvm_vcpu *vcpu,u32 msr_index,u64 *data);int kvm_set_msr (struct kvm_vcpu *vcpu,struct msr_data *msr);
arch/x86/kvm/vmx.c +40 -0
@@ -7327,6 +7327,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)struct vcpu_vmx *vmx =to_vmx (vcpu);int cpu;struct loaded_vmcs *vmcs02; +bool ia32e;if (!nested_vmx_check_permission (vcpu) || !nested_vmx_check_vmcs12 (vcpu))
@@ -7415,6 +7416,45 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) }/* +* If the “load IA32_EFER” VM-entry control is 1, the following checks +* are performed on the field for the IA32_EFER MSR: +* - Bits reserved in the IA32_EFER MSR must be 0. +* - Bit 10 (corresponding to IA32_EFER.LMA) must equal the value of +* the IA-32e mode guest VM-exit control. It must also be identical +* to bit 8 (LME) if bit 31 in the CR0 field (corresponding to +* CR0.PG) is 1. +*/ +if (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_IA32_EFER ) { + ia32e = (vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) !=0 ; +if (!kvm_valid_efer (vcpu, vmcs12->guest_ia32_efer) || + ia32e != !!(vmcs12->guest_ia32_efer &EFER_LMA ) || + ((vmcs12->guest_cr0 &X86_CR0_PG ) && + ia32e != !!(vmcs12->guest_ia32_efer &EFER_LME ))) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + } + } + +/* +* If the load IA32_EFER VM-exit control is 1, bits reserved in the +* IA32_EFER MSR must be 0 in the field for that register. In addition, +* the values of the LMA and LME bits in the field must each be that of +* the host address-space size VM-exit control. +*/ +if (vmcs12->vm_exit_controls &VM_EXIT_LOAD_IA32_EFER ) { + ia32e = (vmcs12->vm_exit_controls & +VM_EXIT_HOST_ADDR_SPACE_SIZE ) !=0 ; +if (!kvm_valid_efer (vcpu, vmcs12->host_ia32_efer) || + ia32e != !!(vmcs12->host_ia32_efer &EFER_LMA ) || + ia32e != !!(vmcs12->host_ia32_efer &EFER_LME )) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + } + } + +/* * We're finally done with prerequisite checking, and can start with * the nested entry. */
arch/x86/kvm/x86.c +19 -10
@@ -845,23 +845,17 @@ static const u32 emulated_msrs[] = { MSR_IA32_MCG_CTL, }; -static int set_efer (struct kvm_vcpu *vcpu,u64 efer) +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer) { -u64 old_efer = vcpu->arch.efer; -if (efer & efer_reserved_bits) -return 1 ; - -if (is_paging (vcpu) - && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) -return 1 ; +return false;if (efer &EFER_FFXSR ) {struct kvm_cpuid_entry2 *feat; feat =kvm_find_cpuid_entry (vcpu,0x80000001 ,0 );if (!feat || !(feat->edx &bit (X86_FEATURE_FXSR_OPT ))) -return 1 ; +return false; }if (efer &EFER_SVME ) {
@@ -869,9 +863,24 @@ static int set_efer(struct kvm_vcpu *vcpu, u64 efer) feat =kvm_find_cpuid_entry (vcpu,0x80000001 ,0 );if (!feat || !(feat->ecx &bit (X86_FEATURE_SVM ))) -return 1 ; +return false; } +return true; +} +EXPORT_SYMBOL_GPL (kvm_valid_efer); + +static int set_efer (struct kvm_vcpu *vcpu,u64 efer) +{ +u64 old_efer = vcpu->arch.efer; + +if (!kvm_valid_efer (vcpu, efer)) +return 1 ; + +if (is_paging (vcpu) + && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) +return 1 ; + efer &= ~EFER_LMA ; efer |= vcpu->arch.efer &EFER_LMA ;
Signature · 1 line
1.7.3.4
Paolo Bonzini
maintainerIl 20/04/2013 10:52, Jan Kiszka ha scritto:
Quoted 72 lines
As we may emulate the loading of EFER on VM-entry and VM-exit, implement the checks that VMX performs on the guest and host values on vmlaunch/ vmresume. Factor out
kvm_valid_eferfor this purpose which checks for set reserved bits.Signed-off-by Jan Kiszka <[email protected]>---
Changes in v2:
- refactored if clauses as requested by Paolo
- fixed typo in comment found my Marceloarch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx.c | 40 +++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 29 ++++++++++++++++++--------- 3 files changed, 60 insertions(+), 10 deletions(-)arch/x86/include/asm/kvm_host.h +1
-0@@ -809,6 +809,7 @@ static inline int emulate_instruction(struct kvm_vcpu *vcpu, }void kvm_enable_efer_bits (u64 ); +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer);int kvm_get_msr (struct kvm_vcpu *vcpu,u32 msr_index,u64 *data);int kvm_set_msr (struct kvm_vcpu *vcpu,struct msr_data *msr);arch/x86/kvm/vmx.c +28
-0@@ -7327,6 +7327,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)struct vcpu_vmx *vmx =to_vmx (vcpu);int cpu;struct loaded_vmcs *vmcs02; +bool ia32e;if (!nested_vmx_check_permission (vcpu) || !nested_vmx_check_vmcs12 (vcpu))@@ -7415,6 +7416,45 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) }/* +* If the “load IA32_EFER” VM-entry control is 1, the following checks +* are performed on the field for the IA32_EFER MSR: +* - Bits reserved in the IA32_EFER MSR must be 0. +* - Bit 10 (corresponding to IA32_EFER.LMA) must equal the value of +* the IA-32e mode guest VM-exit control. It must also be identical +* to bit 8 (LME) if bit 31 in the CR0 field (corresponding to +* CR0.PG) is 1. +*/ +if (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_IA32_EFER ) { + ia32e = (vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) !=0 ; +if (!kvm_valid_efer (vcpu, vmcs12->guest_ia32_efer) || + ia32e != !!(vmcs12->guest_ia32_efer &EFER_LMA ) || + ((vmcs12->guest_cr0 &X86_CR0_PG ) && + ia32e != !!(vmcs12->guest_ia32_efer &EFER_LME ))) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + } + } + +/* +* If the load IA32_EFER VM-exit control is 1, bits reserved in the +* IA32_EFER MSR must be 0 in the field for that register. In addition, +* the values of the LMA and LME bits in the field must each be that of +* the host address-space size VM-exit control. +*/ +if (vmcs12->vm_exit_controls &VM_EXIT_LOAD_IA32_EFER ) {
arch/x86/kvm/vmx.c static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) · line 7455
Quoted 10 lines
arch/x86/kvm/vmx.c +10
-0+ ia32e = (vmcs12->vm_exit_controls & +VM_EXIT_HOST_ADDR_SPACE_SIZE ) !=0 ; +if (!kvm_valid_efer (vcpu, vmcs12->host_ia32_efer) || + ia32e != !!(vmcs12->host_ia32_efer &EFER_LMA ) || + ia32e != !!(vmcs12->host_ia32_efer &EFER_LME )) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + } + }
Looks good, difficult to do better with C's operator precedence rules.
Paolo
Quoted 62 lines
arch/x86/kvm/vmx.c +1
-0+/* * We're finally done with prerequisite checking, and can start with * the nested entry. */ arch/x86/kvm/x86.c +19
-10@@ -845,23 +845,17 @@ static const u32 emulated_msrs[] = { MSR_IA32_MCG_CTL, }; -static int set_efer (struct kvm_vcpu *vcpu,u64 efer) +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer) { -u64 old_efer = vcpu->arch.efer; -if (efer & efer_reserved_bits) -return 1 ; - -if (is_paging (vcpu) - && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) -return 1 ; +return false;if (efer &EFER_FFXSR ) {struct kvm_cpuid_entry2 *feat; feat =kvm_find_cpuid_entry (vcpu,0x80000001 ,0 );if (!feat || !(feat->edx &bit (X86_FEATURE_FXSR_OPT ))) -return 1 ; +return false; }if (efer &EFER_SVME ) {@@ -869,9 +863,24 @@ static int set_efer(struct kvm_vcpu *vcpu, u64 efer) feat =kvm_find_cpuid_entry (vcpu,0x80000001 ,0 );if (!feat || !(feat->ecx &bit (X86_FEATURE_SVM ))) -return 1 ; +return false; } +return true; +} +EXPORT_SYMBOL_GPL (kvm_valid_efer); + +static int set_efer (struct kvm_vcpu *vcpu,u64 efer) +{ +u64 old_efer = vcpu->arch.efer; + +if (!kvm_valid_efer (vcpu, efer)) +return 1 ; + +if (is_paging (vcpu) + && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) +return 1 ; + efer &= ~EFER_LMA ; efer |= vcpu->arch.efer &EFER_LMA ;
Quoted 8 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
As we may emulate the loading of EFER on VM-entry and VM-exit, implement the checks that VMX performs on the guest and host values on vmlaunch/ vmresume. Factor out
kvm_valid_eferfor this purpose which checks for set reserved bits.Signed-off-by Jan Kiszka <[email protected]>
Applied v2 of 1/2 and 2/2.
Quoted 126 lines
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx.c | 38 ++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 29 +++++++++++++++++++---------- 3 files changed, 58 insertions(+), 10 deletions(-)arch/x86/include/asm/kvm_host.h +1
-0@@ -805,6 +805,7 @@ static inline int emulate_instruction(struct kvm_vcpu *vcpu, }void kvm_enable_efer_bits (u64 ); +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer);int kvm_get_msr (struct kvm_vcpu *vcpu,u32 msr_index,u64 *data);int kvm_set_msr (struct kvm_vcpu *vcpu,struct msr_data *msr);arch/x86/kvm/vmx.c +38
-0@@ -7257,6 +7257,44 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) }/* +* If the “load IA32_EFER” VM-entry control is 1, the following checks +* are performed on the field for the IA32_EFER MSR: +* - Bits reserved in the IA32_EFER MSR must be 0. +* - Bit 10 (corresponding to IA32_EFER.LMA) must equal the value of +* the IA-32e mode guest VM-exit control. It must also be identical +* to bit 8 (LME) if bit 31 in the CR0 field (corresponding to +* CR0.PG) is 1.1 +*/ +if (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_IA32_EFER && + (!kvm_valid_efer (vcpu, vmcs12->guest_ia32_efer) || + !!(vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) != + !!(vmcs12->guest_ia32_efer &EFER_LMA ) || + (vmcs12->guest_cr0 &X86_CR0_PG && + !!(vmcs12->vm_entry_controls &VM_ENTRY_IA32E_MODE ) != + !!(vmcs12->guest_ia32_efer &EFER_LME )))) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + } + +/* +* If the load IA32_EFER VM-exit control is 1, bits reserved in the +* IA32_EFER MSR must be 0 in the field for that register. In addition, +* the values of the LMA and LME bits in the field must each be that of +* the host address-space size VM-exit control. +*/ +if (vmcs12->vm_exit_controls &VM_EXIT_LOAD_IA32_EFER && + (!kvm_valid_efer (vcpu, vmcs12->host_ia32_efer) || + !!(vmcs12->vm_exit_controls &VM_EXIT_HOST_ADDR_SPACE_SIZE ) != + !!(vmcs12->host_ia32_efer &EFER_LMA ) || + !!(vmcs12->vm_exit_controls &VM_EXIT_HOST_ADDR_SPACE_SIZE ) != + !!(vmcs12->host_ia32_efer &EFER_LME ))) { +nested_vmx_entry_failure (vcpu, vmcs12, +EXIT_REASON_INVALID_STATE ,ENTRY_FAIL_DEFAULT ); +return 1 ; + } + +/* * We're finally done with prerequisite checking, and can start with * the nested entry. */ arch/x86/kvm/x86.c +19
-10@@ -845,23 +845,17 @@ static const u32 emulated_msrs[] = { MSR_IA32_MCG_CTL, }; -static int set_efer (struct kvm_vcpu *vcpu,u64 efer) +bool kvm_valid_efer (struct kvm_vcpu *vcpu,u64 efer) { -u64 old_efer = vcpu->arch.efer; -if (efer & efer_reserved_bits) -return 1 ; - -if (is_paging (vcpu) - && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) -return 1 ; +return false;if (efer &EFER_FFXSR ) {struct kvm_cpuid_entry2 *feat; feat =kvm_find_cpuid_entry (vcpu,0x80000001 ,0 );if (!feat || !(feat->edx &bit (X86_FEATURE_FXSR_OPT ))) -return 1 ; +return false; }if (efer &EFER_SVME ) {@@ -869,9 +863,24 @@ static int set_efer(struct kvm_vcpu *vcpu, u64 efer) feat =kvm_find_cpuid_entry (vcpu,0x80000001 ,0 );if (!feat || !(feat->ecx &bit (X86_FEATURE_SVM ))) -return 1 ; +return false; } +return true; +} +EXPORT_SYMBOL_GPL (kvm_valid_efer); + +static int set_efer (struct kvm_vcpu *vcpu,u64 efer) +{ +u64 old_efer = vcpu->arch.efer; + +if (!kvm_valid_efer (vcpu, efer)) +return 1 ; + +if (is_paging (vcpu) + && (vcpu->arch.efer &EFER_LME ) != (efer &EFER_LME )) +return 1 ; + efer &= ~EFER_LMA ; efer |= vcpu->arch.efer &EFER_LMA ;Signature · 1 line
1.7.3.4
--
Gleb.