KVM: x86: fix maintenance of guest/host xcr0 state
** Untested **.
Emulation of xcr0 writes zero guest_xcr0_loaded variable so that subsequent VM-entry reloads CPU's xcr0 with guests xcr0 value.
However, this is incorrect because guest_xcr0_loaded variable is read to decide whether to reload hosts xcr0.
In case the vcpu thread is scheduled out after the guest_xcr0_loaded = 0 assignment, and scheduler decides to preload FPU:
switch_to
{
__switch_to
__math_state_restore
restore_fpu_checking
fpu_restore_checking
if (use_xsave())
fpu_xrstor_checking
xrstor64 with CPU's xcr0 == guests xcr0Fix by properly restoring hosts xcr0 during emulation of xcr0 writes.
arch/x86/kvm/x86.c +20 -20
@@ -555,6 +555,25 @@ void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) }EXPORT_SYMBOL_GPL (kvm_lmsw); +static void kvm_load_guest_xcr0 (struct kvm_vcpu *vcpu) +{ +if (kvm_read_cr4_bits (vcpu,X86_CR4_OSXSAVE ) && + !vcpu->guest_xcr0_loaded) { +/* kvm_set_xcr() also depends on this */ +xsetbv (XCR_XFEATURE_ENABLED_MASK , vcpu->arch.xcr0); + vcpu->guest_xcr0_loaded =1 ; + } +} + +static void kvm_put_guest_xcr0 (struct kvm_vcpu *vcpu) +{ +if (vcpu->guest_xcr0_loaded) { +if (vcpu->arch.xcr0 != host_xcr0) +xsetbv (XCR_XFEATURE_ENABLED_MASK , host_xcr0); + vcpu->guest_xcr0_loaded =0 ; + } +} +int __kvm_set_xcr (struct kvm_vcpu *vcpu,u32 index,u64 xcr) {u64 xcr0;
@@ -571,8 +590,8 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)return 1 ;if (xcr0 & ~host_xcr0)return 1 ; +kvm_put_guest_xcr0 (vcpu); vcpu->arch.xcr0 = xcr0; - vcpu->guest_xcr0_loaded =0 ;return 0 ; }
@@ -5600,25 +5619,6 @@ static void inject_pending_event(struct kvm_vcpu *vcpu) } } -static void kvm_load_guest_xcr0 (struct kvm_vcpu *vcpu) -{ -if (kvm_read_cr4_bits (vcpu,X86_CR4_OSXSAVE ) && - !vcpu->guest_xcr0_loaded) { -/* kvm_set_xcr() also depends on this */ -xsetbv (XCR_XFEATURE_ENABLED_MASK , vcpu->arch.xcr0); - vcpu->guest_xcr0_loaded =1 ; - } -} - -static void kvm_put_guest_xcr0 (struct kvm_vcpu *vcpu) -{ -if (vcpu->guest_xcr0_loaded) { -if (vcpu->arch.xcr0 != host_xcr0) -xsetbv (XCR_XFEATURE_ENABLED_MASK , host_xcr0); - vcpu->guest_xcr0_loaded =0 ; - } -} -static void process_nmi (struct kvm_vcpu *vcpu) {unsigned limit =2 ;
Il 16/04/2013 04:30, Marcelo Tosatti ha scritto:
Quoted 47 lines
** Untested **.
Emulation of xcr0 writes zero
guest_xcr0_loadedvariable so that subsequent VM-entry reloads CPU's xcr0 with guests xcr0 value.However, this is incorrect because
guest_xcr0_loadedvariable is read to decide whether to reload hosts xcr0.In case the vcpu thread is scheduled out after the
guest_xcr0_loaded= 0 assignment, and scheduler decides to preload FPU:
switch_to
{
__switch_to__math_state_restore restore_fpu_checking fpu_restore_checking if (use_xsave()) fpu_xrstor_checking xrstor64 with CPU's xcr0 == guests xcr0Fix by properly restoring hosts xcr0 during emulation of xcr0 writes.
Analyzed-by Ulrich Obergfell <[email protected]>Signed-off-by Marcelo Tosatti <[email protected]>arch/x86/kvm/x86.c +12
-0@@ -555,6 +555,25 @@ void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) }EXPORT_SYMBOL_GPL (kvm_lmsw); +static void kvm_load_guest_xcr0 (struct kvm_vcpu *vcpu) +{ +if (kvm_read_cr4_bits (vcpu,X86_CR4_OSXSAVE ) && + !vcpu->guest_xcr0_loaded) { +/* kvm_set_xcr() also depends on this */ +xsetbv (XCR_XFEATURE_ENABLED_MASK , vcpu->arch.xcr0); + vcpu->guest_xcr0_loaded =1 ; + } +} + +static void kvm_put_guest_xcr0 (struct kvm_vcpu *vcpu) +{
arch/x86/kvm/x86.c void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) · line 579
Quoted 10 lines
arch/x86/kvm/x86.c +7
-0+if (vcpu->guest_xcr0_loaded) { +if (vcpu->arch.xcr0 != host_xcr0) +xsetbv (XCR_XFEATURE_ENABLED_MASK , host_xcr0); + vcpu->guest_xcr0_loaded =0 ; + } +} +int __kvm_set_xcr (struct kvm_vcpu *vcpu,u32 index,u64 xcr) {u64 xcr0;
This is just code movement...
arch/x86/kvm/x86.c int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr) · line 597
Quoted 10 lines
arch/x86/kvm/x86.c +1
-1@@ -571,8 +590,8 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)return 1 ;if (xcr0 & ~host_xcr0)return 1 ; +kvm_put_guest_xcr0 (vcpu); vcpu->arch.xcr0 = xcr0; - vcpu->guest_xcr0_loaded =0 ;return 0 ; }
... and this is the bulk of the fix: never set guest_xcr0_loaded, always go through kvm_load/put_guest_xcr0.
Pending test,
Paolo
Quoted 27 lines
arch/x86/kvm/x86.c +0
-19@@ -5600,25 +5619,6 @@ static void inject_pending_event(struct kvm_vcpu *vcpu) } } -static void kvm_load_guest_xcr0 (struct kvm_vcpu *vcpu) -{ -if (kvm_read_cr4_bits (vcpu,X86_CR4_OSXSAVE ) && - !vcpu->guest_xcr0_loaded) { -/* kvm_set_xcr() also depends on this */ -xsetbv (XCR_XFEATURE_ENABLED_MASK , vcpu->arch.xcr0); - vcpu->guest_xcr0_loaded =1 ; - } -} - -static void kvm_put_guest_xcr0 (struct kvm_vcpu *vcpu) -{ -if (vcpu->guest_xcr0_loaded) { -if (vcpu->arch.xcr0 != host_xcr0) -xsetbv (XCR_XFEATURE_ENABLED_MASK , host_xcr0); - vcpu->guest_xcr0_loaded =0 ; - } -} -static void process_nmi (struct kvm_vcpu *vcpu) {unsigned limit =2 ;
Gleb Natapov
Reviewed-byQuoted 22 lines · Marcelo Tosatti
** Untested **.
Emulation of xcr0 writes zero
guest_xcr0_loadedvariable so that subsequent VM-entry reloads CPU's xcr0 with guests xcr0 value.However, this is incorrect because
guest_xcr0_loadedvariable is read to decide whether to reload hosts xcr0.In case the vcpu thread is scheduled out after the
guest_xcr0_loaded= 0 assignment, and scheduler decides to preload FPU:
switch_to
{
__switch_to__math_state_restore restore_fpu_checking fpu_restore_checking if (use_xsave()) fpu_xrstor_checking xrstor64 with CPU's xcr0 == guests xcr0
Quoted 5 lines
Fix by properly restoring hosts xcr0 during emulation of xcr0 writes.
Analyzed-by Ulrich Obergfell <[email protected]>Signed-off-by Marcelo Tosatti <[email protected]>
Quoted 56 lines
arch/x86/kvm/x86.c +20
-13@@ -555,6 +555,25 @@ void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) }EXPORT_SYMBOL_GPL (kvm_lmsw); +static void kvm_load_guest_xcr0 (struct kvm_vcpu *vcpu) +{ +if (kvm_read_cr4_bits (vcpu,X86_CR4_OSXSAVE ) && + !vcpu->guest_xcr0_loaded) { +/* kvm_set_xcr() also depends on this */ +xsetbv (XCR_XFEATURE_ENABLED_MASK , vcpu->arch.xcr0); + vcpu->guest_xcr0_loaded =1 ; + } +} + +static void kvm_put_guest_xcr0 (struct kvm_vcpu *vcpu) +{ +if (vcpu->guest_xcr0_loaded) { +if (vcpu->arch.xcr0 != host_xcr0) +xsetbv (XCR_XFEATURE_ENABLED_MASK , host_xcr0); + vcpu->guest_xcr0_loaded =0 ; + } +} +int __kvm_set_xcr (struct kvm_vcpu *vcpu,u32 index,u64 xcr) {u64 xcr0;@@ -571,8 +590,8 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)return 1 ;if (xcr0 & ~host_xcr0)return 1 ; +kvm_put_guest_xcr0 (vcpu); vcpu->arch.xcr0 = xcr0; - vcpu->guest_xcr0_loaded =0 ;return 0 ; }@@ -5600,25 +5619,6 @@ static void inject_pending_event(struct kvm_vcpu *vcpu) } } -static void kvm_load_guest_xcr0 (struct kvm_vcpu *vcpu) -{ -if (kvm_read_cr4_bits (vcpu,X86_CR4_OSXSAVE ) && - !vcpu->guest_xcr0_loaded) { -/* kvm_set_xcr() also depends on this */ -xsetbv (XCR_XFEATURE_ENABLED_MASK , vcpu->arch.xcr0); - vcpu->guest_xcr0_loaded =1 ; - } -} - -static void kvm_put_guest_xcr0 (struct kvm_vcpu *vcpu) -{
arch/x86/kvm/x86.c static void inject_pending_event(struct kvm_vcpu *vcpu) · line 5624
Quoted 10 lines
arch/x86/kvm/x86.c +0
-7-if (vcpu->guest_xcr0_loaded) { -if (vcpu->arch.xcr0 != host_xcr0) -xsetbv (XCR_XFEATURE_ENABLED_MASK , host_xcr0); - vcpu->guest_xcr0_loaded =0 ; - } -} -static void process_nmi (struct kvm_vcpu *vcpu) {unsigned limit =2 ;
--
Gleb.
Gleb Natapov
AppliedQuoted 22 lines · Marcelo Tosatti
** Untested **.
Emulation of xcr0 writes zero
guest_xcr0_loadedvariable so that subsequent VM-entry reloads CPU's xcr0 with guests xcr0 value.However, this is incorrect because
guest_xcr0_loadedvariable is read to decide whether to reload hosts xcr0.In case the vcpu thread is scheduled out after the
guest_xcr0_loaded= 0 assignment, and scheduler decides to preload FPU:
switch_to
{
__switch_to__math_state_restore restore_fpu_checking fpu_restore_checking if (use_xsave()) fpu_xrstor_checking xrstor64 with CPU's xcr0 == guests xcr0
Quoted 5 lines
Fix by properly restoring hosts xcr0 during emulation of xcr0 writes.
Analyzed-by Ulrich Obergfell <[email protected]>Signed-off-by Marcelo Tosatti <[email protected]>
Applied, thanks.
Quoted 56 lines
arch/x86/kvm/x86.c +20
-13@@ -555,6 +555,25 @@ void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) }EXPORT_SYMBOL_GPL (kvm_lmsw); +static void kvm_load_guest_xcr0 (struct kvm_vcpu *vcpu) +{ +if (kvm_read_cr4_bits (vcpu,X86_CR4_OSXSAVE ) && + !vcpu->guest_xcr0_loaded) { +/* kvm_set_xcr() also depends on this */ +xsetbv (XCR_XFEATURE_ENABLED_MASK , vcpu->arch.xcr0); + vcpu->guest_xcr0_loaded =1 ; + } +} + +static void kvm_put_guest_xcr0 (struct kvm_vcpu *vcpu) +{ +if (vcpu->guest_xcr0_loaded) { +if (vcpu->arch.xcr0 != host_xcr0) +xsetbv (XCR_XFEATURE_ENABLED_MASK , host_xcr0); + vcpu->guest_xcr0_loaded =0 ; + } +} +int __kvm_set_xcr (struct kvm_vcpu *vcpu,u32 index,u64 xcr) {u64 xcr0;@@ -571,8 +590,8 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)return 1 ;if (xcr0 & ~host_xcr0)return 1 ; +kvm_put_guest_xcr0 (vcpu); vcpu->arch.xcr0 = xcr0; - vcpu->guest_xcr0_loaded =0 ;return 0 ; }@@ -5600,25 +5619,6 @@ static void inject_pending_event(struct kvm_vcpu *vcpu) } } -static void kvm_load_guest_xcr0 (struct kvm_vcpu *vcpu) -{ -if (kvm_read_cr4_bits (vcpu,X86_CR4_OSXSAVE ) && - !vcpu->guest_xcr0_loaded) { -/* kvm_set_xcr() also depends on this */ -xsetbv (XCR_XFEATURE_ENABLED_MASK , vcpu->arch.xcr0); - vcpu->guest_xcr0_loaded =1 ; - } -} - -static void kvm_put_guest_xcr0 (struct kvm_vcpu *vcpu) -{
arch/x86/kvm/x86.c static void inject_pending_event(struct kvm_vcpu *vcpu) · line 5624
Quoted 10 lines
arch/x86/kvm/x86.c +0
-7-if (vcpu->guest_xcr0_loaded) { -if (vcpu->arch.xcr0 != host_xcr0) -xsetbv (XCR_XFEATURE_ENABLED_MASK , host_xcr0); - vcpu->guest_xcr0_loaded =0 ; - } -} -static void process_nmi (struct kvm_vcpu *vcpu) {unsigned limit =2 ;
--
Gleb.