[v2,10/21] KVM:x86: Add #CP support in guest exception classification

Message ID 20230421134615.62539-11-weijiang.yang@intel.com
State New
Headers
Series Enable CET Virtualization |

Commit Message

Yang, Weijiang April 21, 2023, 1:46 p.m. UTC
  Add handling for Control Protection (#CP) exceptions(vector 21).
The new vector is introduced for Intel's Control-Flow Enforcement
Technology (CET) relevant violation cases.
See Intel's SDM for details.

Signed-off-by: Yang Weijiang <weijiang.yang@intel.com>
---
 arch/x86/include/uapi/asm/kvm.h |  1 +
 arch/x86/kvm/vmx/nested.c       |  2 +-
 arch/x86/kvm/x86.c              | 10 +++++++---
 arch/x86/kvm/x86.h              | 13 ++++++++++---
 4 files changed, 19 insertions(+), 7 deletions(-)
  

Comments

Binbin Wu April 28, 2023, 6:09 a.m. UTC | #1
On 4/21/2023 9:46 PM, Yang Weijiang wrote:
> Add handling for Control Protection (#CP) exceptions(vector 21).
> The new vector is introduced for Intel's Control-Flow Enforcement
> Technology (CET) relevant violation cases.
> See Intel's SDM for details.
>
> Signed-off-by: Yang Weijiang <weijiang.yang@intel.com>
> ---
>   arch/x86/include/uapi/asm/kvm.h |  1 +
>   arch/x86/kvm/vmx/nested.c       |  2 +-
>   arch/x86/kvm/x86.c              | 10 +++++++---
>   arch/x86/kvm/x86.h              | 13 ++++++++++---
>   4 files changed, 19 insertions(+), 7 deletions(-)
>
> diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
> index 7f467fe05d42..1c002abe2be8 100644
> --- a/arch/x86/include/uapi/asm/kvm.h
> +++ b/arch/x86/include/uapi/asm/kvm.h
> @@ -33,6 +33,7 @@
>   #define MC_VECTOR 18
>   #define XM_VECTOR 19
>   #define VE_VECTOR 20
> +#define CP_VECTOR 21
>   
>   /* Select x86 specific features in <linux/kvm.h> */
>   #define __KVM_HAVE_PIT
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index 96ede74a6067..7bc62cd72748 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -2850,7 +2850,7 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu,
>   		/* VM-entry interruption-info field: deliver error code */
>   		should_have_error_code =
>   			intr_type == INTR_TYPE_HARD_EXCEPTION && prot_mode &&
> -			x86_exception_has_error_code(vector);
> +			x86_exception_has_error_code(vcpu, vector);
>   		if (CC(has_error_code != should_have_error_code))
>   			return -EINVAL;
>   
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 7788646bbf1f..a768cbf3fbb7 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -520,11 +520,15 @@ EXPORT_SYMBOL_GPL(kvm_spurious_fault);
>   #define EXCPT_CONTRIBUTORY	1
>   #define EXCPT_PF		2
>   
> -static int exception_class(int vector)
> +static int exception_class(struct kvm_vcpu *vcpu, int vector)
>   {
>   	switch (vector) {
>   	case PF_VECTOR:
>   		return EXCPT_PF;
> +	case CP_VECTOR:
> +		if (vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET)
> +			return EXCPT_BENIGN;
> +		return EXCPT_CONTRIBUTORY;
By definition, #CP is Contributory.
Can you explain more about this change here which treats #CP as 
EXCPT_BENIGN when CET is not enabled in guest?

In current KVM code, there is suppose no #CP triggered in guest if CET 
is not enalbed in guest, right?
>   	case DE_VECTOR:
>   	case TS_VECTOR:
>   	case NP_VECTOR:
> @@ -707,8 +711,8 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
>   		kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
>   		return;
>   	}
> -	class1 = exception_class(prev_nr);
> -	class2 = exception_class(nr);
> +	class1 = exception_class(vcpu, prev_nr);
> +	class2 = exception_class(vcpu, nr);
>   	if ((class1 == EXCPT_CONTRIBUTORY && class2 == EXCPT_CONTRIBUTORY) ||
>   	    (class1 == EXCPT_PF && class2 != EXCPT_BENIGN)) {
>   		/*
> diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
> index c544602d07a3..2ba7c7fc4846 100644
> --- a/arch/x86/kvm/x86.h
> +++ b/arch/x86/kvm/x86.h
> @@ -171,13 +171,20 @@ static inline bool is_64_bit_hypercall(struct kvm_vcpu *vcpu)
>   	return vcpu->arch.guest_state_protected || is_64_bit_mode(vcpu);
>   }
>   
> -static inline bool x86_exception_has_error_code(unsigned int vector)
> +static inline bool x86_exception_has_error_code(struct kvm_vcpu *vcpu,
> +						unsigned int vector)
>   {
>   	static u32 exception_has_error_code = BIT(DF_VECTOR) | BIT(TS_VECTOR) |
>   			BIT(NP_VECTOR) | BIT(SS_VECTOR) | BIT(GP_VECTOR) |
> -			BIT(PF_VECTOR) | BIT(AC_VECTOR);
> +			BIT(PF_VECTOR) | BIT(AC_VECTOR) | BIT(CP_VECTOR);
>   
> -	return (1U << vector) & exception_has_error_code;
> +	if (!((1U << vector) & exception_has_error_code))
> +		return false;
> +
> +	if (vector == CP_VECTOR)
> +		return !(vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET);
> +
> +	return true;
>   }
>   
>   static inline bool mmu_is_nested(struct kvm_vcpu *vcpu)
  
Yang, Weijiang May 4, 2023, 3:41 a.m. UTC | #2
On 4/28/2023 2:09 PM, Binbin Wu wrote:
>
>
> On 4/21/2023 9:46 PM, Yang Weijiang wrote:
>> Add handling for Control Protection (#CP) exceptions(vector 21).
>> The new vector is introduced for Intel's Control-Flow Enforcement
>> Technology (CET) relevant violation cases.
>> See Intel's SDM for details.
>>
[...]
>>   -static int exception_class(int vector)
>> +static int exception_class(struct kvm_vcpu *vcpu, int vector)
>>   {
>>       switch (vector) {
>>       case PF_VECTOR:
>>           return EXCPT_PF;
>> +    case CP_VECTOR:
>> +        if (vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET)
>> +            return EXCPT_BENIGN;
>> +        return EXCPT_CONTRIBUTORY;
> By definition, #CP is Contributory.
> Can you explain more about this change here which treats #CP as 
> EXCPT_BENIGN when CET is not enabled in guest?

I check the history of this patch, found maintainer modified the patch 
due to some unit test issue in L1. You can check the

details here:

Re: [PATCH v15 04/14] KVM: x86: Add #CP support in guest exception 
dispatch - Sean Christopherson (kernel.org) 
<https://lore.kernel.org/all/YBsZwvwhshw+s7yQ@google.com/>


>
> In current KVM code, there is suppose no #CP triggered in guest if CET 
> is not enalbed in guest, right?

Yes.

>>       case DE_VECTOR:
>>       case TS_VECTOR:
>>       case NP_VECTOR:


[...]
  
Binbin Wu May 4, 2023, 5:36 a.m. UTC | #3
On 5/4/2023 11:41 AM, Yang, Weijiang wrote:
>
> On 4/28/2023 2:09 PM, Binbin Wu wrote:
>>
>>
>> On 4/21/2023 9:46 PM, Yang Weijiang wrote:
>>> Add handling for Control Protection (#CP) exceptions(vector 21).
>>> The new vector is introduced for Intel's Control-Flow Enforcement
>>> Technology (CET) relevant violation cases.
>>> See Intel's SDM for details.
>>>
> [...]
>>>   -static int exception_class(int vector)
>>> +static int exception_class(struct kvm_vcpu *vcpu, int vector)
>>>   {
>>>       switch (vector) {
>>>       case PF_VECTOR:
>>>           return EXCPT_PF;
>>> +    case CP_VECTOR:
>>> +        if (vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET)
>>> +            return EXCPT_BENIGN;
>>> +        return EXCPT_CONTRIBUTORY;
>> By definition, #CP is Contributory.
>> Can you explain more about this change here which treats #CP as 
>> EXCPT_BENIGN when CET is not enabled in guest?
>
> I check the history of this patch, found maintainer modified the patch 
> due to some unit test issue in L1. You can check the
>
> details here:
>
> Re: [PATCH v15 04/14] KVM: x86: Add #CP support in guest exception 
> dispatch - Sean Christopherson (kernel.org) 
> <https://lore.kernel.org/all/YBsZwvwhshw+s7yQ@google.com/>
>
OK, is it better to add the reason in changelog?

IIUC, a new contributory exception vector (if any) should be handled 
similarly (i.e., treated as contributory conditionally) in the future, 
right?


>
>>
>> In current KVM code, there is suppose no #CP triggered in guest if 
>> CET is not enalbed in guest, right?
>
> Yes.
>
>>>       case DE_VECTOR:
>>>       case TS_VECTOR:
>>>       case NP_VECTOR:
>
>
> [...]
>
  
Yang, Weijiang May 4, 2023, 6:59 a.m. UTC | #4
On 5/4/2023 1:36 PM, Binbin Wu wrote:
>
>
> On 5/4/2023 11:41 AM, Yang, Weijiang wrote:
>>
>> On 4/28/2023 2:09 PM, Binbin Wu wrote:
>>>
>>>
>>> On 4/21/2023 9:46 PM, Yang Weijiang wrote:
>>>> Add handling for Control Protection (#CP) exceptions(vector 21).
>>>> The new vector is introduced for Intel's Control-Flow Enforcement
>>>> Technology (CET) relevant violation cases.
>>>> See Intel's SDM for details.
>>>>
>> [...]
>>>>   -static int exception_class(int vector)
>>>> +static int exception_class(struct kvm_vcpu *vcpu, int vector)
>>>>   {
>>>>       switch (vector) {
>>>>       case PF_VECTOR:
>>>>           return EXCPT_PF;
>>>> +    case CP_VECTOR:
>>>> +        if (vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET)
>>>> +            return EXCPT_BENIGN;
>>>> +        return EXCPT_CONTRIBUTORY;
>>> By definition, #CP is Contributory.
>>> Can you explain more about this change here which treats #CP as 
>>> EXCPT_BENIGN when CET is not enabled in guest?
>>
>> I check the history of this patch, found maintainer modified the 
>> patch due to some unit test issue in L1. You can check the
>>
>> details here:
>>
>> Re: [PATCH v15 04/14] KVM: x86: Add #CP support in guest exception 
>> dispatch - Sean Christopherson (kernel.org) 
>> <https://lore.kernel.org/all/YBsZwvwhshw+s7yQ@google.com/>
>>
> OK, is it better to add the reason in changelog?
>
> IIUC, a new contributory exception vector (if any) should be handled 
> similarly (i.e., treated as contributory conditionally) in the future, 
> right?

Agree although the issue happens in an uncommon case, I'll add some 
description in changelog in following version, thanks!

>
>
>>
>>>
>>> In current KVM code, there is suppose no #CP triggered in guest if 
>>> CET is not enalbed in guest, right?
>>
>> Yes.
>>
>>>>       case DE_VECTOR:
>>>>       case TS_VECTOR:
>>>>       case NP_VECTOR:
>>
>>
>> [...]
>>
>
  

Patch

diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 7f467fe05d42..1c002abe2be8 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -33,6 +33,7 @@ 
 #define MC_VECTOR 18
 #define XM_VECTOR 19
 #define VE_VECTOR 20
+#define CP_VECTOR 21
 
 /* Select x86 specific features in <linux/kvm.h> */
 #define __KVM_HAVE_PIT
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 96ede74a6067..7bc62cd72748 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -2850,7 +2850,7 @@  static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu,
 		/* VM-entry interruption-info field: deliver error code */
 		should_have_error_code =
 			intr_type == INTR_TYPE_HARD_EXCEPTION && prot_mode &&
-			x86_exception_has_error_code(vector);
+			x86_exception_has_error_code(vcpu, vector);
 		if (CC(has_error_code != should_have_error_code))
 			return -EINVAL;
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7788646bbf1f..a768cbf3fbb7 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -520,11 +520,15 @@  EXPORT_SYMBOL_GPL(kvm_spurious_fault);
 #define EXCPT_CONTRIBUTORY	1
 #define EXCPT_PF		2
 
-static int exception_class(int vector)
+static int exception_class(struct kvm_vcpu *vcpu, int vector)
 {
 	switch (vector) {
 	case PF_VECTOR:
 		return EXCPT_PF;
+	case CP_VECTOR:
+		if (vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET)
+			return EXCPT_BENIGN;
+		return EXCPT_CONTRIBUTORY;
 	case DE_VECTOR:
 	case TS_VECTOR:
 	case NP_VECTOR:
@@ -707,8 +711,8 @@  static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
 		kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
 		return;
 	}
-	class1 = exception_class(prev_nr);
-	class2 = exception_class(nr);
+	class1 = exception_class(vcpu, prev_nr);
+	class2 = exception_class(vcpu, nr);
 	if ((class1 == EXCPT_CONTRIBUTORY && class2 == EXCPT_CONTRIBUTORY) ||
 	    (class1 == EXCPT_PF && class2 != EXCPT_BENIGN)) {
 		/*
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index c544602d07a3..2ba7c7fc4846 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -171,13 +171,20 @@  static inline bool is_64_bit_hypercall(struct kvm_vcpu *vcpu)
 	return vcpu->arch.guest_state_protected || is_64_bit_mode(vcpu);
 }
 
-static inline bool x86_exception_has_error_code(unsigned int vector)
+static inline bool x86_exception_has_error_code(struct kvm_vcpu *vcpu,
+						unsigned int vector)
 {
 	static u32 exception_has_error_code = BIT(DF_VECTOR) | BIT(TS_VECTOR) |
 			BIT(NP_VECTOR) | BIT(SS_VECTOR) | BIT(GP_VECTOR) |
-			BIT(PF_VECTOR) | BIT(AC_VECTOR);
+			BIT(PF_VECTOR) | BIT(AC_VECTOR) | BIT(CP_VECTOR);
 
-	return (1U << vector) & exception_has_error_code;
+	if (!((1U << vector) & exception_has_error_code))
+		return false;
+
+	if (vector == CP_VECTOR)
+		return !(vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET);
+
+	return true;
 }
 
 static inline bool mmu_is_nested(struct kvm_vcpu *vcpu)