From 3760b1666518b8134dbbf15fa8e0dfa9ed21a4cc Mon Sep 17 00:00:00 2001 From: Eduardo Habkost <ehabkost@redhat.com> Date: Mon, 5 Oct 2009 14:32:45 -0300 Subject: [PATCH 2/6] KVM: When switching to a vm8086 task, load segments as 16-bit RH-Author: Eduardo Habkost <ehabkost@redhat.com> Message-id: <1253315933-28308-4-git-send-email-ehabkost@redhat.com> Patchwork-id: 3462 O-Subject: [RHEL-5.5 KVM PATCH 3/3] KVM: When switching to a vm8086 task, load segments as 16-bit Bugzilla: 517324 RH-Acked-by: Gleb Natapov <gleb@redhat.com> RH-Acked-by: Markus Armbruster <armbru@redhat.com> RH-Acked-by: Juan Quintela <quintela@redhat.com> Bugzilla: https://bugzilla.redhat.com/517324 RH-Upstream-status: backport-from-upstream From: Anthony Liguori <aliguori@us.ibm.com> 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> --- arch/x86/kvm/x86.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- 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 032feb0..c2c9d52 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3572,12 +3572,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; -- 1.6.3.rc4.29.g8146