From b6f573ff432fbf1f31cd5a6c2b25da21af9b67df Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 26 May 2022 14:22:34 +0000 Subject: [PATCH] ANDROID: KVM: Define mem_relinquish interface for releasing memory to a hypervisor. On PKVM/ARM64 this uses the ARM SMCCC relinquish hypercall when available. Memory relinquish interface is used by both memory ballooning and by page reporting. It must be built if either is specified. Bug: 357781595 Change-Id: Ifa85b641a48f348a2364cf8c6b06b6417f1eeedb Signed-off-by: Keir Fraser --- arch/Kconfig | 3 ++ drivers/virt/coco/pkvm-guest/Kconfig | 1 + drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 51 +++++++++++++++---- include/linux/mem_relinquish.h | 22 ++++++++ mm/Kconfig | 7 +++ 5 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 include/linux/mem_relinquish.h diff --git a/arch/Kconfig b/arch/Kconfig index 00163e4a237c..2cd8591a8cfe 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1517,6 +1517,9 @@ config RELR config ARCH_HAS_MEM_ENCRYPT bool +config ARCH_HAS_MEM_RELINQUISH + bool + config ARCH_HAS_CC_PLATFORM bool diff --git a/drivers/virt/coco/pkvm-guest/Kconfig b/drivers/virt/coco/pkvm-guest/Kconfig index d2f344f1f98f..dac8b71069fb 100644 --- a/drivers/virt/coco/pkvm-guest/Kconfig +++ b/drivers/virt/coco/pkvm-guest/Kconfig @@ -1,6 +1,7 @@ config ARM_PKVM_GUEST bool "Arm pKVM protected guest driver" depends on ARM64 + select ARCH_HAS_MEM_RELINQUISH help Protected guests running under the pKVM hypervisor on arm64 are isolated from the host and must issue hypercalls to enable diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c index e23f1333af5f..0672e3637731 100644 --- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c +++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -99,20 +100,40 @@ static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size, return 0; } +#ifdef CONFIG_MEMORY_RELINQUISH + +static bool mem_relinquish_available; + +void page_relinquish(struct page *page) +{ + phys_addr_t phys, end; + u32 func_id = ARM_SMCCC_VENDOR_HYP_KVM_MEM_RELINQUISH_FUNC_ID; + + if (!mem_relinquish_available) + return; + + phys = page_to_phys(page); + end = phys + PAGE_SIZE; + + while (phys < end) { + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(func_id, phys, 0, 0, &res); + BUG_ON(res.a0 != SMCCC_RET_SUCCESS); + + phys += pkvm_granule; + } +} +EXPORT_SYMBOL_GPL(page_relinquish); + +#endif + void pkvm_init_hyp_services(void) { - int i; struct arm_smccc_res res; - const u32 funcs[] = { - ARM_SMCCC_KVM_FUNC_HYP_MEMINFO, - ARM_SMCCC_KVM_FUNC_MEM_SHARE, - ARM_SMCCC_KVM_FUNC_MEM_UNSHARE, - }; - for (i = 0; i < ARRAY_SIZE(funcs); ++i) { - if (!kvm_arm_hyp_service_available(funcs[i])) - return; - } + if (!kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_HYP_MEMINFO)) + return; arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID, 0, 0, 0, &res); @@ -120,8 +141,16 @@ void pkvm_init_hyp_services(void) return; pkvm_granule = res.a0; - arm64_mem_crypt_ops_register(&pkvm_crypt_ops); + + if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MEM_SHARE) && + kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MEM_UNSHARE)) + arm64_mem_crypt_ops_register(&pkvm_crypt_ops); if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD_MAP)) arm64_ioremap_prot_hook_register(&mmio_guard_ioremap_hook); + +#ifdef CONFIG_MEMORY_RELINQUISH + if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MEM_RELINQUISH)) + mem_relinquish_available = true; +#endif } diff --git a/include/linux/mem_relinquish.h b/include/linux/mem_relinquish.h new file mode 100644 index 000000000000..3a006ae6ca79 --- /dev/null +++ b/include/linux/mem_relinquish.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022 Google LLC + * Author: Keir Fraser + */ + +#ifndef __MEM_RELINQUISH_H__ +#define __MEM_RELINQUISH_H__ + +struct page; + +#ifdef CONFIG_MEMORY_RELINQUISH + +void page_relinquish(struct page *page); + +#else /* !CONFIG_MEMORY_RELINQUISH */ + +static inline void page_relinquish(struct page *page) { } + +#endif /* CONFIG_MEMORY_RELINQUISH */ + +#endif /* __MEM_RELINQUISH_H__ */ diff --git a/mm/Kconfig b/mm/Kconfig index 4c9f5ea13271..952765c1fc42 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -613,6 +613,13 @@ config SPLIT_PMD_PTLOCKS config MEMORY_BALLOON bool +# +# support for memory relinquish +config MEMORY_RELINQUISH + def_bool y + depends on ARCH_HAS_MEM_RELINQUISH + depends on MEMORY_BALLOON || PAGE_REPORTING + # # support for memory balloon compaction config BALLOON_COMPACTION