AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/10 06:12 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvm_arm_vcpu_alloc_hdbss",
    "kvm_arm_vcpu_free_hdbss",
    "kvm_flush_hdbss_buffer",
    "kvm_handle_hdbss_fault",
    "kvm_arm_enable_hdbss_global",
    "kvm_arm_disable_hdbss_global",
    "kvm_arm_hdbss_on_dirty_logging_change",
    "kvm_arch_sync_dirty_log"
  ],
  "Reasoning": "The patch introduces Hardware Dirty state tracking structure (HDBSS) support for KVM on arm64. It modifies core KVM logic for dirty page logging and memory management, which is reachable from userspace via KVM ioctls and guest execution.",
  "WorthFuzzing": true
}

1/1 2026/07/10 06:12 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 0bba3b915a1dbc87d29204275b15545c71ca2fdc\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Fri Jul 10 06:12:02 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h\nindex a57870fa96db5b..bdfab086fd9453 100644\n--- a/arch/arm64/include/asm/cpufeature.h\n+++ b/arch/arm64/include/asm/cpufeature.h\n@@ -863,6 +863,11 @@ static inline bool system_supports_haft(void)\n \treturn cpus_have_final_cap(ARM64_HAFT);\n }\n \n+static inline bool system_supports_hdbss(void)\n+{\n+\treturn cpus_have_final_cap(ARM64_HAS_HDBSS);\n+}\n+\n static __always_inline bool system_supports_mpam(void)\n {\n \treturn alternative_has_cap_unlikely(ARM64_MPAM);\ndiff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h\nindex 81c17320a588d9..2e6b679b590808 100644\n--- a/arch/arm64/include/asm/esr.h\n+++ b/arch/arm64/include/asm/esr.h\n@@ -437,6 +437,11 @@\n #ifndef __ASSEMBLER__\n #include \u003casm/types.h\u003e\n \n+static inline bool esr_iss2_is_hdbssf(unsigned long esr)\n+{\n+\treturn ESR_ELx_ISS2(esr) \u0026 ESR_ELx_HDBSSF;\n+}\n+\n static inline unsigned long esr_brk_comment(unsigned long esr)\n {\n \treturn esr \u0026 ESR_ELx_BRK64_ISS_COMMENT_MASK;\ndiff --git a/arch/arm64/include/asm/kvm_dirty_bit.h b/arch/arm64/include/asm/kvm_dirty_bit.h\nnew file mode 100644\nindex 00000000000000..a4cda8cdab2472\n--- /dev/null\n+++ b/arch/arm64/include/asm/kvm_dirty_bit.h\n@@ -0,0 +1,29 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/*\n+ * Copyright (C) 2026 ARM Ltd.\n+ * Author: Leonardo Bras \u003cleo.bras@arm.com\u003e\n+ */\n+\n+#ifndef __ARM64_KVM_DIRTY_BIT_H__\n+#define __ARM64_KVM_DIRTY_BIT_H__\n+\n+#include \u003casm/kvm_pgtable.h\u003e\n+#include \u003casm/sysreg.h\u003e\n+\n+/* HDBSS entry field definitions */\n+#define HDBSS_ENTRY_VALID\tBIT(0)\n+#define HDBSS_ENTRY_TTWL_SHIFT (1)\n+#define HDBSS_ENTRY_TTWL_MASK (GENMASK(3, 1))\n+#define HDBSS_ENTRY_TTWL(x) \\\n+\t(((x) \u003c\u003c HDBSS_ENTRY_TTWL_SHIFT) \u0026 HDBSS_ENTRY_TTWL_MASK)\n+#define HDBSS_ENTRY_TTWL_RESV HDBSS_ENTRY_TTWL(-4)\n+#define HDBSS_ENTRY_IPA\tGENMASK_ULL(55, 12)\n+\n+int kvm_arm_vcpu_alloc_hdbss(struct kvm_vcpu *vcpu, unsigned int order);\n+void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);\n+void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu);\n+int kvm_handle_hdbss_fault(struct kvm_vcpu *vcpu);\n+void kvm_arm_hdbss_on_dirty_logging_change(struct kvm *kvm, int nr_memslots_logging);\n+void kvm_arm_disable_hdbss_global(struct kvm *kvm);\n+\n+#endif /* __ARM64_KVM_DIRTY_BIT_H__ */\ndiff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h\nindex bae2c4f92ef5c0..cecfb884a64fa7 100644\n--- a/arch/arm64/include/asm/kvm_host.h\n+++ b/arch/arm64/include/asm/kvm_host.h\n@@ -55,6 +55,7 @@\n #define KVM_REQ_GUEST_HYP_IRQ_PENDING\tKVM_ARCH_REQ(9)\n #define KVM_REQ_MAP_L1_VNCR_EL2\t\tKVM_ARCH_REQ(10)\n #define KVM_REQ_VGIC_PROCESS_UPDATE\tKVM_ARCH_REQ(11)\n+#define KVM_REQ_FLUSH_HDBSS\t\t\tKVM_ARCH_REQ(12)\n \n #define KVM_DIRTY_LOG_MANUAL_CAPS   (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \\\n \t\t\t\t     KVM_DIRTY_LOG_INITIALLY_SET)\n@@ -420,6 +421,10 @@ struct kvm_arch {\n \t */\n \tstruct kvm_protected_vm pkvm;\n \n+\t/* HDBSS: per-VM dirty tracking state */\n+\tbool enable_hdbss;\n+\tunsigned int hdbss_order;\n+\n #ifdef CONFIG_PTDUMP_STAGE2_DEBUGFS\n \t/* Nested virtualization info */\n \tstruct dentry *debugfs_nv_dentry;\n@@ -838,6 +843,12 @@ struct vcpu_reset_state {\n \tbool\t\treset;\n };\n \n+struct vcpu_hdbss_state {\n+\tphys_addr_t base_phys;   /* for memory free */\n+\tu64 hdbssbr_el2;         /* load directly */\n+\tu64 hdbssprod_el2;       /* save directly */\n+};\n+\n struct vncr_tlb;\n \n struct kvm_vcpu_arch {\n@@ -945,6 +956,9 @@ struct kvm_vcpu_arch {\n \n \t/* Hyp-readable copy of kvm_vcpu::pid */\n \tpid_t pid;\n+\n+\t/* HDBSS registers info */\n+\tstruct vcpu_hdbss_state hdbss;\n };\n \n /*\ndiff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h\nindex 41a8687938eb6b..5e0fac4bfa5369 100644\n--- a/arch/arm64/include/asm/kvm_pgtable.h\n+++ b/arch/arm64/include/asm/kvm_pgtable.h\n@@ -93,6 +93,8 @@ typedef u64 kvm_pte_t;\n \n #define KVM_PTE_LEAF_ATTR_HI_S2_XN\tGENMASK(54, 53)\n \n+#define KVM_PTE_LEAF_ATTR_HI_S2_DBM\tBIT(51)\n+\n #define KVM_PTE_LEAF_ATTR_HI_S1_GP\tBIT(50)\n \n #define KVM_PTE_LEAF_ATTR_S2_PERMS\t(KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | \\\n@@ -249,10 +251,12 @@ struct kvm_pgtable_mm_ops {\n  * enum kvm_pgtable_stage2_flags - Stage-2 page-table flags.\n  * @KVM_PGTABLE_S2_IDMAP:\tOnly use identity mappings.\n  * @KVM_PGTABLE_S2_AS_S1:\tFinal memory attributes are that of Stage-1.\n+ * @KVM_PGTABLE_S2_DBM:\tHardware-managed DBM for writable pages.\n  */\n enum kvm_pgtable_stage2_flags {\n \tKVM_PGTABLE_S2_IDMAP\t\t\t= BIT(0),\n \tKVM_PGTABLE_S2_AS_S1\t\t\t= BIT(1),\n+\tKVM_PGTABLE_S2_DBM\t\t\t= BIT(2),\n };\n \n /**\ndiff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h\nindex 7aa08d59d49448..1354a58c33167b 100644\n--- a/arch/arm64/include/asm/sysreg.h\n+++ b/arch/arm64/include/asm/sysreg.h\n@@ -1039,6 +1039,17 @@\n \n #define GCS_CAP(x)\t((((unsigned long)x) \u0026 GCS_CAP_ADDR_MASK) | \\\n \t\t\t\t\t       GCS_CAP_VALID_TOKEN)\n+\n+/*\n+ * Definitions for the HDBSS feature\n+ */\n+#define HDBSS_MAX_ORDER\t\tHDBSSBR_EL2_SZ_2MB\n+\n+#define HDBSSBR_EL2(baddr, sz)\t(((baddr) \u0026 HDBSSBR_EL2_BADDR_MASK) | \\\n+\t\t\t\t FIELD_PREP(HDBSSBR_EL2_SZ_MASK, sz))\n+\n+#define HDBSSPROD_IDX(prod)\tFIELD_GET(HDBSSPROD_EL2_INDEX_MASK, prod)\n+\n /*\n  * Definitions for GICv5 instructions\n  */\ndiff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c\nindex 9a22df0c5120f3..aa327eebaf1ca8 100644\n--- a/arch/arm64/kernel/cpufeature.c\n+++ b/arch/arm64/kernel/cpufeature.c\n@@ -2131,6 +2131,11 @@ static bool hvhe_possible(const struct arm64_cpu_capabilities *entry,\n \treturn arm64_test_sw_feature_override(ARM64_SW_FEATURE_OVERRIDE_HVHE);\n }\n \n+static bool has_vhe_hdbss(const struct arm64_cpu_capabilities *entry, int cope)\n+{\n+\treturn is_kernel_in_hyp_mode() \u0026\u0026 has_cpuid_feature(entry, cope);\n+}\n+\n bool cpu_supports_bbml2_noabort(void)\n {\n \t/*\n@@ -2781,6 +2786,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {\n \t\tARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HAFT)\n \t},\n #endif\n+\t{\n+\t\t.desc = \"Hardware Dirty state tracking structure (HDBSS)\",\n+\t\t.type = ARM64_CPUCAP_SYSTEM_FEATURE,\n+\t\t.capability = ARM64_HAS_HDBSS,\n+\t\t.matches = has_vhe_hdbss,\n+\t\tARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HDBSS)\n+\t},\n \t{\n \t\t.desc = \"CRC32 instructions\",\n \t\t.capability = ARM64_HAS_CRC32,\ndiff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile\nindex 59612d2f277c1d..ec2749af64fa4c 100644\n--- a/arch/arm64/kvm/Makefile\n+++ b/arch/arm64/kvm/Makefile\n@@ -18,6 +18,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \\\n \t guest.o debug.o reset.o sys_regs.o stacktrace.o \\\n \t vgic-sys-reg-v3.o fpsimd.o pkvm.o \\\n \t arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \\\n+\t dirty_bit.o \\\n \t vgic/vgic.o vgic/vgic-init.o \\\n \t vgic/vgic-irqfd.o vgic/vgic-v2.o \\\n \t vgic/vgic-v3.o vgic/vgic-v4.o \\\ndiff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c\nindex 50adfff75be82e..536d94799ba8f9 100644\n--- a/arch/arm64/kvm/arm.c\n+++ b/arch/arm64/kvm/arm.c\n@@ -38,6 +38,7 @@\n #include \u003casm/kvm_asm.h\u003e\n #include \u003casm/kvm_emulate.h\u003e\n #include \u003casm/kvm_hyp.h\u003e\n+#include \u003casm/kvm_dirty_bit.h\u003e\n #include \u003casm/kvm_mmu.h\u003e\n #include \u003casm/kvm_nested.h\u003e\n #include \u003casm/kvm_pkvm.h\u003e\n@@ -316,6 +317,14 @@ void kvm_arch_destroy_vm(struct kvm *kvm)\n \tif (is_protected_kvm_enabled())\n \t\tpkvm_destroy_hyp_vm(kvm);\n \n+\t/*\n+\t * Userspace may destroy the VM without disabling dirty logging,\n+\t * so the auto-disable path is never reached. Force disable HDBSS\n+\t * here to ensure vCPU buffers are freed and prevent memory leaks.\n+\t */\n+\tif (kvm-\u003earch.enable_hdbss)\n+\t\tkvm_arm_disable_hdbss_global(kvm);\n+\n \tkvm_uninit_stage2_mmu(kvm);\n \tkvm_destroy_mpidr_data(kvm);\n \n@@ -565,6 +574,12 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)\n \tif (err)\n \t\tkvm_vgic_vcpu_destroy(vcpu);\n \n+\tif (vcpu-\u003ekvm-\u003earch.enable_hdbss) {\n+\t\terr = kvm_arm_vcpu_alloc_hdbss(vcpu, vcpu-\u003ekvm-\u003earch.hdbss_order);\n+\t\tif (err)\n+\t\t\tkvm_vgic_vcpu_destroy(vcpu);\n+\t}\n+\n \treturn err;\n }\n \n@@ -748,6 +763,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)\n \t\tkvm_vcpu_put_hw_mmu(vcpu);\n \tkvm_arm_vmid_clear_active();\n \n+\tif (vcpu-\u003ekvm-\u003earch.enable_hdbss)\n+\t\tkvm_flush_hdbss_buffer(vcpu);\n+\n \tvcpu_clear_on_unsupported_cpu(vcpu);\n \tvcpu-\u003ecpu = -1;\n }\n@@ -1150,6 +1168,9 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)\n \t\tif (kvm_dirty_ring_check_request(vcpu))\n \t\t\treturn 0;\n \n+\t\tif (kvm_check_request(KVM_REQ_FLUSH_HDBSS, vcpu))\n+\t\t\tkvm_flush_hdbss_buffer(vcpu);\n+\n \t\tcheck_nested_vcpu_requests(vcpu);\n \t}\n \n@@ -1964,7 +1985,15 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,\n \n void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)\n {\n+\t/*\n+\t * Flush all CPUs' dirty log buffers to the dirty_bitmap.  Called\n+\t * before reporting dirty_bitmap to userspace. Send a request with\n+\t * KVM_REQUEST_WAIT to flush buffer synchronously.\n+\t */\n+\tif (!kvm-\u003earch.enable_hdbss)\n+\t\treturn;\n \n+\tkvm_make_all_cpus_request(kvm, KVM_REQ_FLUSH_HDBSS | KVM_REQUEST_WAIT);\n }\n \n static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,\ndiff --git a/arch/arm64/kvm/dirty_bit.c b/arch/arm64/kvm/dirty_bit.c\nnew file mode 100644\nindex 00000000000000..c5bf866c23ef2b\n--- /dev/null\n+++ b/arch/arm64/kvm/dirty_bit.c\n@@ -0,0 +1,219 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Copyright (C) 2026 ARM Ltd.\n+ * Author: Leonardo Bras \u003cleo.bras@arm.com\u003e\n+ */\n+\n+#include \u003casm/kvm_dirty_bit.h\u003e\n+#include \u003casm/kvm_mmu.h\u003e\n+#include \u003casm/sysreg.h\u003e\n+#include \u003clinux/gfp.h\u003e\n+#include \u003clinux/kconfig.h\u003e\n+#include \u003clinux/mm.h\u003e\n+\n+int kvm_arm_vcpu_alloc_hdbss(struct kvm_vcpu *vcpu, unsigned int order)\n+{\n+\tstruct page *hdbss_pg = NULL;\n+\n+\tif (vcpu-\u003earch.hdbss.hdbssbr_el2 || !system_supports_hdbss())\n+\t\treturn 0;\n+\n+\tif (order \u003e HDBSS_MAX_ORDER)\n+\t\treturn -EINVAL;\n+\n+\thdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, order);\n+\tif (!hdbss_pg)\n+\t\treturn -ENOMEM;\n+\n+\tvcpu-\u003earch.hdbss = (struct vcpu_hdbss_state) {\n+\t\t.base_phys = page_to_phys(hdbss_pg),\n+\t\t.hdbssbr_el2 = HDBSSBR_EL2(page_to_phys(hdbss_pg), order),\n+\t\t.hdbssprod_el2 = 0,\n+\t};\n+\n+\treturn 0;\n+}\n+\n+void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)\n+{\n+\tstruct page *hdbss_pg;\n+\n+\tif (!vcpu-\u003earch.hdbss.hdbssbr_el2) {\n+\t\treturn;\n+\t}\n+\n+\thdbss_pg = phys_to_page(vcpu-\u003earch.hdbss.base_phys);\n+\tif (hdbss_pg)\n+\t\t__free_pages(hdbss_pg,\n+\t\t     FIELD_GET(HDBSSBR_EL2_SZ_MASK,\n+\t\t\t       vcpu-\u003earch.hdbss.hdbssbr_el2));\n+\n+\tvcpu-\u003earch.hdbss.hdbssbr_el2 = 0;\n+}\n+\n+void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)\n+{\n+\tint idx, curr_idx;\n+\tu64 *hdbss_buf;\n+\tstruct kvm *kvm = vcpu-\u003ekvm;\n+\n+\tif (!kvm-\u003earch.enable_hdbss)\n+\t\treturn;\n+\n+\tcurr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));\n+\n+\t/* Do nothing if HDBSS buffer is empty or br_el2 is NULL */\n+\tif (curr_idx == 0 || vcpu-\u003earch.hdbss.hdbssbr_el2 == 0)\n+\t\treturn;\n+\n+\thdbss_buf = page_address(phys_to_page(vcpu-\u003earch.hdbss.base_phys));\n+\tif (!hdbss_buf)\n+\t\treturn;\n+\n+\tguard(write_lock_irqsave)(\u0026vcpu-\u003ekvm-\u003emmu_lock);\n+\tfor (idx = 0; idx \u003c curr_idx; idx++) {\n+\t\tu64 gpa;\n+\n+\t\tgpa = hdbss_buf[idx];\n+\t\tif (!(gpa \u0026 HDBSS_ENTRY_VALID))\n+\t\t\tcontinue;\n+\n+\t\tgpa \u0026= HDBSS_ENTRY_IPA;\n+\t\tkvm_vcpu_mark_page_dirty(vcpu, gpa \u003e\u003e PAGE_SHIFT);\n+\t}\n+\n+\t/* reset HDBSS index */\n+\twrite_sysreg_s(0, SYS_HDBSSPROD_EL2);\n+\tvcpu-\u003earch.hdbss.hdbssprod_el2 = 0;\n+\tisb();\n+}\n+\n+int kvm_handle_hdbss_fault(struct kvm_vcpu *vcpu)\n+{\n+\tu64 prod;\n+\tu64 fsc;\n+\n+\tprod = read_sysreg_s(SYS_HDBSSPROD_EL2);\n+\tfsc = FIELD_GET(HDBSSPROD_EL2_FSC_MASK, prod);\n+\n+\tswitch (fsc) {\n+\tcase HDBSSPROD_EL2_FSC_OK:\n+\t\t/* Buffer full, set request to flush on next vcpu exit */\n+\t\tkvm_make_request(KVM_REQ_FLUSH_HDBSS, vcpu);\n+\t\treturn 1;\n+\tcase HDBSSPROD_EL2_FSC_ExternalAbort:\n+\tcase HDBSSPROD_EL2_FSC_GPF:\n+\t\treturn -EFAULT;\n+\tdefault:\n+\t\t/* Unknown fault. */\n+\t\tWARN_ONCE(1,\n+\t\t\t  \"Unexpected HDBSS fault type, FSC: 0x%llx (prod=0x%llx, vcpu=%d)\\n\",\n+\t\t\t  fsc, prod, vcpu-\u003evcpu_id);\n+\t\treturn -EFAULT;\n+\t}\n+}\n+\n+static unsigned int hdbss_auto_select_order(struct kvm *kvm)\n+{\n+\tunsigned long npages = 0;\n+\tstruct kvm_memory_slot *memslot;\n+\tint bkt;\n+\n+\tkvm_for_each_memslot(memslot, bkt, kvm_memslots(kvm))\n+\t\tnpages += memslot-\u003enpages;\n+\n+\tif (npages \u003c= 16384)\n+\t\treturn 0;\n+\telse if (npages \u003c= 262144)\n+\t\treturn 3;\n+\telse if (npages \u003c= 4194304)\n+\t\treturn 6;\n+\telse\n+\t\treturn 9;\n+}\n+\n+/*\n+ * Enable HDBSS for all vCPUs in the VM.\n+ *\n+ * Called from kvm_arm_hdbss_on_dirty_logging_change() which is invoked\n+ * by kvm_arch_commit_memory_region() under kvm-\u003eslots_lock.\n+ *\n+ * If buffer allocation fails, HDBSS remains disabled and dirty tracking\n+ * falls back to the traditional software-based approach (PTE write-protect\n+ * + software dirty marking). This does not affect correctness; dirty\n+ * logging remains functional without HDBSS.\n+ */\n+static int kvm_arm_enable_hdbss_global(struct kvm *kvm)\n+{\n+\tint err;\n+\tunsigned long i;\n+\tunsigned int order;\n+\tstruct kvm_vcpu *vcpu;\n+\n+\tif (!system_supports_hdbss())\n+\t\treturn 0;\n+\n+\tif (kvm-\u003edirty_ring_size) /* Don't support HDBSS in dirty ring mode */\n+\t\treturn 0;\n+\n+\tif (kvm-\u003earch.enable_hdbss) /* Already On */\n+\t\treturn 0;\n+\n+\t/* Turn it on */\n+\torder = hdbss_auto_select_order(kvm);\n+\tkvm_for_each_vcpu(i, vcpu, kvm) {\n+\t\terr = kvm_arm_vcpu_alloc_hdbss(vcpu, order);\n+\t\tif (err)\n+\t\t\tgoto error_alloc;\n+\t}\n+\n+\tkvm-\u003earch.enable_hdbss = true;\n+\tkvm-\u003earch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS | VTCR_EL2_HA;\n+\n+\t/*\n+\t * We should kick vcpus out of guest mode here to load new\n+\t * vtcr value to vtcr_el2 register when re-enter guest mode.\n+\t */\n+\tkvm_for_each_vcpu(i, vcpu, kvm)\n+\t\tkvm_vcpu_kick(vcpu);\n+\n+\treturn 0;\n+\n+error_alloc:\n+\tkvm_for_each_vcpu(i, vcpu, kvm)\n+\t\tif (vcpu-\u003earch.hdbss.base_phys)\n+\t\t\tkvm_arm_vcpu_free_hdbss(vcpu);\n+\n+\tpr_warn_once(\"kvm: failed to allocate HDBSS buffers (order=%u), \"\n+\t\t     \"falling back to software dirty tracking\\n\", order);\n+\treturn -ENOMEM;\n+}\n+\n+void kvm_arm_disable_hdbss_global(struct kvm *kvm)\n+{\n+\tunsigned long i;\n+\tstruct kvm_vcpu *vcpu;\n+\n+\tif (!kvm-\u003earch.enable_hdbss) /* Already Off */\n+\t\treturn;\n+\n+\t/* Turn it off */\n+\tkvm-\u003earch.mmu.vtcr \u0026= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS | VTCR_EL2_HA);\n+\n+\tkvm_for_each_vcpu(i, vcpu, kvm)\n+\t\tkvm_arm_vcpu_free_hdbss(vcpu);\n+\n+\tkvm-\u003earch.enable_hdbss = false;\n+}\n+\n+void kvm_arm_hdbss_on_dirty_logging_change(struct kvm *kvm, int nr_memslots_logging)\n+{\n+\t/*\n+\t * Called from kvm_arch_commit_memory_region() under kvm-\u003eslots_lock.\n+\t * All state transitions are serialized by slots_lock.\n+\t */\n+\tif (nr_memslots_logging \u003e 0 \u0026\u0026 !kvm-\u003earch.enable_hdbss)\n+\t\tkvm_arm_enable_hdbss_global(kvm);\n+\telse if (nr_memslots_logging == 0 \u0026\u0026 kvm-\u003earch.enable_hdbss)\n+\t\tkvm_arm_disable_hdbss_global(kvm);\n+}\ndiff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c\nindex 91a7dfad668660..21ec456ecc411a 100644\n--- a/arch/arm64/kvm/hyp/pgtable.c\n+++ b/arch/arm64/kvm/hyp/pgtable.c\n@@ -731,9 +731,23 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p\n \tif (prot \u0026 KVM_PGTABLE_PROT_R)\n \t\tattr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;\n \n-\tif (prot \u0026 KVM_PGTABLE_PROT_W)\n+\tif (prot \u0026 KVM_PGTABLE_PROT_W) {\n \t\tattr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;\n \n+\t\t/*\n+\t\t * Set DBM bit for writable non-device pages if the page-table\n+\t\t * has KVM_PGTABLE_S2_DBM flag (system supports HDBSS).\n+\t\t *\n+\t\t * For stage 2 translations using Indirect permissions, if the\n+\t\t * Effective value of VTCR_EL2.HD is 0, then dirty state is\n+\t\t * managed by software. Hardware only updates the dirty state\n+\t\t * when VTCR_EL2.HD=1 (HDBSS enabled).\n+\t\t */\n+\t\tif ((pgt-\u003eflags \u0026 KVM_PGTABLE_S2_DBM) \u0026\u0026\n+\t\t    !(prot \u0026 KVM_PGTABLE_PROT_DEVICE))\n+\t\t\tattr |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;\n+\t}\n+\n \tif (!kvm_lpa2_is_enabled())\n \t\tattr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);\n \n@@ -1367,9 +1381,26 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,\n \tif (prot \u0026 KVM_PGTABLE_PROT_R)\n \t\tset |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;\n \n-\tif (prot \u0026 KVM_PGTABLE_PROT_W)\n+\tif (prot \u0026 KVM_PGTABLE_PROT_W) {\n \t\tset |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;\n \n+\t\t/*\n+\t\t * No DEVICE filter needed here: relax_perms is only called\n+\t\t * on FSC_PERM faults. Device pages always get full RW from\n+\t\t * initial mapping and are never write-protected during\n+\t\t * migration, so they never trigger a permission fault.\n+\t\t */\n+\t\tif (pgt-\u003eflags \u0026 KVM_PGTABLE_S2_DBM)\n+\t\t\tset |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;\n+\t} else {\n+\t\t/*\n+\t\t * Clear DBM on W→RO downgrade to prevent hardware from\n+\t\t * silently upgrading RO+DBM back to W+dirty, which would\n+\t\t * bypass KVM's write tracking and cause data corruption.\n+\t\t */\n+\t\tclr |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;\n+\t}\n+\n \tret = stage2_set_xn_attr(prot, \u0026xn);\n \tif (ret)\n \t\treturn ret;\ndiff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c\nindex bbe9cebd3d9d57..fe72944bfd3d5b 100644\n--- a/arch/arm64/kvm/hyp/vhe/switch.c\n+++ b/arch/arm64/kvm/hyp/vhe/switch.c\n@@ -22,6 +22,7 @@\n #include \u003casm/kvm_emulate.h\u003e\n #include \u003casm/kvm_hyp.h\u003e\n #include \u003casm/kvm_mmu.h\u003e\n+#include \u003casm/kvm_dirty_bit.h\u003e\n #include \u003casm/fpsimd.h\u003e\n #include \u003casm/debug-monitors.h\u003e\n #include \u003casm/processor.h\u003e\n@@ -213,6 +214,19 @@ static void __vcpu_put_deactivate_traps(struct kvm_vcpu *vcpu)\n \tlocal_irq_restore(flags);\n }\n \n+static void __load_hdbss(struct kvm_vcpu *vcpu)\n+{\n+\tstruct kvm *kvm = vcpu-\u003ekvm;\n+\n+\tif (!kvm-\u003earch.enable_hdbss)\n+\t\treturn;\n+\n+\twrite_sysreg_s(vcpu-\u003earch.hdbss.hdbssbr_el2, SYS_HDBSSBR_EL2);\n+\twrite_sysreg_s(vcpu-\u003earch.hdbss.hdbssprod_el2, SYS_HDBSSPROD_EL2);\n+\n+\tisb();\n+}\n+\n void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)\n {\n \thost_data_ptr(host_ctxt)-\u003e__hyp_running_vcpu = vcpu;\n@@ -220,6 +234,7 @@ void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)\n \t__vcpu_load_switch_sysregs(vcpu);\n \t__vcpu_load_activate_traps(vcpu);\n \t__load_stage2(vcpu-\u003earch.hw_mmu);\n+\t__load_hdbss(vcpu);\n }\n \n void kvm_vcpu_put_vhe(struct kvm_vcpu *vcpu)\ndiff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c\nindex 6c941aaa10c639..484f48dae0003c 100644\n--- a/arch/arm64/kvm/mmu.c\n+++ b/arch/arm64/kvm/mmu.c\n@@ -16,6 +16,7 @@\n #include \u003casm/cacheflush.h\u003e\n #include \u003casm/kvm_arm.h\u003e\n #include \u003casm/kvm_mmu.h\u003e\n+#include \u003casm/kvm_dirty_bit.h\u003e\n #include \u003casm/kvm_pgtable.h\u003e\n #include \u003casm/kvm_pkvm.h\u003e\n #include \u003casm/kvm_asm.h\u003e\n@@ -1014,6 +1015,9 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t\n \tif (err)\n \t\tgoto out_free_pgtable;\n \n+\tif (system_supports_hdbss())\n+\t\tpgt-\u003eflags |= KVM_PGTABLE_S2_DBM;\n+\n \tmmu-\u003epgt = pgt;\n \tif (is_protected_kvm_enabled())\n \t\treturn 0;\n@@ -1027,8 +1031,12 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t\n \tfor_each_possible_cpu(cpu)\n \t\t*per_cpu_ptr(mmu-\u003elast_vcpu_ran, cpu) = -1;\n \n-\t /* The eager page splitting is disabled by default */\n-\tmmu-\u003esplit_page_chunk_size = KVM_ARM_EAGER_SPLIT_CHUNK_SIZE_DEFAULT;\n+\t /* The eager page splitting is disabled by default if system has no HDBSS */\n+\tif (system_supports_hdbss())\n+\t\tmmu-\u003esplit_page_chunk_size = 256 * 1024 * PAGE_SIZE;\n+\telse\n+\t\tmmu-\u003esplit_page_chunk_size = KVM_ARM_EAGER_SPLIT_CHUNK_SIZE_DEFAULT;\n+\n \tmmu-\u003esplit_page_cache.gfp_zero = __GFP_ZERO;\n \n \tmmu-\u003epgd_phys = __pa(pgt-\u003epgd);\n@@ -2234,6 +2242,7 @@ int kvm_handle_guest_sea(struct kvm_vcpu *vcpu)\n }\n \n /**\n+\n  * kvm_handle_guest_abort - handles all 2nd stage aborts\n  * @vcpu:\tthe VCPU pointer\n  *\n@@ -2271,6 +2280,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)\n \n \tis_iabt = kvm_vcpu_trap_is_iabt(vcpu);\n \n+\tif (esr_iss2_is_hdbssf(esr))\n+\t\treturn kvm_handle_hdbss_fault(vcpu);\n+\n \tif (esr_fsc_is_translation_fault(esr)) {\n \t\t/* Beyond sanitised PARange (which is the IPA limit) */\n \t\tif (fault_ipa \u003e= BIT_ULL(get_kvm_ipa_limit())) {\n@@ -2576,6 +2588,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,\n {\n \tbool log_dirty_pages = new \u0026\u0026 new-\u003eflags \u0026 KVM_MEM_LOG_DIRTY_PAGES;\n \n+\tkvm_arm_hdbss_on_dirty_logging_change(kvm,\n+\t\tatomic_read(\u0026kvm-\u003enr_memslots_dirty_logging));\n+\n \t/*\n \t * At this point memslot has been committed and there is an\n \t * allocated dirty_bitmap[], dirty pages will be tracked while the\ndiff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c\nindex b963fd975aacaf..d8104bcbd9ffad 100644\n--- a/arch/arm64/kvm/reset.c\n+++ b/arch/arm64/kvm/reset.c\n@@ -27,6 +27,7 @@\n #include \u003casm/kvm_asm.h\u003e\n #include \u003casm/kvm_emulate.h\u003e\n #include \u003casm/kvm_mmu.h\u003e\n+#include \u003casm/kvm_dirty_bit.h\u003e\n #include \u003casm/kvm_nested.h\u003e\n #include \u003casm/virt.h\u003e\n \n@@ -161,6 +162,9 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu)\n \tfree_page((unsigned long)vcpu-\u003earch.ctxt.vncr_array);\n \tkfree(vcpu-\u003earch.vncr_tlb);\n \tkfree(vcpu-\u003earch.ccsidr);\n+\n+\tif (vcpu-\u003ekvm-\u003earch.enable_hdbss)\n+\t\tkvm_arm_vcpu_free_hdbss(vcpu);\n }\n \n static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)\ndiff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps\nindex 9b85a84f6fd494..a87706c9d160e0 100644\n--- a/arch/arm64/tools/cpucaps\n+++ b/arch/arm64/tools/cpucaps\n@@ -69,6 +69,7 @@ HAS_VA52\n HAS_VIRT_HOST_EXTN\n HAS_WFXT\n HAS_XNX\n+HAS_HDBSS\n HAFT\n HW_DBM\n KVM_HVHE\n"
}

2/1 2026/07/10 06:12 agent patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvm_arm_vcpu_alloc_hdbss",
    "kvm_arm_vcpu_free_hdbss",
    "kvm_flush_hdbss_buffer",
    "kvm_handle_hdbss_fault",
    "kvm_arm_enable_hdbss_global",
    "kvm_arm_disable_hdbss_global",
    "kvm_arm_hdbss_on_dirty_logging_change",
    "kvm_arch_sync_dirty_log"
  ],
  "Reasoning": "The patch introduces Hardware Dirty state tracking structure (HDBSS) support for KVM on arm64. It modifies core KVM logic for dirty page logging and memory management, which is reachable from userspace via KVM ioctls and guest execution.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit 0bba3b915a1dbc87d29204275b15545c71ca2fdc
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Jul 10 06:12:02 2026 +0000

    syz-cluster: applied patch under review

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index a57870fa96db5b..bdfab086fd9453 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -863,6 +863,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/esr.h b/arch/arm64/include/asm/esr.h
index 81c17320a588d9..2e6b679b590808 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -437,6 +437,11 @@
 #ifndef __ASSEMBLER__
 #include <asm/types.h>
 
+static inline bool esr_iss2_is_hdbssf(unsigned long esr)
+{
+	return ESR_ELx_ISS2(esr) & ESR_ELx_HDBSSF;
+}
+
 static inline unsigned long esr_brk_comment(unsigned long esr)
 {
 	return esr & ESR_ELx_BRK64_ISS_COMMENT_MASK;
diff --git a/arch/arm64/include/asm/kvm_dirty_bit.h b/arch/arm64/include/asm/kvm_dirty_bit.h
new file mode 100644
index 00000000000000..a4cda8cdab2472
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_dirty_bit.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 ARM Ltd.
+ * Author: Leonardo Bras <leo.bras@arm.com>
+ */
+
+#ifndef __ARM64_KVM_DIRTY_BIT_H__
+#define __ARM64_KVM_DIRTY_BIT_H__
+
+#include <asm/kvm_pgtable.h>
+#include <asm/sysreg.h>
+
+/* HDBSS entry field definitions */
+#define HDBSS_ENTRY_VALID	BIT(0)
+#define HDBSS_ENTRY_TTWL_SHIFT (1)
+#define HDBSS_ENTRY_TTWL_MASK (GENMASK(3, 1))
+#define HDBSS_ENTRY_TTWL(x) \
+	(((x) << HDBSS_ENTRY_TTWL_SHIFT) & HDBSS_ENTRY_TTWL_MASK)
+#define HDBSS_ENTRY_TTWL_RESV HDBSS_ENTRY_TTWL(-4)
+#define HDBSS_ENTRY_IPA	GENMASK_ULL(55, 12)
+
+int kvm_arm_vcpu_alloc_hdbss(struct kvm_vcpu *vcpu, unsigned int order);
+void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu);
+void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu);
+int kvm_handle_hdbss_fault(struct kvm_vcpu *vcpu);
+void kvm_arm_hdbss_on_dirty_logging_change(struct kvm *kvm, int nr_memslots_logging);
+void kvm_arm_disable_hdbss_global(struct kvm *kvm);
+
+#endif /* __ARM64_KVM_DIRTY_BIT_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index bae2c4f92ef5c0..cecfb884a64fa7 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -55,6 +55,7 @@
 #define KVM_REQ_GUEST_HYP_IRQ_PENDING	KVM_ARCH_REQ(9)
 #define KVM_REQ_MAP_L1_VNCR_EL2		KVM_ARCH_REQ(10)
 #define KVM_REQ_VGIC_PROCESS_UPDATE	KVM_ARCH_REQ(11)
+#define KVM_REQ_FLUSH_HDBSS			KVM_ARCH_REQ(12)
 
 #define KVM_DIRTY_LOG_MANUAL_CAPS   (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
 				     KVM_DIRTY_LOG_INITIALLY_SET)
@@ -420,6 +421,10 @@ struct kvm_arch {
 	 */
 	struct kvm_protected_vm pkvm;
 
+	/* HDBSS: per-VM dirty tracking state */
+	bool enable_hdbss;
+	unsigned int hdbss_order;
+
 #ifdef CONFIG_PTDUMP_STAGE2_DEBUGFS
 	/* Nested virtualization info */
 	struct dentry *debugfs_nv_dentry;
@@ -838,6 +843,12 @@ struct vcpu_reset_state {
 	bool		reset;
 };
 
+struct vcpu_hdbss_state {
+	phys_addr_t base_phys;   /* for memory free */
+	u64 hdbssbr_el2;         /* load directly */
+	u64 hdbssprod_el2;       /* save directly */
+};
+
 struct vncr_tlb;
 
 struct kvm_vcpu_arch {
@@ -945,6 +956,9 @@ struct kvm_vcpu_arch {
 
 	/* Hyp-readable copy of kvm_vcpu::pid */
 	pid_t pid;
+
+	/* HDBSS registers info */
+	struct vcpu_hdbss_state hdbss;
 };
 
 /*
diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 41a8687938eb6b..5e0fac4bfa5369 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -93,6 +93,8 @@ typedef u64 kvm_pte_t;
 
 #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
 
+#define KVM_PTE_LEAF_ATTR_HI_S2_DBM	BIT(51)
+
 #define KVM_PTE_LEAF_ATTR_HI_S1_GP	BIT(50)
 
 #define KVM_PTE_LEAF_ATTR_S2_PERMS	(KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | \
@@ -249,10 +251,12 @@ struct kvm_pgtable_mm_ops {
  * enum kvm_pgtable_stage2_flags - Stage-2 page-table flags.
  * @KVM_PGTABLE_S2_IDMAP:	Only use identity mappings.
  * @KVM_PGTABLE_S2_AS_S1:	Final memory attributes are that of Stage-1.
+ * @KVM_PGTABLE_S2_DBM:	Hardware-managed DBM for writable pages.
  */
 enum kvm_pgtable_stage2_flags {
 	KVM_PGTABLE_S2_IDMAP			= BIT(0),
 	KVM_PGTABLE_S2_AS_S1			= BIT(1),
+	KVM_PGTABLE_S2_DBM			= BIT(2),
 };
 
 /**
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 7aa08d59d49448..1354a58c33167b 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -1039,6 +1039,17 @@
 
 #define GCS_CAP(x)	((((unsigned long)x) & GCS_CAP_ADDR_MASK) | \
 					       GCS_CAP_VALID_TOKEN)
+
+/*
+ * Definitions for the HDBSS feature
+ */
+#define HDBSS_MAX_ORDER		HDBSSBR_EL2_SZ_2MB
+
+#define HDBSSBR_EL2(baddr, sz)	(((baddr) & HDBSSBR_EL2_BADDR_MASK) | \
+				 FIELD_PREP(HDBSSBR_EL2_SZ_MASK, sz))
+
+#define HDBSSPROD_IDX(prod)	FIELD_GET(HDBSSPROD_EL2_INDEX_MASK, prod)
+
 /*
  * Definitions for GICv5 instructions
  */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 9a22df0c5120f3..aa327eebaf1ca8 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2131,6 +2131,11 @@ static bool hvhe_possible(const struct arm64_cpu_capabilities *entry,
 	return arm64_test_sw_feature_override(ARM64_SW_FEATURE_OVERRIDE_HVHE);
 }
 
+static bool has_vhe_hdbss(const struct arm64_cpu_capabilities *entry, int cope)
+{
+	return is_kernel_in_hyp_mode() && has_cpuid_feature(entry, cope);
+}
+
 bool cpu_supports_bbml2_noabort(void)
 {
 	/*
@@ -2781,6 +2786,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HAFT)
 	},
 #endif
+	{
+		.desc = "Hardware Dirty state tracking structure (HDBSS)",
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.capability = ARM64_HAS_HDBSS,
+		.matches = has_vhe_hdbss,
+		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HDBSS)
+	},
 	{
 		.desc = "CRC32 instructions",
 		.capability = ARM64_HAS_CRC32,
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 59612d2f277c1d..ec2749af64fa4c 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -18,6 +18,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
 	 guest.o debug.o reset.o sys_regs.o stacktrace.o \
 	 vgic-sys-reg-v3.o fpsimd.o pkvm.o \
 	 arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \
+	 dirty_bit.o \
 	 vgic/vgic.o vgic/vgic-init.o \
 	 vgic/vgic-irqfd.o vgic/vgic-v2.o \
 	 vgic/vgic-v3.o vgic/vgic-v4.o \
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 50adfff75be82e..536d94799ba8f9 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -38,6 +38,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
+#include <asm/kvm_dirty_bit.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_nested.h>
 #include <asm/kvm_pkvm.h>
@@ -316,6 +317,14 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 	if (is_protected_kvm_enabled())
 		pkvm_destroy_hyp_vm(kvm);
 
+	/*
+	 * Userspace may destroy the VM without disabling dirty logging,
+	 * so the auto-disable path is never reached. Force disable HDBSS
+	 * here to ensure vCPU buffers are freed and prevent memory leaks.
+	 */
+	if (kvm->arch.enable_hdbss)
+		kvm_arm_disable_hdbss_global(kvm);
+
 	kvm_uninit_stage2_mmu(kvm);
 	kvm_destroy_mpidr_data(kvm);
 
@@ -565,6 +574,12 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 	if (err)
 		kvm_vgic_vcpu_destroy(vcpu);
 
+	if (vcpu->kvm->arch.enable_hdbss) {
+		err = kvm_arm_vcpu_alloc_hdbss(vcpu, vcpu->kvm->arch.hdbss_order);
+		if (err)
+			kvm_vgic_vcpu_destroy(vcpu);
+	}
+
 	return err;
 }
 
@@ -748,6 +763,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 		kvm_vcpu_put_hw_mmu(vcpu);
 	kvm_arm_vmid_clear_active();
 
+	if (vcpu->kvm->arch.enable_hdbss)
+		kvm_flush_hdbss_buffer(vcpu);
+
 	vcpu_clear_on_unsupported_cpu(vcpu);
 	vcpu->cpu = -1;
 }
@@ -1150,6 +1168,9 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)
 		if (kvm_dirty_ring_check_request(vcpu))
 			return 0;
 
+		if (kvm_check_request(KVM_REQ_FLUSH_HDBSS, vcpu))
+			kvm_flush_hdbss_buffer(vcpu);
+
 		check_nested_vcpu_requests(vcpu);
 	}
 
@@ -1964,7 +1985,15 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
 
 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. Send a request with
+	 * KVM_REQUEST_WAIT to flush buffer synchronously.
+	 */
+	if (!kvm->arch.enable_hdbss)
+		return;
 
+	kvm_make_all_cpus_request(kvm, KVM_REQ_FLUSH_HDBSS | KVM_REQUEST_WAIT);
 }
 
 static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
diff --git a/arch/arm64/kvm/dirty_bit.c b/arch/arm64/kvm/dirty_bit.c
new file mode 100644
index 00000000000000..c5bf866c23ef2b
--- /dev/null
+++ b/arch/arm64/kvm/dirty_bit.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 ARM Ltd.
+ * Author: Leonardo Bras <leo.bras@arm.com>
+ */
+
+#include <asm/kvm_dirty_bit.h>
+#include <asm/kvm_mmu.h>
+#include <asm/sysreg.h>
+#include <linux/gfp.h>
+#include <linux/kconfig.h>
+#include <linux/mm.h>
+
+int kvm_arm_vcpu_alloc_hdbss(struct kvm_vcpu *vcpu, unsigned int order)
+{
+	struct page *hdbss_pg = NULL;
+
+	if (vcpu->arch.hdbss.hdbssbr_el2 || !system_supports_hdbss())
+		return 0;
+
+	if (order > HDBSS_MAX_ORDER)
+		return -EINVAL;
+
+	hdbss_pg = alloc_pages(GFP_KERNEL_ACCOUNT, order);
+	if (!hdbss_pg)
+		return -ENOMEM;
+
+	vcpu->arch.hdbss = (struct vcpu_hdbss_state) {
+		.base_phys = page_to_phys(hdbss_pg),
+		.hdbssbr_el2 = HDBSSBR_EL2(page_to_phys(hdbss_pg), order),
+		.hdbssprod_el2 = 0,
+	};
+
+	return 0;
+}
+
+void kvm_arm_vcpu_free_hdbss(struct kvm_vcpu *vcpu)
+{
+	struct page *hdbss_pg;
+
+	if (!vcpu->arch.hdbss.hdbssbr_el2) {
+		return;
+	}
+
+	hdbss_pg = phys_to_page(vcpu->arch.hdbss.base_phys);
+	if (hdbss_pg)
+		__free_pages(hdbss_pg,
+		     FIELD_GET(HDBSSBR_EL2_SZ_MASK,
+			       vcpu->arch.hdbss.hdbssbr_el2));
+
+	vcpu->arch.hdbss.hdbssbr_el2 = 0;
+}
+
+void kvm_flush_hdbss_buffer(struct kvm_vcpu *vcpu)
+{
+	int idx, curr_idx;
+	u64 *hdbss_buf;
+	struct kvm *kvm = vcpu->kvm;
+
+	if (!kvm->arch.enable_hdbss)
+		return;
+
+	curr_idx = HDBSSPROD_IDX(read_sysreg_s(SYS_HDBSSPROD_EL2));
+
+	/* Do nothing if HDBSS buffer is empty or br_el2 is NULL */
+	if (curr_idx == 0 || vcpu->arch.hdbss.hdbssbr_el2 == 0)
+		return;
+
+	hdbss_buf = page_address(phys_to_page(vcpu->arch.hdbss.base_phys));
+	if (!hdbss_buf)
+		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.hdbssprod_el2 = 0;
+	isb();
+}
+
+int kvm_handle_hdbss_fault(struct kvm_vcpu *vcpu)
+{
+	u64 prod;
+	u64 fsc;
+
+	prod = read_sysreg_s(SYS_HDBSSPROD_EL2);
+	fsc = FIELD_GET(HDBSSPROD_EL2_FSC_MASK, prod);
+
+	switch (fsc) {
+	case HDBSSPROD_EL2_FSC_OK:
+		/* Buffer full, set request to flush on next vcpu exit */
+		kvm_make_request(KVM_REQ_FLUSH_HDBSS, vcpu);
+		return 1;
+	case HDBSSPROD_EL2_FSC_ExternalAbort:
+	case HDBSSPROD_EL2_FSC_GPF:
+		return -EFAULT;
+	default:
+		/* Unknown fault. */
+		WARN_ONCE(1,
+			  "Unexpected HDBSS fault type, FSC: 0x%llx (prod=0x%llx, vcpu=%d)\n",
+			  fsc, prod, vcpu->vcpu_id);
+		return -EFAULT;
+	}
+}
+
+static unsigned int hdbss_auto_select_order(struct kvm *kvm)
+{
+	unsigned long npages = 0;
+	struct kvm_memory_slot *memslot;
+	int bkt;
+
+	kvm_for_each_memslot(memslot, bkt, kvm_memslots(kvm))
+		npages += memslot->npages;
+
+	if (npages <= 16384)
+		return 0;
+	else if (npages <= 262144)
+		return 3;
+	else if (npages <= 4194304)
+		return 6;
+	else
+		return 9;
+}
+
+/*
+ * Enable HDBSS for all vCPUs in the VM.
+ *
+ * Called from kvm_arm_hdbss_on_dirty_logging_change() which is invoked
+ * by kvm_arch_commit_memory_region() under kvm->slots_lock.
+ *
+ * If buffer allocation fails, HDBSS remains disabled and dirty tracking
+ * falls back to the traditional software-based approach (PTE write-protect
+ * + software dirty marking). This does not affect correctness; dirty
+ * logging remains functional without HDBSS.
+ */
+static int kvm_arm_enable_hdbss_global(struct kvm *kvm)
+{
+	int err;
+	unsigned long i;
+	unsigned int order;
+	struct kvm_vcpu *vcpu;
+
+	if (!system_supports_hdbss())
+		return 0;
+
+	if (kvm->dirty_ring_size) /* Don't support HDBSS in dirty ring mode */
+		return 0;
+
+	if (kvm->arch.enable_hdbss) /* Already On */
+		return 0;
+
+	/* Turn it on */
+	order = hdbss_auto_select_order(kvm);
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		err = kvm_arm_vcpu_alloc_hdbss(vcpu, order);
+		if (err)
+			goto error_alloc;
+	}
+
+	kvm->arch.enable_hdbss = true;
+	kvm->arch.mmu.vtcr |= VTCR_EL2_HD | VTCR_EL2_HDBSS | VTCR_EL2_HA;
+
+	/*
+	 * 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);
+
+	return 0;
+
+error_alloc:
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		if (vcpu->arch.hdbss.base_phys)
+			kvm_arm_vcpu_free_hdbss(vcpu);
+
+	pr_warn_once("kvm: failed to allocate HDBSS buffers (order=%u), "
+		     "falling back to software dirty tracking\n", order);
+	return -ENOMEM;
+}
+
+void kvm_arm_disable_hdbss_global(struct kvm *kvm)
+{
+	unsigned long i;
+	struct kvm_vcpu *vcpu;
+
+	if (!kvm->arch.enable_hdbss) /* Already Off */
+		return;
+
+	/* Turn it off */
+	kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS | VTCR_EL2_HA);
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_arm_vcpu_free_hdbss(vcpu);
+
+	kvm->arch.enable_hdbss = false;
+}
+
+void kvm_arm_hdbss_on_dirty_logging_change(struct kvm *kvm, int nr_memslots_logging)
+{
+	/*
+	 * Called from kvm_arch_commit_memory_region() under kvm->slots_lock.
+	 * All state transitions are serialized by slots_lock.
+	 */
+	if (nr_memslots_logging > 0 && !kvm->arch.enable_hdbss)
+		kvm_arm_enable_hdbss_global(kvm);
+	else if (nr_memslots_logging == 0 && kvm->arch.enable_hdbss)
+		kvm_arm_disable_hdbss_global(kvm);
+}
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 91a7dfad668660..21ec456ecc411a 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -731,9 +731,23 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
 	if (prot & KVM_PGTABLE_PROT_R)
 		attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;
 
-	if (prot & KVM_PGTABLE_PROT_W)
+	if (prot & KVM_PGTABLE_PROT_W) {
 		attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
 
+		/*
+		 * Set DBM bit for writable non-device pages if the page-table
+		 * has KVM_PGTABLE_S2_DBM flag (system supports HDBSS).
+		 *
+		 * For stage 2 translations using Indirect permissions, if the
+		 * Effective value of VTCR_EL2.HD is 0, then dirty state is
+		 * managed by software. Hardware only updates the dirty state
+		 * when VTCR_EL2.HD=1 (HDBSS enabled).
+		 */
+		if ((pgt->flags & KVM_PGTABLE_S2_DBM) &&
+		    !(prot & KVM_PGTABLE_PROT_DEVICE))
+			attr |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;
+	}
+
 	if (!kvm_lpa2_is_enabled())
 		attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
 
@@ -1367,9 +1381,26 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
 	if (prot & KVM_PGTABLE_PROT_R)
 		set |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;
 
-	if (prot & KVM_PGTABLE_PROT_W)
+	if (prot & KVM_PGTABLE_PROT_W) {
 		set |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
 
+		/*
+		 * No DEVICE filter needed here: relax_perms is only called
+		 * on FSC_PERM faults. Device pages always get full RW from
+		 * initial mapping and are never write-protected during
+		 * migration, so they never trigger a permission fault.
+		 */
+		if (pgt->flags & KVM_PGTABLE_S2_DBM)
+			set |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;
+	} else {
+		/*
+		 * Clear DBM on W→RO downgrade to prevent hardware from
+		 * silently upgrading RO+DBM back to W+dirty, which would
+		 * bypass KVM's write tracking and cause data corruption.
+		 */
+		clr |= KVM_PTE_LEAF_ATTR_HI_S2_DBM;
+	}
+
 	ret = stage2_set_xn_attr(prot, &xn);
 	if (ret)
 		return ret;
diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c
index bbe9cebd3d9d57..fe72944bfd3d5b 100644
--- a/arch/arm64/kvm/hyp/vhe/switch.c
+++ b/arch/arm64/kvm/hyp/vhe/switch.c
@@ -22,6 +22,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_dirty_bit.h>
 #include <asm/fpsimd.h>
 #include <asm/debug-monitors.h>
 #include <asm/processor.h>
@@ -213,6 +214,19 @@ static void __vcpu_put_deactivate_traps(struct kvm_vcpu *vcpu)
 	local_irq_restore(flags);
 }
 
+static void __load_hdbss(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+
+	if (!kvm->arch.enable_hdbss)
+		return;
+
+	write_sysreg_s(vcpu->arch.hdbss.hdbssbr_el2, SYS_HDBSSBR_EL2);
+	write_sysreg_s(vcpu->arch.hdbss.hdbssprod_el2, SYS_HDBSSPROD_EL2);
+
+	isb();
+}
+
 void kvm_vcpu_load_vhe(struct kvm_vcpu *vcpu)
 {
 	host_data_ptr(host_ctxt)->__hyp_running_vcpu = vcpu;
@@ -220,6 +234,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);
+	__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 6c941aaa10c639..484f48dae0003c 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -16,6 +16,7 @@
 #include <asm/cacheflush.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_dirty_bit.h>
 #include <asm/kvm_pgtable.h>
 #include <asm/kvm_pkvm.h>
 #include <asm/kvm_asm.h>
@@ -1014,6 +1015,9 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
 	if (err)
 		goto out_free_pgtable;
 
+	if (system_supports_hdbss())
+		pgt->flags |= KVM_PGTABLE_S2_DBM;
+
 	mmu->pgt = pgt;
 	if (is_protected_kvm_enabled())
 		return 0;
@@ -1027,8 +1031,12 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
 	for_each_possible_cpu(cpu)
 		*per_cpu_ptr(mmu->last_vcpu_ran, cpu) = -1;
 
-	 /* The eager page splitting is disabled by default */
-	mmu->split_page_chunk_size = KVM_ARM_EAGER_SPLIT_CHUNK_SIZE_DEFAULT;
+	 /* The eager page splitting is disabled by default if system has no HDBSS */
+	if (system_supports_hdbss())
+		mmu->split_page_chunk_size = 256 * 1024 * PAGE_SIZE;
+	else
+		mmu->split_page_chunk_size = KVM_ARM_EAGER_SPLIT_CHUNK_SIZE_DEFAULT;
+
 	mmu->split_page_cache.gfp_zero = __GFP_ZERO;
 
 	mmu->pgd_phys = __pa(pgt->pgd);
@@ -2234,6 +2242,7 @@ int kvm_handle_guest_sea(struct kvm_vcpu *vcpu)
 }
 
 /**
+
  * kvm_handle_guest_abort - handles all 2nd stage aborts
  * @vcpu:	the VCPU pointer
  *
@@ -2271,6 +2280,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
 
 	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
 
+	if (esr_iss2_is_hdbssf(esr))
+		return kvm_handle_hdbss_fault(vcpu);
+
 	if (esr_fsc_is_translation_fault(esr)) {
 		/* Beyond sanitised PARange (which is the IPA limit) */
 		if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
@@ -2576,6 +2588,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 {
 	bool log_dirty_pages = new && new->flags & KVM_MEM_LOG_DIRTY_PAGES;
 
+	kvm_arm_hdbss_on_dirty_logging_change(kvm,
+		atomic_read(&kvm->nr_memslots_dirty_logging));
+
 	/*
 	 * At this point memslot has been committed and there is an
 	 * allocated dirty_bitmap[], dirty pages will be tracked while the
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index b963fd975aacaf..d8104bcbd9ffad 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -27,6 +27,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_dirty_bit.h>
 #include <asm/kvm_nested.h>
 #include <asm/virt.h>
 
@@ -161,6 +162,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->kvm->arch.enable_hdbss)
+		kvm_arm_vcpu_free_hdbss(vcpu);
 }
 
 static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 9b85a84f6fd494..a87706c9d160e0 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -69,6 +69,7 @@ HAS_VA52
 HAS_VIRT_HOST_EXTN
 HAS_WFXT
 HAS_XNX
+HAS_HDBSS
 HAFT
 HW_DBM
 KVM_HVHE

3/2 2026/07/10 06:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11661
							output: 206
							thoughts: 1325
						

Thoughts:
**Analysis of HDBSS Patch for KVM on arm64**

Okay, so I've got this patch introducing HDBSS support for KVM on arm64. My initial assessment is that this is a functional change, a pretty significant one, to the core KVM logic. Therefore, fuzzing is definitely warranted. Given my expertise, I need to pinpoint the critical areas for fuzzing and the right configuration to enable this.

First, let's identify the specific functions this patch touches. Looks like it's adding new files `arch/arm64/kvm/dirty_bit.c`, `arch/arm64/include/asm/kvm_dirty_bit.h`, and modifying several existing KVM files. I see modifications in `kvm_arch_vcpu_create`, `kvm_arch_vcpu_put`, `check_vcpu_requests`, and the like – core KVM stuff. I need to dig deeper into the HDBSS-specific functions.

I can see some key functions related to the HDBSS implementation that are added/modified. These are my main targets:
- `kvm_arm_vcpu_alloc_hdbss`
- `kvm_arm_vcpu_free_hdbss`
- `kvm_flush_hdbss_buffer`
- `kvm_handle_hdbss_fault`
- `kvm_arm_enable_hdbss_global`
- `kvm_arm_disable_hdbss_global`
- `kvm_arm_hdbss_on_dirty_logging_change`
- `kvm_arch_sync_dirty_log`

Now, let's check for any specific configuration options this patch introduces. Looking at the `Makefile`, I see that the `dirty_bit.o` file is being unconditionally built when KVM is enabled. So, the primary configuration needed is `KVM`. Nothing else appears to be added in the Kconfig or similar files.

Initially, I'd thought about omitting static functions like `kvm_arm_enable_hdbss_global` and `kvm_arm_disable_hdbss_global` from the `FocusSymbols` list, assuming the fuzzer might not directly target them. However, for coverage and to guide the fuzzer, including them makes sense.

After some more thought, I've decided to include `kvm_arch_sync_dirty_log`, it's a critical function for dirty log synchronization. Now, `kvm_arch_commit_memory_region` is also a critical component to fuzz. Avoiding `kvm_handle_guest_abort` as it's likely a hot-path function and might be less profitable for fuzzing.

My reasoning is this: This patch fundamentally changes how dirty page logging and memory management work within KVM on arm64. Since this is an integration that will be accessible to userspace via the KVM ioctls, this is worth fuzzing and including this critical component will help.

So, here's my plan to call `set-results`:

`WorthFuzzing: true`
`FocusSymbols`:
- kvm_arm_vcpu_alloc_hdbss
- kvm_arm_vcpu_free_hdbss
- kvm_flush_hdbss_buffer
- kvm_handle_hdbss_fault
- kvm_arm_enable_hdbss_global
- kvm_arm_disable_hdbss_global
- kvm_arm_hdbss_on_dirty_logging_change
- kvm_arch_sync_dirty_log
`EnableConfigs`:
- KVM

I'm confident this is the right approach to ensure this patch gets thorough fuzzing coverage.



4/2 2026/07/10 06:12 tool set-results
0m Args:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvm_arm_vcpu_alloc_hdbss",
    "kvm_arm_vcpu_free_hdbss",
    "kvm_flush_hdbss_buffer",
    "kvm_handle_hdbss_fault",
    "kvm_arm_enable_hdbss_global",
    "kvm_arm_disable_hdbss_global",
    "kvm_arm_hdbss_on_dirty_logging_change",
    "kvm_arch_sync_dirty_log"
  ],
  "Reasoning": "The patch introduces Hardware Dirty state tracking structure (HDBSS) support for KVM on arm64. It modifies core KVM logic for dirty page logging and memory management, which is reachable from userspace via KVM ioctls and guest execution.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvm_arm_vcpu_alloc_hdbss",
    "kvm_arm_vcpu_free_hdbss",
    "kvm_flush_hdbss_buffer",
    "kvm_handle_hdbss_fault",
    "kvm_arm_enable_hdbss_global",
    "kvm_arm_disable_hdbss_global",
    "kvm_arm_hdbss_on_dirty_logging_change",
    "kvm_arch_sync_dirty_log"
  ],
  "Reasoning": "The patch introduces Hardware Dirty state tracking structure (HDBSS) support for KVM on arm64. It modifies core KVM logic for dirty page logging and memory management, which is reachable from userspace via KVM ioctls and guest execution.",
  "WorthFuzzing": true
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)