958e1b
From 848115120ffa7b2287069fe6d23683304b9ffec1 Mon Sep 17 00:00:00 2001
958e1b
From: Paolo Bonzini <pbonzini@redhat.com>
958e1b
Date: Fri, 12 Sep 2014 11:56:31 +0200
958e1b
Subject: [PATCH 31/43] target-i386: get CPL from SS.DPL
958e1b
958e1b
Message-id: <1410522991-11612-2-git-send-email-pbonzini@redhat.com>
958e1b
Patchwork-id: 61022
958e1b
O-Subject: [RHEL 7.1 qemu-kvm PATCH] target-i386: get CPL from SS.DPL
958e1b
Bugzilla: 1097363
958e1b
RH-Acked-by: wei@redhat.com
958e1b
RH-Acked-by: Radim Krcmar <rkrcmar@redhat.com>
958e1b
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
958e1b
958e1b
CS.RPL is not equal to the CPL in the few instructions between
958e1b
setting CR0.PE and reloading CS.  We get this right in the common
958e1b
case, because writes to CR0 do not modify the CPL, but it would
958e1b
not be enough if an SMI comes exactly during that brief period.
958e1b
Were this to happen, the RSM instruction would erroneously set
958e1b
CPL to the low two bits of the real-mode selector; and if they are
958e1b
not 00, the next instruction fetch cannot access the code segment
958e1b
and causes a triple fault.
958e1b
958e1b
However, SS.DPL *is* always equal to the CPL.  In real processors
958e1b
(AMD only) there is a weird case of SYSRET setting SS.DPL=SS.RPL
958e1b
from the STAR register while forcing CPL=3, but we do not emulate
958e1b
that.
958e1b
958e1b
Tested-by: Kevin O'Connor <kevin@koconnor.net>
958e1b
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
958e1b
(cherry picked from commit 7125c937c97d9ec4a41b3cb6d1b3e805ec53e255)
958e1b
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
958e1b
958e1b
Conflicts:
958e1b
	target-i386/cpu.h [only needed for TCG and has other dependencies]
958e1b
---
958e1b
 target-i386/kvm.c     | 2 +-
958e1b
 target-i386/machine.c | 8 ++++++++
958e1b
 2 files changed, 9 insertions(+), 1 deletion(-)
958e1b
958e1b
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
958e1b
index 6b250f5..65362ac 100644
958e1b
--- a/target-i386/kvm.c
958e1b
+++ b/target-i386/kvm.c
958e1b
@@ -1381,7 +1381,7 @@ static int kvm_get_sregs(X86CPU *cpu)
958e1b
        HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
958e1b
        HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)
958e1b
 
958e1b
-    hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
958e1b
+    hflags = (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
958e1b
     hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
958e1b
     hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
958e1b
                 (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
958e1b
diff --git a/target-i386/machine.c b/target-i386/machine.c
958e1b
index 42b049b..87fd496 100644
958e1b
--- a/target-i386/machine.c
958e1b
+++ b/target-i386/machine.c
958e1b
@@ -296,6 +296,14 @@ static int cpu_post_load(void *opaque, int version_id)
958e1b
         env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK);
958e1b
     }
958e1b
 
958e1b
+    /* Older versions of QEMU incorrectly used CS.DPL as the CPL when
958e1b
+     * running under KVM.  This is wrong for conforming code segments.
958e1b
+     * Luckily, in our implementation the CPL field of hflags is redundant
958e1b
+     * and we can get the right value from the SS descriptor privilege level.
958e1b
+     */
958e1b
+    env->hflags &= ~HF_CPL_MASK;
958e1b
+    env->hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
958e1b
+
958e1b
     /* XXX: restore FPU round state */
958e1b
     env->fpstt = (env->fpus_vmstate >> 11) & 7;
958e1b
     env->fpus = env->fpus_vmstate & ~0x3800;
958e1b
-- 
958e1b
1.8.3.1
958e1b