KVM: Prevent guest fpu state from leaking into the host

The lazy fpu changes did not take into account that some vmexit handlers
can sleep. Move loading the guest state into the inner loop so that it
can be reloaded if necessary, and move loading the host state into
vmx_vcpu_put() so it can be performed whenever we relinquish the vcpu.

Signed-off-by: Avi Kivity <avi@qumranet.com>

+28 -9
+3
drivers/kvm/kvm.h
··· 304 304 char *host_fx_image; 305 305 char *guest_fx_image; 306 306 int fpu_active; 307 + int guest_fpu_loaded; 307 308 308 309 int mmio_needed; 309 310 int mmio_read_completed; ··· 509 508 void load_msrs(struct vmx_msr_entry *e, int n); 510 509 void save_msrs(struct vmx_msr_entry *e, int n); 511 510 void kvm_resched(struct kvm_vcpu *vcpu); 511 + void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); 512 + void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); 512 513 513 514 int kvm_read_guest(struct kvm_vcpu *vcpu, 514 515 gva_t addr,
+22
drivers/kvm/kvm_main.c
··· 253 253 } 254 254 EXPORT_SYMBOL_GPL(kvm_write_guest); 255 255 256 + void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) 257 + { 258 + if (!vcpu->fpu_active || vcpu->guest_fpu_loaded) 259 + return; 260 + 261 + vcpu->guest_fpu_loaded = 1; 262 + fx_save(vcpu->host_fx_image); 263 + fx_restore(vcpu->guest_fx_image); 264 + } 265 + EXPORT_SYMBOL_GPL(kvm_load_guest_fpu); 266 + 267 + void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) 268 + { 269 + if (!vcpu->guest_fpu_loaded) 270 + return; 271 + 272 + vcpu->guest_fpu_loaded = 0; 273 + fx_save(vcpu->guest_fx_image); 274 + fx_restore(vcpu->host_fx_image); 275 + } 276 + EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); 277 + 256 278 /* 257 279 * Switches to specified vcpu, until a matching vcpu_put() 258 280 */
+3 -9
drivers/kvm/vmx.c
··· 280 280 281 281 static void vmx_vcpu_put(struct kvm_vcpu *vcpu) 282 282 { 283 + kvm_put_guest_fpu(vcpu); 283 284 put_cpu(); 284 285 } 285 286 ··· 1848 1847 if (vcpu->guest_debug.enabled) 1849 1848 kvm_guest_debug_pre(vcpu); 1850 1849 1851 - if (vcpu->fpu_active) { 1852 - fx_save(vcpu->host_fx_image); 1853 - fx_restore(vcpu->guest_fx_image); 1854 - } 1850 + kvm_load_guest_fpu(vcpu); 1851 + 1855 1852 /* 1856 1853 * Loading guest fpu may have cleared host cr0.ts 1857 1854 */ ··· 2010 2011 load_msrs(vcpu->host_msrs, NR_BAD_MSRS); 2011 2012 } 2012 2013 #endif 2013 - 2014 - if (vcpu->fpu_active) { 2015 - fx_save(vcpu->guest_fx_image); 2016 - fx_restore(vcpu->host_fx_image); 2017 - } 2018 2014 2019 2015 vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; 2020 2016