Blob Blame History Raw
From 848115120ffa7b2287069fe6d23683304b9ffec1 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Fri, 12 Sep 2014 11:56:31 +0200
Subject: [PATCH 31/43] target-i386: get CPL from SS.DPL

Message-id: <1410522991-11612-2-git-send-email-pbonzini@redhat.com>
Patchwork-id: 61022
O-Subject: [RHEL 7.1 qemu-kvm PATCH] target-i386: get CPL from SS.DPL
Bugzilla: 1097363
RH-Acked-by: wei@redhat.com
RH-Acked-by: Radim Krcmar <rkrcmar@redhat.com>
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>

CS.RPL is not equal to the CPL in the few instructions between
setting CR0.PE and reloading CS.  We get this right in the common
case, because writes to CR0 do not modify the CPL, but it would
not be enough if an SMI comes exactly during that brief period.
Were this to happen, the RSM instruction would erroneously set
CPL to the low two bits of the real-mode selector; and if they are
not 00, the next instruction fetch cannot access the code segment
and causes a triple fault.

However, SS.DPL *is* always equal to the CPL.  In real processors
(AMD only) there is a weird case of SYSRET setting SS.DPL=SS.RPL
from the STAR register while forcing CPL=3, but we do not emulate
that.

Tested-by: Kevin O'Connor <kevin@koconnor.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 7125c937c97d9ec4a41b3cb6d1b3e805ec53e255)
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>

Conflicts:
	target-i386/cpu.h [only needed for TCG and has other dependencies]
---
 target-i386/kvm.c     | 2 +-
 target-i386/machine.c | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 6b250f5..65362ac 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1381,7 +1381,7 @@ static int kvm_get_sregs(X86CPU *cpu)
        HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
        HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)
 
-    hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
+    hflags = (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
     hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
     hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
                 (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 42b049b..87fd496 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -296,6 +296,14 @@ static int cpu_post_load(void *opaque, int version_id)
         env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK);
     }
 
+    /* Older versions of QEMU incorrectly used CS.DPL as the CPL when
+     * running under KVM.  This is wrong for conforming code segments.
+     * Luckily, in our implementation the CPL field of hflags is redundant
+     * and we can get the right value from the SS descriptor privilege level.
+     */
+    env->hflags &= ~HF_CPL_MASK;
+    env->hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
+
     /* XXX: restore FPU round state */
     env->fpstt = (env->fpus_vmstate >> 11) & 7;
     env->fpus = env->fpus_vmstate & ~0x3800;
-- 
1.8.3.1