From: Oliver Upton <oupton@kernel.org>
To: Tian Zheng <zhengtian10@huawei.com>
Cc: maz@kernel.org, catalin.marinas@arm.com, will@kernel.org,
corbet@lwn.net, pbonzini@redhat.com, leo.bras@arm.com,
yuzenghui@huawei.com, wangzhou1@hisilicon.com,
yangjinqian1@huawei.com, caijian11@h-partners.com,
liuyonglong@huawei.com, tangchengchang@huawei.com,
yezhenyu2@huawei.com, yubihong@huawei.com, linuxarm@huawei.com,
joey.gouly@arm.com, kvmarm@lists.linux.dev, kvm@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, seiden@linux.ibm.com,
suzuki.poulose@arm.com, fuad.tabba@linux.dev,
mark.rutland@arm.com, seanjc@google.com, rdunlap@infradead.org,
linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org,
skhan@linuxfoundation.org
Subject: Re: [PATCH v5 02/15] KVM: arm64: Add KVM_PGTABLE_PROT_DIRTY
Date: Tue, 29 Sep 2026 17:35:15 -0700 [thread overview]
Message-ID: <arxZQwkLCLBnITzH@kernel.org> (raw)
In-Reply-To: <20260929103655.85107-3-zhengtian10@huawei.com>
On Tue, Sep 29, 2026 at 06:36:42PM +0800, Tian Zheng wrote:
> @@ -731,8 +731,12 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
> if (prot & KVM_PGTABLE_PROT_R)
> attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;
>
> - if (prot & KVM_PGTABLE_PROT_W)
> - attr |= KVM_PTE_LEAF_ATTR_HI_S2_DBM | KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
> + if (prot & KVM_PGTABLE_PROT_W) {
> + attr |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;
> +
> + if (prot & KVM_PGTABLE_PROT_DIRTY)
> + attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
> + }
Can you introduce the dirty state first? You're temporarily setting
DBM+S2AP[1] as a workaround in the preceding patch.
Then we can have it encoded such that when FEAT_HAFDBS is implemented:
KVM_PGTABLE_PROT_W => KVM_PTE_LEAF_ATTR_HI_S2_DBM
KVM_PGTABLE_PROT_DIRTY => KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W
And if FEAT_HAFDBS is *not* implemented:
KVM_PGTABLE_PROT_W => KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W
KVM_PGTABLE_PROT_DIRTY => KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W
i.e. aliasing both to bit 7.
Thanks,
Oliver
> if (!kvm_lpa2_is_enabled())
> attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
> @@ -753,9 +757,13 @@ enum kvm_pgtable_prot kvm_pgtable_stage2_pte_prot(kvm_pte_t pte)
>
> if (pte & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R)
> prot |= KVM_PGTABLE_PROT_R;
> - if (pte & KVM_PTE_LEAF_ATTR_HI_S2_DBM)
> + if (pte & KVM_PTE_LEAF_ATTR_HI_S2_DBM) {
> prot |= KVM_PGTABLE_PROT_W;
>
> + if (pte & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W)
> + prot |= KVM_PGTABLE_PROT_DIRTY;
> + }
> +
> switch (FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, pte)) {
> case 0b00:
> prot |= KVM_PGTABLE_PROT_PX | KVM_PGTABLE_PROT_UX;
> @@ -1288,7 +1296,6 @@ static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr,
> int kvm_pgtable_stage2_wrprotect(struct kvm_pgtable *pgt, u64 addr, u64 size)
> {
> return stage2_update_leaf_attrs(pgt, addr, size, 0,
> - KVM_PTE_LEAF_ATTR_HI_S2_DBM |
> KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W,
> NULL, NULL,
> KVM_PGTABLE_WALK_IGNORE_EAGAIN);
> @@ -1368,8 +1375,12 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
> if (prot & KVM_PGTABLE_PROT_R)
> set |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;
>
> - if (prot & KVM_PGTABLE_PROT_W)
> - set |= KVM_PTE_LEAF_ATTR_HI_S2_DBM | KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
> + if (prot & KVM_PGTABLE_PROT_W) {
> + set |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;
> +
> + if (prot & KVM_PGTABLE_PROT_DIRTY)
> + set |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
> + }
>
> if (prot & KVM_PGTABLE_PROT_X) {
> ret = stage2_set_xn_attr(prot, &xn);
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 2d44cd6a5aed..698a87e85a6d 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1221,7 +1221,9 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
> struct kvm_pgtable *pgt = mmu->pgt;
> enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_DEVICE |
> KVM_PGTABLE_PROT_R |
> - (writable ? KVM_PGTABLE_PROT_W : 0);
> + (writable ?
> + (KVM_PGTABLE_PROT_W | KVM_PGTABLE_PROT_DIRTY) :
> + 0);
>
> if (is_protected_kvm_enabled())
> return -EPERM;
> @@ -1587,7 +1589,7 @@ static enum kvm_pgtable_prot adjust_nested_fault_perms(struct kvm_s2_trans *nest
> enum kvm_pgtable_prot prot)
> {
> if (!kvm_s2_trans_writable(nested))
> - prot &= ~KVM_PGTABLE_PROT_W;
> + prot &= ~(KVM_PGTABLE_PROT_W | KVM_PGTABLE_PROT_DIRTY);
> if (!kvm_s2_trans_readable(nested))
> prot &= ~KVM_PGTABLE_PROT_R;
>
> @@ -1658,7 +1660,7 @@ static int gmem_abort(const struct kvm_s2_fault_desc *s2fd)
> }
>
> if (!(s2fd->memslot->flags & KVM_MEM_READONLY))
> - prot |= KVM_PGTABLE_PROT_W;
> + prot |= KVM_PGTABLE_PROT_W | KVM_PGTABLE_PROT_DIRTY;
>
> if (s2fd->nested)
> prot = adjust_nested_fault_perms(s2fd->nested, prot);
> @@ -1690,10 +1692,17 @@ static int gmem_abort(const struct kvm_s2_fault_desc *s2fd)
> }
>
> out_unlock:
> + /*
> + * Dirty the folio for any write-permitting mapping: hardware can
> + * promote a writable-clean entry to writable-dirty without a VM
> + * exit, so a clean release could lose a guest write at reclaim.
> + * The dirty bitmap is only marked for mappings installed dirty,
> + * or pre-copy would treat every writable page as dirty.
> + */
> kvm_release_faultin_page(kvm, page, !!ret, prot & KVM_PGTABLE_PROT_W);
> kvm_fault_unlock(kvm);
>
> - if ((prot & KVM_PGTABLE_PROT_W) && !ret)
> + if ((prot & KVM_PGTABLE_PROT_DIRTY) && !ret)
> mark_page_dirty_in_slot(kvm, s2fd->memslot, gfn);
>
> return ret != -EAGAIN ? ret : 0;
> @@ -1993,11 +2002,14 @@ static int kvm_s2_fault_compute_prot(const struct kvm_s2_fault_desc *s2fd,
>
> *prot = KVM_PGTABLE_PROT_R;
>
> - if (s2vi->map_writable && (s2vi->device ||
> - !memslot_is_logging(s2fd->memslot) ||
> - kvm_is_write_fault(s2fd->vcpu)))
> + if (s2vi->map_writable) {
> *prot |= KVM_PGTABLE_PROT_W;
>
> + if (s2vi->device || !memslot_is_logging(s2fd->memslot) ||
> + kvm_is_write_fault(s2fd->vcpu))
> + *prot |= KVM_PGTABLE_PROT_DIRTY;
> + }
> +
> if (s2fd->nested)
> *prot = adjust_nested_fault_perms(s2fd->nested, *prot);
>
> @@ -2028,7 +2040,7 @@ static int kvm_s2_fault_map(const struct kvm_s2_fault_desc *s2fd,
> void *memcache)
> {
> enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_SHARED;
> - bool writable = prot & KVM_PGTABLE_PROT_W;
> + bool dirty = prot & KVM_PGTABLE_PROT_DIRTY;
> struct kvm *kvm = s2fd->vcpu->kvm;
> struct kvm_pgtable *pgt;
> long perm_fault_granule;
> @@ -2091,7 +2103,11 @@ static int kvm_s2_fault_map(const struct kvm_s2_fault_desc *s2fd,
> }
>
> out_unlock:
> - kvm_release_faultin_page(kvm, s2vi->page, !!ret, writable);
> + /*
> + * Speculative folio dirtying: W, not DIRTY, per the contract
> + * documented in kvm_release_faultin_page().
> + */
> + kvm_release_faultin_page(kvm, s2vi->page, !!ret, prot & KVM_PGTABLE_PROT_W);
> kvm_fault_unlock(kvm);
>
> /*
> @@ -2099,7 +2115,7 @@ static int kvm_s2_fault_map(const struct kvm_s2_fault_desc *s2fd,
> * making sure we adjust the canonical IPA if the mapping size has
> * been updated (via a THP upgrade, for example).
> */
> - if (writable && !ret) {
> + if (dirty && !ret) {
> phys_addr_t ipa = gfn_to_gpa(get_canonical_gfn(s2fd, s2vi));
> ipa &= ~(mapping_size - 1);
> mark_page_dirty_in_slot(kvm, s2fd->memslot, gpa_to_gfn(ipa));
> diff --git a/arch/arm64/kvm/ptdump.c b/arch/arm64/kvm/ptdump.c
> index b0cb8d84a9e9..a1251e252b4f 100644
> --- a/arch/arm64/kvm/ptdump.c
> +++ b/arch/arm64/kvm/ptdump.c
> @@ -45,6 +45,12 @@ static const struct ptdump_prot_bits stage2_pte_bits[] = {
> .set = "W",
> .clear = " ",
> },
> + {
> + .mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W,
> + .val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W,
> + .set = "D",
> + .clear = "C",
> + },
> {
> .mask = KVM_PTE_LEAF_ATTR_HI_S2_XN,
> .val = 0b00UL << __bf_shf(KVM_PTE_LEAF_ATTR_HI_S2_XN),
> --
> 2.43.0
>
next prev parent reply other threads:[~2026-09-30 0:35 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-29 10:36 [PATCH v5 00/15] KVM: arm64: FEAT_HDBSS support for stage-2 dirty tracking Tian Zheng
2026-09-29 10:36 ` [PATCH v5 01/15] KVM: arm64: pgtables: Change write bit from S2AP_W to DBM Tian Zheng
2026-09-30 0:25 ` Oliver Upton
2026-09-30 2:44 ` Tian Zheng
2026-09-29 10:36 ` [PATCH v5 02/15] KVM: arm64: Add KVM_PGTABLE_PROT_DIRTY Tian Zheng
2026-09-30 0:35 ` Oliver Upton [this message]
2026-09-30 2:57 ` Tian Zheng
2026-09-29 10:36 ` [PATCH v5 03/15] KVM: arm64: Introduce a dedicated walker for stage2 write-protect Tian Zheng
2026-09-29 10:36 ` [PATCH v5 04/15] KVM: arm64: Add KVM_REQ_RELOAD_STAGE2 Tian Zheng
2026-09-29 10:50 ` sashiko-bot
2026-09-30 1:44 ` Tian Zheng
2026-09-29 10:36 ` [PATCH v5 05/15] KVM: arm64: Harvest stage-2 dirty state into the host folio account Tian Zheng
2026-09-29 10:36 ` [PATCH v5 06/15] KVM: arm64: Add support for FEAT_HDBSS Tian Zheng
2026-09-29 10:36 ` [PATCH v5 07/15] KVM: arm64: Add HDBSS per-vCPU buffer management Tian Zheng
2026-09-29 10:36 ` [PATCH v5 08/15] KVM: arm64: Flush the HDBSS buffer on VM exit Tian Zheng
2026-09-29 10:36 ` [PATCH v5 09/15] KVM: arm64: Handle HDBSS faults Tian Zheng
2026-09-29 10:53 ` sashiko-bot
2026-09-29 10:36 ` [PATCH v5 10/15] KVM: Add kvm_arch_dirty_ring_size_updated() hook Tian Zheng
2026-09-29 10:52 ` sashiko-bot
2026-09-29 10:36 ` [PATCH v5 11/15] KVM: arm64: Reserve dirty ring space for the HDBSS buffer Tian Zheng
2026-09-29 11:00 ` sashiko-bot
2026-09-29 10:36 ` [PATCH v5 12/15] KVM: arm64: Derive the VM hardware dirty mode from dirty logging Tian Zheng
2026-09-29 11:16 ` sashiko-bot
2026-09-30 8:27 ` Tian Zheng
2026-09-29 10:36 ` [PATCH v5 13/15] KVM: arm64: Add HDBSS buffer size ioctl for dirty-bitmap mode Tian Zheng
2026-09-29 10:36 ` [PATCH v5 14/15] KVM: arm64: Document HDBSS buffer size ioctl Tian Zheng
2026-09-29 11:06 ` sashiko-bot
2026-09-29 10:36 ` [PATCH v5 15/15] KVM: arm64: selftests: Add HDBSS buffer size ioctl interface test Tian Zheng
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=arxZQwkLCLBnITzH@kernel.org \
--to=oupton@kernel.org \
--cc=caijian11@h-partners.com \
--cc=catalin.marinas@arm.com \
--cc=corbet@lwn.net \
--cc=fuad.tabba@linux.dev \
--cc=joey.gouly@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=leo.bras@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linuxarm@huawei.com \
--cc=liuyonglong@huawei.com \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=pbonzini@redhat.com \
--cc=rdunlap@infradead.org \
--cc=seanjc@google.com \
--cc=seiden@linux.ibm.com \
--cc=skhan@linuxfoundation.org \
--cc=suzuki.poulose@arm.com \
--cc=tangchengchang@huawei.com \
--cc=wangzhou1@hisilicon.com \
--cc=will@kernel.org \
--cc=yangjinqian1@huawei.com \
--cc=yezhenyu2@huawei.com \
--cc=yubihong@huawei.com \
--cc=yuzenghui@huawei.com \
--cc=zhengtian10@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.