diff mbox

[v2] KVM: x86: Check for host supported fields in shadow vmcs

Message ID jpgk3aiv6a9.fsf@nelium.bos.redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Bandan Das April 21, 2014, 7:20 p.m. UTC
We track shadow vmcs fields through two static lists,
one for read only and another for r/w fields. However, with
addition of new vmcs fields, not all fields may be supported on
all hosts. If so, copy_vmcs12_to_shadow() trying to vmwrite on
unsupported hosts will result in a vmwrite error. For example, commit
36be0b9deb23161 introduced GUEST_BNDCFGS, which is not supported
by all processors. Filter out host unsupported fields before
letting guests use shadow vmcs

Signed-off-by: Bandan Das <bsd@redhat.com>
---
v2:
  - Just compress the original lists instead of creating new ones
  - Change commit message slightly to reflect this change

 arch/x86/kvm/vmx.c | 54 ++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 42 insertions(+), 12 deletions(-)

Comments

Paolo Bonzini April 22, 2014, 3:29 a.m. UTC | #1
Il 21/04/2014 15:20, Bandan Das ha scritto:
> +	for (i = j = 0; i < max_shadow_read_write_fields; i++) {
> +

Extra empty line.  Not a big deal, but...

> +		switch (shadow_read_write_fields[i]) {
> +		case GUEST_BNDCFGS:
> +			if (!vmx_mpx_supported())
> +				continue;
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		if (j < i)
> +			shadow_read_write_fields[j] =
> +				shadow_read_write_fields[i];
> +		j++;

... you need to respin anyway because the j++ is wrong.  It should be 
inside the "if".  If you prefer, you can put it in the lhs of the 
assignment, otherwise a separate statement is fine by me too.

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bandan Das April 22, 2014, 4:25 p.m. UTC | #2
Paolo Bonzini <pbonzini@redhat.com> writes:

> Il 21/04/2014 15:20, Bandan Das ha scritto:
>> +	for (i = j = 0; i < max_shadow_read_write_fields; i++) {
>> +
>
> Extra empty line.  Not a big deal, but...
>
>> +		switch (shadow_read_write_fields[i]) {
>> +		case GUEST_BNDCFGS:
>> +			if (!vmx_mpx_supported())
>> +				continue;
>> +			break;
>> +		default:
>> +			break;
>> +		}
>> +
>> +		if (j < i)
>> +			shadow_read_write_fields[j] =
>> +				shadow_read_write_fields[i];
>> +		j++;
>
> ... you need to respin anyway because the j++ is wrong.  It should be
> inside the "if".  If you prefer, you can put it in the lhs of the

j++ outside the "if" looks right to me. Can you please explain why
you think it shouldn't be that way ?

> assignment, otherwise a separate statement is fine by me too.
>
> Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paolo Bonzini April 22, 2014, 7:13 p.m. UTC | #3
Il 22/04/2014 12:25, Bandan Das ha scritto:
>>> >> +		if (j < i)
>>> >> +			shadow_read_write_fields[j] =
>>> >> +				shadow_read_write_fields[i];
>>> >> +		j++;
>> >
>> > ... you need to respin anyway because the j++ is wrong.  It should be
>> > inside the "if".  If you prefer, you can put it in the lhs of the
> j++ outside the "if" looks right to me. Can you please explain why
> you think it shouldn't be that way ?
>

The way you wrote it, j will always be equal to i.

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bandan Das April 22, 2014, 7:31 p.m. UTC | #4
Paolo Bonzini <pbonzini@redhat.com> writes:

> Il 22/04/2014 12:25, Bandan Das ha scritto:
>>>> >> +		if (j < i)
>>>> >> +			shadow_read_write_fields[j] =
>>>> >> +				shadow_read_write_fields[i];
>>>> >> +		j++;
>>> >
>>> > ... you need to respin anyway because the j++ is wrong.  It should be
>>> > inside the "if".  If you prefer, you can put it in the lhs of the
>> j++ outside the "if" looks right to me. Can you please explain why
>> you think it shouldn't be that way ?
>>
>
> The way you wrote it, j will always be equal to i.

Right, and that's what we want unless we come across an unsupported 
field. We then overwrite the unsupported field with the next
field supported. j this way keeps track of the "real" length.

> Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paolo Bonzini April 26, 2014, 9:42 a.m. UTC | #5
Il 22/04/2014 21:31, Bandan Das ha scritto:
> Paolo Bonzini <pbonzini@redhat.com> writes:
>
>> Il 22/04/2014 12:25, Bandan Das ha scritto:
>>>>>>> +		if (j < i)
>>>>>>> +			shadow_read_write_fields[j] =
>>>>>>> +				shadow_read_write_fields[i];
>>>>>>> +		j++;
>>>>>
>>>>> ... you need to respin anyway because the j++ is wrong.  It should be
>>>>> inside the "if".  If you prefer, you can put it in the lhs of the
>>> j++ outside the "if" looks right to me. Can you please explain why
>>> you think it shouldn't be that way ?
>>>
>>
>> The way you wrote it, j will always be equal to i.
>
> Right, and that's what we want unless we come across an unsupported
> field. We then overwrite the unsupported field with the next
> field supported. j this way keeps track of the "real" length.

Doh, brain fart.

Paolo

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paolo Bonzini April 28, 2014, 9:14 a.m. UTC | #6
Il 21/04/2014 21:20, Bandan Das ha scritto:
>
> We track shadow vmcs fields through two static lists,
> one for read only and another for r/w fields. However, with
> addition of new vmcs fields, not all fields may be supported on
> all hosts. If so, copy_vmcs12_to_shadow() trying to vmwrite on
> unsupported hosts will result in a vmwrite error. For example, commit
> 36be0b9deb23161 introduced GUEST_BNDCFGS, which is not supported
> by all processors. Filter out host unsupported fields before
> letting guests use shadow vmcs
>
> Signed-off-by: Bandan Das <bsd@redhat.com>
> ---
> v2:
>   - Just compress the original lists instead of creating new ones
>   - Change commit message slightly to reflect this change
>
>  arch/x86/kvm/vmx.c | 54 ++++++++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 42 insertions(+), 12 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index 7bed3e3..26a632f 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -503,7 +503,7 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
>  				[number##_HIGH] = VMCS12_OFFSET(name)+4
>
>
> -static const unsigned long shadow_read_only_fields[] = {
> +static unsigned long shadow_read_only_fields[] = {
>  	/*
>  	 * We do NOT shadow fields that are modified when L0
>  	 * traps and emulates any vmx instruction (e.g. VMPTRLD,
> @@ -526,10 +526,10 @@ static const unsigned long shadow_read_only_fields[] = {
>  	GUEST_LINEAR_ADDRESS,
>  	GUEST_PHYSICAL_ADDRESS
>  };
> -static const int max_shadow_read_only_fields =
> +static int max_shadow_read_only_fields =
>  	ARRAY_SIZE(shadow_read_only_fields);
>
> -static const unsigned long shadow_read_write_fields[] = {
> +static unsigned long shadow_read_write_fields[] = {
>  	GUEST_RIP,
>  	GUEST_RSP,
>  	GUEST_CR0,
> @@ -558,7 +558,7 @@ static const unsigned long shadow_read_write_fields[] = {
>  	HOST_FS_SELECTOR,
>  	HOST_GS_SELECTOR
>  };
> -static const int max_shadow_read_write_fields =
> +static int max_shadow_read_write_fields =
>  	ARRAY_SIZE(shadow_read_write_fields);
>
>  static const unsigned short vmcs_field_to_offset_table[] = {
> @@ -3009,6 +3009,42 @@ static void free_kvm_area(void)
>  	}
>  }
>
> +static void init_vmcs_shadow_fields(void)
> +{
> +	int i, j;
> +
> +	/* No checks for read only fields yet */
> +
> +	for (i = j = 0; i < max_shadow_read_write_fields; i++) {
> +
> +		switch (shadow_read_write_fields[i]) {
> +		case GUEST_BNDCFGS:
> +			if (!vmx_mpx_supported())
> +				continue;
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		if (j < i)
> +			shadow_read_write_fields[j] =
> +				shadow_read_write_fields[i];
> +		j++;
> +	}
> +	max_shadow_read_write_fields = j;
> +
> +	/* shadowed fields guest access without vmexit */
> +	for (i = 0; i < max_shadow_read_write_fields; i++) {
> +		clear_bit(shadow_read_write_fields[i],
> +			  vmx_vmwrite_bitmap);
> +		clear_bit(shadow_read_write_fields[i],
> +			  vmx_vmread_bitmap);
> +	}
> +	for (i = 0; i < max_shadow_read_only_fields; i++)
> +		clear_bit(shadow_read_only_fields[i],
> +			  vmx_vmread_bitmap);
> +}
> +
>  static __init int alloc_kvm_area(void)
>  {
>  	int cpu;
> @@ -3039,6 +3075,8 @@ static __init int hardware_setup(void)
>  		enable_vpid = 0;
>  	if (!cpu_has_vmx_shadow_vmcs())
>  		enable_shadow_vmcs = 0;
> +	if (enable_shadow_vmcs)
> +		init_vmcs_shadow_fields();
>
>  	if (!cpu_has_vmx_ept() ||
>  	    !cpu_has_vmx_ept_4levels()) {
> @@ -8817,14 +8855,6 @@ static int __init vmx_init(void)
>
>  	memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE);
>  	memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE);
> -	/* shadowed read/write fields */
> -	for (i = 0; i < max_shadow_read_write_fields; i++) {
> -		clear_bit(shadow_read_write_fields[i], vmx_vmwrite_bitmap);
> -		clear_bit(shadow_read_write_fields[i], vmx_vmread_bitmap);
> -	}
> -	/* shadowed read only fields */
> -	for (i = 0; i < max_shadow_read_only_fields; i++)
> -		clear_bit(shadow_read_only_fields[i], vmx_vmread_bitmap);
>
>  	/*
>  	 * Allow direct access to the PC debug port (it is often used for I/O
>

Applying this to kvm/master, thanks.

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 7bed3e3..26a632f 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -503,7 +503,7 @@  static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
 				[number##_HIGH] = VMCS12_OFFSET(name)+4
 
 
-static const unsigned long shadow_read_only_fields[] = {
+static unsigned long shadow_read_only_fields[] = {
 	/*
 	 * We do NOT shadow fields that are modified when L0
 	 * traps and emulates any vmx instruction (e.g. VMPTRLD,
@@ -526,10 +526,10 @@  static const unsigned long shadow_read_only_fields[] = {
 	GUEST_LINEAR_ADDRESS,
 	GUEST_PHYSICAL_ADDRESS
 };
-static const int max_shadow_read_only_fields =
+static int max_shadow_read_only_fields =
 	ARRAY_SIZE(shadow_read_only_fields);
 
-static const unsigned long shadow_read_write_fields[] = {
+static unsigned long shadow_read_write_fields[] = {
 	GUEST_RIP,
 	GUEST_RSP,
 	GUEST_CR0,
@@ -558,7 +558,7 @@  static const unsigned long shadow_read_write_fields[] = {
 	HOST_FS_SELECTOR,
 	HOST_GS_SELECTOR
 };
-static const int max_shadow_read_write_fields =
+static int max_shadow_read_write_fields =
 	ARRAY_SIZE(shadow_read_write_fields);
 
 static const unsigned short vmcs_field_to_offset_table[] = {
@@ -3009,6 +3009,42 @@  static void free_kvm_area(void)
 	}
 }
 
+static void init_vmcs_shadow_fields(void)
+{
+	int i, j;
+
+	/* No checks for read only fields yet */
+
+	for (i = j = 0; i < max_shadow_read_write_fields; i++) {
+
+		switch (shadow_read_write_fields[i]) {
+		case GUEST_BNDCFGS:
+			if (!vmx_mpx_supported())
+				continue;
+			break;
+		default:
+			break;
+		}
+
+		if (j < i)
+			shadow_read_write_fields[j] =
+				shadow_read_write_fields[i];
+		j++;
+	}
+	max_shadow_read_write_fields = j;
+
+	/* shadowed fields guest access without vmexit */
+	for (i = 0; i < max_shadow_read_write_fields; i++) {
+		clear_bit(shadow_read_write_fields[i],
+			  vmx_vmwrite_bitmap);
+		clear_bit(shadow_read_write_fields[i],
+			  vmx_vmread_bitmap);
+	}
+	for (i = 0; i < max_shadow_read_only_fields; i++)
+		clear_bit(shadow_read_only_fields[i],
+			  vmx_vmread_bitmap);
+}
+
 static __init int alloc_kvm_area(void)
 {
 	int cpu;
@@ -3039,6 +3075,8 @@  static __init int hardware_setup(void)
 		enable_vpid = 0;
 	if (!cpu_has_vmx_shadow_vmcs())
 		enable_shadow_vmcs = 0;
+	if (enable_shadow_vmcs)
+		init_vmcs_shadow_fields();
 
 	if (!cpu_has_vmx_ept() ||
 	    !cpu_has_vmx_ept_4levels()) {
@@ -8817,14 +8855,6 @@  static int __init vmx_init(void)
 
 	memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE);
 	memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE);
-	/* shadowed read/write fields */
-	for (i = 0; i < max_shadow_read_write_fields; i++) {
-		clear_bit(shadow_read_write_fields[i], vmx_vmwrite_bitmap);
-		clear_bit(shadow_read_write_fields[i], vmx_vmread_bitmap);
-	}
-	/* shadowed read only fields */
-	for (i = 0; i < max_shadow_read_only_fields; i++)
-		clear_bit(shadow_read_only_fields[i], vmx_vmread_bitmap);
 
 	/*
 	 * Allow direct access to the PC debug port (it is often used for I/O