[v2,10/21] KVM:x86: Add #CP support in guest exception classification
Commit Message
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
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)
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:
[...]
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:
>
>
> [...]
>
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:
>>
>>
>> [...]
>>
>
@@ -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
@@ -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;
@@ -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)) {
/*
@@ -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)