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 <keirf@google.com>
This commit is contained in:
Keir Fraser
2022-05-26 14:22:34 +00:00
parent 4f63005d09
commit b6f573ff43
5 changed files with 73 additions and 11 deletions
+3
View File
@@ -1517,6 +1517,9 @@ config RELR
config ARCH_HAS_MEM_ENCRYPT
bool
config ARCH_HAS_MEM_RELINQUISH
bool
config ARCH_HAS_CC_PLATFORM
bool
+1
View File
@@ -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
+40 -11
View File
@@ -11,6 +11,7 @@
#include <linux/array_size.h>
#include <linux/io.h>
#include <linux/mem_encrypt.h>
#include <linux/mem_relinquish.h>
#include <linux/mm.h>
#include <linux/pgtable.h>
@@ -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
}
+22
View File
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2022 Google LLC
* Author: Keir Fraser <keirf@google.com>
*/
#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__ */
+7
View File
@@ -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