linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5
@ 2025-11-21  9:23 Tian Zheng
  2025-11-21  9:23 ` [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information Tian Zheng
                   ` (5 more replies)
  0 siblings, 6 replies; 21+ messages in thread
From: Tian Zheng @ 2025-11-21  9:23 UTC (permalink / raw)
  To: maz, oliver.upton, catalin.marinas, corbet, pbonzini, will
  Cc: linux-kernel, zhengtian10, yuzenghui, wangzhou1, yezhenyu2,
	xiexiangyou, zhengchuan, linuxarm, joey.gouly, kvmarm, kvm,
	linux-arm-kernel, linux-doc, suzuki.poulose

This series of patches add support to the Hardware Dirty state tracking
Structure(HDBSS) feature, which is introduced by the ARM architecture
in the DDI0601(ID121123) version.

The HDBSS feature is an extension to the architecture that enhances
tracking translation table descriptors' dirty state, identified as
FEAT_HDBSS. The goal of this feature is to reduce the cost of surveying
for dirtied granules, with minimal effect on recording when a granule
has been dirtied.

The purpose of this feature is to make the execution overhead of live
migration lower to both the guest and the host, compared to existing
approaches (write-protect or search stage 2 tables).

After these patches, users(such as qemu) can use the
KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl to enable or disable the HDBSS
feature before and after the live migration.

This feature is similar to Intel's Page Modification Logging (PML),
offering hardware-assisted dirty tracking to reduce live migration
overhead. With PML support expanding beyond Intel, HDBSS introduces a
comparable mechanism for ARM.

eillon (4):
  arm64/sysreg: Add HDBSS related register information
  KVM: arm64: Support set the DBM attr during memory abort
  KVM: arm64: Add support for FEAT_HDBSS
  KVM: arm64: Enable HDBSS support and handle HDBSSF events

Tian Zheng (1):
  KVM: arm64: Document HDBSS ioctl

 Documentation/virt/kvm/api.rst       |  15 ++++
 arch/arm64/Kconfig                   |  14 ++++
 arch/arm64/include/asm/cpucaps.h     |   2 +
 arch/arm64/include/asm/cpufeature.h  |   5 ++
 arch/arm64/include/asm/esr.h         |   2 +
 arch/arm64/include/asm/kvm_arm.h     |   1 +
 arch/arm64/include/asm/kvm_host.h    |  14 ++++
 arch/arm64/include/asm/kvm_mmu.h     |  17 +++++
 arch/arm64/include/asm/kvm_pgtable.h |   4 +
 arch/arm64/include/asm/sysreg.h      |  12 +++
 arch/arm64/kernel/cpufeature.c       |   9 +++
 arch/arm64/kvm/arm.c                 | 107 +++++++++++++++++++++++++++
 arch/arm64/kvm/handle_exit.c         |  45 +++++++++++
 arch/arm64/kvm/hyp/pgtable.c         |   6 ++
 arch/arm64/kvm/hyp/vhe/switch.c      |   1 +
 arch/arm64/kvm/mmu.c                 |  10 +++
 arch/arm64/kvm/reset.c               |   3 +
 arch/arm64/tools/cpucaps             |   1 +
 arch/arm64/tools/sysreg              |  28 +++++++
 include/linux/kvm_host.h             |   1 +
 include/uapi/linux/kvm.h             |   1 +
 tools/include/uapi/linux/kvm.h       |   1 +
 22 files changed, 299 insertions(+)

--
2.33.0



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information
  2025-11-21  9:23 [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Tian Zheng
@ 2025-11-21  9:23 ` Tian Zheng
  2025-11-22 12:40   ` Marc Zyngier
  2025-11-21  9:23 ` [PATCH v2 2/5] KVM: arm64: Support set the DBM attr during memory abort Tian Zheng
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 21+ messages in thread
From: Tian Zheng @ 2025-11-21  9:23 UTC (permalink / raw)
  To: maz, oliver.upton, catalin.marinas, corbet, pbonzini, will
  Cc: linux-kernel, zhengtian10, yuzenghui, wangzhou1, yezhenyu2,
	xiexiangyou, zhengchuan, linuxarm, joey.gouly, kvmarm, kvm,
	linux-arm-kernel, linux-doc, suzuki.poulose

From: eillon <yezhenyu2@huawei.com>

The ARM architecture added the HDBSS feature and descriptions of
related registers (HDBSSBR/HDBSSPROD) in the DDI0601(ID121123) version,
add them to Linux.

Signed-off-by: eillon <yezhenyu2@huawei.com>
Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
---
 arch/arm64/include/asm/esr.h     |  2 ++
 arch/arm64/include/asm/kvm_arm.h |  1 +
 arch/arm64/tools/sysreg          | 28 ++++++++++++++++++++++++++++
 3 files changed, 31 insertions(+)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index e1deed824464..a6f3cf0b9b86 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -159,6 +159,8 @@
 #define ESR_ELx_CM 		(UL(1) << ESR_ELx_CM_SHIFT)

 /* ISS2 field definitions for Data Aborts */
+#define ESR_ELx_HDBSSF_SHIFT	(11)
+#define ESR_ELx_HDBSSF		(UL(1) << ESR_ELx_HDBSSF_SHIFT)
 #define ESR_ELx_TnD_SHIFT	(10)
 #define ESR_ELx_TnD 		(UL(1) << ESR_ELx_TnD_SHIFT)
 #define ESR_ELx_TagAccess_SHIFT	(9)
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 1da290aeedce..b71122680a03 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -124,6 +124,7 @@
 			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)

 /* VTCR_EL2 Registers bits */
+#define VTCR_EL2_HDBSS		(1UL << 45)
 #define VTCR_EL2_DS		TCR_EL2_DS
 #define VTCR_EL2_RES1		(1U << 31)
 #define VTCR_EL2_HD		(1 << 22)
diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
index 1c6cdf9d54bb..f489703338b5 100644
--- a/arch/arm64/tools/sysreg
+++ b/arch/arm64/tools/sysreg
@@ -4408,6 +4408,34 @@ Sysreg	GCSPR_EL2	3	4	2	5	1
 Fields	GCSPR_ELx
 EndSysreg

+Sysreg	HDBSSBR_EL2	3	4	2	3	2
+Res0	63:56
+Field	55:12	BADDR
+Res0	11:4
+Enum	3:0	SZ
+	0b0001	8KB
+	0b0010	16KB
+	0b0011	32KB
+	0b0100	64KB
+	0b0101	128KB
+	0b0110	256KB
+	0b0111	512KB
+	0b1000	1MB
+	0b1001	2MB
+EndEnum
+EndSysreg
+
+Sysreg	HDBSSPROD_EL2	3	4	2	3	3
+Res0	63:32
+Enum	31:26	FSC
+	0b000000	OK
+	0b010000	ExternalAbort
+	0b101000	GPF
+EndEnum
+Res0	25:19
+Field	18:0	INDEX
+EndSysreg
+
 Sysreg	DACR32_EL2	3	4	3	0	0
 Res0	63:32
 Field	31:30	D15
--
2.33.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 2/5] KVM: arm64: Support set the DBM attr during memory abort
  2025-11-21  9:23 [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Tian Zheng
  2025-11-21  9:23 ` [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information Tian Zheng
@ 2025-11-21  9:23 ` Tian Zheng
  2025-11-22 12:54   ` Marc Zyngier
  2025-11-21  9:23 ` [PATCH v2 3/5] KVM: arm64: Add support for FEAT_HDBSS Tian Zheng
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 21+ messages in thread
From: Tian Zheng @ 2025-11-21  9:23 UTC (permalink / raw)
  To: maz, oliver.upton, catalin.marinas, corbet, pbonzini, will
  Cc: linux-kernel, zhengtian10, yuzenghui, wangzhou1, yezhenyu2,
	xiexiangyou, zhengchuan, linuxarm, joey.gouly, kvmarm, kvm,
	linux-arm-kernel, linux-doc, suzuki.poulose

From: eillon <yezhenyu2@huawei.com>

Add DBM support to automatically promote write-clean pages to
write-dirty, preventing users from being trapped in EL2 due to
missing write permissions.

Since the DBM attribute was introduced in ARMv8.1 and remains
optional in later architecture revisions, including ARMv9.5.

Support set the DBM attr during user_mem_abort().

Signed-off-by: eillon <yezhenyu2@huawei.com>
Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
---
 arch/arm64/include/asm/kvm_pgtable.h | 4 ++++
 arch/arm64/kvm/hyp/pgtable.c         | 6 ++++++
 2 files changed, 10 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 2888b5d03757..2fa24953d1a6 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -91,6 +91,8 @@ typedef u64 kvm_pte_t;

 #define KVM_PTE_LEAF_ATTR_HI_S2_XN	BIT(54)

+#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 | \
@@ -245,6 +247,7 @@ enum kvm_pgtable_stage2_flags {
  * @KVM_PGTABLE_PROT_R:		Read permission.
  * @KVM_PGTABLE_PROT_DEVICE:	Device attributes.
  * @KVM_PGTABLE_PROT_NORMAL_NC:	Normal noncacheable attributes.
+ * @KVM_PGTABLE_PROT_DBM:	Dirty bit management attribute.
  * @KVM_PGTABLE_PROT_SW0:	Software bit 0.
  * @KVM_PGTABLE_PROT_SW1:	Software bit 1.
  * @KVM_PGTABLE_PROT_SW2:	Software bit 2.
@@ -257,6 +260,7 @@ enum kvm_pgtable_prot {

 	KVM_PGTABLE_PROT_DEVICE			= BIT(3),
 	KVM_PGTABLE_PROT_NORMAL_NC		= BIT(4),
+	KVM_PGTABLE_PROT_DBM			= BIT(5),

 	KVM_PGTABLE_PROT_SW0			= BIT(55),
 	KVM_PGTABLE_PROT_SW1			= BIT(56),
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index c351b4abd5db..ce41c6924ebe 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -694,6 +694,9 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
 	if (prot & KVM_PGTABLE_PROT_W)
 		attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;

+	if (prot & KVM_PGTABLE_PROT_DBM)
+		attr |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;
+
 	if (!kvm_lpa2_is_enabled())
 		attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);

@@ -1303,6 +1306,9 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
 	if (prot & KVM_PGTABLE_PROT_W)
 		set |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;

+	if (prot & KVM_PGTABLE_PROT_DBM)
+		set |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;
+
 	if (prot & KVM_PGTABLE_PROT_X)
 		clr |= KVM_PTE_LEAF_ATTR_HI_S2_XN;

--
2.33.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 3/5] KVM: arm64: Add support for FEAT_HDBSS
  2025-11-21  9:23 [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Tian Zheng
  2025-11-21  9:23 ` [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information Tian Zheng
  2025-11-21  9:23 ` [PATCH v2 2/5] KVM: arm64: Support set the DBM attr during memory abort Tian Zheng
@ 2025-11-21  9:23 ` Tian Zheng
  2025-11-22 13:25   ` Marc Zyngier
  2025-11-21  9:23 ` [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events Tian Zheng
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 21+ messages in thread
From: Tian Zheng @ 2025-11-21  9:23 UTC (permalink / raw)
  To: maz, oliver.upton, catalin.marinas, corbet, pbonzini, will
  Cc: linux-kernel, zhengtian10, yuzenghui, wangzhou1, yezhenyu2,
	xiexiangyou, zhengchuan, linuxarm, joey.gouly, kvmarm, kvm,
	linux-arm-kernel, linux-doc, suzuki.poulose

From: eillon <yezhenyu2@huawei.com>

Armv9.5 introduces the Hardware Dirty Bit State Structure (HDBSS) feature,
indicated by ID_AA64MMFR1_EL1.HAFDBS == 0b0100.

Add the Kconfig for FEAT_HDBSS and support detecting and enabling the
feature. A CPU capability is added to notify the user of the feature.

Add KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl and basic framework for
ARM64 HDBSS support. Since the HDBSS buffer size is configurable and
cannot be determined at KVM initialization, an IOCTL interface is
required.

Actually exposing the new capability to user space happens in a later
patch.

Signed-off-by: eillon <yezhenyu2@huawei.com>
Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
---
 arch/arm64/Kconfig                  | 14 ++++++++++++++
 arch/arm64/include/asm/cpucaps.h    |  2 ++
 arch/arm64/include/asm/cpufeature.h |  5 +++++
 arch/arm64/include/asm/kvm_host.h   |  4 ++++
 arch/arm64/include/asm/sysreg.h     | 12 ++++++++++++
 arch/arm64/kernel/cpufeature.c      |  9 +++++++++
 arch/arm64/tools/cpucaps            |  1 +
 include/uapi/linux/kvm.h            |  1 +
 tools/include/uapi/linux/kvm.h      |  1 +
 9 files changed, 49 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6663ffd23f25..1edf75888a09 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2201,6 +2201,20 @@ config ARM64_GCS

 endmenu # "ARMv9.4 architectural features"

+menu "ARMv9.5 architectural features"
+
+config ARM64_HDBSS
+	bool "Enable support for Hardware Dirty state tracking Structure (HDBSS)"
+	help
+	  Hardware Dirty state tracking Structure(HDBSS) enhances tracking
+	  translation table descriptors' dirty state to reduce the cost of
+	  surveying for dirtied granules.
+
+	  The feature introduces new assembly registers (HDBSSBR_EL2 and
+	  HDBSSPROD_EL2), which are accessed via generated register accessors.
+
+endmenu # "ARMv9.5 architectural features"
+
 config ARM64_SVE
 	bool "ARM Scalable Vector Extension support"
 	default y
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 9d769291a306..5e5a26f28dec 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -48,6 +48,8 @@ cpucap_is_possible(const unsigned int cap)
 		return IS_ENABLED(CONFIG_ARM64_GCS);
 	case ARM64_HAFT:
 		return IS_ENABLED(CONFIG_ARM64_HAFT);
+	case ARM64_HAS_HDBSS:
+		return IS_ENABLED(CONFIG_ARM64_HDBSS);
 	case ARM64_UNMAP_KERNEL_AT_EL0:
 		return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0);
 	case ARM64_WORKAROUND_843419:
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index e223cbf350e4..b231415a2b76 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -856,6 +856,11 @@ static inline bool system_supports_haft(void)
 	return cpus_have_final_cap(ARM64_HAFT);
 }

+static inline bool system_supports_hdbss(void)
+{
+	return cpus_have_final_cap(ARM64_HAS_HDBSS);
+}
+
 static __always_inline bool system_supports_mpam(void)
 {
 	return alternative_has_cap_unlikely(ARM64_MPAM);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 64302c438355..d962932f0e5f 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -60,6 +60,10 @@

 #define KVM_HAVE_MMU_RWLOCK

+/* HDBSS entry field definitions */
+#define HDBSS_ENTRY_VALID BIT(0)
+#define HDBSS_ENTRY_IPA GENMASK_ULL(55, 12)
+
 /*
  * Mode of operation configurable with kvm-arm.mode early param.
  * See Documentation/admin-guide/kernel-parameters.txt for more information.
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index c231d2a3e515..3511edea1fbc 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -1129,6 +1129,18 @@
 #define gicr_insn(insn)			read_sysreg_s(GICV5_OP_GICR_##insn)
 #define gic_insn(v, insn)		write_sysreg_s(v, GICV5_OP_GIC_##insn)

+/*
+ * Definitions for the HDBSS feature
+ */
+#define HDBSS_MAX_SIZE		HDBSSBR_EL2_SZ_2MB
+
+#define HDBSSBR_EL2(baddr, sz)	(((baddr) & GENMASK(55, 12 + sz)) | \
+				 FIELD_PREP(HDBSSBR_EL2_SZ_MASK, sz))
+#define HDBSSBR_BADDR(br)	((br) & GENMASK(55, (12 + HDBSSBR_SZ(br))))
+#define HDBSSBR_SZ(br)		FIELD_GET(HDBSSBR_EL2_SZ_MASK, br)
+
+#define HDBSSPROD_IDX(prod)	FIELD_GET(HDBSSPROD_EL2_INDEX_MASK, prod)
+
 #define ARM64_FEATURE_FIELD_BITS	4

 #ifdef __ASSEMBLY__
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index e25b0f84a22d..f39973b68bdb 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2710,6 +2710,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.matches = has_cpuid_feature,
 		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HAFT)
 	},
+#endif
+#ifdef CONFIG_ARM64_HDBSS
+	{
+		.desc = "Hardware Dirty state tracking structure (HDBSS)",
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.capability = ARM64_HAS_HDBSS,
+		.matches = has_cpuid_feature,
+		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HDBSS)
+	},
 #endif
 	{
 		.desc = "CRC32 instructions",
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 1b32c1232d28..4be19bb4543e 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -64,6 +64,7 @@ HAS_TLB_RANGE
 HAS_VA52
 HAS_VIRT_HOST_EXTN
 HAS_WFXT
+HAS_HDBSS
 HAFT
 HW_DBM
 KVM_HVHE
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 52f6000ab020..59340189afac 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -963,6 +963,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_RISCV_MP_STATE_RESET 242
 #define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
 #define KVM_CAP_GUEST_MEMFD_FLAGS 244
+#define KVM_CAP_ARM_HW_DIRTY_STATE_TRACK 245

 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h
index 52f6000ab020..59340189afac 100644
--- a/tools/include/uapi/linux/kvm.h
+++ b/tools/include/uapi/linux/kvm.h
@@ -963,6 +963,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_RISCV_MP_STATE_RESET 242
 #define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
 #define KVM_CAP_GUEST_MEMFD_FLAGS 244
+#define KVM_CAP_ARM_HW_DIRTY_STATE_TRACK 245

 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
--
2.33.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events
  2025-11-21  9:23 [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Tian Zheng
                   ` (2 preceding siblings ...)
  2025-11-21  9:23 ` [PATCH v2 3/5] KVM: arm64: Add support for FEAT_HDBSS Tian Zheng
@ 2025-11-21  9:23 ` Tian Zheng
  2025-11-22 16:17   ` Marc Zyngier
  2025-12-17 13:39   ` Robert Hoo
  2025-11-21  9:23 ` [PATCH v2 5/5] KVM: arm64: Document HDBSS ioctl Tian Zheng
  2025-11-21  9:54 ` [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Marc Zyngier
  5 siblings, 2 replies; 21+ messages in thread
From: Tian Zheng @ 2025-11-21  9:23 UTC (permalink / raw)
  To: maz, oliver.upton, catalin.marinas, corbet, pbonzini, will
  Cc: linux-kernel, zhengtian10, yuzenghui, wangzhou1, yezhenyu2,
	xiexiangyou, zhengchuan, linuxarm, joey.gouly, kvmarm, kvm,
	linux-arm-kernel, linux-doc, suzuki.poulose

From: eillon <yezhenyu2@huawei.com>

Implement the HDBSS enable/disable functionality using the
KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.

Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
at the start of live migration, configuring the buffer size.
The feature is disabled by invoking the ioctl again with size
set to 0 once migration completes.

Add support for updating the dirty bitmap based on the HDBSS
buffer. Similar to the x86 PML implementation, KVM flushes the
buffer on all VM-Exits, so running vCPUs only need to be kicked
to force a VM-Exit.

Signed-off-by: eillon <yezhenyu2@huawei.com>
Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
---
 arch/arm64/include/asm/kvm_host.h |  10 +++
 arch/arm64/include/asm/kvm_mmu.h  |  17 +++++
 arch/arm64/kvm/arm.c              | 107 ++++++++++++++++++++++++++++++
 arch/arm64/kvm/handle_exit.c      |  45 +++++++++++++
 arch/arm64/kvm/hyp/vhe/switch.c   |   1 +
 arch/arm64/kvm/mmu.c              |  10 +++
 arch/arm64/kvm/reset.c            |   3 +
 include/linux/kvm_host.h          |   1 +
 8 files changed, 194 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index d962932f0e5f..408e4c2b3d1a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
 u32 __attribute_const__ kvm_target_cpu(void);
 void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
+void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);

 struct kvm_hyp_memcache {
 	phys_addr_t head;
@@ -793,6 +794,12 @@ struct vcpu_reset_state {
 	bool		reset;
 };

+struct vcpu_hdbss_state {
+	phys_addr_t base_phys;
+	u32 size;
+	u32 next_index;
+};
+
 struct vncr_tlb;

 struct kvm_vcpu_arch {
@@ -897,6 +904,9 @@ struct kvm_vcpu_arch {

 	/* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
 	struct vncr_tlb	*vncr_tlb;
+
+	/* HDBSS registers info */
+	struct vcpu_hdbss_state hdbss;
 };

 /*
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index e4069f2ce642..6ace1080aed5 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct kvm_s2_mmu *mmu,
 	asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
 }

+static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+	u64 br_el2, prod_el2;
+
+	if (!kvm->enable_hdbss)
+		return;
+
+	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
+	prod_el2 = vcpu->arch.hdbss.next_index;
+
+	write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
+	write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
+
+	isb();
+}
+
 static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
 {
 	return container_of(mmu->arch, struct kvm, arch);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 870953b4a8a7..64f65e3c2a89 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
 	return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
 }

+void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
+{
+	struct page *hdbss_pg = NULL;
+
+	hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
+	if (hdbss_pg)
+		__free_pages(hdbss_pg, vcpu->arch.hdbss.size);
+
+	vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
+		.base_phys = 0,
+		.size = 0,
+		.next_index = 0,
+	};
+}
+
+static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
+				    struct kvm_enable_cap *cap)
+{
+	unsigned long i;
+	struct kvm_vcpu *vcpu;
+	struct page *hdbss_pg = NULL;
+	int size = cap->args[0];
+	int ret = 0;
+
+	if (!system_supports_hdbss()) {
+		kvm_err("This system does not support HDBSS!\n");
+		return -EINVAL;
+	}
+
+	if (size < 0 || size > HDBSS_MAX_SIZE) {
+		kvm_err("Invalid HDBSS buffer size: %d!\n", size);
+		return -EINVAL;
+	}
+
+	/* Enable the HDBSS feature if size > 0, otherwise disable it. */
+	if (size) {
+		kvm_for_each_vcpu(i, vcpu, kvm) {
+			hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
+			if (!hdbss_pg) {
+				kvm_err("Alloc HDBSS buffer failed!\n");
+				ret = -ENOMEM;
+				goto error_alloc;
+			}
+
+			vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
+				.base_phys = page_to_phys(hdbss_pg),
+				.size = size,
+				.next_index = 0,
+			};
+		}
+
+		kvm->enable_hdbss = true;
+		kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;
+
+		/*
+		 * We should kick vcpus out of guest mode here to load new
+		 * vtcr value to vtcr_el2 register when re-enter guest mode.
+		 */
+		kvm_for_each_vcpu(i, vcpu, kvm)
+			kvm_vcpu_kick(vcpu);
+	} else if (kvm->enable_hdbss) {
+		kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS);
+
+		kvm_for_each_vcpu(i, vcpu, kvm) {
+			/* Kick vcpus to flush hdbss buffer. */
+			kvm_vcpu_kick(vcpu);
+
+			kvm_arm_vcpu_free_hdbss(vcpu);
+		}
+
+		kvm->enable_hdbss = false;
+	}
+
+	return ret;
+
+error_alloc:
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (!vcpu->arch.hdbss.base_phys && !vcpu->arch.hdbss.size)
+			continue;
+
+		kvm_arm_vcpu_free_hdbss(vcpu);
+	}
+
+	return ret;
+}
+
 int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 			    struct kvm_enable_cap *cap)
 {
@@ -132,6 +218,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 		}
 		mutex_unlock(&kvm->lock);
 		break;
+	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
+		mutex_lock(&kvm->lock);
+		r = kvm_cap_arm_enable_hdbss(kvm, cap);
+		mutex_unlock(&kvm->lock);
+		break;
 	default:
 		break;
 	}
@@ -420,6 +511,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 			r = kvm_supports_cacheable_pfnmap();
 		break;

+	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
+		r = system_supports_hdbss();
+		break;
 	default:
 		r = 0;
 	}
@@ -1837,7 +1931,20 @@ long kvm_arch_vcpu_ioctl(struct file *filp,

 void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
 {
+	/*
+	 * Flush all CPUs' dirty log buffers to the dirty_bitmap.  Called
+	 * before reporting dirty_bitmap to userspace.  KVM flushes the buffers
+	 * on all VM-Exits, thus we only need to kick running vCPUs to force a
+	 * VM-Exit.
+	 */
+	struct kvm_vcpu *vcpu;
+	unsigned long i;

+	if (!kvm->enable_hdbss)
+		return;
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vcpu_kick(vcpu);
 }

 static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index cc7d5d1709cb..9ba0ea6305ef 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -412,6 +412,49 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
 	return arm_exit_handlers[esr_ec];
 }

+static void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)
+{
+	int idx, curr_idx;
+	u64 *hdbss_buf;
+	struct kvm *kvm = vcpu->kvm;
+	u64 br_el2;
+
+	if (!kvm->enable_hdbss)
+		return;
+
+	dsb(sy);
+	isb();
+	curr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));
+	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
+
+	/* Do nothing if HDBSS buffer is empty or br_el2 is NULL */
+	if (curr_idx == 0 || br_el2 == 0)
+		return;
+
+	hdbss_buf = page_address(phys_to_page(vcpu->arch.hdbss.base_phys));
+	if (!hdbss_buf) {
+		kvm_err("Enter flush hdbss buffer with buffer == NULL!");
+		return;
+	}
+
+	guard(write_lock_irqsave)(&vcpu->kvm->mmu_lock);
+	for (idx = 0; idx < curr_idx; idx++) {
+		u64 gpa;
+
+		gpa = hdbss_buf[idx];
+		if (!(gpa & HDBSS_ENTRY_VALID))
+			continue;
+
+		gpa &= HDBSS_ENTRY_IPA;
+		kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
+	}
+
+	/* reset HDBSS index */
+	write_sysreg_s(0, SYS_HDBSSPROD_EL2);
+	vcpu->arch.hdbss.next_index = 0;
+	isb();
+}
+
 /*
  * We may be single-stepping an emulated instruction. If the emulation
  * has been completed in the kernel, we can return to userspace with a
@@ -447,6 +490,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
 {
 	struct kvm_run *run = vcpu->run;

+	kvm_flush_hdbss_buffer(vcpu);
+
 	if (ARM_SERROR_PENDING(exception_index)) {
 		/*
 		 * The SError is handled by handle_exit_early(). If the guest
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index 9984c492305a..3787c9c5810d 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -220,6 +220,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)
 	__vcpu_load_switch_sysregs(vcpu);
 	__vcpu_load_activate_traps(vcpu);
 	__load_stage2(vcpu->arch.hw_mmu, vcpu->arch.hw_mmu->arch);
+	__load_hdbss(vcpu);
 }

 void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 7cc964af8d30..91a2f9dbb406 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1843,6 +1843,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 	if (writable)
 		prot |= KVM_PGTABLE_PROT_W;

+	if (writable && kvm->enable_hdbss && logging_active)
+		prot |= KVM_PGTABLE_PROT_DBM;
+
 	if (exec_fault)
 		prot |= KVM_PGTABLE_PROT_X;

@@ -1950,6 +1953,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)

 	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);

+	/*
+	 * HDBSS buffer already flushed when enter handle_trap_exceptions().
+	 * Nothing to do here.
+	 */
+	if (ESR_ELx_ISS2(esr) & ESR_ELx_HDBSSF)
+		return 1;
+
 	if (esr_fsc_is_translation_fault(esr)) {
 		/* Beyond sanitised PARange (which is the IPA limit) */
 		if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 959532422d3a..65e8f890f863 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -161,6 +161,9 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
 	free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
 	kfree(vcpu->arch.vncr_tlb);
 	kfree(vcpu->arch.ccsidr);
+
+	if (vcpu->arch.hdbss.base_phys || vcpu->arch.hdbss.size)
+		kvm_arm_vcpu_free_hdbss(vcpu);
 }

 static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 5bd76cf394fa..aa8138604b1e 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -876,6 +876,7 @@ struct kvm {
 	struct xarray mem_attr_array;
 #endif
 	char stats_id[KVM_STATS_NAME_SIZE];
+	bool enable_hdbss;
 };

 #define kvm_err(fmt, ...) \
--
2.33.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 5/5] KVM: arm64: Document HDBSS ioctl
  2025-11-21  9:23 [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Tian Zheng
                   ` (3 preceding siblings ...)
  2025-11-21  9:23 ` [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events Tian Zheng
@ 2025-11-21  9:23 ` Tian Zheng
  2025-11-21  9:54 ` [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Marc Zyngier
  5 siblings, 0 replies; 21+ messages in thread
From: Tian Zheng @ 2025-11-21  9:23 UTC (permalink / raw)
  To: maz, oliver.upton, catalin.marinas, corbet, pbonzini, will
  Cc: linux-kernel, zhengtian10, yuzenghui, wangzhou1, yezhenyu2,
	xiexiangyou, zhengchuan, linuxarm, joey.gouly, kvmarm, kvm,
	linux-arm-kernel, linux-doc, suzuki.poulose

A new ioctl (KVM_CAP_ARM_HW_DIRTY_STATE_TRACK) provides a mechanism for
userspace to configure the HDBSS buffer size during live migration,
enabling hardware-assisted dirty page tracking.

Signed-off-by: eillon <yezhenyu2@huawei.com>
Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
---
 Documentation/virt/kvm/api.rst | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 57061fa29e6a..25d60ff136e9 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -8703,6 +8703,21 @@ This capability indicate to the userspace whether a PFNMAP memory region
 can be safely mapped as cacheable. This relies on the presence of
 force write back (FWB) feature support on the hardware.

+7.44 KVM_CAP_ARM_HW_DIRTY_STATE_TRACK
+:Architectures: arm64
+:Type: VM
+:Parameters: args[0] is the allocation order determining HDBSS buffer size
+:Returns: 0 on success, negative value on failure
+
+Enables hardware-assisted dirty page tracking via the Hardware Dirty State
+Tracking Structure (HDBSS).
+
+When live migration is initiated, userspace can enable this feature by
+setting KVM_CAP_ARM_HW_DIRTY_STATE_TRACK through IOCTL. KVM will allocate
+per-vCPU HDBSS buffers.
+
+The feature is disabled by invoking the ioctl again.
+
 8. Other capabilities.
 ======================

--
2.33.0



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5
  2025-11-21  9:23 [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Tian Zheng
                   ` (4 preceding siblings ...)
  2025-11-21  9:23 ` [PATCH v2 5/5] KVM: arm64: Document HDBSS ioctl Tian Zheng
@ 2025-11-21  9:54 ` Marc Zyngier
  2025-11-21 10:21   ` z00939249
  5 siblings, 1 reply; 21+ messages in thread
From: Marc Zyngier @ 2025-11-21  9:54 UTC (permalink / raw)
  To: Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, linuxarm, joey.gouly, kvmarm, kvm, linux-arm-kernel,
	linux-doc, suzuki.poulose

On Fri, 21 Nov 2025 09:23:37 +0000,
Tian Zheng <zhengtian10@huawei.com> wrote:
> 
> This series of patches add support to the Hardware Dirty state tracking
> Structure(HDBSS) feature, which is introduced by the ARM architecture
> in the DDI0601(ID121123) version.
> 
> The HDBSS feature is an extension to the architecture that enhances
> tracking translation table descriptors' dirty state, identified as
> FEAT_HDBSS. The goal of this feature is to reduce the cost of surveying
> for dirtied granules, with minimal effect on recording when a granule
> has been dirtied.
> 
> The purpose of this feature is to make the execution overhead of live
> migration lower to both the guest and the host, compared to existing
> approaches (write-protect or search stage 2 tables).
> 
> After these patches, users(such as qemu) can use the
> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl to enable or disable the HDBSS
> feature before and after the live migration.
> 
> This feature is similar to Intel's Page Modification Logging (PML),
> offering hardware-assisted dirty tracking to reduce live migration
> overhead. With PML support expanding beyond Intel, HDBSS introduces a
> comparable mechanism for ARM.

Where is the change log describing what was changed compared to the
previous version?

We gave you extensive comments back in March. You never replied to the
feedback. And you now dump a whole set of patches, 6 months later,
without the slightest indication of what has changed?

Why should we make the effort to review this again?

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5
  2025-11-21  9:54 ` [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Marc Zyngier
@ 2025-11-21 10:21   ` z00939249
  2025-11-22 16:23     ` Marc Zyngier
  0 siblings, 1 reply; 21+ messages in thread
From: z00939249 @ 2025-11-21 10:21 UTC (permalink / raw)
  To: Marc Zyngier, Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose

On 2025/11/21 17:54, Marc Zyngier wrote:
> On Fri, 21 Nov 2025 09:23:37 +0000,
> Tian Zheng <zhengtian10@huawei.com> wrote:
>>
>> This series of patches add support to the Hardware Dirty state tracking
>> Structure(HDBSS) feature, which is introduced by the ARM architecture
>> in the DDI0601(ID121123) version.
>>
>> The HDBSS feature is an extension to the architecture that enhances
>> tracking translation table descriptors' dirty state, identified as
>> FEAT_HDBSS. The goal of this feature is to reduce the cost of surveying
>> for dirtied granules, with minimal effect on recording when a granule
>> has been dirtied.
>>
>> The purpose of this feature is to make the execution overhead of live
>> migration lower to both the guest and the host, compared to existing
>> approaches (write-protect or search stage 2 tables).
>>
>> After these patches, users(such as qemu) can use the
>> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl to enable or disable the HDBSS
>> feature before and after the live migration.
>>
>> This feature is similar to Intel's Page Modification Logging (PML),
>> offering hardware-assisted dirty tracking to reduce live migration
>> overhead. With PML support expanding beyond Intel, HDBSS introduces a
>> comparable mechanism for ARM.
> 
> Where is the change log describing what was changed compared to the
> previous version?
> 
> We gave you extensive comments back in March. You never replied to the
> feedback. And you now dump a whole set of patches, 6 months later,
> without the slightest indication of what has changed?
> 
> Why should we make the effort to review this again?

Apologies for the lack of proper changelog and the delayed follow-up on 
the feedback provided in March. This was an oversight on our part during 
the transition of maintainership for the HDBSS patch series. We 
sincerely appreciate the thorough comments you shared earlier and regret 
not responding in a timely manner.

Below is a summary of the changes made from v1 to v2.

v1:
https://lore.kernel.org/kvm/20250311040321.1460-1-yezhenyu2@huawei.com/

v1->v2 changes:
- Removed redundant macro definitions and switched to tool-generated.
- Split HDBSS interface and implementation into separate patches.
- Integrate system_supports_hdbss() into ARM feature initialization.
- Refactored HDBSS data structure to store meaningful values instead
of raw register contents.
- Fixed permission checks when applying DBM bits in page tables to
prevent potential memory corruption.
- Removed unnecessary dsb instructions.
- Drop the debugging printks.
- Merged the two patches "using ioctl to enable/disable the HDBSS
feature" and "support to handle the HDBSSF event" into one.

We apologize again for the delay and the missing changelog, and we 
greatly appreciate your time in reviewing this updated version.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information
  2025-11-21  9:23 ` [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information Tian Zheng
@ 2025-11-22 12:40   ` Marc Zyngier
  2025-11-27 11:48     ` Tian Zheng
  2025-12-02  6:51     ` Tian Zheng
  0 siblings, 2 replies; 21+ messages in thread
From: Marc Zyngier @ 2025-11-22 12:40 UTC (permalink / raw)
  To: Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, linuxarm, joey.gouly, kvmarm, kvm, linux-arm-kernel,
	linux-doc, suzuki.poulose

On Fri, 21 Nov 2025 09:23:38 +0000,
Tian Zheng <zhengtian10@huawei.com> wrote:
> 
> From: eillon <yezhenyu2@huawei.com>
> 
> The ARM architecture added the HDBSS feature and descriptions of
> related registers (HDBSSBR/HDBSSPROD) in the DDI0601(ID121123) version,
> add them to Linux.
> 
> Signed-off-by: eillon <yezhenyu2@huawei.com>
> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
> ---
>  arch/arm64/include/asm/esr.h     |  2 ++
>  arch/arm64/include/asm/kvm_arm.h |  1 +
>  arch/arm64/tools/sysreg          | 28 ++++++++++++++++++++++++++++
>  3 files changed, 31 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
> index e1deed824464..a6f3cf0b9b86 100644
> --- a/arch/arm64/include/asm/esr.h
> +++ b/arch/arm64/include/asm/esr.h
> @@ -159,6 +159,8 @@
>  #define ESR_ELx_CM 		(UL(1) << ESR_ELx_CM_SHIFT)
> 
>  /* ISS2 field definitions for Data Aborts */
> +#define ESR_ELx_HDBSSF_SHIFT	(11)
> +#define ESR_ELx_HDBSSF		(UL(1) << ESR_ELx_HDBSSF_SHIFT)
>  #define ESR_ELx_TnD_SHIFT	(10)
>  #define ESR_ELx_TnD 		(UL(1) << ESR_ELx_TnD_SHIFT)
>  #define ESR_ELx_TagAccess_SHIFT	(9)
> diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
> index 1da290aeedce..b71122680a03 100644
> --- a/arch/arm64/include/asm/kvm_arm.h
> +++ b/arch/arm64/include/asm/kvm_arm.h
> @@ -124,6 +124,7 @@
>  			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
> 
>  /* VTCR_EL2 Registers bits */
> +#define VTCR_EL2_HDBSS		(1UL << 45)

I think it is time to convert VTCR_EL2 to the sysreg infrastructure
instead of adding extra bits here.

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 2/5] KVM: arm64: Support set the DBM attr during memory abort
  2025-11-21  9:23 ` [PATCH v2 2/5] KVM: arm64: Support set the DBM attr during memory abort Tian Zheng
@ 2025-11-22 12:54   ` Marc Zyngier
  2025-11-27 12:19     ` Tian Zheng
  0 siblings, 1 reply; 21+ messages in thread
From: Marc Zyngier @ 2025-11-22 12:54 UTC (permalink / raw)
  To: Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, linuxarm, joey.gouly, kvmarm, kvm, linux-arm-kernel,
	linux-doc, suzuki.poulose

On Fri, 21 Nov 2025 09:23:39 +0000,
Tian Zheng <zhengtian10@huawei.com> wrote:
> 
> From: eillon <yezhenyu2@huawei.com>
> 
> Add DBM support to automatically promote write-clean pages to
> write-dirty, preventing users from being trapped in EL2 due to
> missing write permissions.
> 
> Since the DBM attribute was introduced in ARMv8.1 and remains
> optional in later architecture revisions, including ARMv9.5.

What is the relevance of this statement?

> 
> Support set the DBM attr during user_mem_abort().

I don't think this commit message accurately describes what the code
does. This merely adds support to the page table code to set the DBM
bit in the S2 PTE, and nothing else.

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 3/5] KVM: arm64: Add support for FEAT_HDBSS
  2025-11-21  9:23 ` [PATCH v2 3/5] KVM: arm64: Add support for FEAT_HDBSS Tian Zheng
@ 2025-11-22 13:25   ` Marc Zyngier
  2025-11-27 13:24     ` Tian Zheng
  0 siblings, 1 reply; 21+ messages in thread
From: Marc Zyngier @ 2025-11-22 13:25 UTC (permalink / raw)
  To: Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, linuxarm, joey.gouly, kvmarm, kvm, linux-arm-kernel,
	linux-doc, suzuki.poulose

On Fri, 21 Nov 2025 09:23:40 +0000,
Tian Zheng <zhengtian10@huawei.com> wrote:
> 
> From: eillon <yezhenyu2@huawei.com>
> 
> Armv9.5 introduces the Hardware Dirty Bit State Structure (HDBSS) feature,
> indicated by ID_AA64MMFR1_EL1.HAFDBS == 0b0100.
> 
> Add the Kconfig for FEAT_HDBSS and support detecting and enabling the
> feature. A CPU capability is added to notify the user of the feature.
> 
> Add KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl and basic framework for
> ARM64 HDBSS support. Since the HDBSS buffer size is configurable and
> cannot be determined at KVM initialization, an IOCTL interface is
> required.
> 
> Actually exposing the new capability to user space happens in a later
> patch.
> 
> Signed-off-by: eillon <yezhenyu2@huawei.com>
> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
> ---
>  arch/arm64/Kconfig                  | 14 ++++++++++++++
>  arch/arm64/include/asm/cpucaps.h    |  2 ++
>  arch/arm64/include/asm/cpufeature.h |  5 +++++
>  arch/arm64/include/asm/kvm_host.h   |  4 ++++
>  arch/arm64/include/asm/sysreg.h     | 12 ++++++++++++
>  arch/arm64/kernel/cpufeature.c      |  9 +++++++++
>  arch/arm64/tools/cpucaps            |  1 +
>  include/uapi/linux/kvm.h            |  1 +
>  tools/include/uapi/linux/kvm.h      |  1 +
>  9 files changed, 49 insertions(+)
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 6663ffd23f25..1edf75888a09 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -2201,6 +2201,20 @@ config ARM64_GCS
> 
>  endmenu # "ARMv9.4 architectural features"
> 
> +menu "ARMv9.5 architectural features"
> +
> +config ARM64_HDBSS
> +	bool "Enable support for Hardware Dirty state tracking Structure (HDBSS)"
> +	help
> +	  Hardware Dirty state tracking Structure(HDBSS) enhances tracking
> +	  translation table descriptors' dirty state to reduce the cost of
> +	  surveying for dirtied granules.
> +
> +	  The feature introduces new assembly registers (HDBSSBR_EL2 and
> +	  HDBSSPROD_EL2), which are accessed via generated register accessors.

This last but means nothing to most people.

But more importantly, I really don't want to see this as a config
option. KVM comes with "battery included", and all features should be
available at all times.

> +
> +endmenu # "ARMv9.5 architectural features"
> +
>  config ARM64_SVE
>  	bool "ARM Scalable Vector Extension support"
>  	default y
> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
> index 9d769291a306..5e5a26f28dec 100644
> --- a/arch/arm64/include/asm/cpucaps.h
> +++ b/arch/arm64/include/asm/cpucaps.h
> @@ -48,6 +48,8 @@ cpucap_is_possible(const unsigned int cap)
>  		return IS_ENABLED(CONFIG_ARM64_GCS);
>  	case ARM64_HAFT:
>  		return IS_ENABLED(CONFIG_ARM64_HAFT);
> +	case ARM64_HAS_HDBSS:
> +		return IS_ENABLED(CONFIG_ARM64_HDBSS);
>  	case ARM64_UNMAP_KERNEL_AT_EL0:
>  		return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0);
>  	case ARM64_WORKAROUND_843419:
> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> index e223cbf350e4..b231415a2b76 100644
> --- a/arch/arm64/include/asm/cpufeature.h
> +++ b/arch/arm64/include/asm/cpufeature.h
> @@ -856,6 +856,11 @@ static inline bool system_supports_haft(void)
>  	return cpus_have_final_cap(ARM64_HAFT);
>  }
> 
> +static inline bool system_supports_hdbss(void)
> +{
> +	return cpus_have_final_cap(ARM64_HAS_HDBSS);
> +}
> +
>  static __always_inline bool system_supports_mpam(void)
>  {
>  	return alternative_has_cap_unlikely(ARM64_MPAM);
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 64302c438355..d962932f0e5f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -60,6 +60,10 @@
> 
>  #define KVM_HAVE_MMU_RWLOCK
> 
> +/* HDBSS entry field definitions */
> +#define HDBSS_ENTRY_VALID BIT(0)
> +#define HDBSS_ENTRY_IPA GENMASK_ULL(55, 12)
> +

None of this is used here. Move it to the patch where it belongs.

>  /*
>   * Mode of operation configurable with kvm-arm.mode early param.
>   * See Documentation/admin-guide/kernel-parameters.txt for more information.
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index c231d2a3e515..3511edea1fbc 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -1129,6 +1129,18 @@
>  #define gicr_insn(insn)			read_sysreg_s(GICV5_OP_GICR_##insn)
>  #define gic_insn(v, insn)		write_sysreg_s(v, GICV5_OP_GIC_##insn)
> 
> +/*
> + * Definitions for the HDBSS feature
> + */
> +#define HDBSS_MAX_SIZE		HDBSSBR_EL2_SZ_2MB
> +
> +#define HDBSSBR_EL2(baddr, sz)	(((baddr) & GENMASK(55, 12 + sz)) | \
> +				 FIELD_PREP(HDBSSBR_EL2_SZ_MASK, sz))
> +#define HDBSSBR_BADDR(br)	((br) & GENMASK(55, (12 + HDBSSBR_SZ(br))))
> +#define HDBSSBR_SZ(br)		FIELD_GET(HDBSSBR_EL2_SZ_MASK, br)

This is a bit backward. When would you need to read-back and mask
random bits off the register?

> +
> +#define HDBSSPROD_IDX(prod)	FIELD_GET(HDBSSPROD_EL2_INDEX_MASK, prod)
> +

As previously said, these definitions don't serve any purpose here,
and would be better in the following patch.

>  #define ARM64_FEATURE_FIELD_BITS	4
> 
>  #ifdef __ASSEMBLY__
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index e25b0f84a22d..f39973b68bdb 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -2710,6 +2710,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
>  		.matches = has_cpuid_feature,
>  		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HAFT)
>  	},
> +#endif
> +#ifdef CONFIG_ARM64_HDBSS
> +	{
> +		.desc = "Hardware Dirty state tracking structure (HDBSS)",
> +		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
> +		.capability = ARM64_HAS_HDBSS,
> +		.matches = has_cpuid_feature,
> +		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HDBSS)
> +	},

I think this is one of the features we should restrict to VHE. I don't
imagine pKVM ever making use of this, and no non-VHE HW will ever
build this.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events
  2025-11-21  9:23 ` [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events Tian Zheng
@ 2025-11-22 16:17   ` Marc Zyngier
  2025-11-28  9:21     ` Tian Zheng
  2025-12-17 13:39   ` Robert Hoo
  1 sibling, 1 reply; 21+ messages in thread
From: Marc Zyngier @ 2025-11-22 16:17 UTC (permalink / raw)
  To: Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, linuxarm, joey.gouly, kvmarm, kvm, linux-arm-kernel,
	linux-doc, suzuki.poulose

On Fri, 21 Nov 2025 09:23:41 +0000,
Tian Zheng <zhengtian10@huawei.com> wrote:
> 
> From: eillon <yezhenyu2@huawei.com>
> 
> Implement the HDBSS enable/disable functionality using the
> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.
> 
> Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
> at the start of live migration, configuring the buffer size.
> The feature is disabled by invoking the ioctl again with size
> set to 0 once migration completes.
> 
> Add support for updating the dirty bitmap based on the HDBSS
> buffer. Similar to the x86 PML implementation, KVM flushes the
> buffer on all VM-Exits, so running vCPUs only need to be kicked
> to force a VM-Exit.

Drop the x86 reference, nobody cares about other architectures.

Instead, please describe what state is handled where. Having to
reverse engineer this is particularly painful.

> 
> Signed-off-by: eillon <yezhenyu2@huawei.com>
> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
> ---
>  arch/arm64/include/asm/kvm_host.h |  10 +++
>  arch/arm64/include/asm/kvm_mmu.h  |  17 +++++
>  arch/arm64/kvm/arm.c              | 107 ++++++++++++++++++++++++++++++
>  arch/arm64/kvm/handle_exit.c      |  45 +++++++++++++
>  arch/arm64/kvm/hyp/vhe/switch.c   |   1 +
>  arch/arm64/kvm/mmu.c              |  10 +++
>  arch/arm64/kvm/reset.c            |   3 +
>  include/linux/kvm_host.h          |   1 +
>  8 files changed, 194 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index d962932f0e5f..408e4c2b3d1a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
>  u32 __attribute_const__ kvm_target_cpu(void);
>  void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>  void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
> 
>  struct kvm_hyp_memcache {
>  	phys_addr_t head;
> @@ -793,6 +794,12 @@ struct vcpu_reset_state {
>  	bool		reset;
>  };
> 
> +struct vcpu_hdbss_state {
> +	phys_addr_t base_phys;
> +	u32 size;
> +	u32 next_index;
> +};
> +
>  struct vncr_tlb;
> 
>  struct kvm_vcpu_arch {
> @@ -897,6 +904,9 @@ struct kvm_vcpu_arch {
> 
>  	/* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
>  	struct vncr_tlb	*vncr_tlb;
> +
> +	/* HDBSS registers info */
> +	struct vcpu_hdbss_state hdbss;
>  };
> 
>  /*
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index e4069f2ce642..6ace1080aed5 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct kvm_s2_mmu *mmu,
>  	asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
>  }
> 
> +static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)

Why is this in an include file? If, as it appears, it is VHE only
(this patch completely ignores the nVHE code path), it should be
strictly local to the VHE code.

> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	u64 br_el2, prod_el2;
> +
> +	if (!kvm->enable_hdbss)
> +		return;

Why is enable_hdbss in the *arch-independent* part of the kvm
structure?

> +
> +	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
> +	prod_el2 = vcpu->arch.hdbss.next_index;
> +
> +	write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
> +	write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
> +
> +	isb();
> +}
> +
>  static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
>  {
>  	return container_of(mmu->arch, struct kvm, arch);
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 870953b4a8a7..64f65e3c2a89 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
>  	return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
>  }
> 
> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
> +{
> +	struct page *hdbss_pg = NULL;

Why the NULL init?

> +
> +	hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
> +	if (hdbss_pg)
> +		__free_pages(hdbss_pg, vcpu->arch.hdbss.size);
> +
> +	vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
> +		.base_phys = 0,
> +		.size = 0,
> +		.next_index = 0,
> +	};

It should be enough to set size to 0.

> +}
> +
> +static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
> +				    struct kvm_enable_cap *cap)
> +{
> +	unsigned long i;
> +	struct kvm_vcpu *vcpu;
> +	struct page *hdbss_pg = NULL;
> +	int size = cap->args[0];

This is the wrong type. Use unsigned types, preferably the same as the
userspace structure.

> +	int ret = 0;
> +
> +	if (!system_supports_hdbss()) {
> +		kvm_err("This system does not support HDBSS!\n");

No. We don't print *anything* on error.

> +		return -EINVAL;
> +	}
> +
> +	if (size < 0 || size > HDBSS_MAX_SIZE) {
> +		kvm_err("Invalid HDBSS buffer size: %d!\n", size);
> +		return -EINVAL;

Same thing. Please remove *all* the kvm_err() crap.

And with an unsigned type, you avoid the < 0 compare.

> +	}
> +
> +	/* Enable the HDBSS feature if size > 0, otherwise disable it. */
> +	if (size) {
> +		kvm_for_each_vcpu(i, vcpu, kvm) {
> +			hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
> +			if (!hdbss_pg) {
> +				kvm_err("Alloc HDBSS buffer failed!\n");
> +				ret = -ENOMEM;
> +				goto error_alloc;
> +			}
> +
> +			vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
> +				.base_phys = page_to_phys(hdbss_pg),
> +				.size = size,
> +				.next_index = 0,
> +			};
> +		}
> +
> +		kvm->enable_hdbss = true;
> +		kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;
> +
> +		/*
> +		 * We should kick vcpus out of guest mode here to load new
> +		 * vtcr value to vtcr_el2 register when re-enter guest mode.
> +		 */
> +		kvm_for_each_vcpu(i, vcpu, kvm)
> +			kvm_vcpu_kick(vcpu);

I don't think this is correct. You should start by stopping all vcpus,
install the logging on all of them, and only then restart them.

Otherwise, your error handling is totally broken. You can end-up
freeing memory that is in active use!

> +	} else if (kvm->enable_hdbss) {
> +		kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS);
> +
> +		kvm_for_each_vcpu(i, vcpu, kvm) {
> +			/* Kick vcpus to flush hdbss buffer. */
> +			kvm_vcpu_kick(vcpu);
> +
> +			kvm_arm_vcpu_free_hdbss(vcpu);
> +		}

Same thing.

> +
> +		kvm->enable_hdbss = false;
> +	}
> +
> +	return ret;
> +
> +error_alloc:
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (!vcpu->arch.hdbss.base_phys && !vcpu->arch.hdbss.size)
> +			continue;
> +
> +		kvm_arm_vcpu_free_hdbss(vcpu);
> +	}
> +
> +	return ret;
> +}
> +
>  int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>  			    struct kvm_enable_cap *cap)
>  {
> @@ -132,6 +218,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>  		}
>  		mutex_unlock(&kvm->lock);
>  		break;
> +	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
> +		mutex_lock(&kvm->lock);
> +		r = kvm_cap_arm_enable_hdbss(kvm, cap);
> +		mutex_unlock(&kvm->lock);
> +		break;
>  	default:
>  		break;
>  	}
> @@ -420,6 +511,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  			r = kvm_supports_cacheable_pfnmap();
>  		break;
> 
> +	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
> +		r = system_supports_hdbss();
> +		break;
>  	default:
>  		r = 0;
>  	}
> @@ -1837,7 +1931,20 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> 
>  void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
>  {
> +	/*
> +	 * Flush all CPUs' dirty log buffers to the dirty_bitmap.  Called
> +	 * before reporting dirty_bitmap to userspace.  KVM flushes the buffers
> +	 * on all VM-Exits, thus we only need to kick running vCPUs to force a
> +	 * VM-Exit.
> +	 */
> +	struct kvm_vcpu *vcpu;
> +	unsigned long i;
> 
> +	if (!kvm->enable_hdbss)
> +		return;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vcpu_kick(vcpu);

And then what? You return to userspace while the stuff is being
written, without any synchronisation? How does userspace know that the
state is consistent?

Also, I'm not sure you can ignore the memslot. It *is* relevant.

>  }
> 
>  static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> index cc7d5d1709cb..9ba0ea6305ef 100644
> --- a/arch/arm64/kvm/handle_exit.c
> +++ b/arch/arm64/kvm/handle_exit.c
> @@ -412,6 +412,49 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
>  	return arm_exit_handlers[esr_ec];
>  }
> 
> +static void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)
> +{
> +	int idx, curr_idx;
> +	u64 *hdbss_buf;
> +	struct kvm *kvm = vcpu->kvm;
> +	u64 br_el2;
> +
> +	if (!kvm->enable_hdbss)
> +		return;
> +
> +	dsb(sy);
> +	isb();

What are these barriers for?

> +	curr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));
> +	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
> +
> +	/* Do nothing if HDBSS buffer is empty or br_el2 is NULL */
> +	if (curr_idx == 0 || br_el2 == 0)
> +		return;
> +
> +	hdbss_buf = page_address(phys_to_page(vcpu->arch.hdbss.base_phys));
> +	if (!hdbss_buf) {
> +		kvm_err("Enter flush hdbss buffer with buffer == NULL!");
> +		return;
> +	}
> +
> +	guard(write_lock_irqsave)(&vcpu->kvm->mmu_lock);
> +	for (idx = 0; idx < curr_idx; idx++) {
> +		u64 gpa;
> +
> +		gpa = hdbss_buf[idx];
> +		if (!(gpa & HDBSS_ENTRY_VALID))
> +			continue;
> +
> +		gpa &= HDBSS_ENTRY_IPA;
> +		kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
> +	}
> +
> +	/* reset HDBSS index */
> +	write_sysreg_s(0, SYS_HDBSSPROD_EL2);
> +	vcpu->arch.hdbss.next_index = 0;
> +	isb();
> +}
> +
>  /*
>   * We may be single-stepping an emulated instruction. If the emulation
>   * has been completed in the kernel, we can return to userspace with a
> @@ -447,6 +490,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
>  {
>  	struct kvm_run *run = vcpu->run;
> 
> +	kvm_flush_hdbss_buffer(vcpu);
> +
>  	if (ARM_SERROR_PENDING(exception_index)) {
>  		/*
>  		 * The SError is handled by handle_exit_early(). If the guest
> diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
> index 9984c492305a..3787c9c5810d 100644
> --- a/arch/arm64/kvm/hyp/vhe/switch.c
> +++ b/arch/arm64/kvm/hyp/vhe/switch.c
> @@ -220,6 +220,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)
>  	__vcpu_load_switch_sysregs(vcpu);
>  	__vcpu_load_activate_traps(vcpu);
>  	__load_stage2(vcpu->arch.hw_mmu, vcpu->arch.hw_mmu->arch);
> +	__load_hdbss(vcpu);
>  }
> 
>  void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 7cc964af8d30..91a2f9dbb406 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1843,6 +1843,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
>  	if (writable)
>  		prot |= KVM_PGTABLE_PROT_W;
> 
> +	if (writable && kvm->enable_hdbss && logging_active)
> +		prot |= KVM_PGTABLE_PROT_DBM;
> +

So all the pages are dirty by default, but the logger can't see it.
This is really broken, and I think you haven't really tested this
code.

>  	if (exec_fault)
>  		prot |= KVM_PGTABLE_PROT_X;
> 
> @@ -1950,6 +1953,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
> 
>  	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
> 
> +	/*
> +	 * HDBSS buffer already flushed when enter handle_trap_exceptions().
> +	 * Nothing to do here.
> +	 */
> +	if (ESR_ELx_ISS2(esr) & ESR_ELx_HDBSSF)
> +		return 1;
> +

Flushing the buffer doesn't solve a potential error state. And what if
you have overflowed the buffer? There is a lot of things that can
happen as a result of R_STJMN, and I don't see any of that being
described here.

>  	if (esr_fsc_is_translation_fault(esr)) {
>  		/* Beyond sanitised PARange (which is the IPA limit) */
>  		if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 959532422d3a..65e8f890f863 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -161,6 +161,9 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
>  	free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
>  	kfree(vcpu->arch.vncr_tlb);
>  	kfree(vcpu->arch.ccsidr);
> +
> +	if (vcpu->arch.hdbss.base_phys || vcpu->arch.hdbss.size)
> +		kvm_arm_vcpu_free_hdbss(vcpu);
>  }
> 
>  static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 5bd76cf394fa..aa8138604b1e 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -876,6 +876,7 @@ struct kvm {
>  	struct xarray mem_attr_array;
>  #endif
>  	char stats_id[KVM_STATS_NAME_SIZE];
> +	bool enable_hdbss;

Well, no.

This is broken in a number of ways, and I haven't considered the UAPI
yet. The error handling is non-existent, and this will actively
corrupt memory (again). Marking writable pages as writable actively
prevents logging, meaning that you will happily miss dirty pages.

I'll stop reviewing this series here.

	M.

-- 
Jazz isn't dead. It just smells funny.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5
  2025-11-21 10:21   ` z00939249
@ 2025-11-22 16:23     ` Marc Zyngier
  0 siblings, 0 replies; 21+ messages in thread
From: Marc Zyngier @ 2025-11-22 16:23 UTC (permalink / raw)
  To: z00939249
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose

On Fri, 21 Nov 2025 10:21:16 +0000,
z00939249 <zhengtian10@huawei.com> wrote:
> 
> On 2025/11/21 17:54, Marc Zyngier wrote:
> > On Fri, 21 Nov 2025 09:23:37 +0000,
> > Tian Zheng <zhengtian10@huawei.com> wrote:
> >> 
> >> This series of patches add support to the Hardware Dirty state tracking
> >> Structure(HDBSS) feature, which is introduced by the ARM architecture
> >> in the DDI0601(ID121123) version.
> >> 
> >> The HDBSS feature is an extension to the architecture that enhances
> >> tracking translation table descriptors' dirty state, identified as
> >> FEAT_HDBSS. The goal of this feature is to reduce the cost of surveying
> >> for dirtied granules, with minimal effect on recording when a granule
> >> has been dirtied.
> >> 
> >> The purpose of this feature is to make the execution overhead of live
> >> migration lower to both the guest and the host, compared to existing
> >> approaches (write-protect or search stage 2 tables).
> >> 
> >> After these patches, users(such as qemu) can use the
> >> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl to enable or disable the HDBSS
> >> feature before and after the live migration.
> >> 
> >> This feature is similar to Intel's Page Modification Logging (PML),
> >> offering hardware-assisted dirty tracking to reduce live migration
> >> overhead. With PML support expanding beyond Intel, HDBSS introduces a
> >> comparable mechanism for ARM.
> > 
> > Where is the change log describing what was changed compared to the
> > previous version?
> > 
> > We gave you extensive comments back in March. You never replied to the
> > feedback. And you now dump a whole set of patches, 6 months later,
> > without the slightest indication of what has changed?
> > 
> > Why should we make the effort to review this again?
> 
> Apologies for the lack of proper changelog and the delayed follow-up
> on the feedback provided in March. This was an oversight on our part
> during the transition of maintainership for the HDBSS patch series. We
> sincerely appreciate the thorough comments you shared earlier and
> regret not responding in a timely manner.
> 
> Below is a summary of the changes made from v1 to v2.
> 
> v1:
> https://lore.kernel.org/kvm/20250311040321.1460-1-yezhenyu2@huawei.com/
> 
> v1->v2 changes:
> - Removed redundant macro definitions and switched to tool-generated.
> - Split HDBSS interface and implementation into separate patches.
> - Integrate system_supports_hdbss() into ARM feature initialization.
> - Refactored HDBSS data structure to store meaningful values instead
> of raw register contents.
> - Fixed permission checks when applying DBM bits in page tables to
> prevent potential memory corruption.
> - Removed unnecessary dsb instructions.
> - Drop the debugging printks.
> - Merged the two patches "using ioctl to enable/disable the HDBSS
> feature" and "support to handle the HDBSSF event" into one.

Thanks for the update.

Please make sure you always include such description in future version
of this series. I hope the next version won't take as long (over 8
months between versions is counter productive).

	M.

-- 
Jazz isn't dead. It just smells funny.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information
  2025-11-22 12:40   ` Marc Zyngier
@ 2025-11-27 11:48     ` Tian Zheng
  2025-12-02  6:51     ` Tian Zheng
  1 sibling, 0 replies; 21+ messages in thread
From: Tian Zheng @ 2025-11-27 11:48 UTC (permalink / raw)
  To: Marc Zyngier, Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose



On 2025/11/22 20:40, Marc Zyngier wrote:
> On Fri, 21 Nov 2025 09:23:38 +0000,
> Tian Zheng <zhengtian10@huawei.com> wrote:
>>
>> From: eillon <yezhenyu2@huawei.com>
>>
>> The ARM architecture added the HDBSS feature and descriptions of
>> related registers (HDBSSBR/HDBSSPROD) in the DDI0601(ID121123) version,
>> add them to Linux.
>>
>> Signed-off-by: eillon <yezhenyu2@huawei.com>
>> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
>> ---
>>   arch/arm64/include/asm/esr.h     |  2 ++
>>   arch/arm64/include/asm/kvm_arm.h |  1 +
>>   arch/arm64/tools/sysreg          | 28 ++++++++++++++++++++++++++++
>>   3 files changed, 31 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
>> index e1deed824464..a6f3cf0b9b86 100644
>> --- a/arch/arm64/include/asm/esr.h
>> +++ b/arch/arm64/include/asm/esr.h
>> @@ -159,6 +159,8 @@
>>   #define ESR_ELx_CM 		(UL(1) << ESR_ELx_CM_SHIFT)
>>
>>   /* ISS2 field definitions for Data Aborts */
>> +#define ESR_ELx_HDBSSF_SHIFT	(11)
>> +#define ESR_ELx_HDBSSF		(UL(1) << ESR_ELx_HDBSSF_SHIFT)
>>   #define ESR_ELx_TnD_SHIFT	(10)
>>   #define ESR_ELx_TnD 		(UL(1) << ESR_ELx_TnD_SHIFT)
>>   #define ESR_ELx_TagAccess_SHIFT	(9)
>> diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
>> index 1da290aeedce..b71122680a03 100644
>> --- a/arch/arm64/include/asm/kvm_arm.h
>> +++ b/arch/arm64/include/asm/kvm_arm.h
>> @@ -124,6 +124,7 @@
>>   			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
>>
>>   /* VTCR_EL2 Registers bits */
>> +#define VTCR_EL2_HDBSS		(1UL << 45)
> 
> I think it is time to convert VTCR_EL2 to the sysreg infrastructure
> instead of adding extra bits here.
> 
Sure, I will move VTCR_EL2_HDBSS into the sysreg description file
alongside VTCR_EL2.
> 	M.




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 2/5] KVM: arm64: Support set the DBM attr during memory abort
  2025-11-22 12:54   ` Marc Zyngier
@ 2025-11-27 12:19     ` Tian Zheng
  0 siblings, 0 replies; 21+ messages in thread
From: Tian Zheng @ 2025-11-27 12:19 UTC (permalink / raw)
  To: Marc Zyngier, Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose



On 2025/11/22 20:54, Marc Zyngier wrote:
> On Fri, 21 Nov 2025 09:23:39 +0000,
> Tian Zheng <zhengtian10@huawei.com> wrote:
>>
>> From: eillon <yezhenyu2@huawei.com>
>>
>> Add DBM support to automatically promote write-clean pages to
>> write-dirty, preventing users from being trapped in EL2 due to
>> missing write permissions.
>>
>> Since the DBM attribute was introduced in ARMv8.1 and remains
>> optional in later architecture revisions, including ARMv9.5.
> 
> What is the relevance of this statement?
> 
I will remove this statement in v3.
>>
>> Support set the DBM attr during user_mem_abort().
> 
> I don't think this commit message accurately describes what the code
> does. This merely adds support to the page table code to set the DBM
> bit in the S2 PTE, and nothing else.
> 
Yes, this patch only adds support to set the DBM attr in the S2 PTE
during user_mem_abort(), and does not implement automatic promote
write-clean pages to write-dirty.

I will reward commit message of this patch like:

This patch adds support to set the DBM attr in S2 PTE during
user_mem_abort(). As long as add the DBM bit, it enable hardware
automatically promote write-clean pages to write-dirty, preventing
users from being trapped in EL2 due to missing write permissions.

> 	M.
> 



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 3/5] KVM: arm64: Add support for FEAT_HDBSS
  2025-11-22 13:25   ` Marc Zyngier
@ 2025-11-27 13:24     ` Tian Zheng
  0 siblings, 0 replies; 21+ messages in thread
From: Tian Zheng @ 2025-11-27 13:24 UTC (permalink / raw)
  To: Marc Zyngier, Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose



On 2025/11/22 21:25, Marc Zyngier wrote:
> On Fri, 21 Nov 2025 09:23:40 +0000,
> Tian Zheng <zhengtian10@huawei.com> wrote:
>>
>> From: eillon <yezhenyu2@huawei.com>
>>
>> Armv9.5 introduces the Hardware Dirty Bit State Structure (HDBSS) feature,
>> indicated by ID_AA64MMFR1_EL1.HAFDBS == 0b0100.
>>
>> Add the Kconfig for FEAT_HDBSS and support detecting and enabling the
>> feature. A CPU capability is added to notify the user of the feature.
>>
>> Add KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl and basic framework for
>> ARM64 HDBSS support. Since the HDBSS buffer size is configurable and
>> cannot be determined at KVM initialization, an IOCTL interface is
>> required.
>>
>> Actually exposing the new capability to user space happens in a later
>> patch.
>>
>> Signed-off-by: eillon <yezhenyu2@huawei.com>
>> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
>> ---
>>   arch/arm64/Kconfig                  | 14 ++++++++++++++
>>   arch/arm64/include/asm/cpucaps.h    |  2 ++
>>   arch/arm64/include/asm/cpufeature.h |  5 +++++
>>   arch/arm64/include/asm/kvm_host.h   |  4 ++++
>>   arch/arm64/include/asm/sysreg.h     | 12 ++++++++++++
>>   arch/arm64/kernel/cpufeature.c      |  9 +++++++++
>>   arch/arm64/tools/cpucaps            |  1 +
>>   include/uapi/linux/kvm.h            |  1 +
>>   tools/include/uapi/linux/kvm.h      |  1 +
>>   9 files changed, 49 insertions(+)
>>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 6663ffd23f25..1edf75888a09 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -2201,6 +2201,20 @@ config ARM64_GCS
>>
>>   endmenu # "ARMv9.4 architectural features"
>>
>> +menu "ARMv9.5 architectural features"
>> +
>> +config ARM64_HDBSS
>> +	bool "Enable support for Hardware Dirty state tracking Structure (HDBSS)"
>> +	help
>> +	  Hardware Dirty state tracking Structure(HDBSS) enhances tracking
>> +	  translation table descriptors' dirty state to reduce the cost of
>> +	  surveying for dirtied granules.
>> +
>> +	  The feature introduces new assembly registers (HDBSSBR_EL2 and
>> +	  HDBSSPROD_EL2), which are accessed via generated register accessors.
> 
> This last but means nothing to most people.
> 
> But more importantly, I really don't want to see this as a config
> option. KVM comes with "battery included", and all features should be
> available at all times.
HDBSS is only designed for KVM, and I agree that it shouldn't be
controlled by a config option. I will remove it.

By the way, I would like to ask for your advice. I have been a bit
confused about when exactly it is necessary to add a config option in
Kconfig for a feature.
> 
>> +
>> +endmenu # "ARMv9.5 architectural features"
>> +
>>   config ARM64_SVE
>>   	bool "ARM Scalable Vector Extension support"
>>   	default y
>> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
>> index 9d769291a306..5e5a26f28dec 100644
>> --- a/arch/arm64/include/asm/cpucaps.h
>> +++ b/arch/arm64/include/asm/cpucaps.h
>> @@ -48,6 +48,8 @@ cpucap_is_possible(const unsigned int cap)
>>   		return IS_ENABLED(CONFIG_ARM64_GCS);
>>   	case ARM64_HAFT:
>>   		return IS_ENABLED(CONFIG_ARM64_HAFT);
>> +	case ARM64_HAS_HDBSS:
>> +		return IS_ENABLED(CONFIG_ARM64_HDBSS);
>>   	case ARM64_UNMAP_KERNEL_AT_EL0:
>>   		return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0);
>>   	case ARM64_WORKAROUND_843419:
>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
>> index e223cbf350e4..b231415a2b76 100644
>> --- a/arch/arm64/include/asm/cpufeature.h
>> +++ b/arch/arm64/include/asm/cpufeature.h
>> @@ -856,6 +856,11 @@ static inline bool system_supports_haft(void)
>>   	return cpus_have_final_cap(ARM64_HAFT);
>>   }
>>
>> +static inline bool system_supports_hdbss(void)
>> +{
>> +	return cpus_have_final_cap(ARM64_HAS_HDBSS);
>> +}
>> +
>>   static __always_inline bool system_supports_mpam(void)
>>   {
>>   	return alternative_has_cap_unlikely(ARM64_MPAM);
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index 64302c438355..d962932f0e5f 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -60,6 +60,10 @@
>>
>>   #define KVM_HAVE_MMU_RWLOCK
>>
>> +/* HDBSS entry field definitions */
>> +#define HDBSS_ENTRY_VALID BIT(0)
>> +#define HDBSS_ENTRY_IPA GENMASK_ULL(55, 12)
>> +
> 
> None of this is used here. Move it to the patch where it belongs.
I will move HDBSS_ENTRY_VALID and HDBSS_ENTRY_IPA to next patch.
> 
>>   /*
>>    * Mode of operation configurable with kvm-arm.mode early param.
>>    * See Documentation/admin-guide/kernel-parameters.txt for more information.
>> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
>> index c231d2a3e515..3511edea1fbc 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -1129,6 +1129,18 @@
>>   #define gicr_insn(insn)			read_sysreg_s(GICV5_OP_GICR_##insn)
>>   #define gic_insn(v, insn)		write_sysreg_s(v, GICV5_OP_GIC_##insn)
>>
>> +/*
>> + * Definitions for the HDBSS feature
>> + */
>> +#define HDBSS_MAX_SIZE		HDBSSBR_EL2_SZ_2MB
>> +
>> +#define HDBSSBR_EL2(baddr, sz)	(((baddr) & GENMASK(55, 12 + sz)) | \
>> +				 FIELD_PREP(HDBSSBR_EL2_SZ_MASK, sz))
>> +#define HDBSSBR_BADDR(br)	((br) & GENMASK(55, (12 + HDBSSBR_SZ(br))))
>> +#define HDBSSBR_SZ(br)		FIELD_GET(HDBSSBR_EL2_SZ_MASK, br)
> 
> This is a bit backward. When would you need to read-back and mask
> random bits off the register?
I will delete the definitions of HDBSSBR_BADDR and HDBSSBR_SZ.
> 
>> +
>> +#define HDBSSPROD_IDX(prod)	FIELD_GET(HDBSSPROD_EL2_INDEX_MASK, prod)
>> +
> 
> As previously said, these definitions don't serve any purpose here,
> and would be better in the following patch.
I will move all the HDBSS definitions to the next patch where they
are actually used.
> 
>>   #define ARM64_FEATURE_FIELD_BITS	4
>>
>>   #ifdef __ASSEMBLY__
>> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
>> index e25b0f84a22d..f39973b68bdb 100644
>> --- a/arch/arm64/kernel/cpufeature.c
>> +++ b/arch/arm64/kernel/cpufeature.c
>> @@ -2710,6 +2710,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
>>   		.matches = has_cpuid_feature,
>>   		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HAFT)
>>   	},
>> +#endif
>> +#ifdef CONFIG_ARM64_HDBSS
>> +	{
>> +		.desc = "Hardware Dirty state tracking structure (HDBSS)",
>> +		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
>> +		.capability = ARM64_HAS_HDBSS,
>> +		.matches = has_cpuid_feature,
>> +		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HDBSS)
>> +	},
> 
> I think this is one of the features we should restrict to VHE. I don't
> imagine pKVM ever making use of this, and no non-VHE HW will ever
> build this.
> 
> Thanks,
I will add a new helper function that checks both VHE and the CPUID
feature, and use it in place of has_cpuid_feature in the .matches field.
> 
> 	M.
> 



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events
  2025-11-22 16:17   ` Marc Zyngier
@ 2025-11-28  9:21     ` Tian Zheng
  0 siblings, 0 replies; 21+ messages in thread
From: Tian Zheng @ 2025-11-28  9:21 UTC (permalink / raw)
  To: Marc Zyngier, Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose

On 2025/11/23 0:17, Marc Zyngier wrote:
> On Fri, 21 Nov 2025 09:23:41 +0000,
> Tian Zheng <zhengtian10@huawei.com> wrote:
>>
>> From: eillon <yezhenyu2@huawei.com>
>>
>> Implement the HDBSS enable/disable functionality using the
>> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.
>>
>> Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
>> at the start of live migration, configuring the buffer size.
>> The feature is disabled by invoking the ioctl again with size
>> set to 0 once migration completes.
>>
>> Add support for updating the dirty bitmap based on the HDBSS
>> buffer. Similar to the x86 PML implementation, KVM flushes the
>> buffer on all VM-Exits, so running vCPUs only need to be kicked
>> to force a VM-Exit.
> 
> Drop the x86 reference, nobody cares about other architectures.
> 
> Instead, please describe what state is handled where. Having to
> reverse engineer this is particularly painful.
> 

I will drop the x86 reference. And I will explain how state is handled
in the commit message in v3, something like:

"- HDBSS is enabled via an ioctl from userspace (e.g. QEMU) at the start
of migration in ram_init_bitmaps.
- Initially, each S2 page doesn't contain the DBM attribute. During
migration, triggers a fault handled by user_mem_abort, which relaxes
permissions and adds the DBM flag if HDBSS is active. Subsequent writes
of this page no longer trap during dirty tracking.
- On sync_dirty_log, all vCPUs are kicked to force a VM-Exit. The HDBSS
buffer is flushed in handle_exit to update the dirty bitmap."

>>
>> Signed-off-by: eillon <yezhenyu2@huawei.com>
>> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
>> ---
>>   arch/arm64/include/asm/kvm_host.h |  10 +++
>>   arch/arm64/include/asm/kvm_mmu.h  |  17 +++++
>>   arch/arm64/kvm/arm.c              | 107 ++++++++++++++++++++++++++++++
>>   arch/arm64/kvm/handle_exit.c      |  45 +++++++++++++
>>   arch/arm64/kvm/hyp/vhe/switch.c   |   1 +
>>   arch/arm64/kvm/mmu.c              |  10 +++
>>   arch/arm64/kvm/reset.c            |   3 +
>>   include/linux/kvm_host.h          |   1 +
>>   8 files changed, 194 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index d962932f0e5f..408e4c2b3d1a 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
>>   u32 __attribute_const__ kvm_target_cpu(void);
>>   void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>>   void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
>>
>>   struct kvm_hyp_memcache {
>>   	phys_addr_t head;
>> @@ -793,6 +794,12 @@ struct vcpu_reset_state {
>>   	bool		reset;
>>   };
>>
>> +struct vcpu_hdbss_state {
>> +	phys_addr_t base_phys;
>> +	u32 size;
>> +	u32 next_index;
>> +};
>> +
>>   struct vncr_tlb;
>>
>>   struct kvm_vcpu_arch {
>> @@ -897,6 +904,9 @@ struct kvm_vcpu_arch {
>>
>>   	/* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
>>   	struct vncr_tlb	*vncr_tlb;
>> +
>> +	/* HDBSS registers info */
>> +	struct vcpu_hdbss_state hdbss;
>>   };
>>
>>   /*
>> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
>> index e4069f2ce642..6ace1080aed5 100644
>> --- a/arch/arm64/include/asm/kvm_mmu.h
>> +++ b/arch/arm64/include/asm/kvm_mmu.h
>> @@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct kvm_s2_mmu *mmu,
>>   	asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
>>   }
>>
>> +static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)
> 
> Why is this in an include file? If, as it appears, it is VHE only
> (this patch completely ignores the nVHE code path), it should be
> strictly local to the VHE code.
> 

So sorry, it seems that I haven't considered the VHE mode during this
series. Next version I will move to the vhe directory.

>> +{
>> +	struct kvm *kvm = vcpu->kvm;
>> +	u64 br_el2, prod_el2;
>> +
>> +	if (!kvm->enable_hdbss)
>> +		return;
> 
> Why is enable_hdbss in the *arch-independent* part of the kvm
> structure?
> 

Thanks, you are right. I will move this value into kvm->arch structure.

>> +
>> +	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
>> +	prod_el2 = vcpu->arch.hdbss.next_index;
>> +
>> +	write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
>> +	write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
>> +
>> +	isb();
>> +}
>> +
>>   static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
>>   {
>>   	return container_of(mmu->arch, struct kvm, arch);
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index 870953b4a8a7..64f65e3c2a89 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
>>   	return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
>>   }
>>
>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
>> +{
>> +	struct page *hdbss_pg = NULL;
> 
> Why the NULL init?
> 
>> +
>> +	hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
>> +	if (hdbss_pg)
>> +		__free_pages(hdbss_pg, vcpu->arch.hdbss.size);
>> +
>> +	vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>> +		.base_phys = 0,
>> +		.size = 0,
>> +		.next_index = 0,
>> +	};
> 
> It should be enough to set size to 0.

Thanks, I will drop the NULL initialization of hdbss_pg and just set
size to 0.

> 
>> +}
>> +
>> +static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
>> +				    struct kvm_enable_cap *cap)
>> +{
>> +	unsigned long i;
>> +	struct kvm_vcpu *vcpu;
>> +	struct page *hdbss_pg = NULL;
>> +	int size = cap->args[0];
> 
> This is the wrong type. Use unsigned types, preferably the same as the
> userspace structure.

Thanks, you are right. I check struct kvm_enable_cap, the size value
should be defined as __u64.

> 
>> +	int ret = 0;
>> +
>> +	if (!system_supports_hdbss()) {
>> +		kvm_err("This system does not support HDBSS!\n");
> 
> No. We don't print *anything* on error.
> 
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (size < 0 || size > HDBSS_MAX_SIZE) {
>> +		kvm_err("Invalid HDBSS buffer size: %d!\n", size);
>> +		return -EINVAL;
> 
> Same thing. Please remove *all* the kvm_err() crap.
> 

Thanks, understood. I will remove all the kvm_err() messages in v3.

> And with an unsigned type, you avoid the < 0 compare.
> 
>> +	}
>> +
>> +	/* Enable the HDBSS feature if size > 0, otherwise disable it. */
>> +	if (size) {
>> +		kvm_for_each_vcpu(i, vcpu, kvm) {
>> +			hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
>> +			if (!hdbss_pg) {
>> +				kvm_err("Alloc HDBSS buffer failed!\n");
>> +				ret = -ENOMEM;
>> +				goto error_alloc;
>> +			}
>> +
>> +			vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>> +				.base_phys = page_to_phys(hdbss_pg),
>> +				.size = size,
>> +				.next_index = 0,
>> +			};
>> +		}
>> +
>> +		kvm->enable_hdbss = true;
>> +		kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;
>> +
>> +		/*
>> +		 * We should kick vcpus out of guest mode here to load new
>> +		 * vtcr value to vtcr_el2 register when re-enter guest mode.
>> +		 */
>> +		kvm_for_each_vcpu(i, vcpu, kvm)
>> +			kvm_vcpu_kick(vcpu);
> 
> I don't think this is correct. You should start by stopping all vcpus,
> install the logging on all of them, and only then restart them.
> 
> Otherwise, your error handling is totally broken. You can end-up
> freeing memory that is in active use!

Hi Marc, I am new to the Linux community, and I sincerely seeking your
advice on this question.

To make sure I understand correctly: are you suggesting we should use
kvm_make_all_cpus_request(kvm, KVM_REQ_SLEEP) to stop all vCPUs before
enabling HDBSS, then enable the feature, and finally kick them to
restart?

Furthermore, I think maybe we don't need to stop vcpus, cause we make
sure enable HDBSS feature after all buffers are allocated successfully.
Therefore, no freeing memory will be used.

> 
>> +	} else if (kvm->enable_hdbss) {
>> +		kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS);
>> +
>> +		kvm_for_each_vcpu(i, vcpu, kvm) {
>> +			/* Kick vcpus to flush hdbss buffer. */
>> +			kvm_vcpu_kick(vcpu);
>> +
>> +			kvm_arm_vcpu_free_hdbss(vcpu);
>> +		}
> 
> Same thing.
> 
>> +
>> +		kvm->enable_hdbss = false;
>> +	}
>> +
>> +	return ret;
>> +
>> +error_alloc:
>> +	kvm_for_each_vcpu(i, vcpu, kvm) {
>> +		if (!vcpu->arch.hdbss.base_phys && !vcpu->arch.hdbss.size)
>> +			continue;
>> +
>> +		kvm_arm_vcpu_free_hdbss(vcpu);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>>   int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>>   			    struct kvm_enable_cap *cap)
>>   {
>> @@ -132,6 +218,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>>   		}
>>   		mutex_unlock(&kvm->lock);
>>   		break;
>> +	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
>> +		mutex_lock(&kvm->lock);
>> +		r = kvm_cap_arm_enable_hdbss(kvm, cap);
>> +		mutex_unlock(&kvm->lock);
>> +		break;
>>   	default:
>>   		break;
>>   	}
>> @@ -420,6 +511,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>>   			r = kvm_supports_cacheable_pfnmap();
>>   		break;
>>
>> +	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
>> +		r = system_supports_hdbss();
>> +		break;
>>   	default:
>>   		r = 0;
>>   	}
>> @@ -1837,7 +1931,20 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>>
>>   void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
>>   {
>> +	/*
>> +	 * Flush all CPUs' dirty log buffers to the dirty_bitmap.  Called
>> +	 * before reporting dirty_bitmap to userspace.  KVM flushes the buffers
>> +	 * on all VM-Exits, thus we only need to kick running vCPUs to force a
>> +	 * VM-Exit.
>> +	 */
>> +	struct kvm_vcpu *vcpu;
>> +	unsigned long i;
>>
>> +	if (!kvm->enable_hdbss)
>> +		return;
>> +
>> +	kvm_for_each_vcpu(i, vcpu, kvm)
>> +		kvm_vcpu_kick(vcpu);
> 
> And then what? You return to userspace while the stuff is being
> written, without any synchronisation? How does userspace know that the
> state is consistent?
> 
> Also, I'm not sure you can ignore the memslot. It *is* relevant.
> 

Hi Marc, we probably haven't thought this through completely.

Let me share our current thinking and ask for your advice:

In v2, we kick all vCPUs to flush the HDBSS buffer in handle_exit using
an asynchronous approach, and simply thought that it would be flushed to
the dirty_bitmap either immediately or later. However, this does risk
missing the page during last time of live migration.

Considering your opinion, I think we should use
kvm_make_all_cpus_request instead of kvm_vcpu_kick to ensure proper
synchronization.

>>   }
>>
>>   static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
>> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
>> index cc7d5d1709cb..9ba0ea6305ef 100644
>> --- a/arch/arm64/kvm/handle_exit.c
>> +++ b/arch/arm64/kvm/handle_exit.c
>> @@ -412,6 +412,49 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
>>   	return arm_exit_handlers[esr_ec];
>>   }
>>
>> +static void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)
>> +{
>> +	int idx, curr_idx;
>> +	u64 *hdbss_buf;
>> +	struct kvm *kvm = vcpu->kvm;
>> +	u64 br_el2;
>> +
>> +	if (!kvm->enable_hdbss)
>> +		return;
>> +
>> +	dsb(sy);
>> +	isb();
> 
> What are these barriers for?

These barriers are not needed here, I will remove them in the next
version.

> 
>> +	curr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));
>> +	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
>> +
>> +	/* Do nothing if HDBSS buffer is empty or br_el2 is NULL */
>> +	if (curr_idx == 0 || br_el2 == 0)
>> +		return;
>> +
>> +	hdbss_buf = page_address(phys_to_page(vcpu->arch.hdbss.base_phys));
>> +	if (!hdbss_buf) {
>> +		kvm_err("Enter flush hdbss buffer with buffer == NULL!");
>> +		return;
>> +	}
>> +
>> +	guard(write_lock_irqsave)(&vcpu->kvm->mmu_lock);
>> +	for (idx = 0; idx < curr_idx; idx++) {
>> +		u64 gpa;
>> +
>> +		gpa = hdbss_buf[idx];
>> +		if (!(gpa & HDBSS_ENTRY_VALID))
>> +			continue;
>> +
>> +		gpa &= HDBSS_ENTRY_IPA;
>> +		kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
>> +	}
>> +
>> +	/* reset HDBSS index */
>> +	write_sysreg_s(0, SYS_HDBSSPROD_EL2);
>> +	vcpu->arch.hdbss.next_index = 0;
>> +	isb();
>> +}
>> +
>>   /*
>>    * We may be single-stepping an emulated instruction. If the emulation
>>    * has been completed in the kernel, we can return to userspace with a
>> @@ -447,6 +490,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
>>   {
>>   	struct kvm_run *run = vcpu->run;
>>
>> +	kvm_flush_hdbss_buffer(vcpu);
>> +
>>   	if (ARM_SERROR_PENDING(exception_index)) {
>>   		/*
>>   		 * The SError is handled by handle_exit_early(). If the guest
>> diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
>> index 9984c492305a..3787c9c5810d 100644
>> --- a/arch/arm64/kvm/hyp/vhe/switch.c
>> +++ b/arch/arm64/kvm/hyp/vhe/switch.c
>> @@ -220,6 +220,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)
>>   	__vcpu_load_switch_sysregs(vcpu);
>>   	__vcpu_load_activate_traps(vcpu);
>>   	__load_stage2(vcpu->arch.hw_mmu, vcpu->arch.hw_mmu->arch);
>> +	__load_hdbss(vcpu);
>>   }
>>
>>   void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)
>> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
>> index 7cc964af8d30..91a2f9dbb406 100644
>> --- a/arch/arm64/kvm/mmu.c
>> +++ b/arch/arm64/kvm/mmu.c
>> @@ -1843,6 +1843,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
>>   	if (writable)
>>   		prot |= KVM_PGTABLE_PROT_W;
>>
>> +	if (writable && kvm->enable_hdbss && logging_active)
>> +		prot |= KVM_PGTABLE_PROT_DBM;
>> +
> 
> So all the pages are dirty by default, but the logger can't see it.
> This is really broken, and I think you haven't really tested this
> code.

Hi Marc, we tested the HDBSS feature by running Redis stress tests on
the source device, and it can run normally on the destination device.

Our understanding is that each S2 page initially does not contain the
DBM attribute. During migration, the first time a write occurs to a
write‑clean page, it will trap to EL2 as in traditional migration, and
user_mem_abort will relax the permission. If HDBSS is enabled, a DBM
flag will then be added to the page, so subsequent writes will no longer
trap during dirty page tracking.

Is there some other detail I haven't thought of yet?

> 
>>   	if (exec_fault)
>>   		prot |= KVM_PGTABLE_PROT_X;
>>
>> @@ -1950,6 +1953,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
>>
>>   	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
>>
>> +	/*
>> +	 * HDBSS buffer already flushed when enter handle_trap_exceptions().
>> +	 * Nothing to do here.
>> +	 */
>> +	if (ESR_ELx_ISS2(esr) & ESR_ELx_HDBSSF)
>> +		return 1;
>> +
> 
> Flushing the buffer doesn't solve a potential error state. And what if
> you have overflowed the buffer? There is a lot of things that can
> happen as a result of R_STJMN, and I don't see any of that being
> described here.

you are right, we just simply flush HDBSS buffer at the beginning of
handle_exit and did not handle these error cases explicitly. We will add
proper error handling in the next version.

> 
>>   	if (esr_fsc_is_translation_fault(esr)) {
>>   		/* Beyond sanitised PARange (which is the IPA limit) */
>>   		if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>> index 959532422d3a..65e8f890f863 100644
>> --- a/arch/arm64/kvm/reset.c
>> +++ b/arch/arm64/kvm/reset.c
>> @@ -161,6 +161,9 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
>>   	free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
>>   	kfree(vcpu->arch.vncr_tlb);
>>   	kfree(vcpu->arch.ccsidr);
>> +
>> +	if (vcpu->arch.hdbss.base_phys || vcpu->arch.hdbss.size)
>> +		kvm_arm_vcpu_free_hdbss(vcpu);
>>   }
>>
>>   static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>> index 5bd76cf394fa..aa8138604b1e 100644
>> --- a/include/linux/kvm_host.h
>> +++ b/include/linux/kvm_host.h
>> @@ -876,6 +876,7 @@ struct kvm {
>>   	struct xarray mem_attr_array;
>>   #endif
>>   	char stats_id[KVM_STATS_NAME_SIZE];
>> +	bool enable_hdbss;
> 
> Well, no.
> 
> This is broken in a number of ways, and I haven't considered the UAPI
> yet. The error handling is non-existent, and this will actively
> corrupt memory (again). Marking writable pages as writable actively
> prevents logging, meaning that you will happily miss dirty pages.
> 
> I'll stop reviewing this series here.
> 

this value will be moved to kvm->arch structure.

> 	M.
> 



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information
  2025-11-22 12:40   ` Marc Zyngier
  2025-11-27 11:48     ` Tian Zheng
@ 2025-12-02  6:51     ` Tian Zheng
  1 sibling, 0 replies; 21+ messages in thread
From: Tian Zheng @ 2025-12-02  6:51 UTC (permalink / raw)
  To: Marc Zyngier, Tian Zheng
  Cc: oliver.upton, catalin.marinas, corbet, pbonzini, will,
	linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose



在 2025/11/22 20:40, Marc Zyngier 写道:
> On Fri, 21 Nov 2025 09:23:38 +0000,
> Tian Zheng <zhengtian10@huawei.com> wrote:
>>
>> From: eillon <yezhenyu2@huawei.com>
>>
>> The ARM architecture added the HDBSS feature and descriptions of
>> related registers (HDBSSBR/HDBSSPROD) in the DDI0601(ID121123) version,
>> add them to Linux.
>>
>> Signed-off-by: eillon <yezhenyu2@huawei.com>
>> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
>> ---
>>   arch/arm64/include/asm/esr.h     |  2 ++
>>   arch/arm64/include/asm/kvm_arm.h |  1 +
>>   arch/arm64/tools/sysreg          | 28 ++++++++++++++++++++++++++++
>>   3 files changed, 31 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
>> index e1deed824464..a6f3cf0b9b86 100644
>> --- a/arch/arm64/include/asm/esr.h
>> +++ b/arch/arm64/include/asm/esr.h
>> @@ -159,6 +159,8 @@
>>   #define ESR_ELx_CM 		(UL(1) << ESR_ELx_CM_SHIFT)
>>
>>   /* ISS2 field definitions for Data Aborts */
>> +#define ESR_ELx_HDBSSF_SHIFT	(11)
>> +#define ESR_ELx_HDBSSF		(UL(1) << ESR_ELx_HDBSSF_SHIFT)
>>   #define ESR_ELx_TnD_SHIFT	(10)
>>   #define ESR_ELx_TnD 		(UL(1) << ESR_ELx_TnD_SHIFT)
>>   #define ESR_ELx_TagAccess_SHIFT	(9)
>> diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
>> index 1da290aeedce..b71122680a03 100644
>> --- a/arch/arm64/include/asm/kvm_arm.h
>> +++ b/arch/arm64/include/asm/kvm_arm.h
>> @@ -124,6 +124,7 @@
>>   			 TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
>>
>>   /* VTCR_EL2 Registers bits */
>> +#define VTCR_EL2_HDBSS		(1UL << 45)
> 
> I think it is time to convert VTCR_EL2 to the sysreg infrastructure
> instead of adding extra bits here.
> 

Hello Marc, I noticed you added VTCR_EL2 to the sysreg infrastructure in 
this patch:

https://lore.kernel.org/linux-arm-kernel/20251129144525.2609207-3-maz@kernel.org/

Once this patch is merged upstream, I will remove my local definition.

> 	M.
> 



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events
  2025-11-21  9:23 ` [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events Tian Zheng
  2025-11-22 16:17   ` Marc Zyngier
@ 2025-12-17 13:39   ` Robert Hoo
  2025-12-24  6:15     ` Tian Zheng
  1 sibling, 1 reply; 21+ messages in thread
From: Robert Hoo @ 2025-12-17 13:39 UTC (permalink / raw)
  To: Tian Zheng, maz, oliver.upton, catalin.marinas, corbet, pbonzini,
	will
  Cc: linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, linuxarm, joey.gouly, kvmarm, kvm, linux-arm-kernel,
	linux-doc, suzuki.poulose

On 11/21/2025 5:23 PM, Tian Zheng wrote:
> From: eillon <yezhenyu2@huawei.com>
> 
> Implement the HDBSS enable/disable functionality using the
> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.
> 
> Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
> at the start of live migration, configuring the buffer size.
> The feature is disabled by invoking the ioctl again with size
> set to 0 once migration completes.
> 
> Add support for updating the dirty bitmap based on the HDBSS
> buffer. Similar to the x86 PML implementation, KVM flushes the
> buffer on all VM-Exits, so running vCPUs only need to be kicked
> to force a VM-Exit.
> 
> Signed-off-by: eillon <yezhenyu2@huawei.com>
> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
> ---
>   arch/arm64/include/asm/kvm_host.h |  10 +++
>   arch/arm64/include/asm/kvm_mmu.h  |  17 +++++
>   arch/arm64/kvm/arm.c              | 107 ++++++++++++++++++++++++++++++
>   arch/arm64/kvm/handle_exit.c      |  45 +++++++++++++
>   arch/arm64/kvm/hyp/vhe/switch.c   |   1 +
>   arch/arm64/kvm/mmu.c              |  10 +++
>   arch/arm64/kvm/reset.c            |   3 +
>   include/linux/kvm_host.h          |   1 +
>   8 files changed, 194 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index d962932f0e5f..408e4c2b3d1a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
>   u32 __attribute_const__ kvm_target_cpu(void);
>   void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>   void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
> 
>   struct kvm_hyp_memcache {
>   	phys_addr_t head;
> @@ -793,6 +794,12 @@ struct vcpu_reset_state {
>   	bool		reset;
>   };
> 
> +struct vcpu_hdbss_state {
> +	phys_addr_t base_phys;
> +	u32 size;
> +	u32 next_index;
> +};
> +
>   struct vncr_tlb;
> 
>   struct kvm_vcpu_arch {
> @@ -897,6 +904,9 @@ struct kvm_vcpu_arch {
> 
>   	/* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
>   	struct vncr_tlb	*vncr_tlb;
> +
> +	/* HDBSS registers info */
> +	struct vcpu_hdbss_state hdbss;
>   };
> 
>   /*
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index e4069f2ce642..6ace1080aed5 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct kvm_s2_mmu *mmu,
>   	asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
>   }
> 
> +static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	u64 br_el2, prod_el2;
> +
> +	if (!kvm->enable_hdbss)
> +		return;
> +
> +	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
> +	prod_el2 = vcpu->arch.hdbss.next_index;
> +
> +	write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
> +	write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
> +
> +	isb();
> +}
> +
>   static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
>   {
>   	return container_of(mmu->arch, struct kvm, arch);
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 870953b4a8a7..64f65e3c2a89 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
>   	return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
>   }
> 
> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
> +{
> +	struct page *hdbss_pg = NULL;
> +
> +	hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
> +	if (hdbss_pg)
> +		__free_pages(hdbss_pg, vcpu->arch.hdbss.size);
> +
> +	vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
> +		.base_phys = 0,
> +		.size = 0,
> +		.next_index = 0,
> +	};
> +}
> +
> +static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
> +				    struct kvm_enable_cap *cap)
> +{
> +	unsigned long i;
> +	struct kvm_vcpu *vcpu;
> +	struct page *hdbss_pg = NULL;
> +	int size = cap->args[0];
> +	int ret = 0;
> +
> +	if (!system_supports_hdbss()) {
> +		kvm_err("This system does not support HDBSS!\n");
> +		return -EINVAL;
> +	}
> +
> +	if (size < 0 || size > HDBSS_MAX_SIZE) {
> +		kvm_err("Invalid HDBSS buffer size: %d!\n", size);
> +		return -EINVAL;
> +	}
> +

I think you should check if it's already enabled here. What if user space calls 
this twice?

> +	/* Enable the HDBSS feature if size > 0, otherwise disable it. */
> +	if (size) {
> +		kvm_for_each_vcpu(i, vcpu, kvm) {
> +			hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
> +			if (!hdbss_pg) {
> +				kvm_err("Alloc HDBSS buffer failed!\n");
> +				ret = -ENOMEM;
> +				goto error_alloc;
> +			}
> +
> +			vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
> +				.base_phys = page_to_phys(hdbss_pg),
> +				.size = size,
> +				.next_index = 0,
> +			};
> +		}
> +
> +		kvm->enable_hdbss = true;
> +		kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;

VTCR_EL2_HA is also a necessity for VTCR_EL2_HDBSS to take effect.

> +
> +		/*
> +		 * We should kick vcpus out of guest mode here to load new
> +		 * vtcr value to vtcr_el2 register when re-enter guest mode.
> +		 */
> +		kvm_for_each_vcpu(i, vcpu, kvm)
> +			kvm_vcpu_kick(vcpu);
> +	} else if (kvm->enable_hdbss) {
> +		kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS);
> +
> +		kvm_for_each_vcpu(i, vcpu, kvm) {
> +			/* Kick vcpus to flush hdbss buffer. */
> +			kvm_vcpu_kick(vcpu);
> +
> +			kvm_arm_vcpu_free_hdbss(vcpu);
> +		}
> +
> +		kvm->enable_hdbss = false;
> +	}
> +
> +	return ret;
> +
> +error_alloc:
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (!vcpu->arch.hdbss.base_phys && !vcpu->arch.hdbss.size)
> +			continue;
> +
> +		kvm_arm_vcpu_free_hdbss(vcpu);
> +	}
> +
> +	return ret;
> +}
> +
>   int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>   			    struct kvm_enable_cap *cap)
>   {
> @@ -132,6 +218,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>   		}
>   		mutex_unlock(&kvm->lock);
>   		break;
> +	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
> +		mutex_lock(&kvm->lock);
> +		r = kvm_cap_arm_enable_hdbss(kvm, cap);
> +		mutex_unlock(&kvm->lock);
> +		break;
>   	default:
>   		break;
>   	}
> @@ -420,6 +511,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>   			r = kvm_supports_cacheable_pfnmap();
>   		break;
> 
> +	case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
> +		r = system_supports_hdbss();
> +		break;
>   	default:
>   		r = 0;
>   	}
> @@ -1837,7 +1931,20 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> 
>   void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
>   {
> +	/*
> +	 * Flush all CPUs' dirty log buffers to the dirty_bitmap.  Called
> +	 * before reporting dirty_bitmap to userspace.  KVM flushes the buffers
> +	 * on all VM-Exits, thus we only need to kick running vCPUs to force a
> +	 * VM-Exit.
> +	 */
> +	struct kvm_vcpu *vcpu;
> +	unsigned long i;
> 
> +	if (!kvm->enable_hdbss)
> +		return;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vcpu_kick(vcpu);
>   }
> 
>   static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> index cc7d5d1709cb..9ba0ea6305ef 100644
> --- a/arch/arm64/kvm/handle_exit.c
> +++ b/arch/arm64/kvm/handle_exit.c
> @@ -412,6 +412,49 @@ static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
>   	return arm_exit_handlers[esr_ec];
>   }
> 
> +static void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)
> +{
> +	int idx, curr_idx;
> +	u64 *hdbss_buf;
> +	struct kvm *kvm = vcpu->kvm;
> +	u64 br_el2;
> +
> +	if (!kvm->enable_hdbss)
> +		return;
> +
> +	dsb(sy);
> +	isb();
> +	curr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));
> +	br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu->arch.hdbss.size);
> +
> +	/* Do nothing if HDBSS buffer is empty or br_el2 is NULL */
> +	if (curr_idx == 0 || br_el2 == 0)
> +		return;
> +
> +	hdbss_buf = page_address(phys_to_page(vcpu->arch.hdbss.base_phys));
> +	if (!hdbss_buf) {
> +		kvm_err("Enter flush hdbss buffer with buffer == NULL!");
> +		return;
> +	}
> +
> +	guard(write_lock_irqsave)(&vcpu->kvm->mmu_lock);
> +	for (idx = 0; idx < curr_idx; idx++) {
> +		u64 gpa;
> +
> +		gpa = hdbss_buf[idx];
> +		if (!(gpa & HDBSS_ENTRY_VALID))
> +			continue;
> +
> +		gpa &= HDBSS_ENTRY_IPA;
> +		kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
> +	}
> +
> +	/* reset HDBSS index */
> +	write_sysreg_s(0, SYS_HDBSSPROD_EL2);
> +	vcpu->arch.hdbss.next_index = 0;
> +	isb();
> +}
> +
>   /*
>    * We may be single-stepping an emulated instruction. If the emulation
>    * has been completed in the kernel, we can return to userspace with a
> @@ -447,6 +490,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
>   {
>   	struct kvm_run *run = vcpu->run;
> 
> +	kvm_flush_hdbss_buffer(vcpu);
> +
>   	if (ARM_SERROR_PENDING(exception_index)) {
>   		/*
>   		 * The SError is handled by handle_exit_early(). If the guest
> diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
> index 9984c492305a..3787c9c5810d 100644
> --- a/arch/arm64/kvm/hyp/vhe/switch.c
> +++ b/arch/arm64/kvm/hyp/vhe/switch.c
> @@ -220,6 +220,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)
>   	__vcpu_load_switch_sysregs(vcpu);
>   	__vcpu_load_activate_traps(vcpu);
>   	__load_stage2(vcpu->arch.hw_mmu, vcpu->arch.hw_mmu->arch);
> +	__load_hdbss(vcpu);
>   }
> 
>   void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index 7cc964af8d30..91a2f9dbb406 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1843,6 +1843,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
>   	if (writable)
>   		prot |= KVM_PGTABLE_PROT_W;
> 
> +	if (writable && kvm->enable_hdbss && logging_active)
> +		prot |= KVM_PGTABLE_PROT_DBM;
> +
>   	if (exec_fault)
>   		prot |= KVM_PGTABLE_PROT_X;
> 
> @@ -1950,6 +1953,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
> 
>   	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
> 
> +	/*
> +	 * HDBSS buffer already flushed when enter handle_trap_exceptions().
> +	 * Nothing to do here.
> +	 */
> +	if (ESR_ELx_ISS2(esr) & ESR_ELx_HDBSSF)
> +		return 1;
> +
>   	if (esr_fsc_is_translation_fault(esr)) {
>   		/* Beyond sanitised PARange (which is the IPA limit) */
>   		if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 959532422d3a..65e8f890f863 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -161,6 +161,9 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
>   	free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
>   	kfree(vcpu->arch.vncr_tlb);
>   	kfree(vcpu->arch.ccsidr);
> +
> +	if (vcpu->arch.hdbss.base_phys || vcpu->arch.hdbss.size)
> +		kvm_arm_vcpu_free_hdbss(vcpu);
>   }
> 
>   static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 5bd76cf394fa..aa8138604b1e 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -876,6 +876,7 @@ struct kvm {
>   	struct xarray mem_attr_array;
>   #endif
>   	char stats_id[KVM_STATS_NAME_SIZE];
> +	bool enable_hdbss;
>   };
> 
>   #define kvm_err(fmt, ...) \
> --
> 2.33.0
> 
> 



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events
  2025-12-17 13:39   ` Robert Hoo
@ 2025-12-24  6:15     ` Tian Zheng
  2025-12-28 13:21       ` Robert Hoo
  0 siblings, 1 reply; 21+ messages in thread
From: Tian Zheng @ 2025-12-24  6:15 UTC (permalink / raw)
  To: Robert Hoo, Tian Zheng, maz, oliver.upton, catalin.marinas,
	corbet, pbonzini, will
  Cc: linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose



On 12/17/2025 9:39 PM, Robert Hoo wrote:
> On 11/21/2025 5:23 PM, Tian Zheng wrote:
>> From: eillon <yezhenyu2@huawei.com>
>>
>> Implement the HDBSS enable/disable functionality using the
>> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.
>>
>> Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
>> at the start of live migration, configuring the buffer size.
>> The feature is disabled by invoking the ioctl again with size
>> set to 0 once migration completes.
>>
>> Add support for updating the dirty bitmap based on the HDBSS
>> buffer. Similar to the x86 PML implementation, KVM flushes the
>> buffer on all VM-Exits, so running vCPUs only need to be kicked
>> to force a VM-Exit.
>>
>> Signed-off-by: eillon <yezhenyu2@huawei.com>
>> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
>> ---
>>   arch/arm64/include/asm/kvm_host.h |  10 +++
>>   arch/arm64/include/asm/kvm_mmu.h  |  17 +++++
>>   arch/arm64/kvm/arm.c              | 107 ++++++++++++++++++++++++++++++
>>   arch/arm64/kvm/handle_exit.c      |  45 +++++++++++++
>>   arch/arm64/kvm/hyp/vhe/switch.c   |   1 +
>>   arch/arm64/kvm/mmu.c              |  10 +++
>>   arch/arm64/kvm/reset.c            |   3 +
>>   include/linux/kvm_host.h          |   1 +
>>   8 files changed, 194 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/ 
>> asm/kvm_host.h
>> index d962932f0e5f..408e4c2b3d1a 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
>>   u32 __attribute_const__ kvm_target_cpu(void);
>>   void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>>   void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
>>
>>   struct kvm_hyp_memcache {
>>       phys_addr_t head;
>> @@ -793,6 +794,12 @@ struct vcpu_reset_state {
>>       bool        reset;
>>   };
>>
>> +struct vcpu_hdbss_state {
>> +    phys_addr_t base_phys;
>> +    u32 size;
>> +    u32 next_index;
>> +};
>> +
>>   struct vncr_tlb;
>>
>>   struct kvm_vcpu_arch {
>> @@ -897,6 +904,9 @@ struct kvm_vcpu_arch {
>>
>>       /* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
>>       struct vncr_tlb    *vncr_tlb;
>> +
>> +    /* HDBSS registers info */
>> +    struct vcpu_hdbss_state hdbss;
>>   };
>>
>>   /*
>> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/ 
>> asm/kvm_mmu.h
>> index e4069f2ce642..6ace1080aed5 100644
>> --- a/arch/arm64/include/asm/kvm_mmu.h
>> +++ b/arch/arm64/include/asm/kvm_mmu.h
>> @@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct 
>> kvm_s2_mmu *mmu,
>>       asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
>>   }
>>
>> +static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)
>> +{
>> +    struct kvm *kvm = vcpu->kvm;
>> +    u64 br_el2, prod_el2;
>> +
>> +    if (!kvm->enable_hdbss)
>> +        return;
>> +
>> +    br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu- 
>> >arch.hdbss.size);
>> +    prod_el2 = vcpu->arch.hdbss.next_index;
>> +
>> +    write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
>> +    write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
>> +
>> +    isb();
>> +}
>> +
>>   static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
>>   {
>>       return container_of(mmu->arch, struct kvm, arch);
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index 870953b4a8a7..64f65e3c2a89 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
>>       return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
>>   }
>>
>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
>> +{
>> +    struct page *hdbss_pg = NULL;
>> +
>> +    hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
>> +    if (hdbss_pg)
>> +        __free_pages(hdbss_pg, vcpu->arch.hdbss.size);
>> +
>> +    vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>> +        .base_phys = 0,
>> +        .size = 0,
>> +        .next_index = 0,
>> +    };
>> +}
>> +
>> +static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
>> +                    struct kvm_enable_cap *cap)
>> +{
>> +    unsigned long i;
>> +    struct kvm_vcpu *vcpu;
>> +    struct page *hdbss_pg = NULL;
>> +    int size = cap->args[0];
>> +    int ret = 0;
>> +
>> +    if (!system_supports_hdbss()) {
>> +        kvm_err("This system does not support HDBSS!\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (size < 0 || size > HDBSS_MAX_SIZE) {
>> +        kvm_err("Invalid HDBSS buffer size: %d!\n", size);
>> +        return -EINVAL;
>> +    }
>> +
> 
> I think you should check if it's already enabled here. What if user 
> space calls this twice?

Ok, I review the implement of qemu, when disable the hdbss feature in
ram_save_cleanup, size=0 will be set, so here can add a check, if (size
&& kvm->arch.enable_hdbss), we will do nothing.

> 
>> +    /* Enable the HDBSS feature if size > 0, otherwise disable it. */
>> +    if (size) {
>> +        kvm_for_each_vcpu(i, vcpu, kvm) {
>> +            hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
>> +            if (!hdbss_pg) {
>> +                kvm_err("Alloc HDBSS buffer failed!\n");
>> +                ret = -ENOMEM;
>> +                goto error_alloc;
>> +            }
>> +
>> +            vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>> +                .base_phys = page_to_phys(hdbss_pg),
>> +                .size = size,
>> +                .next_index = 0,
>> +            };
>> +        }
>> +
>> +        kvm->enable_hdbss = true;
>> +        kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;
> 
> VTCR_EL2_HA is also a necessity for VTCR_EL2_HDBSS to take effect.

I see, thanks! I checked the architecture spec, and it indeed states
that HA needs to be enabled for AF hardware management to function
properly.

> 
>> +
>> +        /*
>> +         * We should kick vcpus out of guest mode here to load new
>> +         * vtcr value to vtcr_el2 register when re-enter guest mode.
>> +         */
>> +        kvm_for_each_vcpu(i, vcpu, kvm)
>> +            kvm_vcpu_kick(vcpu);
>> +    } else if (kvm->enable_hdbss) {
>> +        kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS);
>> +
>> +        kvm_for_each_vcpu(i, vcpu, kvm) {
>> +            /* Kick vcpus to flush hdbss buffer. */
>> +            kvm_vcpu_kick(vcpu);
>> +
>> +            kvm_arm_vcpu_free_hdbss(vcpu);
>> +        }
>> +
>> +        kvm->enable_hdbss = false;
>> +    }
>> +
>> +    return ret;
>> +
>> +error_alloc:
>> +    kvm_for_each_vcpu(i, vcpu, kvm) {
>> +        if (!vcpu->arch.hdbss.base_phys && !vcpu->arch.hdbss.size)
>> +            continue;
>> +
>> +        kvm_arm_vcpu_free_hdbss(vcpu);
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>>   int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>>                   struct kvm_enable_cap *cap)
>>   {
>> @@ -132,6 +218,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>>           }
>>           mutex_unlock(&kvm->lock);
>>           break;
>> +    case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
>> +        mutex_lock(&kvm->lock);
>> +        r = kvm_cap_arm_enable_hdbss(kvm, cap);
>> +        mutex_unlock(&kvm->lock);
>> +        break;
>>       default:
>>           break;
>>       }
>> @@ -420,6 +511,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, 
>> long ext)
>>               r = kvm_supports_cacheable_pfnmap();
>>           break;
>>
>> +    case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
>> +        r = system_supports_hdbss();
>> +        break;
>>       default:
>>           r = 0;
>>       }
>> @@ -1837,7 +1931,20 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>>
>>   void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot 
>> *memslot)
>>   {
>> +    /*
>> +     * Flush all CPUs' dirty log buffers to the dirty_bitmap.  Called
>> +     * before reporting dirty_bitmap to userspace.  KVM flushes the 
>> buffers
>> +     * on all VM-Exits, thus we only need to kick running vCPUs to 
>> force a
>> +     * VM-Exit.
>> +     */
>> +    struct kvm_vcpu *vcpu;
>> +    unsigned long i;
>>
>> +    if (!kvm->enable_hdbss)
>> +        return;
>> +
>> +    kvm_for_each_vcpu(i, vcpu, kvm)
>> +        kvm_vcpu_kick(vcpu);
>>   }
>>
>>   static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
>> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
>> index cc7d5d1709cb..9ba0ea6305ef 100644
>> --- a/arch/arm64/kvm/handle_exit.c
>> +++ b/arch/arm64/kvm/handle_exit.c
>> @@ -412,6 +412,49 @@ static exit_handle_fn kvm_get_exit_handler(struct 
>> kvm_vcpu *vcpu)
>>       return arm_exit_handlers[esr_ec];
>>   }
>>
>> +static void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)
>> +{
>> +    int idx, curr_idx;
>> +    u64 *hdbss_buf;
>> +    struct kvm *kvm = vcpu->kvm;
>> +    u64 br_el2;
>> +
>> +    if (!kvm->enable_hdbss)
>> +        return;
>> +
>> +    dsb(sy);
>> +    isb();
>> +    curr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));
>> +    br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu- 
>> >arch.hdbss.size);
>> +
>> +    /* Do nothing if HDBSS buffer is empty or br_el2 is NULL */
>> +    if (curr_idx == 0 || br_el2 == 0)
>> +        return;
>> +
>> +    hdbss_buf = page_address(phys_to_page(vcpu->arch.hdbss.base_phys));
>> +    if (!hdbss_buf) {
>> +        kvm_err("Enter flush hdbss buffer with buffer == NULL!");
>> +        return;
>> +    }
>> +
>> +    guard(write_lock_irqsave)(&vcpu->kvm->mmu_lock);
>> +    for (idx = 0; idx < curr_idx; idx++) {
>> +        u64 gpa;
>> +
>> +        gpa = hdbss_buf[idx];
>> +        if (!(gpa & HDBSS_ENTRY_VALID))
>> +            continue;
>> +
>> +        gpa &= HDBSS_ENTRY_IPA;
>> +        kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
>> +    }
>> +
>> +    /* reset HDBSS index */
>> +    write_sysreg_s(0, SYS_HDBSSPROD_EL2);
>> +    vcpu->arch.hdbss.next_index = 0;
>> +    isb();
>> +}
>> +
>>   /*
>>    * We may be single-stepping an emulated instruction. If the emulation
>>    * has been completed in the kernel, we can return to userspace with a
>> @@ -447,6 +490,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int 
>> exception_index)
>>   {
>>       struct kvm_run *run = vcpu->run;
>>
>> +    kvm_flush_hdbss_buffer(vcpu);
>> +
>>       if (ARM_SERROR_PENDING(exception_index)) {
>>           /*
>>            * The SError is handled by handle_exit_early(). If the guest
>> diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/ 
>> switch.c
>> index 9984c492305a..3787c9c5810d 100644
>> --- a/arch/arm64/kvm/hyp/vhe/switch.c
>> +++ b/arch/arm64/kvm/hyp/vhe/switch.c
>> @@ -220,6 +220,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)
>>       __vcpu_load_switch_sysregs(vcpu);
>>       __vcpu_load_activate_traps(vcpu);
>>       __load_stage2(vcpu->arch.hw_mmu, vcpu->arch.hw_mmu->arch);
>> +    __load_hdbss(vcpu);
>>   }
>>
>>   void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)
>> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
>> index 7cc964af8d30..91a2f9dbb406 100644
>> --- a/arch/arm64/kvm/mmu.c
>> +++ b/arch/arm64/kvm/mmu.c
>> @@ -1843,6 +1843,9 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, 
>> phys_addr_t fault_ipa,
>>       if (writable)
>>           prot |= KVM_PGTABLE_PROT_W;
>>
>> +    if (writable && kvm->enable_hdbss && logging_active)
>> +        prot |= KVM_PGTABLE_PROT_DBM;
>> +
>>       if (exec_fault)
>>           prot |= KVM_PGTABLE_PROT_X;
>>
>> @@ -1950,6 +1953,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
>>
>>       is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
>>
>> +    /*
>> +     * HDBSS buffer already flushed when enter handle_trap_exceptions().
>> +     * Nothing to do here.
>> +     */
>> +    if (ESR_ELx_ISS2(esr) & ESR_ELx_HDBSSF)
>> +        return 1;
>> +
>>       if (esr_fsc_is_translation_fault(esr)) {
>>           /* Beyond sanitised PARange (which is the IPA limit) */
>>           if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>> index 959532422d3a..65e8f890f863 100644
>> --- a/arch/arm64/kvm/reset.c
>> +++ b/arch/arm64/kvm/reset.c
>> @@ -161,6 +161,9 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)
>>       free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
>>       kfree(vcpu->arch.vncr_tlb);
>>       kfree(vcpu->arch.ccsidr);
>> +
>> +    if (vcpu->arch.hdbss.base_phys || vcpu->arch.hdbss.size)
>> +        kvm_arm_vcpu_free_hdbss(vcpu);
>>   }
>>
>>   static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>> index 5bd76cf394fa..aa8138604b1e 100644
>> --- a/include/linux/kvm_host.h
>> +++ b/include/linux/kvm_host.h
>> @@ -876,6 +876,7 @@ struct kvm {
>>       struct xarray mem_attr_array;
>>   #endif
>>       char stats_id[KVM_STATS_NAME_SIZE];
>> +    bool enable_hdbss;
>>   };
>>
>>   #define kvm_err(fmt, ...) \
>> -- 
>> 2.33.0
>>
>>
> 



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events
  2025-12-24  6:15     ` Tian Zheng
@ 2025-12-28 13:21       ` Robert Hoo
  0 siblings, 0 replies; 21+ messages in thread
From: Robert Hoo @ 2025-12-28 13:21 UTC (permalink / raw)
  To: Tian Zheng, maz, oliver.upton, catalin.marinas, corbet, pbonzini,
	will
  Cc: linux-kernel, yuzenghui, wangzhou1, yezhenyu2, xiexiangyou,
	zhengchuan, joey.gouly, kvmarm, kvm, linux-arm-kernel, linux-doc,
	suzuki.poulose

On 12/24/2025 2:15 PM, Tian Zheng wrote:
> 
> 
> On 12/17/2025 9:39 PM, Robert Hoo wrote:
>> On 11/21/2025 5:23 PM, Tian Zheng wrote:
>>> From: eillon <yezhenyu2@huawei.com>
>>>
>>> Implement the HDBSS enable/disable functionality using the
>>> KVM_CAP_ARM_HW_DIRTY_STATE_TRACK ioctl.
>>>
>>> Userspace (e.g., QEMU) can enable HDBSS by invoking the ioctl
>>> at the start of live migration, configuring the buffer size.
>>> The feature is disabled by invoking the ioctl again with size
>>> set to 0 once migration completes.
>>>
>>> Add support for updating the dirty bitmap based on the HDBSS
>>> buffer. Similar to the x86 PML implementation, KVM flushes the
>>> buffer on all VM-Exits, so running vCPUs only need to be kicked
>>> to force a VM-Exit.
>>>
>>> Signed-off-by: eillon <yezhenyu2@huawei.com>
>>> Signed-off-by: Tian Zheng <zhengtian10@huawei.com>
>>> ---
>>>   arch/arm64/include/asm/kvm_host.h |  10 +++
>>>   arch/arm64/include/asm/kvm_mmu.h  |  17 +++++
>>>   arch/arm64/kvm/arm.c              | 107 ++++++++++++++++++++++++++++++
>>>   arch/arm64/kvm/handle_exit.c      |  45 +++++++++++++
>>>   arch/arm64/kvm/hyp/vhe/switch.c   |   1 +
>>>   arch/arm64/kvm/mmu.c              |  10 +++
>>>   arch/arm64/kvm/reset.c            |   3 +
>>>   include/linux/kvm_host.h          |   1 +
>>>   8 files changed, 194 insertions(+)
>>>
>>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/ 
>>> asm/kvm_host.h
>>> index d962932f0e5f..408e4c2b3d1a 100644
>>> --- a/arch/arm64/include/asm/kvm_host.h
>>> +++ b/arch/arm64/include/asm/kvm_host.h
>>> @@ -87,6 +87,7 @@ int __init kvm_arm_init_sve(void);
>>>   u32 __attribute_const__ kvm_target_cpu(void);
>>>   void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>>>   void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
>>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
>>>
>>>   struct kvm_hyp_memcache {
>>>       phys_addr_t head;
>>> @@ -793,6 +794,12 @@ struct vcpu_reset_state {
>>>       bool        reset;
>>>   };
>>>
>>> +struct vcpu_hdbss_state {
>>> +    phys_addr_t base_phys;
>>> +    u32 size;
>>> +    u32 next_index;
>>> +};
>>> +
>>>   struct vncr_tlb;
>>>
>>>   struct kvm_vcpu_arch {
>>> @@ -897,6 +904,9 @@ struct kvm_vcpu_arch {
>>>
>>>       /* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */
>>>       struct vncr_tlb    *vncr_tlb;
>>> +
>>> +    /* HDBSS registers info */
>>> +    struct vcpu_hdbss_state hdbss;
>>>   };
>>>
>>>   /*
>>> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/ 
>>> asm/kvm_mmu.h
>>> index e4069f2ce642..6ace1080aed5 100644
>>> --- a/arch/arm64/include/asm/kvm_mmu.h
>>> +++ b/arch/arm64/include/asm/kvm_mmu.h
>>> @@ -331,6 +331,23 @@ static __always_inline void __load_stage2(struct 
>>> kvm_s2_mmu *mmu,
>>>       asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
>>>   }
>>>
>>> +static __always_inline void __load_hdbss(struct kvm_vcpu *vcpu)
>>> +{
>>> +    struct kvm *kvm = vcpu->kvm;
>>> +    u64 br_el2, prod_el2;
>>> +
>>> +    if (!kvm->enable_hdbss)
>>> +        return;
>>> +
>>> +    br_el2 = HDBSSBR_EL2(vcpu->arch.hdbss.base_phys, vcpu- >arch.hdbss.size);
>>> +    prod_el2 = vcpu->arch.hdbss.next_index;
>>> +
>>> +    write_sysreg_s(br_el2, SYS_HDBSSBR_EL2);
>>> +    write_sysreg_s(prod_el2, SYS_HDBSSPROD_EL2);
>>> +
>>> +    isb();
>>> +}
>>> +
>>>   static inline struct kvm *kvm_s2_mmu_to_kvm(struct kvm_s2_mmu *mmu)
>>>   {
>>>       return container_of(mmu->arch, struct kvm, arch);
>>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>>> index 870953b4a8a7..64f65e3c2a89 100644
>>> --- a/arch/arm64/kvm/arm.c
>>> +++ b/arch/arm64/kvm/arm.c
>>> @@ -79,6 +79,92 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
>>>       return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
>>>   }
>>>
>>> +void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
>>> +{
>>> +    struct page *hdbss_pg = NULL;
>>> +
>>> +    hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
>>> +    if (hdbss_pg)
>>> +        __free_pages(hdbss_pg, vcpu->arch.hdbss.size);
>>> +
>>> +    vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>>> +        .base_phys = 0,
>>> +        .size = 0,
>>> +        .next_index = 0,
>>> +    };
>>> +}
>>> +
>>> +static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
>>> +                    struct kvm_enable_cap *cap)
>>> +{
>>> +    unsigned long i;
>>> +    struct kvm_vcpu *vcpu;
>>> +    struct page *hdbss_pg = NULL;
>>> +    int size = cap->args[0];
>>> +    int ret = 0;
>>> +
>>> +    if (!system_supports_hdbss()) {
>>> +        kvm_err("This system does not support HDBSS!\n");
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    if (size < 0 || size > HDBSS_MAX_SIZE) {
>>> +        kvm_err("Invalid HDBSS buffer size: %d!\n", size);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>
>> I think you should check if it's already enabled here. What if user space 
>> calls this twice?
> 
> Ok, I review the implement of qemu, when disable the hdbss feature in
> ram_save_cleanup, size=0 will be set, so here can add a check, if (size
> && kvm->arch.enable_hdbss), we will do nothing.
> 

I mean you should check if ' kvm->enable_hdbss' is already set, if so, return 
rather than alloc_pages() in below (you have allocated in previous call with 
valid 'size').

qemu is just one of the user space applications that would possibly call this 
API, you cannot rely on your qemu patch's flow/sequence as assumption to design 
a KVM API's implementation.

>>
>>> +    /* Enable the HDBSS feature if size > 0, otherwise disable it. */
>>> +    if (size) {
>>> +        kvm_for_each_vcpu(i, vcpu, kvm) {
>>> +            hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, size);
>>> +            if (!hdbss_pg) {
>>> +                kvm_err("Alloc HDBSS buffer failed!\n");
>>> +                ret = -ENOMEM;
>>> +                goto error_alloc;
>>> +            }
>>> +
>>> +            vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
>>> +                .base_phys = page_to_phys(hdbss_pg),
>>> +                .size = size,
>>> +                .next_index = 0,
>>> +            };
>>> +        }
>>> +
>>> +        kvm->enable_hdbss = true;
>>> +        kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS;
>>




^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2025-12-28 13:21 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-21  9:23 [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Tian Zheng
2025-11-21  9:23 ` [PATCH v2 1/5] arm64/sysreg: Add HDBSS related register information Tian Zheng
2025-11-22 12:40   ` Marc Zyngier
2025-11-27 11:48     ` Tian Zheng
2025-12-02  6:51     ` Tian Zheng
2025-11-21  9:23 ` [PATCH v2 2/5] KVM: arm64: Support set the DBM attr during memory abort Tian Zheng
2025-11-22 12:54   ` Marc Zyngier
2025-11-27 12:19     ` Tian Zheng
2025-11-21  9:23 ` [PATCH v2 3/5] KVM: arm64: Add support for FEAT_HDBSS Tian Zheng
2025-11-22 13:25   ` Marc Zyngier
2025-11-27 13:24     ` Tian Zheng
2025-11-21  9:23 ` [PATCH v2 4/5] KVM: arm64: Enable HDBSS support and handle HDBSSF events Tian Zheng
2025-11-22 16:17   ` Marc Zyngier
2025-11-28  9:21     ` Tian Zheng
2025-12-17 13:39   ` Robert Hoo
2025-12-24  6:15     ` Tian Zheng
2025-12-28 13:21       ` Robert Hoo
2025-11-21  9:23 ` [PATCH v2 5/5] KVM: arm64: Document HDBSS ioctl Tian Zheng
2025-11-21  9:54 ` [PATCH v2 0/5] Support the FEAT_HDBSS introduced in Armv9.5 Marc Zyngier
2025-11-21 10:21   ` z00939249
2025-11-22 16:23     ` Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).