diff options
author | Gleb Natapov <gleb@redhat.com> | 2009-03-30 09:03:24 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:37 -0400 |
commit | b237ac37a149e8b56436fabf093532483bff13b0 (patch) | |
tree | c5b8070059f88085472ce5fefc11f41d62b53d6a /arch/x86/kvm/x86.c | |
parent | 8843419048e500f8f38df555bca1bf7948804b7f (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.c | 40 |
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 | ||
3723 | static int load_state_from_tss32(struct kvm_vcpu *vcpu, | 3722 | static 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 | ||
3816 | static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector, | 3815 | static 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 | ||
3845 | static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector, | 3854 | static 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); |