diff options
author | Will Deacon <willdeacon@google.com> | 2022-01-18 09:28:12 +0000 |
---|---|---|
committer | Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org> | 2023-03-29 15:55:16 +0800 |
commit | 366d5432991f729576079665db7b98c2f5cc311b (patch) | |
tree | 478174585cc561ced7dcb45026147d21c4c97961 | |
parent | d072eff4d37cfd54132f5e40317e3a8a59d0b13f (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.c | 98 | ||||
-rw-r--r-- | include/linux/arm-smccc.h | 49 |
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 |