Skip to contentSkip to conversation

KVM: VMX: fix incorrect cached cpl value with real/v8086 modes

PATCH Marcelo Tosatti 2 participants 14 messages Dec 19, 2012 – Jan 8, 2013 1 message not in the archive

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +7 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-	if (!is_protmode(vcpu))
-		return 0;
-
-	if (!is_long_mode(vcpu)
-	    && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086 */
-		return 3;
-
 	return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;
 }
 
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+	if (!is_protmode(vcpu))
+		return 0;
+
+	if (!is_long_mode(vcpu)
+	    && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086 */
+		return 3;
+
 	/*
 	 * If we enter real mode with cs.sel & 3 != 0, the normal CPL calculations
 	 * fail; use the cache instead.

A message that is not in the archive (sent off-list or not yet received): CAEbWair0awmpB9QXFGXJmooSsHg3B6P3uZrmLcyzs=T70TS7VA@mail.gmail.com

#2 lore raw
Quoted 44 lines · Avi Kivity
Quoted 42 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +0 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu
 *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-       if (!is_protmode(vcpu))
-               return 0;
-
-       if (!is_long_mode(vcpu)
-           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
-               return 3;
-
        return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;

}

arch/x86/kvm/vmx.c +7 -0
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (!is_protmode(vcpu))
+               return 0;
+
+       if (!is_long_mode(vcpu)
+           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
+               return 3;
+
        /*
Quoted 8 lines
Quoted 4 lines
arch/x86/kvm/vmx.c +0 -0
         * If we enter real mode with cs.sel & 3 != 0, the normal CPL

calculations
* fail; use the cache instead.

This undoes the cache, now every vmx_get_cpl() in protected mode has to VMREAD(GUEST_RFLAGS).

True. Marcelo what failure do you see without the patch?

--
Gleb.

#3 lore raw
Quoted 53 lines · Gleb Natapov
Quoted 44 lines · Avi Kivity
Quoted 42 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +0 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu
 *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-       if (!is_protmode(vcpu))
-               return 0;
-
-       if (!is_long_mode(vcpu)
-           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
-               return 3;
-
        return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;

}

arch/x86/kvm/vmx.c +7 -0
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (!is_protmode(vcpu))
+               return 0;
+
+       if (!is_long_mode(vcpu)
+           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
+               return 3;
+
        /*
Quoted 8 lines
Quoted 4 lines
arch/x86/kvm/vmx.c +0 -0
         * If we enter real mode with cs.sel & 3 != 0, the normal CPL

calculations
* fail; use the cache instead.

This undoes the cache, now every vmx_get_cpl() in protected mode has to VMREAD(GUEST_RFLAGS).

Quoted 4 lines

True. Marcelo what failure do you see without the patch?

--
Gleb.

On transition _to_ real mode, linearize fails due to CPL checks (FreeBSD). I'll resend the patch with use of cache for VMREAD(GUEST_RFLAGS), which is already implemented.

#4 lore raw
Quoted 54 lines · Marcelo Tosatti
Quoted 53 lines · Gleb Natapov
Quoted 52 lines · Avi Kivity
Quoted 43 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +0 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu
 *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-       if (!is_protmode(vcpu))
-               return 0;
-
-       if (!is_long_mode(vcpu)
-           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
-               return 3;
-
        return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;

}

arch/x86/kvm/vmx.c +7 -0
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (!is_protmode(vcpu))
+               return 0;
+
+       if (!is_long_mode(vcpu)
+           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
+               return 3;
+
        /*
         * If we enter real mode with cs.sel & 3 != 0, the normal CPL
Quoted 3 lines

calculations
* fail; use the cache instead.

This undoes the cache, now every vmx_get_cpl() in protected mode has to VMREAD(GUEST_RFLAGS).

Quoted 8 lines
Quoted 4 lines

True. Marcelo what failure do you see without the patch?

--
Gleb.

On transition _to_ real mode, linearize fails due to CPL checks (FreeBSD). I'll resend the patch with use of cache for VMREAD(GUEST_RFLAGS), which is already implemented.

I am curious does it still fails with all my vmx patches applied too? The question is how does it happen that we enter real mode while cache is set to 3. It should never be 3 during boot since boot process never enters the userspace.

--
Gleb.

#5 lore raw
Quoted 57 lines · Gleb Natapov
Quoted 56 lines · Marcelo Tosatti
Quoted 55 lines · Gleb Natapov
Quoted 44 lines · Avi Kivity
Quoted 42 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +0 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu
 *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-       if (!is_protmode(vcpu))
-               return 0;
-
-       if (!is_long_mode(vcpu)
-           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
-               return 3;
-
        return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;

}

arch/x86/kvm/vmx.c +7 -0
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (!is_protmode(vcpu))
+               return 0;
+
+       if (!is_long_mode(vcpu)
+           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
+               return 3;
+
        /*
Quoted 8 lines
Quoted 4 lines
arch/x86/kvm/vmx.c +0 -0
         * If we enter real mode with cs.sel & 3 != 0, the normal CPL

calculations
* fail; use the cache instead.

This undoes the cache, now every vmx_get_cpl() in protected mode has to VMREAD(GUEST_RFLAGS).

True. Marcelo what failure do you see without the patch?

Quoted 7 lines
Quoted 6 lines
Quoted 2 lines

--
Gleb.

On transition _to_ real mode, linearize fails due to CPL checks (FreeBSD). I'll resend the patch with use of cache for VMREAD(GUEST_RFLAGS), which is already implemented.

I am curious does it still fails with all my vmx patches applied too?

Yes.

Quoted 3 lines

The question is how does it happen that we enter real mode while cache is set to 3. It should never be 3 during boot since boot process never enters the userspace.

Its transition _to_ real mode (from protected).

#6 lore raw
Quoted 61 lines · Marcelo Tosatti
Quoted 60 lines · Gleb Natapov
Quoted 59 lines · Marcelo Tosatti
Quoted 57 lines · Gleb Natapov
Quoted 44 lines · Avi Kivity
Quoted 42 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +0 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu
 *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-       if (!is_protmode(vcpu))
-               return 0;
-
-       if (!is_long_mode(vcpu)
-           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
-               return 3;
-
        return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;

}

arch/x86/kvm/vmx.c +7 -0
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (!is_protmode(vcpu))
+               return 0;
+
+       if (!is_long_mode(vcpu)
+           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
+               return 3;
+
        /*
Quoted 8 lines
Quoted 4 lines
arch/x86/kvm/vmx.c +0 -0
         * If we enter real mode with cs.sel & 3 != 0, the normal CPL

calculations
* fail; use the cache instead.

This undoes the cache, now every vmx_get_cpl() in protected mode has to VMREAD(GUEST_RFLAGS).

True. Marcelo what failure do you see without the patch?

--
Gleb.

Quoted 7 lines
Quoted 4 lines
Quoted 3 lines

On transition _to_ real mode, linearize fails due to CPL checks (FreeBSD). I'll resend the patch with use of cache for VMREAD(GUEST_RFLAGS), which is already implemented.

I am curious does it still fails with all my vmx patches applied too?

Yes.

Which FreeBSD exactly? Cannot reproduce with FreeBSD 9 64 bits here.

Quoted 5 lines
Quoted 3 lines

The question is how does it happen that we enter real mode while cache is set to 3. It should never be 3 during boot since boot process never enters the userspace.

Its transition _to_ real mode (from protected).

But in protected mode CPL should be 0 during boot.

--
Gleb.

#7 lore raw
Quoted 62 lines · Gleb Natapov
Quoted 61 lines · Marcelo Tosatti
Quoted 60 lines · Gleb Natapov
Quoted 59 lines · Marcelo Tosatti
Quoted 57 lines · Gleb Natapov
Quoted 44 lines · Avi Kivity
Quoted 42 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +0 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu
 *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-       if (!is_protmode(vcpu))
-               return 0;
-
-       if (!is_long_mode(vcpu)
-           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
-               return 3;
-
        return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;

}

arch/x86/kvm/vmx.c +7 -0
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (!is_protmode(vcpu))
+               return 0;
+
+       if (!is_long_mode(vcpu)
+           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
+               return 3;
+
        /*
Quoted 8 lines
Quoted 4 lines
arch/x86/kvm/vmx.c +0 -0
         * If we enter real mode with cs.sel & 3 != 0, the normal CPL

calculations
* fail; use the cache instead.

This undoes the cache, now every vmx_get_cpl() in protected mode has to VMREAD(GUEST_RFLAGS).

True. Marcelo what failure do you see without the patch?

--
Gleb.

Quoted 8 lines
Quoted 7 lines
Quoted 4 lines
Quoted 3 lines

On transition _to_ real mode, linearize fails due to CPL checks (FreeBSD). I'll resend the patch with use of cache for VMREAD(GUEST_RFLAGS), which is already implemented.

I am curious does it still fails with all my vmx patches applied too?

Yes.

Which FreeBSD exactly? Cannot reproduce with FreeBSD 9 64 bits here.

FreeBSD 9.1 with -smp 2.

Quoted 7 lines
Quoted 6 lines
Quoted 4 lines

The question is how does it happen that we enter real mode while cache is set to 3. It should never be 3 during boot since boot process never enters the userspace.

Its transition _to_ real mode (from protected).

But in protected mode CPL should be 0 during boot.

BTX (FreeBSD's bootloader) does:

http://people.freebsd.org/~jhb/docs/loader.txt.

#8 lore raw
Quoted 66 lines · Marcelo Tosatti
Quoted 65 lines · Gleb Natapov
Quoted 64 lines · Marcelo Tosatti
Quoted 63 lines · Gleb Natapov
Quoted 62 lines · Marcelo Tosatti
Quoted 53 lines · Gleb Natapov
Quoted 44 lines · Avi Kivity
Quoted 42 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +0 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu
 *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-       if (!is_protmode(vcpu))
-               return 0;
-
-       if (!is_long_mode(vcpu)
-           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
-               return 3;
-
        return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;

}

arch/x86/kvm/vmx.c +7 -0
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (!is_protmode(vcpu))
+               return 0;
+
+       if (!is_long_mode(vcpu)
+           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
+               return 3;
+
        /*
Quoted 8 lines
Quoted 4 lines
arch/x86/kvm/vmx.c +0 -0
         * If we enter real mode with cs.sel & 3 != 0, the normal CPL

calculations
* fail; use the cache instead.

This undoes the cache, now every vmx_get_cpl() in protected mode has to VMREAD(GUEST_RFLAGS).

Quoted 4 lines

True. Marcelo what failure do you see without the patch?

--
Gleb.

On transition _to_ real mode, linearize fails due to CPL checks (FreeBSD). I'll resend the patch with use of cache for VMREAD(GUEST_RFLAGS), which is already implemented.

Quoted 7 lines
Quoted 5 lines
Quoted 4 lines
Quoted 1 line

I am curious does it still fails with all my vmx patches applied too?

Yes.

Which FreeBSD exactly? Cannot reproduce with FreeBSD 9 64 bits here.

FreeBSD 9.1 with -smp 2.

I cannot reproduce. I do see boot failure on the next branch with 9.[01] 64 bit -smp 2 here, but it is caused but segment registers been all incorrect on a secondary vcpu and this patch does not help. Applying
http://comments.gmane.org/gmane.comp.emulators.kvm.devel/102593 fixes it.

Quoted 11 lines
Quoted 7 lines
Quoted 6 lines
Quoted 4 lines

The question is how does it happen that we enter real mode while cache is set to 3. It should never be 3 during boot since boot process never enters the userspace.

Its transition _to_ real mode (from protected).

But in protected mode CPL should be 0 during boot.

BTX (FreeBSD's bootloader) does:

http://people.freebsd.org/~jhb/docs/loader.txt.

Crazy. Regardless, I think your patch is correct and the current code that uses cpl cache during emulation is wrong and it remains wrong even after your patch. What if last time cpl cache was updated was while vcpu ran in cpl 3? Commit message says that it tries to fix the case when CS.selector&3 != 0 during transition to protected mode, but this can be fixed by setting cpl cache to 0 in vmx_set_cr0() instead of clearing it.

Two things about the patch itself. Get rid of __vmx_get_cpl() and call to vmx_read_guest_seg_selector() directly from vmx_get_cpl() and drop __clear_bit(VCPU_EXREG_CPL) from vmx_set_rflags() and vmx_set_cr0() since vmx->cpl no longer depends on rflags and cr0.

--
Gleb.

#9 lore raw
Quoted 17 lines · Gleb Natapov
Quoted 1 line

FreeBSD 9.1 with -smp 2.

I cannot reproduce. I do see boot failure on the next branch with 9.[01] 64 bit -smp 2 here, but it is caused but segment registers been all incorrect on a secondary vcpu and this patch does not help. Applying
http://comments.gmane.org/gmane.comp.emulators.kvm.devel/102593 fixes it.

Quoted 10 lines
Quoted 7 lines
Quoted 6 lines
Quoted 4 lines

The question is how does it happen that we enter real mode while cache is set to 3. It should never be 3 during boot since boot process never enters the userspace.

Its transition _to_ real mode (from protected).

But in protected mode CPL should be 0 during boot.

BTX (FreeBSD's bootloader) does:

Quoted 7 lines
Quoted 1 line

http://people.freebsd.org/~jhb/docs/loader.txt.

Crazy. Regardless, I think your patch is correct and the current code that uses cpl cache during emulation is wrong and it remains wrong even after your patch. What if last time cpl cache was updated was while vcpu ran in cpl 3? Commit message says that it tries to fix the case when CS.selector&3 != 0 during transition to protected mode, but this can be fixed by setting cpl cache to 0 in vmx_set_cr0() instead of clearing it.

Yes, i suppose so, can be done by a separatch patch, though.

Quoted 4 lines

Two things about the patch itself. Get rid of __vmx_get_cpl() and call to vmx_read_guest_seg_selector() directly from vmx_get_cpl() and drop __clear_bit(VCPU_EXREG_CPL) from vmx_set_rflags() and vmx_set_cr0() since vmx->cpl no longer depends on rflags and cr0.

You still want to invalidate vmx->cpl cache on cr0 writes:
think protected -> real -> protected transition. And as for EFLAGS, agreed. Sending new patch.

#10 lore raw
Quoted 19 lines · Marcelo Tosatti
Quoted 18 lines · Gleb Natapov
Quoted 1 line

FreeBSD 9.1 with -smp 2.

I cannot reproduce. I do see boot failure on the next branch with 9.[01] 64 bit -smp 2 here, but it is caused but segment registers been all incorrect on a secondary vcpu and this patch does not help. Applying
http://comments.gmane.org/gmane.comp.emulators.kvm.devel/102593 fixes it.

Quoted 11 lines
Quoted 7 lines
Quoted 6 lines
Quoted 4 lines

The question is how does it happen that we enter real mode while cache is set to 3. It should never be 3 during boot since boot process never enters the userspace.

Its transition _to_ real mode (from protected).

But in protected mode CPL should be 0 during boot.

BTX (FreeBSD's bootloader) does:

http://people.freebsd.org/~jhb/docs/loader.txt.

Quoted 9 lines
Quoted 6 lines

Crazy. Regardless, I think your patch is correct and the current code that uses cpl cache during emulation is wrong and it remains wrong even after your patch. What if last time cpl cache was updated was while vcpu ran in cpl 3? Commit message says that it tries to fix the case when CS.selector&3 != 0 during transition to protected mode, but this can be fixed by setting cpl cache to 0 in vmx_set_cr0() instead of clearing it.

Yes, i suppose so, can be done by a separatch patch, though.

Yes. I will send the patch.

Quoted 7 lines
Quoted 4 lines

Two things about the patch itself. Get rid of __vmx_get_cpl() and call to vmx_read_guest_seg_selector() directly from vmx_get_cpl() and drop __clear_bit(VCPU_EXREG_CPL) from vmx_set_rflags() and vmx_set_cr0() since vmx->cpl no longer depends on rflags and cr0.

You still want to invalidate vmx->cpl cache on cr0 writes:
think protected -> real -> protected transition.

If CS.selector didn't change during the transition vmx->cpl will be set to the same value and if it changes cpl cache will be cleared either by vmx_set_segment() or vmexit.

Quoted 1 line

And as for EFLAGS, agreed. Sending new patch.

--
Gleb.

#11 lore raw
In reply to a message not in the archive
Quoted 44 lines · Avi Kivity
Quoted 42 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +0 -7
index a4ecf7c..3abe433 100644
@@ -3215,13 +3215,6 @@ static u64 vmx_get_segment_base(struct kvm_vcpu
 *vcpu, int seg)
 
 static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
-       if (!is_protmode(vcpu))
-               return 0;
-
-       if (!is_long_mode(vcpu)
-           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
-               return 3;
-
        return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;

}

arch/x86/kvm/vmx.c +7 -0
@@ -3229,6 +3222,13 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (!is_protmode(vcpu))
+               return 0;
+
+       if (!is_long_mode(vcpu)
+           && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086
 */
+               return 3;
+
        /*
Quoted 8 lines
Quoted 4 lines
arch/x86/kvm/vmx.c +0 -0
         * If we enter real mode with cs.sel & 3 != 0, the normal CPL

calculations
* fail; use the cache instead.

This undoes the cache, now every vmx_get_cpl() in protected mode has to VMREAD(GUEST_RFLAGS).

Yes, but GUEST_RFLAGS reads are cached. So its read once per exit.

#12 lore raw

KVM: VMX: fix incorrect cached cpl value with real/v8086 modes (v2)

In reply to Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +4 -10
index 55dfc37..849f5f2 100644
@@ -1696,7 +1696,6 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
 static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
 	__set_bit(VCPU_EXREG_RFLAGS, (ulong *)&vcpu->arch.regs_avail);
-	__clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
 	to_vmx(vcpu)->rflags = rflags;
 	if (to_vmx(vcpu)->rmode.vm86_active) {
 		to_vmx(vcpu)->rmode.save_rflags = rflags;
@@ -3220,8 +3219,10 @@ static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
 	return vmx_read_guest_seg_base(to_vmx(vcpu), seg);
 }
 
-static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
+static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+
 	if (!is_protmode(vcpu))
 		return 0;
 
@@ -3229,13 +3230,6 @@ static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 	    && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086 */
 		return 3;
 
-	return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;
-}
-
-static int vmx_get_cpl(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-
 	/*
 	 * If we enter real mode with cs.sel & 3 != 0, the normal CPL calculations
 	 * fail; use the cache instead.
@@ -3246,7 +3240,7 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 
 	if (!test_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail)) {
 		__set_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
-		vmx->cpl = __vmx_get_cpl(vcpu);
+		vmx->cpl = vmx_read_guest_seg_selector(vmx, VCPU_SREG_CS) & 3;
 	}
 
 	return vmx->cpl;
#13 lore raw

KVM: VMX: fix incorrect cached cpl value with real/v8086 modes (v3)

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

arch/x86/kvm/vmx.c +4 -11
index 55dfc37..dd2a85c 100644
@@ -1696,7 +1696,6 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
 static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
 	__set_bit(VCPU_EXREG_RFLAGS, (ulong *)&vcpu->arch.regs_avail);
-	__clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
 	to_vmx(vcpu)->rflags = rflags;
 	if (to_vmx(vcpu)->rmode.vm86_active) {
 		to_vmx(vcpu)->rmode.save_rflags = rflags;
@@ -3110,7 +3109,6 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 	vmcs_writel(CR0_READ_SHADOW, cr0);
 	vmcs_writel(GUEST_CR0, hw_cr0);
 	vcpu->arch.cr0 = cr0;
-	__clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
 }
 
 static u64 construct_eptp(unsigned long root_hpa)
@@ -3220,8 +3218,10 @@ static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
 	return vmx_read_guest_seg_base(to_vmx(vcpu), seg);
 }
 
-static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
+static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+
 	if (!is_protmode(vcpu))
 		return 0;
 
@@ -3229,13 +3229,6 @@ static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 	    && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086 */
 		return 3;
 
-	return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;
-}
-
-static int vmx_get_cpl(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-
 	/*
 	 * If we enter real mode with cs.sel & 3 != 0, the normal CPL calculations
 	 * fail; use the cache instead.
@@ -3246,7 +3239,7 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 
 	if (!test_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail)) {
 		__set_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
-		vmx->cpl = __vmx_get_cpl(vcpu);
+		vmx->cpl = vmx_read_guest_seg_selector(vmx, VCPU_SREG_CS) & 3;
 	}
 
 	return vmx->cpl;
Reviewed-by
#14 lore raw

Re: KVM: VMX: fix incorrect cached cpl value with real/v8086 modes (v3)

Quoted 8 lines · Marcelo Tosatti

CPL is always 0 when in real mode, and always 3 when virtual 8086 mode.

Using values other than those can cause failures on operations that check CPL.

Quoted 47 lines
arch/x86/kvm/vmx.c +3 -10
index 55dfc37..dd2a85c 100644
@@ -1696,7 +1696,6 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
 static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
 	__set_bit(VCPU_EXREG_RFLAGS, (ulong *)&vcpu->arch.regs_avail);
-	__clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
 	to_vmx(vcpu)->rflags = rflags;
 	if (to_vmx(vcpu)->rmode.vm86_active) {
 		to_vmx(vcpu)->rmode.save_rflags = rflags;
@@ -3110,7 +3109,6 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 	vmcs_writel(CR0_READ_SHADOW, cr0);
 	vmcs_writel(GUEST_CR0, hw_cr0);
 	vcpu->arch.cr0 = cr0;
-	__clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
 }
 
 static u64 construct_eptp(unsigned long root_hpa)
@@ -3220,8 +3218,10 @@ static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
 	return vmx_read_guest_seg_base(to_vmx(vcpu), seg);
 }
 
-static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
+static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 {
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+
 	if (!is_protmode(vcpu))
 		return 0;
 
@@ -3229,13 +3229,6 @@ static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
 	    && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086 */
 		return 3;
 
-	return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;
-}
-
-static int vmx_get_cpl(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-
 	/*
 	 * If we enter real mode with cs.sel & 3 != 0, the normal CPL calculations
 	 * fail; use the cache instead.

arch/x86/kvm/vmx.c static int vmx_get_cpl(struct kvm_vcpu *vcpu) · line 3245

Quoted 8 lines
arch/x86/kvm/vmx.c +1 -1
@@ -3246,7 +3239,7 @@ static int vmx_get_cpl(struct kvm_vcpu *vcpu)
 
 	if (!test_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail)) {
 		__set_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
-		vmx->cpl = __vmx_get_cpl(vcpu);
+		vmx->cpl = vmx_read_guest_seg_selector(vmx, VCPU_SREG_CS) & 3;
 	}
 
 	return vmx->cpl;

--
Gleb.