Re: [RFC PATCH v2 10/26] KVM: arm64: Introduce an early Hyp page allocator
From: Will Deacon <will@kernel.org>
Date: 2021-02-01 19:00:59
Also in:
kvmarm, linux-arm-kernel, lkml
On Fri, Jan 08, 2021 at 12:15:08PM +0000, Quentin Perret wrote:
quoted hunk ↗ jump to hunk
diff --git a/arch/arm64/kvm/hyp/nvhe/early_alloc.c b/arch/arm64/kvm/hyp/nvhe/early_alloc.c new file mode 100644 index 000000000000..de4c45662970 --- /dev/null +++ b/arch/arm64/kvm/hyp/nvhe/early_alloc.c@@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Google LLC + * Author: Quentin Perret <qperret@google.com> + */ + +#include <asm/kvm_pgtable.h> + +#include <nvhe/memory.h> + +struct kvm_pgtable_mm_ops hyp_early_alloc_mm_ops; +s64 __ro_after_init hyp_physvirt_offset; + +static unsigned long base; +static unsigned long end; +static unsigned long cur; + +unsigned long hyp_early_alloc_nr_pages(void) +{ + return (cur - base) >> PAGE_SHIFT; +}
nit: but I find this function name confusing (it's returning the number of _allocated_ pages, not the number of _free_ pages!). How about something like hyp_early_alloc_size() to match hyp_s1_pgtable_size() which you add later? [and move the shift out to the caller]?
+ +extern void clear_page(void *to);
Stick this in a header?
+ +void *hyp_early_alloc_contig(unsigned int nr_pages)
I think order might make more sense, or do you need to allocate non-power-of-2 batches of pages?
+{
+ unsigned long ret = cur, i, p;
+
+ if (!nr_pages)
+ return NULL;
+
+ cur += nr_pages << PAGE_SHIFT;
+ if (cur > end) {This would mean that concurrent hyp_early_alloc_nr_pages() would transiently give the wrong answer. Might be worth sticking the locking expectations with the function prototypes. That said, maybe it would be better to write this check as: if (end - cur < (nr_pages << PAGE_SHIFT)) as that also removes the need to worry about overflow if nr_pages is huge (which would be a bug in the hypervisor, which we would then catch here).
+ cur = ret;
+ return NULL;
+ }
+
+ for (i = 0; i < nr_pages; i++) {
+ p = ret + (i << PAGE_SHIFT);
+ clear_page((void *)(p));
+ }
+
+ return (void *)ret;
+}
+
+void *hyp_early_alloc_page(void *arg)
+{
+ return hyp_early_alloc_contig(1);
+}
+
+void hyp_early_alloc_init(unsigned long virt, unsigned long size)
+{
+ base = virt;
+ end = virt + size;
+ cur = virt;nit: base = cur = virt; Will