aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Deacon <willdeacon@google.com>2022-01-18 09:28:12 +0000
committerYing-Chun Liu (PaulLiu) <paul.liu@linaro.org>2023-03-29 15:55:16 +0800
commit366d5432991f729576079665db7b98c2f5cc311b (patch)
tree478174585cc561ced7dcb45026147d21c4c97961
parentd072eff4d37cfd54132f5e40317e3a8a59d0b13f (diff)
ANDROID: kvm: Hook up share/unshare callbacks for pKVM hyp servicespaulliu-kvm-hyp-services
Probe for the presence of ARM_SMCCC_KVM_FUNC_HYP_MEMINFO and hook up the SHARE/UNSHARE hypercalls if available. Bug: 209797374 Signed-off-by: Will Deacon <willdeacon@google.com> Change-Id: Iea6f4100c1b44714b4f7751d2ca5706d6c2f2952
-rw-r--r--drivers/firmware/kvm-hyp-services.c98
-rw-r--r--include/linux/arm-smccc.h49
2 files changed, 146 insertions, 1 deletions
diff --git a/drivers/firmware/kvm-hyp-services.c b/drivers/firmware/kvm-hyp-services.c
index bfb5ab5fba1..2e62f16aa50 100644
--- a/drivers/firmware/kvm-hyp-services.c
+++ b/drivers/firmware/kvm-hyp-services.c
@@ -5,8 +5,14 @@
#include <common.h>
#include <dm.h>
+#include <malloc.h>
+#include <virtio_types.h>
+#include <virtio.h>
+#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/arm-smccc.h>
+#include <linux/compat.h>
+#include <linux/psci.h>
#define DRIVER_NAME "kvm-hyp-services"
@@ -16,6 +22,23 @@ static bool kvm_hyp_services_is_supported(void (*invoke_fn)(unsigned long a0, un
unsigned long a6, unsigned long a7,
struct arm_smccc_res *res))
{
+ u32 smccc_version = ARM_SMCCC_VERSION_1_0;
+ struct arm_smccc_res res;
+
+ smccc_version = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
+
+ if (smccc_version < ARM_SMCCC_VERSION_1_1)
+ return false;
+
+ (*invoke_fn)(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID,
+ 0, 0, 0, 0, 0, 0, 0, &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 false;
+
return true;
}
@@ -24,11 +47,84 @@ ARM_SMCCC_FEATURE_DRIVER(kvm_hyp_services) = {
.is_supported = kvm_hyp_services_is_supported,
};
-static int kvm_hyp_services_probe(struct udevice *dev)
+extern struct virtio_iommu_platform_ops *virtio_iommu_platform_ops;
+
+static int kvm_hyp_mem_share(struct udevice *udev, void *addr, u32 npages)
+{
+ struct psci_plat_data *smccc = dev_get_parent_plat(udev);
+
+ while (npages--) {
+ struct arm_smccc_res res;
+ phys_addr_t phys = virt_to_phys(addr);
+
+ smccc->invoke_fn(ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID,
+ phys, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0 != SMCCC_RET_SUCCESS)
+ return -EPERM;
+
+ addr += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static int kvm_hyp_mem_unshare(struct udevice *udev, void *addr, u32 npages)
+{
+ struct psci_plat_data *smccc = dev_get_parent_plat(udev);
+
+ while (npages--) {
+ struct arm_smccc_res res;
+ phys_addr_t phys = virt_to_phys(addr);
+
+ smccc->invoke_fn(ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID,
+ phys, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0 != SMCCC_RET_SUCCESS)
+ return -EPERM;
+
+ addr += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static int kvm_hyp_memshare_init(unsigned long features, struct psci_plat_data *smccc)
{
+ static struct virtio_iommu_platform_ops ops = {
+ .map = kvm_hyp_mem_share,
+ .unmap = kvm_hyp_mem_unshare,
+ };
+ struct arm_smccc_res res;
+
+ smccc->invoke_fn(ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+
+ if (res.a0 != PAGE_SIZE)
+ return -ENXIO;
+
+ virtio_iommu_platform_ops = &ops;
return 0;
}
+static int kvm_hyp_services_probe(struct udevice *dev)
+{
+ int ret = 0;
+ struct psci_plat_data *smccc = dev_get_parent_plat(dev);
+ struct arm_smccc_res res;
+
+ if (!(kvm_hyp_services_is_supported(smccc->invoke_fn)))
+ return -ENXIO;
+
+ memset(&res, 0, sizeof(res));
+ smccc->invoke_fn(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+
+ if (res.a0 & BIT(ARM_SMCCC_KVM_FUNC_HYP_MEMINFO))
+ ret = kvm_hyp_memshare_init(res.a0, smccc);
+
+ pr_debug("Probed KVM hypervisor services: 0x%08x\n", (u32)res.a0);
+ return ret;
+}
+
U_BOOT_DRIVER(kvm_hyp_services) = {
.name = DRIVER_NAME,
.id = UCLASS_FIRMWARE,
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 49838ad51b5..9f983c64b6c 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -43,11 +43,15 @@
#define ARM_SMCCC_OWNER_SIP 2
#define ARM_SMCCC_OWNER_OEM 3
#define ARM_SMCCC_OWNER_STANDARD 4
+#define ARM_SMCCC_OWNER_STANDARD_HYP 5
+#define ARM_SMCCC_OWNER_VENDOR_HYP 6
#define ARM_SMCCC_OWNER_TRUSTED_APP 48
#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49
#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 */
@@ -69,6 +73,51 @@
ARM_SMCCC_SMC_32, \
0, 1)
+#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_PTP 1
+#define ARM_SMCCC_KVM_FUNC_HYP_MEMINFO 2
+#define ARM_SMCCC_KVM_FUNC_MEM_SHARE 3
+#define ARM_SMCCC_KVM_FUNC_MEM_UNSHARE 4
+#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 ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_VENDOR_HYP, \
+ ARM_SMCCC_KVM_FUNC_HYP_MEMINFO)
+
+#define ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_VENDOR_HYP, \
+ ARM_SMCCC_KVM_FUNC_MEM_SHARE)
+
+#define ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_VENDOR_HYP, \
+ ARM_SMCCC_KVM_FUNC_MEM_UNSHARE)
+
/*
* Return codes defined in ARM DEN 0070A
* ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C