* [RFC PATCH v2 1/3] KVM: arm64: pgtables: Set DBM attribute on writable Stage-2 PTEs
2026-10-26 14:44 [RFC PATCH v2 0/3] Set DBM bit on writable pages Leonardo Bras
@ 2026-10-26 14:44 ` Leonardo Bras
2026-10-26 14:44 ` [RFC PATCH v2 2/3] KVM: arm64: Introduce a dedicated walker for stage2 write-protect Leonardo Bras
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Leonardo Bras @ 2026-10-26 14:44 UTC (permalink / raw)
To: Oliver Upton, Marc Zyngier, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Catalin Marinas,
Will Deacon, Mark Rutland, Leonardo Bras, Raghavendra Rao Ananta,
Tian Zheng
Cc: linux-arm-kernel, kvmarm, linux-kernel
As a preparation to the introduction of HAFDBS-based features, set the DBM
bit (along with S2AP[1]) to all writable PTEs. Also unset DBM and S2AP[1]
when a PTE is made read-only again.
DBM bit works as following:
- If HAFDBS is disabled, DBM bit is ignored.
- If HAFDBS is enabled, and DBM bit is set, a write to non-writable page
can promote it's PTE to writable (S2AP[1]=1) without taking a fault.
Since it's being set on writable and unset on read-only, it should cause no
functional change.
Signed-off-by: Leonardo Bras <leo.bras@arm.com>
---
arch/arm64/include/asm/kvm_pgtable.h | 3 +++
arch/arm64/kvm/hyp/pgtable.c | 5 +++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 41a8687938eb..37baa86d6fd8 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -91,14 +91,17 @@ typedef u64 kvm_pte_t;
#define KVM_PTE_LEAF_ATTR_HI_S1_UXN BIT(54)
#define KVM_PTE_LEAF_ATTR_HI_S1_PXN BIT(53)
#define KVM_PTE_LEAF_ATTR_HI_S2_XN GENMASK(54, 53)
+#define KVM_PTE_LEAF_ATTR_HI_S2_DBM BIT(51)
+
#define KVM_PTE_LEAF_ATTR_HI_S1_GP BIT(50)
#define KVM_PTE_LEAF_ATTR_S2_PERMS (KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | \
KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | \
+ KVM_PTE_LEAF_ATTR_HI_S2_DBM | \
KVM_PTE_LEAF_ATTR_HI_S2_XN)
/* pKVM invalid pte encodings */
#define KVM_INVALID_PTE_TYPE_MASK GENMASK(63, 60)
#define KVM_INVALID_PTE_ANNOT_MASK ~(KVM_PTE_VALID | \
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index b74dd5ce1efd..8c2320c6a7f1 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -730,11 +730,11 @@ 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_LO_S2_S2AP_W;
+ attr |= KVM_PTE_LEAF_ATTR_HI_S2_DBM | KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
if (!kvm_lpa2_is_enabled())
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
attr |= KVM_PTE_LEAF_ATTR_LO_S2_AF;
@@ -1286,10 +1286,11 @@ 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);
}
@@ -1366,11 +1367,11 @@ 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_LO_S2_S2AP_W;
+ set |= KVM_PTE_LEAF_ATTR_HI_S2_DBM | KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
if (prot & KVM_PGTABLE_PROT_X) {
ret = stage2_set_xn_attr(prot, &xn);
if (ret)
return ret;
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [RFC PATCH v2 2/3] KVM: arm64: Introduce a dedicated walker for stage2 write-protect
2026-10-26 14:44 [RFC PATCH v2 0/3] Set DBM bit on writable pages Leonardo Bras
2026-10-26 14:44 ` [RFC PATCH v2 1/3] KVM: arm64: pgtables: Set DBM attribute on writable Stage-2 PTEs Leonardo Bras
@ 2026-10-26 14:44 ` Leonardo Bras
2026-10-26 14:44 ` [RFC PATCH v2 3/3] KVM: arm64: Add KVM_REQ_RELOAD_STAGE2 Leonardo Bras
2026-10-26 19:08 ` [RFC PATCH v2 0/3] Set DBM bit on writable pages Oliver Upton
3 siblings, 0 replies; 5+ messages in thread
From: Leonardo Bras @ 2026-10-26 14:44 UTC (permalink / raw)
To: Oliver Upton, Marc Zyngier, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Catalin Marinas,
Will Deacon, Mark Rutland, Leonardo Bras, Raghavendra Rao Ananta,
Tian Zheng
Cc: linux-arm-kernel, kvmarm, linux-kernel
When write-protecting a range, clean the writable bit (S2AP[1]) and keep
the DBM bit set for pages, so on HDBSS-enabled systems we can skip the
fault for making it writable again.
On block entries clean both the writable bit and the DBM bit, so we fault
even on HDBSS-enabled systems, in order to have hugepage splitting.
With disabled HDBSS, there should be no change in faulting behavior.
Signed-off-by: Leonardo Bras <leo.bras@arm.com>
---
arch/arm64/kvm/hyp/pgtable.c | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 8c2320c6a7f1..837546be5c13 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -1283,17 +1283,34 @@ static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr,
if (level)
*level = data.level;
return 0;
}
+static int stage2_wrprotect_walker(const struct kvm_pgtable_visit_ctx *ctx,
+ enum kvm_pgtable_walk_flags visit)
+{
+ kvm_pte_t new = ctx->old & ~KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
+
+ /* We remove DBM on blocks so they can fault and get split */
+ if (ctx->level < KVM_PGTABLE_LAST_LEVEL)
+ new &= ~KVM_PTE_LEAF_ATTR_HI_S2_DBM;
+
+ if (kvm_pte_valid(ctx->old) && ctx->old != new)
+ WRITE_ONCE(*ctx->ptep, new);
+
+ return 0;
+}
+
+
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);
+ struct kvm_pgtable_walker walker = {
+ .cb = stage2_wrprotect_walker,
+ .flags = KVM_PGTABLE_WALK_LEAF,
+ };
+
+ return kvm_pgtable_walk(pgt, addr, size, &walker);
}
void kvm_pgtable_stage2_mkyoung(struct kvm_pgtable *pgt, u64 addr,
enum kvm_pgtable_walk_flags flags)
{
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [RFC PATCH v2 3/3] KVM: arm64: Add KVM_REQ_RELOAD_STAGE2
2026-10-26 14:44 [RFC PATCH v2 0/3] Set DBM bit on writable pages Leonardo Bras
2026-10-26 14:44 ` [RFC PATCH v2 1/3] KVM: arm64: pgtables: Set DBM attribute on writable Stage-2 PTEs Leonardo Bras
2026-10-26 14:44 ` [RFC PATCH v2 2/3] KVM: arm64: Introduce a dedicated walker for stage2 write-protect Leonardo Bras
@ 2026-10-26 14:44 ` Leonardo Bras
2026-10-26 19:08 ` [RFC PATCH v2 0/3] Set DBM bit on writable pages Oliver Upton
3 siblings, 0 replies; 5+ messages in thread
From: Leonardo Bras @ 2026-10-26 14:44 UTC (permalink / raw)
To: Oliver Upton, Marc Zyngier, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Catalin Marinas,
Will Deacon, Mark Rutland, Leonardo Bras, Raghavendra Rao Ananta,
Tian Zheng
Cc: linux-arm-kernel, kvmarm, linux-kernel
Add a vcpu request to exit guest, reload Stage2, and then come back to
guest.
This will be used on future patches that enable HDBSS, as they may need to
change VTCR bits for enabling/disabling the feature when the vcpus are
still running.
On non-VHE systems, just skip this request as Stage2 is being reloaded
on every guest entry.
Signed-off-by: Leonardo Bras <leo.bras@arm.com>
---
arch/arm64/include/asm/kvm_host.h | 2 ++
arch/arm64/kvm/arm.c | 10 ++++++++++
2 files changed, 12 insertions(+)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index cd9b9d2462f9..86a4d6e50934 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -53,10 +53,12 @@
#define KVM_REQ_RESYNC_PMU_EL0 KVM_ARCH_REQ(7)
#define KVM_REQ_NESTED_S2_UNMAP KVM_ARCH_REQ(8)
#define KVM_REQ_GUEST_HYP_IRQ_PENDING KVM_ARCH_REQ(9)
#define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10)
#define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11)
+#define KVM_REQ_RELOAD_STAGE2 \
+ KVM_ARCH_REQ_FLAGS(12, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
KVM_DIRTY_LOG_INITIALLY_SET)
#define KVM_HAVE_MMU_RWLOCK
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 0576c2022ef5..d311637e0b13 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1173,10 +1173,20 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)
return kvm_vcpu_suspend(vcpu);
if (kvm_dirty_ring_check_request(vcpu))
return 0;
+ /* Non-vhe systems already reload Stage2 on guest entry */
+ if (kvm_check_request(KVM_REQ_RELOAD_STAGE2, vcpu) &&
+ has_vhe()) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ __load_stage2(vcpu->arch.hw_mmu);
+ local_irq_restore(flags);
+ }
+
check_nested_vcpu_requests(vcpu);
}
return 1;
}
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [RFC PATCH v2 0/3] Set DBM bit on writable pages
2026-10-26 14:44 [RFC PATCH v2 0/3] Set DBM bit on writable pages Leonardo Bras
` (2 preceding siblings ...)
2026-10-26 14:44 ` [RFC PATCH v2 3/3] KVM: arm64: Add KVM_REQ_RELOAD_STAGE2 Leonardo Bras
@ 2026-10-26 19:08 ` Oliver Upton
3 siblings, 0 replies; 5+ messages in thread
From: Oliver Upton @ 2026-10-26 19:08 UTC (permalink / raw)
To: Leonardo Bras
Cc: Marc Zyngier, Fuad Tabba, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Mark Rutland, Raghavendra Rao Ananta, Tian Zheng,
linux-arm-kernel, kvmarm, linux-kernel
On Mon, Oct 26, 2026 at 02:44:06PM +0000, Leonardo Bras wrote:
> When HAFDBS is enabled (VTCR_EL2.{HA,HD}={1,1}), having a DBM bit allows
> hardware to promote a non-writable page to writable by setting (S2AP[1]=1),
> without having to take a fault.
>
> The reason for this patchset is to add the DBM bit when setting-up writable
> pages, so the code is prepared for future patches that make use of
> HDBSS/HACDBS to accelerate dirty-tracking. Write-bit detection still
> happens based only in S2AP[1], so no change in that aspect.
>
> Having DBM set on block entries is undesired, as we benefit from the first
> fault for splitting it in PAGE_SIZE entries, which is the granularity used
> to track the dirty pages in KVM. So introduce a new walker that, on top of
> clearing S2AP[1] for every entry, also clear DBM for block entries.
>
> Also introduce a new VCPU request to reload Stage2, as it will be needed on
> future HDBSS/HAFDBS patchsets.
>
> Please let me know of what do you think!
I'm pretty sure I shared this feedback before, but patches that enable
DBM do not make sense in isolation. We need a single series that
contains the DBM enablement as well as the corresponding HDBSS support.
> Changes since RFCv1:
> - Dropped patch #5 on enabling HAFDBS on non-dirty-tracking guests, as it
> proved to be counter-productive on wrprotect, contrary to expectations
> - No more moving writable-bit to DBM. That does not seem to be the intended
> use. It makes sense and it's easier to convert code to new DBM approach.
Sorry, where was this concluded?
The abstract permission flags need to have a WRITE an DIRTY state, which
we then map to hardware based on the capabilities of the system.
!FEAT_HAFDBS:
DIRTY => S2AP[1]
WRITE => S2AP[1]
FEAT_HAFDBS:
DIRTY => S2AP[1]
WRITE => DBM
Beyond making the whole HAFDBS easy to reason about, I want this for
FEAT_S2PIE which reimagines bit 7 as a literal dirty bit that can be
managed by software or hardware.
Thanks,
Oliver
^ permalink raw reply [flat|nested] 5+ messages in thread