From 49b37e78cbf64e5980b9595c3aef62a4f40cca0d Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Fri, 15 Nov 2024 17:13:52 +0000 Subject: [PATCH] ANDROID: KVM: Do not memset hyp_page from reclaim_hyp_pool() reclaim_hyp_pool() zeroes the entire struct hyp_page when returning a page to the host. However, this is no longer the canonical way to do it since we store the host ownership state in struct hyp_page. Fix this by only changing the refcount and order members of the hyp_page, and while at it make the code common with drain_hyp_pool() which does something very similar. Bug: 379022162 Change-Id: I58941ae6ef8e62ff17cba8508cb41cddfefebe1d Signed-off-by: Quentin Perret --- arch/arm64/kvm/hyp/nvhe/mem_protect.c | 9 +-------- arch/arm64/kvm/hyp/nvhe/mm.c | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 154ca6d6973b..10cef39924ff 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -2441,14 +2441,7 @@ void destroy_hyp_vm_pgt(struct pkvm_hyp_vm *vm) void drain_hyp_pool(struct pkvm_hyp_vm *vm, struct kvm_hyp_memcache *mc) { - void *addr = hyp_alloc_pages(&vm->pool, 0); - - while (addr) { - hyp_page_ref_dec(hyp_virt_to_page(addr)); - push_hyp_memcache(mc, addr, hyp_virt_to_phys, 0); - WARN_ON(__pkvm_hyp_donate_host(hyp_virt_to_pfn(addr), 1)); - addr = hyp_alloc_pages(&vm->pool, 0); - } + WARN_ON(reclaim_hyp_pool(&vm->pool, mc, INT_MAX) != -ENOMEM); } int __pkvm_host_reclaim_page(struct pkvm_hyp_vm *vm, u64 pfn, u64 ipa) diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c index 776fc693e858..9d3a76ef6e02 100644 --- a/arch/arm64/kvm/hyp/nvhe/mm.c +++ b/arch/arm64/kvm/hyp/nvhe/mm.c @@ -548,18 +548,31 @@ int refill_hyp_pool(struct hyp_pool *pool, struct kvm_hyp_memcache *host_mc) int reclaim_hyp_pool(struct hyp_pool *pool, struct kvm_hyp_memcache *host_mc, int nr_pages) { - void *p; struct hyp_page *page; + u8 order; + void *p; while (nr_pages > 0) { p = hyp_alloc_pages(pool, 0); if (!p) return -ENOMEM; page = hyp_virt_to_page(p); - nr_pages -= (1 << page->order); - push_hyp_memcache(host_mc, p, hyp_virt_to_phys, page->order); - WARN_ON(__pkvm_hyp_donate_host(hyp_virt_to_pfn(p), 1 << page->order)); - memset(page, 0, sizeof(struct hyp_page)); + order = page->order; + nr_pages -= (1 << order); + + /* + * For a compound page all the tail pages should normally + * have page->order == HYP_NO_ORDER which would need to be + * cleared one by one. But in this instance, the order 0 + * allocation above can only return an _external_ compound + * page which is in fact ignored by the buddy logic, and the + * tail pages are never touched. + */ + page->order = 0; + hyp_page_ref_dec(page); + + push_hyp_memcache(host_mc, p, hyp_virt_to_phys, order); + WARN_ON(__pkvm_hyp_donate_host(hyp_virt_to_pfn(p), 1 << order)); } return 0;