From: Vincent Donnefort <vdonnefort@google.com>
To: Wei-Lin Chang <weilin.chang@arm.com>
Cc: maz@kernel.org, oupton@kernel.org, kvmarm@lists.linux.dev,
linux-arm-kernel@lists.infradead.org, joey.gouly@arm.com,
seiden@linux.ibm.com, suzuki.poulose@arm.com,
yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
kernel-team@android.com, fuad.tabba@linux.dev,
qperret@google.com, keirf@google.com
Subject: Re: [PATCH 16/20] KVM: arm64: Add __pkvm_host_split_guest HVC
Date: Tue, 8 Sep 2026 15:46:51 +0100 [thread overview]
Message-ID: <aqAf27qhViD-V5ao@google.com> (raw)
In-Reply-To: <hrhbuwdfu625jtzm75t6wnva6odgreshchyv75ebqntlymslz7@adyxhe7oyypc>
On Mon, Sep 07, 2026 at 06:39:49PM +0100, Wei-Lin Chang wrote:
> On Mon, Aug 03, 2026 at 11:09:00AM +0100, Vincent Donnefort wrote:
>
> [...]
>
> > diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> > index 41a8687938eb..355573d53fed 100644
> > --- a/arch/arm64/include/asm/kvm_pgtable.h
> > +++ b/arch/arm64/include/asm/kvm_pgtable.h
> > @@ -824,8 +824,7 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size);
> > * kvm_pgtable_stage2_split() is best effort: it tries to break as many
> > * blocks in the input range as allowed by @mc_capacity.
>
> Maybe also adjust the comment and remove @mc_capacity while changing
> this, looks like it was included by mistake.
>
> > */
> > -int kvm_pgtable_stage2_split(struct kvm_pgtable *pgt, u64 addr, u64 size,
> > - struct kvm_mmu_memory_cache *mc);
> > +int kvm_pgtable_stage2_split(struct kvm_pgtable *pgt, u64 addr, u64 size, void *mc);
> >
>
> [...]
>
> > +static int host_stage2_split_gfn_meta(phys_addr_t phys, u64 ipa, u64 size, struct pkvm_hyp_vm *vm)
> > +{
> > + pkvm_handle_t handle;
> > + kvm_pte_t pte;
> > + u64 gfn, end;
> > + s8 level;
> > + int ret;
> > +
> > + ret = kvm_pgtable_get_leaf(&host_mmu.pgt, phys, &pte, &level);
> > + if (ret)
> > + return ret;
> > +
> > + if (kvm_granule_size(level) != size)
> > + return -EINVAL;
> > +
> > + ret = host_stage2_decode_gfn_meta(pte, &handle, &gfn);
> > + if (ret)
> > + return ret;
> > +
> > + if (handle != vm->kvm.arch.pkvm.handle || gfn != (ipa >> PAGE_SHIFT))
> > + return -EINVAL;
> > +
> > + end = phys + size;
> > + while (phys < end) {
> > + u64 meta = host_stage2_encode_gfn_meta(vm, gfn);
> > + kvm_pte_t annotation = FIELD_PREP(KVM_HOST_DONATION_PTE_OWNER_MASK, PKVM_ID_GUEST) |
> > + FIELD_PREP(KVM_HOST_DONATION_PTE_EXTRA_MASK, meta);
> > +
> > + ret = host_stage2_try(kvm_pgtable_stage2_annotate, &host_mmu.pgt,
> > + phys, PAGE_SIZE, &host_s2_pool,
> > + KVM_HOST_INVALID_PTE_TYPE_DONATION, annotation);
> > + if (WARN_ON(ret))
> > + return ret;
> > +
> > + phys += PAGE_SIZE;
> > + gfn++;
>
> Annotating every PTE is required here because patch 2's
> stage2_map_prefault_idmap() copies the same annotation to each PTE, so
> the resulting PTEs all contain the same gfn.
>
> In other words patch 2 simply leaves wrong annotations in this case, and
> we make up for it here.
>
> We can't just remove patch 2 because a HYP owned block needs to be
> broken down with HYP owned annotations when a single page is donated
> back to the host.
>
> With this, would it be a better design to have an annotation-aware
> helper that splits a host block properly including the annotations, and
> call it whenever pKVM annotates or maps host stage-2?
I ended-up with that solution because it is difficult to draw the line between
pulling pKVM specific knowledge in pgtable.c and reusing pgtable.c private
functions in mem_protect.c. So I wanted a mem_protect.c function that can split
the annotations, but without having to touch pgtable.c. Indeed, that isn't the
most optimal.
Looking again at stage2_split_walker(), perhaps pgtable.c could export only a
single additional function to allow implementing a pkvm version of stage2_split.
This stage2 split can then be used for both guest and host.
Let me see if I can optimise that
Eventually part of the "pkvm_stage2_split()" could be reused by
stage2_map_prefault_idmap() I'll see if that's worth it.
>
> > }
> >
> > - *gfn = FIELD_GET(KVM_HOST_PTE_OWNER_GUEST_GFN_MASK, meta);
> > return 0;
> > }
> >
>
> [...]
>
> > diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> > index c4ebae0544d4..986b5a19b07a 100644
> > --- a/arch/arm64/kvm/hyp/pgtable.c
> > +++ b/arch/arm64/kvm/hyp/pgtable.c
> > @@ -1537,9 +1537,10 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx,
> > enum kvm_pgtable_walk_flags visit)
> > {
> > struct kvm_pgtable_mm_ops *mm_ops = ctx->mm_ops;
> > - struct kvm_mmu_memory_cache *mc = ctx->arg;
> > - struct kvm_s2_mmu *mmu;
> > + struct stage2_map_data *data = ctx->arg;
> > kvm_pte_t pte = ctx->old, new, *childp;
> > + struct kvm_s2_mmu *mmu = data->mmu;
> > + void *mc = data->memcache;
> > enum kvm_pgtable_prot prot;
> > s8 level = ctx->level;
> > bool force_pte;
> > @@ -1554,30 +1555,37 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx,
> > if (!kvm_pte_valid(pte))
> > return 0;
> >
> > - nr_pages = stage2_block_get_nr_page_tables(level);
> > - if (nr_pages < 0)
> > - return nr_pages;
> > -
> > - if (mc->nobjs >= nr_pages) {
> > - /* Build a tree mapped down to the PTE granularity. */
> > + if (unlikely(is_protected_kvm_enabled())) {
> > + /* pKVM only supports splitting PMD-level blocks */
> > + if (level != KVM_PGTABLE_LAST_LEVEL - 1)
> > + return -EINVAL;
> > force_pte = true;
> > } else {
> > - /*
> > - * Don't force PTEs, so create_unlinked() below does
> > - * not populate the tree up to the PTE level. The
> > - * consequence is that the call will require a single
> > - * page of level 2 entries at level 1, or a single
> > - * page of PTEs at level 2. If we are at level 1, the
> > - * PTEs will be created recursively.
> > - */
> > - force_pte = false;
> > - nr_pages = 1;
> > + struct kvm_mmu_memory_cache *host_mc = mc;
> > +
> > + nr_pages = stage2_block_get_nr_page_tables(level);
> > + if (nr_pages < 0)
> > + return nr_pages;
> > +
> > + if (host_mc->nobjs >= nr_pages) {
> > + /* Build a tree mapped down to the PTE granularity. */
> > + force_pte = true;
> > + } else if (host_mc->nobjs) {
> > + /*
> > + * Don't force PTEs, so create_unlinked() below does
> > + * not populate the tree up to the PTE level. The
> > + * consequence is that the call will require a single
> > + * page of level 2 entries at level 1, or a single
> > + * page of PTEs at level 2. If we are at level 1, the
> > + * PTEs will be created recursively.
> > + */
> > + force_pte = false;
> > + nr_pages = 1;
> > + } else {
> > + return -ENOMEM;
> > + }
> > }
> >
> > - if (mc->nobjs < nr_pages)
> > - return -ENOMEM;
> > -
> > - mmu = container_of(mc, struct kvm_s2_mmu, split_page_cache);
> > phys = kvm_pte_to_phys(pte);
> > prot = kvm_pgtable_stage2_pte_prot(pte);
>
> I feel like this change is trying too hard to make the pKVM case fit
> in stage2_split_walker(). The assumptions differ by much: the original
> usage assumes kvm_mmu_memory_cache, can potentially split more than one
> level, and makes decisions base on the memcache's reserve.
>
> Perhaps create another function for pKVM?
Looking at this version, the pKVM case is rather small, hence reusing the same
function made sense to me.
A completely separate function is actually what we have in Android kernels at
the moment.
Anyway, as per the discussion above, I'll probably try to create a pKVM specific
version of the split.
>
> Thanks,
> Wei-Lin Chang
>
> [...]
next prev parent reply other threads:[~2026-09-08 14:47 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-03 10:08 [PATCH 00/20] Huge mapping support for protected VMs Vincent Donnefort
2026-08-03 10:08 ` [PATCH 01/20] KVM: arm64: Prefault host stage-2 entries on block split Vincent Donnefort
2026-08-03 10:31 ` sashiko-bot
2026-09-07 18:34 ` Wei-Lin Chang
2026-08-03 10:08 ` [PATCH 02/20] KVM: arm64: Propagate host stage-2 annotated " Vincent Donnefort
2026-09-07 13:58 ` Wei-Lin Chang
2026-09-08 10:07 ` Vincent Donnefort
2026-08-03 10:08 ` [PATCH 03/20] KVM: arm64: Allow block-level stage-2 annotation Vincent Donnefort
2026-08-03 10:40 ` sashiko-bot
2026-08-03 10:08 ` [PATCH 04/20] KVM: arm64: Use block-level annotations when setting up the host stage-2 Vincent Donnefort
2026-09-07 14:37 ` Wei-Lin Chang
2026-09-08 10:18 ` Vincent Donnefort
2026-08-03 10:08 ` [PATCH 05/20] KVM: arm64: Make pKVM ownership selftest an HVC Vincent Donnefort
2026-08-03 10:08 ` [PATCH 06/20] KVM: arm64: Add a range to __pkvm_host_share/unshare_hyp() Vincent Donnefort
2026-08-03 10:08 ` [PATCH 07/20] KVM: arm64: Add a range to __pkvm_host_donate_guest() Vincent Donnefort
2026-08-03 10:26 ` sashiko-bot
2026-08-03 10:08 ` [PATCH 08/20] KVM: arm64: Add a range to __pkvm_host_reclaim_page_guest() Vincent Donnefort
2026-08-03 10:28 ` sashiko-bot
2026-09-07 14:52 ` Wei-Lin Chang
2026-09-08 10:22 ` Vincent Donnefort
2026-08-03 10:08 ` [PATCH 09/20] KVM: arm64: Add a range to __pkvm_guest_share_host() Vincent Donnefort
2026-08-03 10:08 ` [PATCH 10/20] KVM: arm64: Add a range to __pkvm_guest_unshare_host() Vincent Donnefort
2026-08-03 10:08 ` [PATCH 11/20] KVM: arm64: Add a range to pKVM ownership selftest Vincent Donnefort
2026-08-03 10:48 ` sashiko-bot
2026-09-07 10:13 ` Vincent Donnefort
2026-09-07 14:58 ` Wei-Lin Chang
2026-09-08 10:25 ` Vincent Donnefort
2026-09-10 10:04 ` Vincent Donnefort
2026-08-03 10:08 ` [PATCH 12/20] KVM: arm64: Handle huge mappings in __pkvm_host_force_reclaim_page_guest() Vincent Donnefort
2026-09-07 16:52 ` Wei-Lin Chang
2026-09-08 10:26 ` Vincent Donnefort
2026-08-03 10:08 ` [PATCH 13/20] KVM: arm64: Handle huge mappings in __pkvm_vcpu_in_poison_fault() Vincent Donnefort
2026-08-03 10:08 ` [PATCH 14/20] KVM: arm64: pkvm: Warn on guest stage-2 block collapse Vincent Donnefort
2026-08-03 10:08 ` [PATCH 15/20] KVM: arm64: Add pkvm_hyp_req infrastructure Vincent Donnefort
2026-08-03 10:46 ` sashiko-bot
2026-08-03 10:09 ` [PATCH 16/20] KVM: arm64: Add __pkvm_host_split_guest HVC Vincent Donnefort
2026-08-03 10:54 ` sashiko-bot
2026-09-07 10:14 ` Vincent Donnefort
2026-09-07 17:39 ` Wei-Lin Chang
2026-09-08 14:46 ` Vincent Donnefort [this message]
2026-08-03 10:09 ` [PATCH 17/20] KVM: arm64: Extend pKVM page ownership selftests to cover guest block split Vincent Donnefort
2026-08-03 11:01 ` sashiko-bot
2026-08-03 10:09 ` [PATCH 18/20] KVM: arm64: Add PKVM_HYP_REQ_SPLIT Vincent Donnefort
2026-08-03 10:54 ` sashiko-bot
2026-09-07 10:23 ` Vincent Donnefort
2026-09-08 10:35 ` Wei-Lin Chang
2026-09-07 18:15 ` Wei-Lin Chang
2026-09-08 14:56 ` Vincent Donnefort
2026-08-03 10:09 ` [PATCH 19/20] KVM: arm64: Raise PKVM_HYP_REQ_SPLIT on guest to host sharing Vincent Donnefort
2026-08-03 11:02 ` sashiko-bot
2026-09-07 10:26 ` Vincent Donnefort
2026-08-03 10:09 ` [PATCH 20/20] KVM: arm64: Stage-2 huge mappings for protected VMs Vincent Donnefort
2026-08-03 11:04 ` sashiko-bot
2026-09-07 18:31 ` Wei-Lin Chang
2026-09-07 18:41 ` [PATCH 00/20] Huge mapping support " Wei-Lin Chang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aqAf27qhViD-V5ao@google.com \
--to=vdonnefort@google.com \
--cc=catalin.marinas@arm.com \
--cc=fuad.tabba@linux.dev \
--cc=joey.gouly@arm.com \
--cc=keirf@google.com \
--cc=kernel-team@android.com \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=qperret@google.com \
--cc=seiden@linux.ibm.com \
--cc=suzuki.poulose@arm.com \
--cc=weilin.chang@arm.com \
--cc=will@kernel.org \
--cc=yuzenghui@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.