[PATCH v4 17/17] KVM: arm64: Alloc simple_buffer_page using pKVM hyp allocator
Fuad Tabba
fuad.tabba at linux.dev
Mon Aug 17 07:16:00 PDT 2026
On Fri, 31 Jul 2026 at 15:36, Vincent Donnefort <vdonnefort at google.com> wrote:
>
> In protected mode, transition the allocation of the simple_ring_buffer
> structures from the host to the hypervisor using the new pKVM heap
> allocator.
>
> Previously, the host allocated and donated a contiguous backing memory
> for these structures. In pKVM the hypervisor can now allocate them
> dynamically.
>
> Use the pkvm_call_hyp_req() wrapper in the host to invoke
> __tracing_load, which automatically handles any top-up requests if the
> hypervisor runs out of heap memory during allocation.
>
> Tested-by: Fuad Tabba <fuad.tabba at linux.dev>
> Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
Reviewed-by: Fuad Tabba <fuad.tabba at linux.dev>
Cheers,
/fuad
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 9bab1e802281..ec5bb8541ceb 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -750,7 +750,7 @@ static void handle___tracing_load(struct kvm_cpu_context *host_ctxt)
> DECLARE_REG(unsigned long, desc_hva, host_ctxt, 1);
> DECLARE_REG(size_t, desc_size, host_ctxt, 2);
>
> - cpu_reg(host_ctxt, 1) = __tracing_load(desc_hva, desc_size);
> + errno_to_smccc(__tracing_load(desc_hva, desc_size), host_ctxt);
> }
>
> static void handle___tracing_unload(struct kvm_cpu_context *host_ctxt)
> diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
> index 96afa3d6de2f..5ff19d210508 100644
> --- a/arch/arm64/kvm/hyp/nvhe/trace.c
> +++ b/arch/arm64/kvm/hyp/nvhe/trace.c
> @@ -4,6 +4,7 @@
> * Author: Vincent Donnefort <vdonnefort at google.com>
> */
>
> +#include <nvhe/alloc.h>
> #include <nvhe/clock.h>
> #include <nvhe/mem_protect.h>
> #include <nvhe/mm.h>
> @@ -62,18 +63,34 @@ static void __release_host_mem(void *start, u64 size)
> WARN_ON(__pkvm_hyp_donate_host(hyp_virt_to_pfn(start), size >> PAGE_SHIFT));
> }
>
> -static int hyp_trace_buffer_load_bpage_backing(struct hyp_trace_buffer *trace_buffer,
> - struct hyp_trace_desc *desc)
> +static int hyp_trace_buffer_alloc_bpages(struct hyp_trace_buffer *trace_buffer,
> + struct hyp_trace_desc *desc)
> {
> - void *start = (void *)kern_hyp_va(desc->bpages_backing_start);
> - size_t size = desc->bpages_backing_size;
> + void *start;
> + size_t size;
> int ret;
>
> - ret = __admit_host_mem(start, size);
> - if (ret)
> - return ret;
> + if (is_protected_kvm_enabled()) {
> + struct ring_buffer_desc *rb_desc;
> + int cpu;
>
> - memset(start, 0, size);
> + size = 0;
> + for_each_ring_buffer_desc(rb_desc, cpu, &desc->trace_buffer_desc)
> + size += rb_desc->nr_page_va * sizeof(struct simple_buffer_page);
> +
> + start = hyp_alloc(size);
> + if (!start)
> + return hyp_alloc_errno();
> + } else {
> + start = (void *)kern_hyp_va(desc->bpages_backing_start);
> + size = desc->bpages_backing_size;
> +
> + ret = __admit_host_mem(start, size);
> + if (ret)
> + return ret;
> +
> + memset(start, 0, size);
> + }
>
> trace_buffer->bpages_backing_start = start;
> trace_buffer->bpages_backing_size = size;
> @@ -81,7 +98,7 @@ static int hyp_trace_buffer_load_bpage_backing(struct hyp_trace_buffer *trace_bu
> return 0;
> }
>
> -static void hyp_trace_buffer_unload_bpage_backing(struct hyp_trace_buffer *trace_buffer)
> +static void hyp_trace_buffer_free_bpages(struct hyp_trace_buffer *trace_buffer)
> {
> void *start = trace_buffer->bpages_backing_start;
> size_t size = trace_buffer->bpages_backing_size;
> @@ -89,9 +106,12 @@ static void hyp_trace_buffer_unload_bpage_backing(struct hyp_trace_buffer *trace
> if (!size)
> return;
>
> - memset(start, 0, size);
> -
> - __release_host_mem(start, size);
> + if (is_protected_kvm_enabled()) {
> + hyp_free(start);
> + } else {
> + memset(start, 0, size);
> + __release_host_mem(start, size);
> + }
>
> trace_buffer->bpages_backing_start = 0;
> trace_buffer->bpages_backing_size = 0;
> @@ -128,7 +148,7 @@ static void hyp_trace_buffer_unload(struct hyp_trace_buffer *trace_buffer)
> simple_ring_buffer_unload_mm(per_cpu_ptr(trace_buffer->simple_rbs, cpu),
> __unpin_shared_page);
>
> - hyp_trace_buffer_unload_bpage_backing(trace_buffer);
> + hyp_trace_buffer_free_bpages(trace_buffer);
> }
>
> static int hyp_trace_buffer_load(struct hyp_trace_buffer *trace_buffer,
> @@ -143,7 +163,7 @@ static int hyp_trace_buffer_load(struct hyp_trace_buffer *trace_buffer,
> if (hyp_trace_buffer_loaded(trace_buffer))
> return -EINVAL;
>
> - ret = hyp_trace_buffer_load_bpage_backing(trace_buffer, desc);
> + ret = hyp_trace_buffer_alloc_bpages(trace_buffer, desc);
> if (ret)
> return ret;
>
> @@ -168,18 +188,16 @@ static bool hyp_trace_desc_is_valid(struct hyp_trace_desc *desc, size_t desc_siz
> {
> struct ring_buffer_desc *rb_desc;
> unsigned int cpu;
> - size_t nr_bpages;
> void *desc_end;
>
> if (!is_protected_kvm_enabled())
> return true;
>
> /*
> - * Both desc_size and bpages_backing_size are untrusted host-provided
> - * values. We rely on __pkvm_host_donate_hyp() to enforce their validity.
> + * desc_size is an untrusted host-provided value. We rely on
> + * __pkvm_host_donate_hyp() to enforce its validity.
> */
> desc_end = (void *)desc + desc_size;
> - nr_bpages = desc->bpages_backing_size / sizeof(struct simple_buffer_page);
>
> if (desc->trace_buffer_desc.nr_cpus != hyp_nr_cpus)
> return false;
> @@ -197,17 +215,8 @@ static bool hyp_trace_desc_is_valid(struct hyp_trace_desc *desc, size_t desc_siz
> if ((void *)rb_desc + struct_size(rb_desc, page_va, rb_desc->nr_page_va) > desc_end)
> return false;
>
> - /* Overflow bpages backing memory? */
> - if (nr_bpages < rb_desc->nr_page_va)
> - return false;
> -
> - if (cpu >= hyp_nr_cpus)
> - return false;
> -
> if (cpu != rb_desc->cpu)
> return false;
> -
> - nr_bpages -= rb_desc->nr_page_va;
> }
>
> return true;
> diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
> index 2411b4c32932..859a926c815f 100644
> --- a/arch/arm64/kvm/hyp_trace.c
> +++ b/arch/arm64/kvm/hyp_trace.c
> @@ -13,6 +13,7 @@
> #include <asm/kvm_host.h>
> #include <asm/kvm_hyptrace.h>
> #include <asm/kvm_mmu.h>
> +#include <asm/kvm_pkvm.h>
>
> #include "hyp_trace.h"
>
> @@ -157,10 +158,17 @@ static void __unshare_page(unsigned long va)
>
> static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_buffer, size_t size)
> {
> - int nr_bpages = (PAGE_ALIGN(size) / PAGE_SIZE) + 1;
> size_t backing_size;
> + int nr_bpages;
> void *start;
>
> + if (is_protected_kvm_enabled()) {
> + trace_buffer->desc->bpages_backing_start = 0;
> + trace_buffer->desc->bpages_backing_size = 0;
> + return 0;
> + }
> +
> + nr_bpages = (PAGE_ALIGN(size) / PAGE_SIZE) + 1;
> backing_size = PAGE_ALIGN(sizeof(struct simple_buffer_page) * nr_bpages *
> num_possible_cpus());
>
> @@ -176,6 +184,9 @@ static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_
>
> static void hyp_trace_buffer_free_bpages_backing(struct hyp_trace_buffer *trace_buffer)
> {
> + if (!trace_buffer->desc->bpages_backing_start)
> + return;
> +
> free_pages_exact((void *)trace_buffer->desc->bpages_backing_start,
> trace_buffer->desc->bpages_backing_size);
> }
> @@ -264,7 +275,7 @@ static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
> if (ret)
> goto err_free_buffer;
>
> - ret = kvm_call_hyp_nvhe(__tracing_load, (unsigned long)desc, desc_size);
> + ret = pkvm_call_hyp_req(__tracing_load, (unsigned long)desc, desc_size);
> if (ret)
> goto err_unload_pages;
>
> --
> 2.55.0.508.g3f0d502094-goog
>
More information about the linux-arm-kernel
mailing list