KVM: arm64: Allow SMCCC_ARCH_WORKAROUND_3 to be discovered and migrated
authorJames Morse <james.morse@arm.com>
Tue, 15 Mar 2022 18:24:14 +0000 (18:24 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 19 Mar 2022 12:40:15 +0000 (13:40 +0100)
commit a5905d6af492ee6a4a2205f0d550b3f931b03d03 upstream.

KVM allows the guest to discover whether the ARCH_WORKAROUND SMCCC are
implemented, and to preserve that state during migration through its
firmware register interface.

Add the necessary boiler plate for SMCCC_ARCH_WORKAROUND_3.

Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
[ kvm code moved to virt/kvm/arm. ]
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/arm/include/asm/kvm_host.h
arch/arm/include/uapi/asm/kvm.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/uapi/asm/kvm.h
virt/kvm/arm/psci.c

index 32564b017ba0635c6e3cab84b0281f2a92b6949e..d8ac89879327df65c732f916204692d25bfed4e9 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
 #include <asm/fpstate.h>
+#include <asm/spectre.h>
 #include <kvm/arm_arch_timer.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -424,4 +425,10 @@ static inline bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
 
 #define kvm_arm_vcpu_loaded(vcpu)      (false)
 
+static inline int kvm_arm_get_spectre_bhb_state(void)
+{
+       /* 32bit guests don't need firmware for this */
+       return SPECTRE_VULNERABLE; /* aka SMCCC_RET_NOT_SUPPORTED */
+}
+
 #endif /* __ARM_KVM_HOST_H__ */
index 2769360f195cafe1ead78ea917495778a7a52c21..89b8e70068a13e5d894ab50d594e8b97ca8b09fe 100644 (file)
@@ -227,6 +227,12 @@ struct kvm_vcpu_events {
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED       3
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED    (1U << 4)
 
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3    KVM_REG_ARM_FW_REG(3)
+       /* Higher values mean better protection. */
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL          0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL              1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED       2
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR      0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
index 697702a1a1ff19c041d21e562b0ce9df5217c05d..e6efdbe88c0a960ebed6a061e9050d72857afcb1 100644 (file)
@@ -684,4 +684,9 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
 
 #define kvm_arm_vcpu_loaded(vcpu)      ((vcpu)->arch.sysregs_loaded_on_cpu)
 
+static inline enum mitigation_state kvm_arm_get_spectre_bhb_state(void)
+{
+       return arm64_get_spectre_bhb_state();
+}
+
 #endif /* __ARM64_KVM_HOST_H__ */
index 67c21f9bdbad2556be4114dfa09b8006a11e708e..08440ce57a1c2b34bbd9319cc4f6984c82d72f45 100644 (file)
@@ -240,6 +240,11 @@ struct kvm_vcpu_events {
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED       3
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED            (1U << 4)
 
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3    KVM_REG_ARM_FW_REG(3)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL          0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL              1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED       2
+
 /* SVE registers */
 #define KVM_REG_ARM64_SVE              (0x15 << KVM_REG_ARM_COPROC_SHIFT)
 
index 48fde38d64c37a3d08e9376de08e8ad3af7fd659..2f5dc7fb437bd70f8726e44b759a31a3a62dc501 100644 (file)
@@ -426,6 +426,18 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
                                break;
                        }
                        break;
+               case ARM_SMCCC_ARCH_WORKAROUND_3:
+                       switch (kvm_arm_get_spectre_bhb_state()) {
+                       case SPECTRE_VULNERABLE:
+                               break;
+                       case SPECTRE_MITIGATED:
+                               val = SMCCC_RET_SUCCESS;
+                               break;
+                       case SPECTRE_UNAFFECTED:
+                               val = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
+                               break;
+                       }
+                       break;
                }
                break;
        default:
@@ -438,7 +450,7 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
-       return 3;               /* PSCI version and two workaround registers */
+       return 4;               /* PSCI version and three workaround registers */
 }
 
 int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
@@ -452,6 +464,9 @@ int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
        if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++))
                return -EFAULT;
 
+       if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, uindices++))
+               return -EFAULT;
+
        return 0;
 }
 
@@ -486,9 +501,20 @@ static int get_kernel_wa_level(u64 regid)
                        return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED;
                case KVM_SSBD_UNKNOWN:
                default:
-                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN;
+                       break;
                }
-       }
+               return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN;
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+               switch (kvm_arm_get_spectre_bhb_state()) {
+               case SPECTRE_VULNERABLE:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+               case SPECTRE_MITIGATED:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
+               case SPECTRE_UNAFFECTED:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
+               }
+               return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+        }
 
        return -EINVAL;
 }
@@ -503,6 +529,7 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
                val = kvm_psci_version(vcpu, vcpu->kvm);
                break;
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
                val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
                break;
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
@@ -555,6 +582,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        }
 
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
                if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
                        return -EINVAL;