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