[PATCH v2 05/18] KVM: arm64: Allow kvm_hyp_memcache usage outside of stage-2

Fuad Tabba fuad.tabba at linux.dev
Tue Jul 14 12:00:50 PDT 2026


On Mon, 6 Jul 2026 at 18:54, Vincent Donnefort <vdonnefort at google.com> wrote:
>
> Although currently limited to guest stage-2 page-table allocations,
> struct kvm_hyp_memcache is a useful primitive for passing a list of
> discontiguous pages between host and hypervisor.
>
> Introduce init_hyp_memcache() to initialise a generic hyp memcache, and
> init_hyp_stage2_memcache() for stage-2 specific memcaches. The generic
> initialiser will be used to top up the upcoming pKVM heap allocator.
>
> Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index bae2c4f92ef5..caea8e9986d1 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -91,9 +91,22 @@ struct kvm_hyp_memcache {
>         struct pkvm_mapping *mapping; /* only used from EL1 */
>
>  #define        HYP_MEMCACHE_ACCOUNT_STAGE2     BIT(1)
> +#define        HYP_MEMCACHE_ACCOUNT_KMEMCG     BIT(2)
>         unsigned long flags;
>  };
>
> +static inline void init_hyp_memcache(struct kvm_hyp_memcache *mc)
> +{
> +       memset(mc, 0, sizeof(*mc));
> +       mc->mapping = ZERO_SIZE_PTR; /* Prevent allocation, solely useful for stage2 memcache */
> +}
> +
> +static inline void init_hyp_stage2_memcache(struct kvm_hyp_memcache *mc)
> +{
> +       memset(mc, 0, sizeof(*mc));
> +       mc->flags = HYP_MEMCACHE_ACCOUNT_STAGE2 | HYP_MEMCACHE_ACCOUNT_KMEMCG;
> +}
> +
>  static inline void push_hyp_memcache(struct kvm_hyp_memcache *mc,
>                                      phys_addr_t *p,
>                                      phys_addr_t (*to_pa)(void *virt))
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 6c941aaa10c6..fb38821f2037 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1159,9 +1159,11 @@ static void hyp_mc_free_fn(void *addr, void *mc)
>  static void *hyp_mc_alloc_fn(void *mc)
>  {
>         struct kvm_hyp_memcache *memcache = mc;
> +       gfp_t gfp = (memcache->flags & HYP_MEMCACHE_ACCOUNT_KMEMCG) ?
> +                   GFP_KERNEL_ACCOUNT : GFP_KERNEL;
>         void *addr;
>
> -       addr = (void *)__get_free_page(GFP_KERNEL_ACCOUNT);
> +       addr = (void *)__get_free_page(gfp);

Generic memcaches are not accounted anymore. That looks intentional
and right since heap pages are hyp-global, not attributable to the
topup'ing task. Maybe worth a line in the commit message confirming
this is deliberate?

Reviewed-by: Fuad Tabba <fuad.tabba at linux.dev>

Cheers,
/fuad

>         if (addr && memcache->flags & HYP_MEMCACHE_ACCOUNT_STAGE2)
>                 kvm_account_pgtable_pages(addr, 1);
>
> diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> index 053e4f733e4b..8324a6a1bc48 100644
> --- a/arch/arm64/kvm/pkvm.c
> +++ b/arch/arm64/kvm/pkvm.c
> @@ -111,7 +111,7 @@ static int __pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu)
>         void *hyp_vcpu;
>         int ret;
>
> -       vcpu->arch.pkvm_memcache.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2;
> +       init_hyp_stage2_memcache(&vcpu->arch.pkvm_memcache);
>
>         hyp_vcpu = alloc_pages_exact(hyp_vcpu_sz, GFP_KERNEL_ACCOUNT);
>         if (!hyp_vcpu)
> @@ -172,7 +172,7 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm)
>                 goto free_vm;
>
>         kvm->arch.pkvm.is_created = true;
> -       kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2;
> +       init_hyp_stage2_memcache(&kvm->arch.pkvm.stage2_teardown_mc);
>         kvm_account_pgtable_pages(pgd, pgd_sz / PAGE_SIZE);
>
>         return 0;
> --
> 2.55.0.rc2.803.g1fd1e6609c-goog
>



More information about the linux-arm-kernel mailing list