diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2009-08-11 16:57:59 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-09-10 03:46:44 -0400 |
commit | c0c7c04b874bf98a10d8e0c8322a5d3bc93536bc (patch) | |
tree | fd1fd86a26767fb8b59db3190f17b2c40a035ba4 /arch/x86/kvm | |
parent | 345dcaa8fde7fa70252d58c862bf41fd2149ca2c (diff) |
KVM: When switching to a vm8086 task, load segments as 16-bit
According to 16.2.5 in the SDM, eflags.vm in the tss is consulted before loading
and new segments. If eflags.vm == 1, then the segments are treated as 16-bit
segments. The LDTR and TR are not normally available in vm86 mode so if they
happen to somehow get loaded, they need to be treated as 32-bit segments.
This fixes an invalid vmentry failure in a custom OS that was happening after
a task switch into vm8086 mode. Since the segments were being mistakenly
treated as 32-bit, we loaded garbage state.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/x86.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 31bf98427f4e..1aa7e6d91d4f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4101,12 +4101,19 @@ static int kvm_load_realmode_segment(struct kvm_vcpu *vcpu, u16 selector, int se | |||
4101 | return 0; | 4101 | return 0; |
4102 | } | 4102 | } |
4103 | 4103 | ||
4104 | static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg) | ||
4105 | { | ||
4106 | return (seg != VCPU_SREG_LDTR) && | ||
4107 | (seg != VCPU_SREG_TR) && | ||
4108 | (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_VM); | ||
4109 | } | ||
4110 | |||
4104 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, | 4111 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, |
4105 | int type_bits, int seg) | 4112 | int type_bits, int seg) |
4106 | { | 4113 | { |
4107 | struct kvm_segment kvm_seg; | 4114 | struct kvm_segment kvm_seg; |
4108 | 4115 | ||
4109 | if (!(vcpu->arch.cr0 & X86_CR0_PE)) | 4116 | if (is_vm86_segment(vcpu, seg) || !(vcpu->arch.cr0 & X86_CR0_PE)) |
4110 | return kvm_load_realmode_segment(vcpu, selector, seg); | 4117 | return kvm_load_realmode_segment(vcpu, selector, seg); |
4111 | if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg)) | 4118 | if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg)) |
4112 | return 1; | 4119 | return 1; |