From 916db397d1c38a2104dcacb819485fecf29fd2e5 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 26 May 2022 14:22:34 +0000 Subject: [PATCH] ANDROID: Define mem_relinquish interface for releasing memory to a hypervisor. On PKVM/ARM64 this uses the ARM SMCCC relinquish hypercall when available. Bug: 240239989 Change-Id: Ifa85b641a48f348a2364cf8c6b06b6417f1eeedb Signed-off-by: Keir Fraser --- arch/Kconfig | 3 ++ arch/arm64/Kconfig | 1 + arch/arm64/include/asm/hypervisor.h | 6 +++ arch/arm64/include/asm/mem_relinquish.h | 12 +++++ arch/arm64/kernel/setup.c | 1 + arch/arm64/mm/Makefile | 1 + arch/arm64/mm/mem_relinquish.c | 58 +++++++++++++++++++++++++ include/linux/mem_relinquish.h | 20 +++++++++ 8 files changed, 102 insertions(+) create mode 100644 arch/arm64/include/asm/mem_relinquish.h create mode 100644 arch/arm64/mm/mem_relinquish.c create mode 100644 include/linux/mem_relinquish.h diff --git a/arch/Kconfig b/arch/Kconfig index b355c344ee72..cc54f3c2ee7e 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1238,6 +1238,9 @@ config RELR config ARCH_HAS_MEM_ENCRYPT bool +config ARCH_HAS_MEM_RELINQUISH + bool + config ARCH_HAS_CC_PLATFORM bool diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 6a496c3c30b1..b5221ff4d6f2 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -31,6 +31,7 @@ config ARM64 select ARCH_HAS_KEEPINITRD select ARCH_HAS_MEMBARRIER_SYNC_CORE select ARCH_HAS_MEM_ENCRYPT + select ARCH_HAS_MEM_RELINQUISH select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PTE_DEVMAP select ARCH_HAS_PTE_SPECIAL diff --git a/arch/arm64/include/asm/hypervisor.h b/arch/arm64/include/asm/hypervisor.h index ee45ae14be27..aa577913d019 100644 --- a/arch/arm64/include/asm/hypervisor.h +++ b/arch/arm64/include/asm/hypervisor.h @@ -10,4 +10,10 @@ void kvm_arm_init_hyp_services(void); void kvm_init_memshare_services(void); void kvm_init_ioremap_services(void); +#ifdef CONFIG_MEMORY_BALLOON +void kvm_init_memrelinquish_services(void); +#else +static inline void kvm_init_memrelinquish_services(void) {} +#endif + #endif diff --git a/arch/arm64/include/asm/mem_relinquish.h b/arch/arm64/include/asm/mem_relinquish.h new file mode 100644 index 000000000000..a4ace9e6e413 --- /dev/null +++ b/arch/arm64/include/asm/mem_relinquish.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022 Google LLC + * Author: Keir Fraser + */ + +#ifndef __ASM_MEM_RELINQUISH_H +#define __ASM_MEM_RELINQUISH_H + +void page_relinquish(struct page *page); + +#endif /* __ASM_MEM_RELINQUISH_H */ diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 6d5851bf913c..d232955738d7 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -452,4 +452,5 @@ void kvm_arm_init_hyp_services(void) { kvm_init_ioremap_services(); kvm_init_memshare_services(); + kvm_init_memrelinquish_services(); } diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile index 7368829df986..55dc9b83b352 100644 --- a/arch/arm64/mm/Makefile +++ b/arch/arm64/mm/Makefile @@ -3,6 +3,7 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ cache.o copypage.o flush.o \ ioremap.o mem_encrypt.o mmap.o pgd.o mmu.o \ context.o proc.o pageattr.o +obj-$(CONFIG_MEMORY_BALLOON) += mem_relinquish.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_PTDUMP_CORE) += ptdump.o obj-$(CONFIG_PTDUMP_DEBUGFS) += ptdump_debugfs.o diff --git a/arch/arm64/mm/mem_relinquish.c b/arch/arm64/mm/mem_relinquish.c new file mode 100644 index 000000000000..c95bcbb14d92 --- /dev/null +++ b/arch/arm64/mm/mem_relinquish.c @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022 Google LLC + * Author: Keir Fraser + */ + +#include +#include +#include +#include + +#include + +static unsigned long memshare_granule_sz; + +void kvm_init_memrelinquish_services(void) +{ + int i; + struct arm_smccc_res res; + const u32 funcs[] = { + ARM_SMCCC_KVM_FUNC_HYP_MEMINFO, + ARM_SMCCC_KVM_FUNC_MEM_RELINQUISH, + }; + + for (i = 0; i < ARRAY_SIZE(funcs); ++i) { + if (!kvm_arm_hyp_service_available(funcs[i])) + return; + } + + arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID, + 0, 0, 0, &res); + if (res.a0 > PAGE_SIZE) /* Includes error codes */ + return; + + memshare_granule_sz = res.a0; +} + +void page_relinquish(struct page *page) +{ + phys_addr_t phys, end; + u32 func_id = ARM_SMCCC_VENDOR_HYP_KVM_MEM_RELINQUISH_FUNC_ID; + + if (!memshare_granule_sz) + 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 += memshare_granule_sz; + } +} +EXPORT_SYMBOL_GPL(page_relinquish); diff --git a/include/linux/mem_relinquish.h b/include/linux/mem_relinquish.h new file mode 100644 index 000000000000..6b7bf861d92d --- /dev/null +++ b/include/linux/mem_relinquish.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022 Google LLC + * Author: Keir Fraser + */ + +#ifndef __MEM_RELINQUISH_H__ +#define __MEM_RELINQUISH_H__ + +#ifdef CONFIG_ARCH_HAS_MEM_RELINQUISH + +#include + +#else /* !CONFIG_ARCH_HAS_MEM_RELINQUISH */ + +static inline void page_relinquish(struct page *page) { } + +#endif /* CONFIG_ARCH_HAS_MEM_RELINQUISH */ + +#endif /* __MEM_RELINQUISH_H__ */