From 29fc73bbf23a56e96be97192aa2baf662ce2ad17 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Fri, 24 Jan 2025 14:34:19 -0800 Subject: [PATCH] ANDROID: virt: gunyah-guest: Add gunyah-guest Add a Gunyah protected guest driver. A Gunyah protected guest needs to be hypervisor-aware to relinquish pages to the host/owner for virtio-balloon. In the Android Virtualization Framework model, the host/owner VM, not the hypervisor, owns the virtio devices. The hypervisor is unaware about the virtio device and thus the guest needs to inform the hypervisor that the host can access guest-private memory. Bug: 395833312 Change-Id: I082dff22d12453005728d229b87ef11a8dce9c6b Signed-off-by: Elliot Berman Signed-off-by: Prakruthi Deepak Heragu --- drivers/virt/coco/Kconfig | 2 + drivers/virt/coco/Makefile | 1 + drivers/virt/coco/gunyah-guest/Kconfig | 12 +++ drivers/virt/coco/gunyah-guest/Makefile | 2 + drivers/virt/coco/gunyah-guest/gunyah-guest.c | 79 +++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 drivers/virt/coco/gunyah-guest/Kconfig create mode 100644 drivers/virt/coco/gunyah-guest/Makefile create mode 100644 drivers/virt/coco/gunyah-guest/gunyah-guest.c diff --git a/drivers/virt/coco/Kconfig b/drivers/virt/coco/Kconfig index d9ff676bf48d..a8c8e17d4ba2 100644 --- a/drivers/virt/coco/Kconfig +++ b/drivers/virt/coco/Kconfig @@ -11,6 +11,8 @@ source "drivers/virt/coco/efi_secret/Kconfig" source "drivers/virt/coco/pkvm-guest/Kconfig" +source "drivers/virt/coco/gunyah-guest/Kconfig" + source "drivers/virt/coco/sev-guest/Kconfig" source "drivers/virt/coco/tdx-guest/Kconfig" diff --git a/drivers/virt/coco/Makefile b/drivers/virt/coco/Makefile index b69c30c1c720..0f48d0b18f1b 100644 --- a/drivers/virt/coco/Makefile +++ b/drivers/virt/coco/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_TSM_REPORTS) += tsm.o obj-$(CONFIG_EFI_SECRET) += efi_secret/ obj-$(CONFIG_ARM_PKVM_GUEST) += pkvm-guest/ +obj-$(CONFIG_GUNYAH_GUEST) += gunyah-guest/ obj-$(CONFIG_SEV_GUEST) += sev-guest/ obj-$(CONFIG_INTEL_TDX_GUEST) += tdx-guest/ diff --git a/drivers/virt/coco/gunyah-guest/Kconfig b/drivers/virt/coco/gunyah-guest/Kconfig new file mode 100644 index 000000000000..7e5ce657ab81 --- /dev/null +++ b/drivers/virt/coco/gunyah-guest/Kconfig @@ -0,0 +1,12 @@ +config GUNYAH_GUEST + bool "Gunyah protected guest driver" + depends on ARM64 + select ARCH_HAS_MEM_RELINQUISH + select GUNYAH_HYPERCALLS + help + Protected guests running under the Gunyah hypervisor + are isolated from the host and must issue hypercalls to enable + interaction with virtual devices. This driver implements + support for probing and issuing these hypercalls. + + If unsure, say 'N'. diff --git a/drivers/virt/coco/gunyah-guest/Makefile b/drivers/virt/coco/gunyah-guest/Makefile new file mode 100644 index 000000000000..0d71d1156737 --- /dev/null +++ b/drivers/virt/coco/gunyah-guest/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_GUNYAH_GUEST) += gunyah-guest.o diff --git a/drivers/virt/coco/gunyah-guest/gunyah-guest.c b/drivers/virt/coco/gunyah-guest/gunyah-guest.c new file mode 100644 index 000000000000..b6c758eddc25 --- /dev/null +++ b/drivers/virt/coco/gunyah-guest/gunyah-guest.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. */ + +#include +#include +#include + +#include + +#define ADDRSPACE_INFO_AREA_ROOTVM_ADDRSPACE_CAP ((uint16_t)0) +struct addrspace_info_area_rootvm_addrspace_cap { + u64 addrspace_cap; + u32 rights; + u32 res0; +}; + +static u64 our_addrspace_capid; + +#ifdef CONFIG_VIRTIO_BALLOON_HYP_OPS +static void gunyah_page_relinquish(struct page *page, unsigned int nr) +{ + /* Release page to Host, so unlock and sanitize */ + u64 flags = BIT_ULL(GUNYAH_ADDRSPC_MODIFY_FLAG_UNLOCK_BIT) | + BIT_ULL(GUNYAH_ADDRSPC_MODIFY_FLAG_SANITIZE_BIT); + phys_addr_t phys, end; + int ret = 0; + + phys = page_to_phys(page); + end = phys + PAGE_SIZE * nr; + + while (phys < end) { + ret = gunyah_hypercall_addrspc_modify_pages(our_addrspace_capid, + phys, PAGE_SIZE, flags); + if (ret) + pr_err_ratelimited("Failed to relinquish page: %016llx %d\n", phys, ret); + + phys += PAGE_SIZE; + } + +} + +static void gunyah_post_page_relinquish_tlb_inv(void) +{ + /* Release page to Host, so unlock and sanitize */ + int ret = 0; + + ret = gunyah_hypercall_addrspc_modify_pages(our_addrspace_capid, 0, 0, 0); + if (ret) + pr_err_ratelimited("Failed to flush tlb: %d\n", ret); +} + +static struct virtio_balloon_hyp_ops gunyah_virtio_balloon_hyp_ops = { + .page_relinquish = gunyah_page_relinquish, + .post_page_relinquish_tlb_inv = gunyah_post_page_relinquish_tlb_inv +}; + +#endif + +static int __init gunyah_guest_init(void) +{ + struct addrspace_info_area_rootvm_addrspace_cap *info; + size_t size; + + info = gunyah_get_info(GUNYAH_INFO_OWNER_ROOTVM, ADDRSPACE_INFO_AREA_ROOTVM_ADDRSPACE_CAP, + &size); + if (IS_ERR(info)) + return PTR_ERR(info); + + if (size != sizeof(*info)) + return -EINVAL; + + our_addrspace_capid = info->addrspace_cap; + +#ifdef CONFIG_VIRTIO_BALLOON_HYP_OPS + virtio_balloon_hyp_ops = &gunyah_virtio_balloon_hyp_ops; +#endif + return 0; +} +core_initcall_sync(gunyah_guest_init);