]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
arm64: kvm, smccc: Introduce and use API for getting hypervisor UUID
authorRoman Kisel <romank@linux.microsoft.com>
Mon, 28 Apr 2025 21:07:32 +0000 (14:07 -0700)
committerWei Liu <wei.liu@kernel.org>
Fri, 23 May 2025 16:30:55 +0000 (16:30 +0000)
The KVM/arm64 uses SMCCC to detect hypervisor presence. That code is
private, and it follows the SMCCC specification. Other existing and
emerging hypervisor guest implementations can and should use that
standard approach as well.

Factor out a common infrastructure that the guests can use, update KVM
to employ the new API. The central notion of the SMCCC method is the
UUID of the hypervisor, and the new API follows that.

No functional changes. Validated with a KVM/arm64 guest.

Signed-off-by: Roman Kisel <romank@linux.microsoft.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Link: https://lore.kernel.org/r/20250428210742.435282-2-romank@linux.microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Message-ID: <20250428210742.435282-2-romank@linux.microsoft.com>

arch/arm64/kvm/hypercalls.c
drivers/firmware/smccc/kvm_guest.c
drivers/firmware/smccc/smccc.c
include/linux/arm-smccc.h

index 569941eeb3fe9f611d6d813895fea9bb38e20d06..58c5fe7d757274d9079606fcc378485980c6c0f8 100644 (file)
@@ -270,6 +270,7 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
        u32 feature;
        u8 action;
        gpa_t gpa;
+       uuid_t uuid;
 
        action = kvm_smccc_get_action(vcpu, func_id);
        switch (action) {
@@ -355,10 +356,11 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
                        val[0] = gpa;
                break;
        case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
-               val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0;
-               val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1;
-               val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2;
-               val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
+               uuid = ARM_SMCCC_VENDOR_HYP_UID_KVM;
+               val[0] = smccc_uuid_to_reg(&uuid, 0);
+               val[1] = smccc_uuid_to_reg(&uuid, 1);
+               val[2] = smccc_uuid_to_reg(&uuid, 2);
+               val[3] = smccc_uuid_to_reg(&uuid, 3);
                break;
        case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
                val[0] = smccc_feat->vendor_hyp_bmap;
index a123c05cbc9e66ad145eb6c230b8867c9d2a6eb8..49e1de83d2e8f4b126f8b908cea103498f2ef2f1 100644 (file)
@@ -17,17 +17,11 @@ static DECLARE_BITMAP(__kvm_arm_hyp_services, ARM_SMCCC_KVM_NUM_FUNCS) __ro_afte
 
 void __init kvm_init_hyp_services(void)
 {
+       uuid_t kvm_uuid = ARM_SMCCC_VENDOR_HYP_UID_KVM;
        struct arm_smccc_res res;
        u32 val[4];
 
-       if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_HVC)
-               return;
-
-       arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res);
-       if (res.a0 != ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 ||
-           res.a1 != ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 ||
-           res.a2 != ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 ||
-           res.a3 != ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3)
+       if (!arm_smccc_hypervisor_has_uuid(&kvm_uuid))
                return;
 
        memset(&res, 0, sizeof(res));
index a74600d9f2d72a5aa0096004f53088c255927a43..cd65b434dc6e8b81ecdf98bc64e3dc67baeb8666 100644 (file)
@@ -67,6 +67,23 @@ s32 arm_smccc_get_soc_id_revision(void)
 }
 EXPORT_SYMBOL_GPL(arm_smccc_get_soc_id_revision);
 
+bool arm_smccc_hypervisor_has_uuid(const uuid_t *hyp_uuid)
+{
+       struct arm_smccc_res res = {};
+       uuid_t uuid;
+
+       if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_HVC)
+               return false;
+
+       arm_smccc_1_1_hvc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res);
+       if (res.a0 == SMCCC_RET_NOT_SUPPORTED)
+               return false;
+
+       uuid = smccc_res_to_uuid(res.a0, res.a1, res.a2, res.a3);
+       return uuid_equal(&uuid, hyp_uuid);
+}
+EXPORT_SYMBOL_GPL(arm_smccc_hypervisor_has_uuid);
+
 static int __init smccc_devices_init(void)
 {
        struct platform_device *pdev;
index a3863da1510ee2f874e21bb16922dec277d55c93..784ebe4607a47b95973d4e33d76469aa52eb7aea 100644 (file)
@@ -7,6 +7,11 @@
 
 #include <linux/args.h>
 #include <linux/init.h>
+
+#ifndef __ASSEMBLY__
+#include <linux/uuid.h>
+#endif
+
 #include <uapi/linux/const.h>
 
 /*
                           ARM_SMCCC_FUNC_QUERY_CALL_UID)
 
 /* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */
-#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0     0xb66fb428U
-#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1     0xe911c52eU
-#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2     0x564bcaa9U
-#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3     0x743a004dU
+#define ARM_SMCCC_VENDOR_HYP_UID_KVM UUID_INIT(\
+       0xb66fb428, 0xc52e, 0xe911, \
+       0xa9, 0xca, 0x4b, 0x56, \
+       0x4d, 0x00, 0x3a, 0x74)
 
 /* KVM "vendor specific" services */
 #define ARM_SMCCC_KVM_FUNC_FEATURES            0
@@ -348,6 +353,57 @@ s32 arm_smccc_get_soc_id_version(void);
  */
 s32 arm_smccc_get_soc_id_revision(void);
 
+#ifndef __ASSEMBLY__
+
+/*
+ * Returns whether a specific hypervisor UUID is advertised for the
+ * Vendor Specific Hypervisor Service range.
+ */
+bool arm_smccc_hypervisor_has_uuid(const uuid_t *uuid);
+
+static inline uuid_t smccc_res_to_uuid(u32 r0, u32 r1, u32 r2, u32 r3)
+{
+       uuid_t uuid = {
+               .b = {
+                       [0]  = (r0 >> 0)  & 0xff,
+                       [1]  = (r0 >> 8)  & 0xff,
+                       [2]  = (r0 >> 16) & 0xff,
+                       [3]  = (r0 >> 24) & 0xff,
+
+                       [4]  = (r1 >> 0)  & 0xff,
+                       [5]  = (r1 >> 8)  & 0xff,
+                       [6]  = (r1 >> 16) & 0xff,
+                       [7]  = (r1 >> 24) & 0xff,
+
+                       [8]  = (r2 >> 0)  & 0xff,
+                       [9]  = (r2 >> 8)  & 0xff,
+                       [10] = (r2 >> 16) & 0xff,
+                       [11] = (r2 >> 24) & 0xff,
+
+                       [12] = (r3 >> 0)  & 0xff,
+                       [13] = (r3 >> 8)  & 0xff,
+                       [14] = (r3 >> 16) & 0xff,
+                       [15] = (r3 >> 24) & 0xff,
+               },
+       };
+
+       return uuid;
+}
+
+static inline u32 smccc_uuid_to_reg(const uuid_t *uuid, int reg)
+{
+       u32 val = 0;
+
+       val |= (u32)(uuid->b[4 * reg + 0] << 0);
+       val |= (u32)(uuid->b[4 * reg + 1] << 8);
+       val |= (u32)(uuid->b[4 * reg + 2] << 16);
+       val |= (u32)(uuid->b[4 * reg + 3] << 24);
+
+       return val;
+}
+
+#endif /* !__ASSEMBLY__ */
+
 /**
  * struct arm_smccc_res - Result from SMC/HVC call
  * @a0-a3 result values from registers 0 to 3