aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86.c
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2009-03-30 09:03:24 -0400
committerAvi Kivity <avi@redhat.com>2009-06-10 04:48:37 -0400
commitb237ac37a149e8b56436fabf093532483bff13b0 (patch)
treec5b8070059f88085472ce5fefc11f41d62b53d6a /arch/x86/kvm/x86.c
parent8843419048e500f8f38df555bca1bf7948804b7f (diff)
KVM: Fix task switch back link handling.
Back link is written to a wrong TSS now. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r--arch/x86/kvm/x86.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 70ee81e50d99..adcf73871a9d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3717,7 +3717,6 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu,
3717 tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS); 3717 tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS);
3718 tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS); 3718 tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS);
3719 tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR); 3719 tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
3720 tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
3721} 3720}
3722 3721
3723static int load_state_from_tss32(struct kvm_vcpu *vcpu, 3722static int load_state_from_tss32(struct kvm_vcpu *vcpu,
@@ -3814,8 +3813,8 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu,
3814} 3813}
3815 3814
3816static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector, 3815static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
3817 u32 old_tss_base, 3816 u16 old_tss_sel, u32 old_tss_base,
3818 struct desc_struct *nseg_desc) 3817 struct desc_struct *nseg_desc)
3819{ 3818{
3820 struct tss_segment_16 tss_segment_16; 3819 struct tss_segment_16 tss_segment_16;
3821 int ret = 0; 3820 int ret = 0;
@@ -3834,6 +3833,16 @@ static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
3834 &tss_segment_16, sizeof tss_segment_16)) 3833 &tss_segment_16, sizeof tss_segment_16))
3835 goto out; 3834 goto out;
3836 3835
3836 if (old_tss_sel != 0xffff) {
3837 tss_segment_16.prev_task_link = old_tss_sel;
3838
3839 if (kvm_write_guest(vcpu->kvm,
3840 get_tss_base_addr(vcpu, nseg_desc),
3841 &tss_segment_16.prev_task_link,
3842 sizeof tss_segment_16.prev_task_link))
3843 goto out;
3844 }
3845
3837 if (load_state_from_tss16(vcpu, &tss_segment_16)) 3846 if (load_state_from_tss16(vcpu, &tss_segment_16))
3838 goto out; 3847 goto out;
3839 3848
@@ -3843,7 +3852,7 @@ out:
3843} 3852}
3844 3853
3845static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector, 3854static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
3846 u32 old_tss_base, 3855 u16 old_tss_sel, u32 old_tss_base,
3847 struct desc_struct *nseg_desc) 3856 struct desc_struct *nseg_desc)
3848{ 3857{
3849 struct tss_segment_32 tss_segment_32; 3858 struct tss_segment_32 tss_segment_32;
@@ -3863,6 +3872,16 @@ static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
3863 &tss_segment_32, sizeof tss_segment_32)) 3872 &tss_segment_32, sizeof tss_segment_32))
3864 goto out; 3873 goto out;
3865 3874
3875 if (old_tss_sel != 0xffff) {
3876 tss_segment_32.prev_task_link = old_tss_sel;
3877
3878 if (kvm_write_guest(vcpu->kvm,
3879 get_tss_base_addr(vcpu, nseg_desc),
3880 &tss_segment_32.prev_task_link,
3881 sizeof tss_segment_32.prev_task_link))
3882 goto out;
3883 }
3884
3866 if (load_state_from_tss32(vcpu, &tss_segment_32)) 3885 if (load_state_from_tss32(vcpu, &tss_segment_32))
3867 goto out; 3886 goto out;
3868 3887
@@ -3918,12 +3937,17 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
3918 3937
3919 kvm_x86_ops->skip_emulated_instruction(vcpu); 3938 kvm_x86_ops->skip_emulated_instruction(vcpu);
3920 3939
3940 /* set back link to prev task only if NT bit is set in eflags
3941 note that old_tss_sel is not used afetr this point */
3942 if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
3943 old_tss_sel = 0xffff;
3944
3921 if (nseg_desc.type & 8) 3945 if (nseg_desc.type & 8)
3922 ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_base, 3946 ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_sel,
3923 &nseg_desc); 3947 old_tss_base, &nseg_desc);
3924 else 3948 else
3925 ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_base, 3949 ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_sel,
3926 &nseg_desc); 3950 old_tss_base, &nseg_desc);
3927 3951
3928 if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) { 3952 if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
3929 u32 eflags = kvm_x86_ops->get_rflags(vcpu); 3953 u32 eflags = kvm_x86_ops->get_rflags(vcpu);