public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] KVM: x86 emulator: Fix segment loading in VM86
@ 2013-04-11 12:06 Kevin Wolf
  2013-04-11 12:53 ` Gleb Natapov
  0 siblings, 1 reply; 2+ messages in thread
From: Kevin Wolf @ 2013-04-11 12:06 UTC (permalink / raw)
  To: kvm; +Cc: kwolf, gleb, mtosatti

This fixes a regression introduced in commit 03ebebeb1 ("KVM: x86
emulator: Leave segment limit and attributs alone in real mode").

The mentioned commit changed the segment descriptors for both real mode
and VM86 to only update the segment base instead of creating a
completely new descriptor with limit 0xffff so that unreal mode keeps
working across a segment register reload.

This leads to an invalid segment descriptor in the eyes of VMX, which
seems to be okay for real mode because KVM will fix it up before the
next VM entry or emulate the state, but it doesn't do this if the guest
is in VM86, so we end up with:

  KVM: entry failed, hardware error 0x80000021

Fix this by effectively reverting commit 03ebebeb1 for VM86 and leaving
it only in place for real mode, which is where it's really needed.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 arch/x86/kvm/emulate.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index a335cc6..069d799 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1578,12 +1578,21 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
 
 	memset(&seg_desc, 0, sizeof seg_desc);
 
-	if ((seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86)
-	    || ctxt->mode == X86EMUL_MODE_REAL) {
-		/* set real mode segment descriptor */
+	if (ctxt->mode == X86EMUL_MODE_REAL) {
+		/* set real mode segment descriptor (keep limit etc. for
+		 * unreal mode) */
 		ctxt->ops->get_segment(ctxt, &dummy, &seg_desc, NULL, seg);
 		set_desc_base(&seg_desc, selector << 4);
 		goto load;
+	} else if (seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86) {
+		/* VM86 needs a clean new segment descriptor */
+		set_desc_base(&seg_desc, selector << 4);
+		set_desc_limit(&seg_desc, 0xffff);
+		seg_desc.type = 3;
+		seg_desc.p = 1;
+		seg_desc.s = 1;
+		seg_desc.dpl = 3;
+		goto load;
 	}
 
 	rpl = selector & 3;
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] KVM: x86 emulator: Fix segment loading in VM86
  2013-04-11 12:06 [PATCH] KVM: x86 emulator: Fix segment loading in VM86 Kevin Wolf
@ 2013-04-11 12:53 ` Gleb Natapov
  0 siblings, 0 replies; 2+ messages in thread
From: Gleb Natapov @ 2013-04-11 12:53 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: kvm, mtosatti

On Thu, Apr 11, 2013 at 02:06:03PM +0200, Kevin Wolf wrote:
> This fixes a regression introduced in commit 03ebebeb1 ("KVM: x86
> emulator: Leave segment limit and attributs alone in real mode").
> 
> The mentioned commit changed the segment descriptors for both real mode
> and VM86 to only update the segment base instead of creating a
> completely new descriptor with limit 0xffff so that unreal mode keeps
> working across a segment register reload.
> 
> This leads to an invalid segment descriptor in the eyes of VMX, which
> seems to be okay for real mode because KVM will fix it up before the
> next VM entry or emulate the state, but it doesn't do this if the guest
> is in VM86, so we end up with:
> 
>   KVM: entry failed, hardware error 0x80000021
> 
> Fix this by effectively reverting commit 03ebebeb1 for VM86 and leaving
> it only in place for real mode, which is where it's really needed.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Applied, thanks.

> ---
>  arch/x86/kvm/emulate.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index a335cc6..069d799 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -1578,12 +1578,21 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
>  
>  	memset(&seg_desc, 0, sizeof seg_desc);
>  
> -	if ((seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86)
> -	    || ctxt->mode == X86EMUL_MODE_REAL) {
> -		/* set real mode segment descriptor */
> +	if (ctxt->mode == X86EMUL_MODE_REAL) {
> +		/* set real mode segment descriptor (keep limit etc. for
> +		 * unreal mode) */
>  		ctxt->ops->get_segment(ctxt, &dummy, &seg_desc, NULL, seg);
>  		set_desc_base(&seg_desc, selector << 4);
>  		goto load;
> +	} else if (seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86) {
> +		/* VM86 needs a clean new segment descriptor */
> +		set_desc_base(&seg_desc, selector << 4);
> +		set_desc_limit(&seg_desc, 0xffff);
> +		seg_desc.type = 3;
> +		seg_desc.p = 1;
> +		seg_desc.s = 1;
> +		seg_desc.dpl = 3;
> +		goto load;
>  	}
>  
>  	rpl = selector & 3;
> -- 
> 1.8.1.4

--
			Gleb.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2013-04-11 12:53 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-11 12:06 [PATCH] KVM: x86 emulator: Fix segment loading in VM86 Kevin Wolf
2013-04-11 12:53 ` Gleb Natapov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox