Re: [PATCH 2/4] kvm: svm: Enable UMIP feature on AMD

From: Jim Mattson
Date: Fri Nov 01 2019 - 14:29:36 EST


On Fri, Nov 1, 2019 at 10:33 AM Moger, Babu <Babu.Moger@xxxxxxx> wrote:
>
> AMD 2nd generation EPYC processors support UMIP (User-Mode Instruction
> Prevention) feature. The UMIP feature prevents the execution of certain
> instructions if the Current Privilege Level (CPL) is greater than 0.
> If any of these instructions are executed with CPL > 0 and UMIP
> is enabled, then kernel reports a #GP exception.
>
> The idea is taken from articles:
> https://lwn.net/Articles/738209/
> https://lwn.net/Articles/694385/
>
> Enable the feature if supported on bare metal and emulate instructions
> to return dummy values for certain cases.
>
> Signed-off-by: Babu Moger <babu.moger@xxxxxxx>
> ---
> arch/x86/kvm/svm.c | 21 ++++++++++++++++-----
> 1 file changed, 16 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index 4153ca8cddb7..79abbdeca148 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -2533,6 +2533,11 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
> {
> }
>
> +static bool svm_umip_emulated(void)
> +{
> + return boot_cpu_has(X86_FEATURE_UMIP);
> +}

This makes no sense to me. If the hardware actually supports UMIP,
then it doesn't have to be emulated.

To the extent that kvm emulates UMIP on Intel CPUs without hardware
UMIP (i.e. smsw is still allowed at CPL>0), we can always do the same
emulation on AMD, because SVM has always offered intercepts of sgdt,
sidt, sldt, and str. So, if you really want to offer this emulation on
pre-EPYC 2 CPUs, this function should just return true. But, I have to
ask, "why?"

*Virtualization* of UMIP on EPYC 2 already works without any of these changes.

> static void update_cr0_intercept(struct vcpu_svm *svm)
> {
> ulong gcr0 = svm->vcpu.arch.cr0;
> @@ -4438,6 +4443,13 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
> return 1;
> }
>
> +static int umip_interception(struct vcpu_svm *svm)
> +{
> + struct kvm_vcpu *vcpu = &svm->vcpu;
> +
> + return kvm_emulate_instruction(vcpu, 0);
> +}
> +
> static int pause_interception(struct vcpu_svm *svm)
> {
> struct kvm_vcpu *vcpu = &svm->vcpu;
> @@ -4775,6 +4787,10 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
> [SVM_EXIT_SMI] = nop_on_interception,
> [SVM_EXIT_INIT] = nop_on_interception,
> [SVM_EXIT_VINTR] = interrupt_window_interception,
> + [SVM_EXIT_IDTR_READ] = umip_interception,
> + [SVM_EXIT_GDTR_READ] = umip_interception,
> + [SVM_EXIT_LDTR_READ] = umip_interception,
> + [SVM_EXIT_TR_READ] = umip_interception,
> [SVM_EXIT_RDPMC] = rdpmc_interception,
> [SVM_EXIT_CPUID] = cpuid_interception,
> [SVM_EXIT_IRET] = iret_interception,
> @@ -5976,11 +5992,6 @@ static bool svm_xsaves_supported(void)
> return boot_cpu_has(X86_FEATURE_XSAVES);
> }
>
> -static bool svm_umip_emulated(void)
> -{
> - return false;
> -}
> -
> static bool svm_pt_supported(void)
> {
> return false;
>