]> www.infradead.org Git - users/willy/xarray.git/commitdiff
arm/arm64: Probe for the presence of KVM hypervisor
authorWill Deacon <will@kernel.org>
Wed, 9 Dec 2020 06:09:24 +0000 (14:09 +0800)
committerMarc Zyngier <maz@kernel.org>
Wed, 31 Mar 2021 08:16:55 +0000 (09:16 +0100)
Although the SMCCC specification provides some limited functionality for
describing the presence of hypervisor and firmware services, this is
generally applicable only to functions designated as "Arm Architecture
Service Functions" and no portable discovery mechanism is provided for
standard hypervisor services, despite having a designated range of
function identifiers reserved by the specification.

In an attempt to avoid the need for additional firmware changes every
time a new function is added, introduce a UID to identify the service
provider as being compatible with KVM. Once this has been established,
additional services can be discovered via a feature bitmap.

Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
[maz: move code to its own file, plug it into PSCI]
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20201209060932.212364-2-jianyong.wu@arm.com
arch/arm/include/asm/hypervisor.h
arch/arm64/include/asm/hypervisor.h
drivers/firmware/psci/psci.c
drivers/firmware/smccc/Makefile
drivers/firmware/smccc/kvm_guest.c [new file with mode: 0644]
drivers/firmware/smccc/smccc.c
include/linux/arm-smccc.h

index df8524365637acf6e138ae223241157370b72385..bd61502b97153cfb83b12ccb9e2d5c42e8df6572 100644 (file)
@@ -4,4 +4,7 @@
 
 #include <asm/xen/hypervisor.h>
 
+void kvm_init_hyp_services(void);
+bool kvm_arm_hyp_service_available(u32 func_id);
+
 #endif
index f9cc1d021791504ee87b18ee22bb8896f4193a99..0ae427f352c8cab9440ae723735c396794cbe208 100644 (file)
@@ -4,4 +4,7 @@
 
 #include <asm/xen/hypervisor.h>
 
+void kvm_init_hyp_services(void);
+bool kvm_arm_hyp_service_available(u32 func_id);
+
 #endif
index f5fc429cae3f78a978697567296ca983c1da8ebd..69e296f02902903c1bef5827ac9272acfd7297a8 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <asm/cpuidle.h>
 #include <asm/cputype.h>
+#include <asm/hypervisor.h>
 #include <asm/system_misc.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
@@ -498,6 +499,7 @@ static int __init psci_probe(void)
                psci_init_cpu_suspend();
                psci_init_system_suspend();
                psci_init_system_reset2();
+               kvm_init_hyp_services();
        }
 
        return 0;
index 72ab840428324292e790aad95756a82aaf371a9f..40d19144a860724bd7fadd652ddbadf737a28695 100644 (file)
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 #
-obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o
+obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
 obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
diff --git a/drivers/firmware/smccc/kvm_guest.c b/drivers/firmware/smccc/kvm_guest.c
new file mode 100644 (file)
index 0000000..2d3e866
--- /dev/null
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "smccc: KVM: " fmt
+
+#include <linux/arm-smccc.h>
+#include <linux/bitmap.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/hypervisor.h>
+
+static DECLARE_BITMAP(__kvm_arm_hyp_services, ARM_SMCCC_KVM_NUM_FUNCS) __ro_after_init = { };
+
+void __init kvm_init_hyp_services(void)
+{
+       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)
+               return;
+
+       memset(&res, 0, sizeof(res));
+       arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID, &res);
+
+       val[0] = lower_32_bits(res.a0);
+       val[1] = lower_32_bits(res.a1);
+       val[2] = lower_32_bits(res.a2);
+       val[3] = lower_32_bits(res.a3);
+
+       bitmap_from_arr32(__kvm_arm_hyp_services, val, ARM_SMCCC_KVM_NUM_FUNCS);
+
+       pr_info("hypervisor services detected (0x%08lx 0x%08lx 0x%08lx 0x%08lx)\n",
+                res.a3, res.a2, res.a1, res.a0);
+}
+
+bool kvm_arm_hyp_service_available(u32 func_id)
+{
+       if (func_id >= ARM_SMCCC_KVM_NUM_FUNCS)
+               return false;
+
+       return test_bit(func_id, __kvm_arm_hyp_services);
+}
+EXPORT_SYMBOL_GPL(kvm_arm_hyp_service_available);
index d52bfc5ed5e4cb63502000dd9f28a022b3514de9..028f81d702cc5caa89f169ad4ec0f8eaf0488f61 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/cache.h>
 #include <linux/init.h>
 #include <linux/arm-smccc.h>
+#include <linux/kernel.h>
 #include <asm/archrandom.h>
 
 static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
index 62c54234576c4ab3e7c5dc13495e0f3a6d905adc..1a27bd9493fee093ae8810db1d70b595abd1a6f1 100644 (file)
@@ -55,6 +55,8 @@
 #define ARM_SMCCC_OWNER_TRUSTED_OS     50
 #define ARM_SMCCC_OWNER_TRUSTED_OS_END 63
 
+#define ARM_SMCCC_FUNC_QUERY_CALL_UID  0xff01
+
 #define ARM_SMCCC_QUIRK_NONE           0
 #define ARM_SMCCC_QUIRK_QCOM_A6                1 /* Save/restore register a6 */
 
                           ARM_SMCCC_SMC_32,                            \
                           0, 0x7fff)
 
+#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID                          \
+       ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,                         \
+                          ARM_SMCCC_SMC_32,                            \
+                          ARM_SMCCC_OWNER_VENDOR_HYP,                  \
+                          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
+
+/* KVM "vendor specific" services */
+#define ARM_SMCCC_KVM_FUNC_FEATURES            0
+#define ARM_SMCCC_KVM_FUNC_FEATURES_2          127
+#define ARM_SMCCC_KVM_NUM_FUNCS                        128
+
+#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID                      \
+       ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,                         \
+                          ARM_SMCCC_SMC_32,                            \
+                          ARM_SMCCC_OWNER_VENDOR_HYP,                  \
+                          ARM_SMCCC_KVM_FUNC_FEATURES)
+
 #define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED   1
 
 /* Paravirtualised time calls (defined by ARM DEN0057A) */