diff options
author | Avi Kivity <avi@qumranet.com> | 2007-09-20 12:27:28 +0200 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-09-20 12:27:28 +0200 |
commit | 5fdd2a196e7975d446fedf6973cbb20708f1359c (patch) | |
tree | 6bccfeb537002bf6bdacb5801db89a16e71d5a43 | |
parent | e8ebaa91f96407a90c1cb81708a87a25f40ba8ab (diff) |
KVM: Fix host oops due to guest changing eferkvm-42
If the guest changes efer from long mode with sce disabled to legacy mode,
then load_transition_efer() zeros vmx->host_state.guest_efer_loaded, but
the SCE-disabled efer remains in effect. So when we return to the host,
we disable SCE and syscalls no longer work.
Fix by (a) not touching vmx->host_state.guest_efer_loaded if we're not
setting it, and instead (b) clearing it explicitly when we switch back.
Also switch back when the guest writes to efer so we start from a clean
slate.
Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r-- | drivers/kvm/vmx.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 7f168ad4b7a3..c342981d5ad7 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -354,17 +354,24 @@ static void load_transition_efer(struct vcpu_vmx *vmx) if (guest_efer & EFER_LMA) ignore_bits &= ~(u64)EFER_SCE; #endif - vmx->host_state.guest_efer_loaded - = (guest_efer & ~ignore_bits) != (host_efer & ~ignore_bits); - - if (!vmx->host_state.guest_efer_loaded) + if ((guest_efer & ~ignore_bits) == (host_efer & ~ignore_bits)) return; + + vmx->host_state.guest_efer_loaded = 1; guest_efer &= ~ignore_bits; guest_efer |= host_efer & ignore_bits; wrmsrl(MSR_EFER, guest_efer); vmx->vcpu.stat.efer_reload++; } +static void reload_host_efer(struct vcpu_vmx *vmx) +{ + if (vmx->host_state.guest_efer_loaded) { + vmx->host_state.guest_efer_loaded = 0; + load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1); + } +} + static void vmx_save_host_state(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -439,8 +446,7 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx) reload_tss(); save_msrs(vmx->guest_msrs, vmx->save_nmsrs); load_msrs(vmx->host_msrs, vmx->save_nmsrs); - if (vmx->host_state.guest_efer_loaded) - load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1); + reload_host_efer(vmx); } /* @@ -728,8 +734,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) #ifdef CONFIG_X86_64 case MSR_EFER: ret = kvm_set_msr_common(vcpu, msr_index, data); - if (vmx->host_state.loaded) + if (vmx->host_state.loaded) { + reload_host_efer(vmx); load_transition_efer(vmx); + } break; case MSR_FS_BASE: vmcs_writel(GUEST_FS_BASE, data); |