forked from Minki/linux
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>
This commit is contained in:
parent
345dcaa8fd
commit
c0c7c04b87
@ -4101,12 +4101,19 @@ static int kvm_load_realmode_segment(struct kvm_vcpu *vcpu, u16 selector, int se
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
|
||||
{
|
||||
return (seg != VCPU_SREG_LDTR) &&
|
||||
(seg != VCPU_SREG_TR) &&
|
||||
(kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_VM);
|
||||
}
|
||||
|
||||
int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
|
||||
int type_bits, int seg)
|
||||
{
|
||||
struct kvm_segment kvm_seg;
|
||||
|
||||
if (!(vcpu->arch.cr0 & X86_CR0_PE))
|
||||
if (is_vm86_segment(vcpu, seg) || !(vcpu->arch.cr0 & X86_CR0_PE))
|
||||
return kvm_load_realmode_segment(vcpu, selector, seg);
|
||||
if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg))
|
||||
return 1;
|
||||
|
Loading…
Reference in New Issue
Block a user