arm/arm64: Probe for the presence of KVM hypervisor
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
This commit is contained in:
parent
1e28eed176
commit
6e085e0ac9
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
@ -87,6 +89,29 @@
|
|||
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) */
|
||||
|
|
Loading…
Reference in New Issue