| 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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |