qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: gleb@kernel.org, jan.kiszka@siemens.com, avi.kivity@gmail.com,
	kvm@vger.kernel.org
Subject: Re: [Qemu-devel] [PATCH] KVM: x86: get/set CPL separately from CS
Date: Wed, 14 May 2014 10:44:13 +0200	[thread overview]
Message-ID: <53732CDD.5000507@redhat.com> (raw)
In-Reply-To: <1399993456-11723-1-git-send-email-pbonzini@redhat.com>

Il 13/05/2014 17:04, Paolo Bonzini ha scritto:
> KVM used to assume that CS.RPL could always be used as the CPL
> value when KVM_SET_SREGS is called.  QEMU could call KVM_GET_SREGS
> and the KVM_SET_SREGS exactly after CR0.PE has been set to 1,
> but before the long jump that reloads CS.  Then, KVM would reset
> the CPL to bits 0-1 of CS (aka CS.RPL).
>
> To avoid this change, KVM introduced a capability that repurposes
> a padding byte in struct kvm_segment as the CPL.  Detect this
> capability and, if it is present, enable it; then get/set the CPL
> together with CS.
>
> The CPL is already migrated separately, as part of hflags.  However,
> the migrated value might be wrong and we need to fix it up in
> the post_load callback.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

This patch is also obsolete, using SS.DPL is a simpler solution.

> ---
> 	Matching the kernel patches just posted, for now without
> 	a separate patch to update the kernel headers.
>
>  linux-headers/asm-x86/kvm.h |  5 ++++-
>  linux-headers/linux/kvm.h   |  3 +++
>  target-i386/kvm.c           | 25 ++++++++++++++++++++++---
>  target-i386/machine.c       | 18 +++++++++++++++++-
>  4 files changed, 46 insertions(+), 5 deletions(-)
>
> diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
> index d3a8778..855b3c7 100644
> --- a/linux-headers/asm-x86/kvm.h
> +++ b/linux-headers/asm-x86/kvm.h
> @@ -126,7 +126,10 @@ struct kvm_segment {
>  	__u8  type;
>  	__u8  present, dpl, db, s, l, g, avl;
>  	__u8  unusable;
> -	__u8  padding;
> +	union {
> +		__u8  cpl;
> +		__u8  padding;
> +	};
>  };
>
>  struct kvm_dtable {
> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> index b278ab3..57aff89 100644
> --- a/linux-headers/linux/kvm.h
> +++ b/linux-headers/linux/kvm.h
> @@ -743,6 +743,9 @@ struct kvm_ppc_smmu_info {
>  #define KVM_CAP_IOAPIC_POLARITY_IGNORED 97
>  #define KVM_CAP_ENABLE_CAP_VM 98
>  #define KVM_CAP_S390_IRQCHIP 99
> +#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
> +#define KVM_CAP_VM_ATTRIBUTES 101
> +#define KVM_CAP_X86_CPL 102
>
>  #ifdef KVM_CAP_IRQ_ROUTING
>
> diff --git a/target-i386/kvm.c b/target-i386/kvm.c
> index 0d894ef..f78e7af 100644
> --- a/target-i386/kvm.c
> +++ b/target-i386/kvm.c
> @@ -722,6 +722,15 @@ int kvm_arch_init_vcpu(CPUState *cs)
>          env->kvm_xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave));
>      }
>
> +    r = kvm_check_extension(cs->kvm_state, KVM_CAP_X86_CPL);
> +    if (r) {
> +        r = kvm_vm_enable_cap(cs->kvm_state, KVM_CAP_X86_CPL, 0);
> +        if (r < 0) {
> +            fprintf(stderr, "KVM_ENABLE_CAP failed\n");
> +            return r;
> +        }
> +    }
> +
>      return 0;
>  }
>
> @@ -1068,6 +1077,7 @@ static int kvm_put_xcrs(X86CPU *cpu)
>  static int kvm_put_sregs(X86CPU *cpu)
>  {
>      CPUX86State *env = &cpu->env;
> +    CPUState *cs = CPU(cpu);
>      struct kvm_sregs sregs;
>
>      memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap));
> @@ -1112,7 +1122,11 @@ static int kvm_put_sregs(X86CPU *cpu)
>
>      sregs.efer = env->efer;
>
> -    return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs);
> +    if (kvm_check_extension(cs->kvm_state, KVM_CAP_X86_CPL)) {
> +        sregs.cs.cpl = env->hflags & HF_CPL_MASK;
> +    }
> +
> +    return kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs);
>  }
>
>  static void kvm_msr_entry_set(struct kvm_msr_entry *entry,
> @@ -1380,11 +1394,12 @@ static int kvm_get_xcrs(X86CPU *cpu)
>  static int kvm_get_sregs(X86CPU *cpu)
>  {
>      CPUX86State *env = &cpu->env;
> +    CPUState *cs = CPU(cpu);
>      struct kvm_sregs sregs;
>      uint32_t hflags;
>      int bit, i, ret;
>
> -    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS, &sregs);
> +    ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -1430,7 +1445,11 @@ 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;
> +    if (kvm_check_extension(cs->kvm_state, KVM_CAP_X86_CPL)) {
> +        hflags = sregs.cs.cpl;
> +    } else {
> +        hflags = (env->segs[R_CS].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 168cab6..328856f 100644
> --- a/target-i386/machine.c
> +++ b/target-i386/machine.c
> @@ -284,7 +284,6 @@ static void cpu_pre_save(void *opaque)
>          env->segs[R_GS].flags &= ~(env->segs[R_GS].flags & DESC_DPL_MASK);
>          env->segs[R_SS].flags &= ~(env->segs[R_SS].flags & DESC_DPL_MASK);
>      }
> -
>  }
>
>  static int cpu_post_load(void *opaque, int version_id)
> @@ -312,6 +311,23 @@ 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 also blindly stored the DPL of CS into
> +     * hflags.  Since we will use hflags to pass the CPL to KVM, fix
> +     * it up just in case it was wrong.
> +     *
> +     * There is still a small window where migration is broken, between
> +     * the time CR0.PE=1 and the subsequent long jump that reloads CS.
> +     * This cannot be fixed.
> +     */
> +    if (!(env->cr[0] & CR0_PE_MASK)) {
> +        /* Force CPL=0 for real mode.  */
> +        env->hflags &= ~HF_CPL_MASK;
> +    } else if ((env->eflags & VM_MASK) &&
> +               !(env->segs[R_CS].flags & DESC_L_MASK)) {
> +        /* Force CPL=3 for VM86 mode.  */
> +        env->hflags |= HF_CPL_MASK;
> +    }
> +
>      /* XXX: restore FPU round state */
>      env->fpstt = (env->fpus_vmstate >> 11) & 7;
>      env->fpus = env->fpus_vmstate & ~0x3800;
>

      reply	other threads:[~2014-05-14  8:44 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-13 15:04 [Qemu-devel] [PATCH] KVM: x86: get/set CPL separately from CS Paolo Bonzini
2014-05-14  8:44 ` Paolo Bonzini [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=53732CDD.5000507@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=avi.kivity@gmail.com \
    --cc=gleb@kernel.org \
    --cc=jan.kiszka@siemens.com \
    --cc=kvm@vger.kernel.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).