AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/01 16:18 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvm_arch_vm_ioctl",
    "kvm_vm_ioctl_enable_cap",
    "kvm_tdp_mmu_map"
  ],
  "Reasoning": "The patch introduces a new KVM capability `KVM_CAP_EVER_MAPPED` and a new ioctl `KVM_GET_EVER_MAPPED_LOG` to track which guest pages have ever been mapped. This is functional and reachable from userspace via KVM ioctls. The feature requires `CONFIG_KVM` and is specific to x86. We focus on the ioctl entry points and the TDP MMU page fault handler where the tracking is updated.",
  "WorthFuzzing": true
}

1/1 2026/08/01 16:18 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 01345aed41c124ceb491a5ac478de8760e408332\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Aug 1 16:18:18 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst\nindex a5f9ee92f43e8..ce6e1d15d48d5 100644\n--- a/Documentation/virt/kvm/api.rst\n+++ b/Documentation/virt/kvm/api.rst\n@@ -6566,6 +6566,53 @@ KVM_S390_KEYOP_SSKE\n   Sets the storage key for the guest address ``guest_addr`` to the key\n   specified in ``key``, returning the previous value in ``key``.\n \n+4.145 KVM_GET_EVER_MAPPED_LOG\n+-----------------------------\n+\n+:Capability: KVM_CAP_EVER_MAPPED\n+:Architectures: x86\n+:Type: vm ioctl\n+:Parameters: struct kvm_ever_mapped_log\n+:Returns: 0 on success, -ERRNO on error\n+\n+Errors:\n+\n+  ======     ============================================================\n+  ENOENT     KVM_CAP_EVER_MAPPED has not been enabled for this VM\n+  EINVAL     ``granule_shift`` is below 21 (internal tracking granularity) or\n+             above 63\n+  EINVAL     ``first_granule`` + ``num_granules`` extendends beyond the maxgpa\n+             set up when KVM_CAP_EVER_MAPPED was enabled\n+  EINVAL     ``flags`` is not 0\n+  EFAULT     copy_{from,to}_user of ``bitmap`` failed, e.g., bitmap wasn't\n+             sufficiently sized\n+  ENOMEM     setting up temporary bitmap for copying to userspace failed\n+  ======     ============================================================\n+\n+This requires KVM_CAP_EVER_MAPPED to have been enabled for the VM with a maxgpa\n+parameter.\n+\n+::\n+\n+  struct kvm_ever_mapped_log {\n+\t__u64 first_granule;\n+\t__u64 num_granules;\n+\t__u32 granule_shift;\n+\t__u32 flags;\n+\tunion {\n+\t\tvoid __user *bitmap;\n+\t\t__u64 padding;\n+\t};\n+\t__u64 reserved[4];\n+  };\n+\n+``first_granule``, ``num_granules``, and ``granule_shift`` encode the GPA range\n+the caller inquires about. For example, values of 2, 25, and 21, respectively,\n+inquire about the address range [4MB, 54MB). The caller provides a ``bitmap``\n+of the required length (in the above case 4 bytes). The call will write a 1 if\n+any memory in the granule has been mapped at some point since\n+KVM_CAP_EVER_MAPPED was enabled, 0 if not.\n+\n .. _kvm_run:\n \n 5. The kvm_run structure\n@@ -8949,6 +8996,26 @@ enabled, cmma can't be enabled anymore and pfmfi and the storage key\n interpretation are disabled. If cmma has already been enabled or the\n hpage_2g module parameter is not set to 1, -EINVAL is returned.\n \n+7.48 KVM_CAP_EVER_MAPPED\n+------------------------\n+\n+:Architectures: x86\n+:Parameters: args[0] - maximum GPA to track mapped memory\n+:Returns: 0 on success, -EOPNOTSUPP if TDP is not available, -EINVAL if args[0]\n+          is 0 or beyond the maximum possible GPA, -ENOMEM if tracking setup\n+          failed, -EEXIST if already set up.\n+\n+The presence of this capability indicates that KVM can track if pages have ever\n+been mapped by the guest. This allows a conservative estimate of which pages\n+are not zero any more.\n+\n+On enabling the capability, the caller provides a max GPA value. KVM will then\n+track GPAs between 0 and this value. Note that this capability can be enabled\n+at any time, but it is strongly recommended to enable it before vCPUs start\n+running. Any page accesses by the guest before capability enablement will not\n+be tracked. The max GPA value can only be set once; subsequent attempts to\n+enable the capability with a different or even same value will fail.\n+\n 8. Other capabilities.\n ======================\n \ndiff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h\nindex b517257a63153..c607a9193f400 100644\n--- a/arch/x86/include/asm/kvm_host.h\n+++ b/arch/x86/include/asm/kvm_host.h\n@@ -1533,6 +1533,15 @@ struct kvm_arch {\n \t */\n \tbool shadow_root_allocated;\n \n+\t/*\n+\t * Tracks which guest pages have ever been mapped. This allows\n+\t * tracking which memory is guaranteed to still be zero, e.g., for\n+\t * supporting the HvExtCallGetBootZeroedMemory enlightenment.\n+\t * The granularity is defined by KVM_EVER_MAPPED_SHIFT.\n+\t */\n+\tunsigned long *ever_mapped_bitmap;\n+\tu64 ever_mapped_max_gpa;\n+\n #ifdef CONFIG_KVM_EXTERNAL_WRITE_TRACKING\n \t/*\n \t * If set, the VM has (or had) an external write tracking user, and\ndiff --git a/arch/x86/kvm/mmu/ever_mapped.h b/arch/x86/kvm/mmu/ever_mapped.h\nnew file mode 100644\nindex 0000000000000..f795337e68486\n--- /dev/null\n+++ b/arch/x86/kvm/mmu/ever_mapped.h\n@@ -0,0 +1,33 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef __KVM_X86_EVER_MAPPED_H\n+#define __KVM_X86_EVER_MAPPED_H\n+\n+#include \u003clinux/kvm_host.h\u003e\n+\n+/*\n+ * Track if pages have ever been mapped at an internal granularity of 2 MB.\n+ */\n+#define KVM_EVER_MAPPED_SHIFT 21\n+\n+static inline void kvm_ever_mapped_set_range(struct kvm *kvm, gfn_t gfn,\n+\t\t\t\t\t     u64 npages)\n+{\n+\tconst unsigned int shift = KVM_EVER_MAPPED_SHIFT - PAGE_SHIFT;\n+\tunsigned long start = gfn \u003e\u003e shift;\n+\tunsigned long end = (gfn + npages + (1UL \u003c\u003c shift) - 1) \u003e\u003e shift;\n+\tunsigned long i;\n+\n+\tend = min(end, kvm-\u003earch.ever_mapped_max_gpa \u003e\u003e KVM_EVER_MAPPED_SHIFT);\n+\tfor (i = start; i \u003c end; i++) {\n+\t\t/*\n+\t\t * re-mapping zapped pages and breaking up of huge pages can\n+\t\t * trigger a number of sets on already set bits, so test first\n+\t\t * before atomic-set. Since bits can never be unset again, this\n+\t\t * is safe against races.\n+\t\t */\n+\t\tif (!test_bit(i, kvm-\u003earch.ever_mapped_bitmap))\n+\t\t\tset_bit(i, kvm-\u003earch.ever_mapped_bitmap);\n+\t}\n+}\n+\n+#endif /* __KVM_X86_EVER_MAPPED_H */\ndiff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c\nindex ce3f2efadb05b..ea2a37a04b2ff 100644\n--- a/arch/x86/kvm/mmu/tdp_mmu.c\n+++ b/arch/x86/kvm/mmu/tdp_mmu.c\n@@ -1,6 +1,7 @@\n // SPDX-License-Identifier: GPL-2.0\n #define pr_fmt(fmt) KBUILD_MODNAME \": \" fmt\n \n+#include \"ever_mapped.h\"\n #include \"mmu.h\"\n #include \"mmu_internal.h\"\n #include \"mmutrace.h\"\n@@ -554,6 +555,17 @@ static int __handle_changed_spte(struct kvm *kvm, struct kvm_mmu_page *sp,\n \t\treturn 0;\n \t}\n \n+\t/*\n+\t * Whenever a page becomes a fresh leaf, mark the memory as mapped.\n+\t * On hugepage breakup, this triggers for each new lower-level page,\n+\t * even though the memory was already marked when the hugepage was\n+\t * mapped, but the overhead is negligible.\n+\t */\n+\tif (unlikely(kvm-\u003earch.ever_mapped_bitmap) \u0026\u0026\n+\t    is_leaf \u0026\u0026 !was_leaf) {\n+\t\tkvm_ever_mapped_set_range(kvm, gfn, KVM_PAGES_PER_HPAGE(level));\n+\t}\n+\n \t/*\n \t * Recursively handle child PTs if the change removed a subtree from\n \t * the paging structure.  Note the WARN on the PFN changing without the\ndiff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c\nindex 0626e835e9eb7..89cbcf8399f49 100644\n--- a/arch/x86/kvm/x86.c\n+++ b/arch/x86/kvm/x86.c\n@@ -25,6 +25,7 @@\n #include \"tss.h\"\n #include \"regs.h\"\n #include \"kvm_emulate.h\"\n+#include \"mmu/ever_mapped.h\"\n #include \"mmu/page_track.h\"\n #include \"x86.h\"\n #include \"cpuid.h\"\n@@ -2391,6 +2392,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)\n \tcase KVM_CAP_READONLY_MEM:\n \t\tr = kvm ? kvm_arch_has_readonly_mem(kvm) : 1;\n \t\tbreak;\n+\tcase KVM_CAP_EVER_MAPPED:\n+\t\tr = (tdp_enabled \u0026\u0026 IS_ENABLED(CONFIG_X86_64));\n+\t\tbreak;\n \tdefault:\n \t\tbreak;\n \t}\n@@ -4190,6 +4194,36 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,\n \t\tmutex_unlock(\u0026kvm-\u003elock);\n \t\tbreak;\n \t}\n+\tcase KVM_CAP_EVER_MAPPED: {\n+\t\tunsigned long *mapped_bitmap;\n+\t\tunsigned long num_granules;\n+\n+\t\tr = 0;\n+\t\tmutex_lock(\u0026kvm-\u003elock);\n+\t\tif (!tdp_enabled) {\n+\t\t\tr = -EOPNOTSUPP;\n+\t\t} else if (kvm-\u003earch.ever_mapped_bitmap) {\n+\t\t\tr = -EEXIST;\n+\t\t} else if (cap-\u003eargs[0] == 0 ||\n+\t\t\t   cap-\u003eargs[0] \u003e (1ULL \u003c\u003c kvm_host.maxphyaddr)) {\n+\t\t\tr = -EINVAL;\n+\t\t} else {\n+\t\t\tnum_granules = DIV_ROUND_UP(cap-\u003eargs[0], 1ULL \u003c\u003c KVM_EVER_MAPPED_SHIFT);\n+\t\t\tmapped_bitmap =\n+\t\t\t\tkvcalloc(BITS_TO_LONGS(num_granules),\n+\t\t\t\t\t sizeof(long), GFP_KERNEL_ACCOUNT);\n+\t\t\tif (!mapped_bitmap)\n+\t\t\t\tr = -ENOMEM;\n+\t\t\telse {\n+\t\t\t\twrite_lock(\u0026kvm-\u003emmu_lock);\n+\t\t\t\tkvm-\u003earch.ever_mapped_bitmap = mapped_bitmap;\n+\t\t\t\tkvm-\u003earch.ever_mapped_max_gpa = num_granules \u003c\u003c KVM_EVER_MAPPED_SHIFT;\n+\t\t\t\twrite_unlock(\u0026kvm-\u003emmu_lock);\n+\t\t\t}\n+\t\t}\n+\t\tmutex_unlock(\u0026kvm-\u003elock);\n+\t\tbreak;\n+\t}\n \tdefault:\n \t\tr = -EINVAL;\n \t\tbreak;\n@@ -4197,6 +4231,73 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,\n \treturn r;\n }\n \n+static int kvm_vm_ioctl_get_ever_mapped_log(struct kvm *kvm,\n+\t\t\t\t\t    struct kvm_ever_mapped_log *log)\n+{\n+\tu64 max_granules;\n+\tunsigned int coarseness;\n+\tunsigned long *bitmap;\n+\tint r;\n+\n+\tif (!kvm-\u003earch.ever_mapped_bitmap)\n+\t\treturn -ENOENT;\n+\n+\tif (log-\u003eflags)\n+\t\treturn -EINVAL;\n+\n+\tif (log-\u003egranule_shift \u003c KVM_EVER_MAPPED_SHIFT || log-\u003egranule_shift \u003e= 64)\n+\t\treturn -EINVAL;\n+\n+\tmax_granules = kvm-\u003earch.ever_mapped_max_gpa \u003e\u003e log-\u003egranule_shift;\n+\tif (log-\u003enum_granules \u003e max_granules ||\n+\t    log-\u003efirst_granule \u003e max_granules - log-\u003enum_granules)\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * For the case where the request uses the same granularity as our internal\n+\t * tracking, and we are byte-aligned (the expected common case), we can\n+\t * just copy_to_user. Otherwise, we have to create a new bitmap to pass.\n+\t *\n+\t * We do not lock against concurrent vCPUs mapping new memory on any of\n+\t * these operations. Bits are set atomically and never cleared, so any race\n+\t * here is indistinguishable from a write happening after this handler\n+\t * finishes but before the caller reads the results.\n+\t */\n+\tcoarseness = log-\u003egranule_shift - KVM_EVER_MAPPED_SHIFT;\n+\tif (coarseness == 0 \u0026\u0026 !(log-\u003efirst_granule \u0026 7) \u0026\u0026 !(log-\u003enum_granules \u0026 7)) {\n+\t\tif (copy_to_user(log-\u003ebitmap,\n+\t\t\t\t (u8 *)kvm-\u003earch.ever_mapped_bitmap + log-\u003efirst_granule / 8,\n+\t\t\t\t log-\u003enum_granules / 8))\n+\t\t\treturn -EFAULT;\n+\t\treturn 0;\n+\t}\n+\n+\tbitmap = kvzalloc(DIV_ROUND_UP(log-\u003enum_granules, 8), GFP_KERNEL_ACCOUNT);\n+\tif (!bitmap)\n+\t\treturn -ENOMEM;\n+\n+\tfor (u64 gran = log-\u003efirst_granule;\n+\t     gran \u003c log-\u003efirst_granule + log-\u003enum_granules;\n+\t     gran++) {\n+\t\tunsigned long start = gran \u003c\u003c coarseness;\n+\t\tunsigned long end = start + (1UL \u003c\u003c coarseness);\n+\n+\t\tif (find_next_bit(kvm-\u003earch.ever_mapped_bitmap, end, start) \u003c end)\n+\t\t\t__set_bit(gran - log-\u003efirst_granule, bitmap);\n+\t}\n+\n+\tif (copy_to_user(log-\u003ebitmap, bitmap, DIV_ROUND_UP(log-\u003enum_granules, 8))) {\n+\t\tr = -EFAULT;\n+\t\tgoto out_free;\n+\t}\n+\n+\tr = 0;\n+\n+out_free:\n+\tkvfree(bitmap);\n+\treturn r;\n+}\n+\n #ifdef CONFIG_KVM_COMPAT\n /* for KVM_X86_SET_MSR_FILTER */\n struct kvm_msr_filter_range_compat {\n@@ -4710,6 +4811,15 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\n \t\tr = kvm_vm_ioctl_set_msr_filter(kvm, \u0026filter);\n \t\tbreak;\n \t}\n+\tcase KVM_GET_EVER_MAPPED_LOG: {\n+\t\tstruct kvm_ever_mapped_log mapped_log;\n+\n+\t\tif (copy_from_user(\u0026mapped_log, argp, sizeof(mapped_log)))\n+\t\t\treturn -EFAULT;\n+\n+\t\tr = kvm_vm_ioctl_get_ever_mapped_log(kvm, \u0026mapped_log);\n+\t\tbreak;\n+\t}\n \tdefault:\n \t\tr = -ENOTTY;\n \t}\ndiff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h\nindex 419011097fa8e..d0be94946a77c 100644\n--- a/include/uapi/linux/kvm.h\n+++ b/include/uapi/linux/kvm.h\n@@ -997,6 +997,7 @@ struct kvm_enable_cap {\n #define KVM_CAP_S390_KEYOP 247\n #define KVM_CAP_S390_VSIE_ESAMODE 248\n #define KVM_CAP_S390_HPAGE_2G 249\n+#define KVM_CAP_EVER_MAPPED 250\n \n struct kvm_irq_routing_irqchip {\n \t__u32 irqchip;\n@@ -1670,4 +1671,18 @@ struct kvm_pre_fault_memory {\n \t__u64 padding[5];\n };\n \n+#define KVM_GET_EVER_MAPPED_LOG  _IOW(KVMIO,  0xd6, struct kvm_ever_mapped_log)\n+\n+struct kvm_ever_mapped_log {\n+\t__u64 first_granule;\n+\t__u64 num_granules;\n+\t__u32 granule_shift;\n+\t__u32 flags;\n+\tunion {\n+\t\tvoid __user *bitmap;\n+\t\t__u64 padding;\n+\t};\n+\t__u64 reserved[4];\n+};\n+\n #endif /* __LINUX_KVM_H */\ndiff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm\nindex 4ace12606e937..1eb0bac1920dc 100644\n--- a/tools/testing/selftests/kvm/Makefile.kvm\n+++ b/tools/testing/selftests/kvm/Makefile.kvm\n@@ -162,6 +162,7 @@ TEST_GEN_PROGS_x86 += rseq_test\n TEST_GEN_PROGS_x86 += steal_time\n TEST_GEN_PROGS_x86 += system_counter_offset_test\n TEST_GEN_PROGS_x86 += pre_fault_memory_test\n+TEST_GEN_PROGS_x86 += ever_mapped_test\n \n # Compiled outputs used by test targets\n TEST_GEN_PROGS_EXTENDED_x86 += x86/nx_huge_pages_test\ndiff --git a/tools/testing/selftests/kvm/ever_mapped_test.c b/tools/testing/selftests/kvm/ever_mapped_test.c\nnew file mode 100644\nindex 0000000000000..76723f0c9ee2c\n--- /dev/null\n+++ b/tools/testing/selftests/kvm/ever_mapped_test.c\n@@ -0,0 +1,191 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * KVM ever-mapped bitmap test\n+ *\n+ * Copyright (C) 2026, Nutanix, Inc.\n+ */\n+\n+#include \u003ctest_util.h\u003e\n+#include \u003ckvm_util.h\u003e\n+#include \u003cprocessor.h\u003e\n+\n+#define KiB 1024u\n+#define MiB (1024 * KiB)\n+\n+static void guest_code(uint64_t base_gpa, size_t len)\n+{\n+\tGUEST_DONE();\n+}\n+\n+static void assert_bitmaps_equal(u8 expected[], u8 actual[], size_t len)\n+{\n+\tfor (size_t i = 0; i \u003c len; i++) {\n+\t\tTEST_ASSERT(expected[i] == actual[i],\n+\t\t\t    \"byte %ld, expected 0x%02x, got 0x%02x\",\n+\t\t\t    i, expected[i], actual[i]);\n+\t}\n+}\n+\n+static void pre_fault(struct kvm_vcpu *vcpu, u64 start, u64 len)\n+{\n+\tstruct kvm_pre_fault_memory range = {\n+\t\t.gpa = start,\n+\t\t.size = len,\n+\t\t.flags = 0,\n+\t};\n+\tvcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, \u0026range);\n+}\n+\n+static void test_one_page(void)\n+{\n+\tstruct kvm_vm *vm;\n+\tstruct kvm_vcpu *vcpu;\n+\tstruct kvm_pre_fault_memory range = {\n+\t\t.gpa = 0x0,\n+\t\t.size = PAGE_SIZE,\n+\t\t.flags = 0,\n+\t};\n+\tunsigned char mapped_bitmap;\n+\tstruct kvm_ever_mapped_log log = {\n+\t\t.first_granule = 0,\n+\t\t.num_granules = 1,\n+\t\t.granule_shift = 21,\n+\t\t.flags = 0,\n+\t\t.bitmap = \u0026mapped_bitmap,\n+\t};\n+\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n+\n+\tvm_enable_cap(vm, KVM_CAP_EVER_MAPPED, PAGE_SIZE);\n+\tvcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, \u0026range);\n+\n+\tvm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tTEST_ASSERT(mapped_bitmap == 0x1, \"expected 0x1, got 0x%x\", mapped_bitmap);\n+}\n+\n+/*\n+ * Add 64MB or memory at GPA 16MB ( --\u003e [16MB, 80MB) ),\n+ * pre-fault [16MB, 48MB), request and check bitmap for [16MB, 80MB).\n+ */\n+static void test_one_block(void)\n+{\n+\tint ret;\n+\tstruct kvm_vm *vm;\n+\tstruct kvm_vcpu *vcpu;\n+\tconst uint64_t map_start = 0x1000000;\n+\tconst uint64_t map_len = 0x4000000;\n+\tu8 mapped_bitmap[4] = { 0xa5, 0xa5, 0xa5, 0xa5 };\n+\tu8 expected_bitmap[4] = { 0xff, 0xff, 0x00, 0x00 };\n+\tstruct kvm_ever_mapped_log log = {\n+\t\t.first_granule = 0x8,\n+\t\t.num_granules = 0x20,\n+\t\t.granule_shift = 21,\n+\t\t.flags = 0,\n+\t\t.bitmap = mapped_bitmap,\n+\t};\n+\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n+\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, map_start, 1, map_len / PAGE_SIZE, 0);\n+\n+\tret = __vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tTEST_ASSERT(ret \u0026\u0026 errno == ENOENT,\n+\t\t    \"expected ENOENT when querying ever-mapped log before enablement, got %d\",\n+\t\t    errno);\n+\tvm_enable_cap(vm, KVM_CAP_EVER_MAPPED, map_start + map_len);\n+\tpre_fault(vcpu, 16 * MiB, 32 * MiB);\n+\n+\tret = __vm_enable_cap(vm, KVM_CAP_EVER_MAPPED, PAGE_SIZE);\n+\tTEST_ASSERT(ret \u0026\u0026 errno == EEXIST,\n+\t\t    \"expected EEXIST when enabling KVM_CAP_EVER_MAPPED twice, got %d\",\n+\t\t    errno);\n+\n+\tvm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tassert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);\n+\n+\tlog.granule_shift = 22;\n+\tlog.first_granule = 0x4;\n+\tlog.num_granules = 0x10;\n+\tmemcpy(mapped_bitmap, (u8[]){ 0xa5, 0xa5, 0xa5, 0xa5 }, 4);\n+\tmemcpy(expected_bitmap, (u8[]){ 0xff, 0x00, 0xa5, 0xa5 }, 4);\n+\tvm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tassert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);\n+\n+\tlog.granule_shift = 23;\n+\tlog.first_granule = 0x2;\n+\tlog.num_granules = 0x8;\n+\tmemcpy(mapped_bitmap, (u8[]){ 0xa5, 0xa5, 0xa5, 0xa5 }, 4);\n+\tmemcpy(expected_bitmap, (u8[]){ 0x0f, 0xa5, 0xa5, 0xa5 }, 4);\n+\tvm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tassert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);\n+\n+\tlog.num_granules = 0xff;\n+\tret = __vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tTEST_ASSERT(ret \u0026\u0026 errno == EINVAL,\n+\t\t    \"expected EINVAL when querying beyond range, got %d\",\n+\t\t    errno);\n+\n+\tlog.num_granules = 0x10;\n+\tlog.granule_shift = 1;\n+\tret = __vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tTEST_ASSERT(ret \u0026\u0026 errno == EINVAL,\n+\t\t    \"expected EINVAL with too small grnaule shift, got %d\",\n+\t\t    errno);\n+}\n+\n+/*\n+ * Add 128MB or memory at GPA 32MB ( --\u003e [32MB, 160MB) ),\n+ * pre-fault [32MB, 64MB), and [90MB, 94MB),\n+ * request and check bitmap for [16MB, 120MB).\n+ */\n+static void test_two_blocks(void)\n+{\n+\tstruct kvm_vm *vm;\n+\tstruct kvm_vcpu *vcpu;\n+\tconst uint64_t map_start = 0x2000000;\n+\tconst uint64_t map_len = 0x8000000;\n+\tu8 mapped_bitmap[7] = { 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5 };\n+\tu8 expected_bitmap[7] = { 0x00, 0xff, 0xff, 0x00, 0x60, 0x00, 0x00 };\n+\tstruct kvm_ever_mapped_log log = {\n+\t\t.first_granule = 0x8,\n+\t\t.num_granules = 0x34,\n+\t\t.granule_shift = 21,\n+\t\t.flags = 0,\n+\t\t.bitmap = mapped_bitmap,\n+\t};\n+\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n+\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, map_start, 1, map_len / PAGE_SIZE, 0);\n+\n+\tvm_enable_cap(vm, KVM_CAP_EVER_MAPPED, map_start + map_len);\n+\tpre_fault(vcpu, 32 * MiB, 32 * MiB);\n+\tpre_fault(vcpu, 90 * MiB, 4 * MiB);\n+\n+\tvm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tassert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);\n+\n+\tlog.granule_shift = 22;\n+\tlog.first_granule = 0x4;\n+\tlog.num_granules = 0x1a;\n+\tmemcpy(mapped_bitmap, (u8[]){ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5}, 7);\n+\tmemcpy(expected_bitmap, (u8[]){ 0xf0, 0x0f, 0x0c, 0x00, 0xa5, 0xa5, 0xa5 }, 7);\n+\tvm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tassert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);\n+\n+\tlog.granule_shift = 23;\n+\tlog.first_granule = 0x2;\n+\tlog.num_granules = 0xd;\n+\tmemcpy(mapped_bitmap, (u8[]){ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5 }, 7);\n+\tmemcpy(expected_bitmap, (u8[]){ 0x3c, 0x02, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5 }, 7);\n+\tvm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, \u0026log);\n+\tassert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);\n+}\n+\n+int main(int argc, char *argv[])\n+{\n+\tTEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY));\n+\tTEST_REQUIRE(kvm_check_cap(KVM_CAP_EVER_MAPPED));\n+\n+\ttest_one_page();\n+\ttest_one_block();\n+\ttest_two_blocks();\n+}\n"
}

2/1 2026/08/01 16:18 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvm_arch_vm_ioctl",
    "kvm_vm_ioctl_enable_cap",
    "kvm_tdp_mmu_map"
  ],
  "Reasoning": "The patch introduces a new KVM capability `KVM_CAP_EVER_MAPPED` and a new ioctl `KVM_GET_EVER_MAPPED_LOG` to track which guest pages have ever been mapped. This is functional and reachable from userspace via KVM ioctls. The feature requires `CONFIG_KVM` and is specific to x86. We focus on the ioctl entry points and the TDP MMU page fault handler where the tracking is updated.",
  "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).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

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.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
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.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. 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 01345aed41c124ceb491a5ac478de8760e408332
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Aug 1 16:18:18 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index a5f9ee92f43e8..ce6e1d15d48d5 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -6566,6 +6566,53 @@ KVM_S390_KEYOP_SSKE
   Sets the storage key for the guest address ``guest_addr`` to the key
   specified in ``key``, returning the previous value in ``key``.
 
+4.145 KVM_GET_EVER_MAPPED_LOG
+-----------------------------
+
+:Capability: KVM_CAP_EVER_MAPPED
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: struct kvm_ever_mapped_log
+:Returns: 0 on success, -ERRNO on error
+
+Errors:
+
+  ======     ============================================================
+  ENOENT     KVM_CAP_EVER_MAPPED has not been enabled for this VM
+  EINVAL     ``granule_shift`` is below 21 (internal tracking granularity) or
+             above 63
+  EINVAL     ``first_granule`` + ``num_granules`` extendends beyond the maxgpa
+             set up when KVM_CAP_EVER_MAPPED was enabled
+  EINVAL     ``flags`` is not 0
+  EFAULT     copy_{from,to}_user of ``bitmap`` failed, e.g., bitmap wasn't
+             sufficiently sized
+  ENOMEM     setting up temporary bitmap for copying to userspace failed
+  ======     ============================================================
+
+This requires KVM_CAP_EVER_MAPPED to have been enabled for the VM with a maxgpa
+parameter.
+
+::
+
+  struct kvm_ever_mapped_log {
+	__u64 first_granule;
+	__u64 num_granules;
+	__u32 granule_shift;
+	__u32 flags;
+	union {
+		void __user *bitmap;
+		__u64 padding;
+	};
+	__u64 reserved[4];
+  };
+
+``first_granule``, ``num_granules``, and ``granule_shift`` encode the GPA range
+the caller inquires about. For example, values of 2, 25, and 21, respectively,
+inquire about the address range [4MB, 54MB). The caller provides a ``bitmap``
+of the required length (in the above case 4 bytes). The call will write a 1 if
+any memory in the granule has been mapped at some point since
+KVM_CAP_EVER_MAPPED was enabled, 0 if not.
+
 .. _kvm_run:
 
 5. The kvm_run structure
@@ -8949,6 +8996,26 @@ enabled, cmma can't be enabled anymore and pfmfi and the storage key
 interpretation are disabled. If cmma has already been enabled or the
 hpage_2g module parameter is not set to 1, -EINVAL is returned.
 
+7.48 KVM_CAP_EVER_MAPPED
+------------------------
+
+:Architectures: x86
+:Parameters: args[0] - maximum GPA to track mapped memory
+:Returns: 0 on success, -EOPNOTSUPP if TDP is not available, -EINVAL if args[0]
+          is 0 or beyond the maximum possible GPA, -ENOMEM if tracking setup
+          failed, -EEXIST if already set up.
+
+The presence of this capability indicates that KVM can track if pages have ever
+been mapped by the guest. This allows a conservative estimate of which pages
+are not zero any more.
+
+On enabling the capability, the caller provides a max GPA value. KVM will then
+track GPAs between 0 and this value. Note that this capability can be enabled
+at any time, but it is strongly recommended to enable it before vCPUs start
+running. Any page accesses by the guest before capability enablement will not
+be tracked. The max GPA value can only be set once; subsequent attempts to
+enable the capability with a different or even same value will fail.
+
 8. Other capabilities.
 ======================
 
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index b517257a63153..c607a9193f400 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1533,6 +1533,15 @@ struct kvm_arch {
 	 */
 	bool shadow_root_allocated;
 
+	/*
+	 * Tracks which guest pages have ever been mapped. This allows
+	 * tracking which memory is guaranteed to still be zero, e.g., for
+	 * supporting the HvExtCallGetBootZeroedMemory enlightenment.
+	 * The granularity is defined by KVM_EVER_MAPPED_SHIFT.
+	 */
+	unsigned long *ever_mapped_bitmap;
+	u64 ever_mapped_max_gpa;
+
 #ifdef CONFIG_KVM_EXTERNAL_WRITE_TRACKING
 	/*
 	 * If set, the VM has (or had) an external write tracking user, and
diff --git a/arch/x86/kvm/mmu/ever_mapped.h b/arch/x86/kvm/mmu/ever_mapped.h
new file mode 100644
index 0000000000000..f795337e68486
--- /dev/null
+++ b/arch/x86/kvm/mmu/ever_mapped.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_X86_EVER_MAPPED_H
+#define __KVM_X86_EVER_MAPPED_H
+
+#include <linux/kvm_host.h>
+
+/*
+ * Track if pages have ever been mapped at an internal granularity of 2 MB.
+ */
+#define KVM_EVER_MAPPED_SHIFT 21
+
+static inline void kvm_ever_mapped_set_range(struct kvm *kvm, gfn_t gfn,
+					     u64 npages)
+{
+	const unsigned int shift = KVM_EVER_MAPPED_SHIFT - PAGE_SHIFT;
+	unsigned long start = gfn >> shift;
+	unsigned long end = (gfn + npages + (1UL << shift) - 1) >> shift;
+	unsigned long i;
+
+	end = min(end, kvm->arch.ever_mapped_max_gpa >> KVM_EVER_MAPPED_SHIFT);
+	for (i = start; i < end; i++) {
+		/*
+		 * re-mapping zapped pages and breaking up of huge pages can
+		 * trigger a number of sets on already set bits, so test first
+		 * before atomic-set. Since bits can never be unset again, this
+		 * is safe against races.
+		 */
+		if (!test_bit(i, kvm->arch.ever_mapped_bitmap))
+			set_bit(i, kvm->arch.ever_mapped_bitmap);
+	}
+}
+
+#endif /* __KVM_X86_EVER_MAPPED_H */
diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index ce3f2efadb05b..ea2a37a04b2ff 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include "ever_mapped.h"
 #include "mmu.h"
 #include "mmu_internal.h"
 #include "mmutrace.h"
@@ -554,6 +555,17 @@ static int __handle_changed_spte(struct kvm *kvm, struct kvm_mmu_page *sp,
 		return 0;
 	}
 
+	/*
+	 * Whenever a page becomes a fresh leaf, mark the memory as mapped.
+	 * On hugepage breakup, this triggers for each new lower-level page,
+	 * even though the memory was already marked when the hugepage was
+	 * mapped, but the overhead is negligible.
+	 */
+	if (unlikely(kvm->arch.ever_mapped_bitmap) &&
+	    is_leaf && !was_leaf) {
+		kvm_ever_mapped_set_range(kvm, gfn, KVM_PAGES_PER_HPAGE(level));
+	}
+
 	/*
 	 * Recursively handle child PTs if the change removed a subtree from
 	 * the paging structure.  Note the WARN on the PFN changing without the
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0626e835e9eb7..89cbcf8399f49 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -25,6 +25,7 @@
 #include "tss.h"
 #include "regs.h"
 #include "kvm_emulate.h"
+#include "mmu/ever_mapped.h"
 #include "mmu/page_track.h"
 #include "x86.h"
 #include "cpuid.h"
@@ -2391,6 +2392,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_READONLY_MEM:
 		r = kvm ? kvm_arch_has_readonly_mem(kvm) : 1;
 		break;
+	case KVM_CAP_EVER_MAPPED:
+		r = (tdp_enabled && IS_ENABLED(CONFIG_X86_64));
+		break;
 	default:
 		break;
 	}
@@ -4190,6 +4194,36 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 		mutex_unlock(&kvm->lock);
 		break;
 	}
+	case KVM_CAP_EVER_MAPPED: {
+		unsigned long *mapped_bitmap;
+		unsigned long num_granules;
+
+		r = 0;
+		mutex_lock(&kvm->lock);
+		if (!tdp_enabled) {
+			r = -EOPNOTSUPP;
+		} else if (kvm->arch.ever_mapped_bitmap) {
+			r = -EEXIST;
+		} else if (cap->args[0] == 0 ||
+			   cap->args[0] > (1ULL << kvm_host.maxphyaddr)) {
+			r = -EINVAL;
+		} else {
+			num_granules = DIV_ROUND_UP(cap->args[0], 1ULL << KVM_EVER_MAPPED_SHIFT);
+			mapped_bitmap =
+				kvcalloc(BITS_TO_LONGS(num_granules),
+					 sizeof(long), GFP_KERNEL_ACCOUNT);
+			if (!mapped_bitmap)
+				r = -ENOMEM;
+			else {
+				write_lock(&kvm->mmu_lock);
+				kvm->arch.ever_mapped_bitmap = mapped_bitmap;
+				kvm->arch.ever_mapped_max_gpa = num_granules << KVM_EVER_MAPPED_SHIFT;
+				write_unlock(&kvm->mmu_lock);
+			}
+		}
+		mutex_unlock(&kvm->lock);
+		break;
+	}
 	default:
 		r = -EINVAL;
 		break;
@@ -4197,6 +4231,73 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 	return r;
 }
 
+static int kvm_vm_ioctl_get_ever_mapped_log(struct kvm *kvm,
+					    struct kvm_ever_mapped_log *log)
+{
+	u64 max_granules;
+	unsigned int coarseness;
+	unsigned long *bitmap;
+	int r;
+
+	if (!kvm->arch.ever_mapped_bitmap)
+		return -ENOENT;
+
+	if (log->flags)
+		return -EINVAL;
+
+	if (log->granule_shift < KVM_EVER_MAPPED_SHIFT || log->granule_shift >= 64)
+		return -EINVAL;
+
+	max_granules = kvm->arch.ever_mapped_max_gpa >> log->granule_shift;
+	if (log->num_granules > max_granules ||
+	    log->first_granule > max_granules - log->num_granules)
+		return -EINVAL;
+
+	/*
+	 * For the case where the request uses the same granularity as our internal
+	 * tracking, and we are byte-aligned (the expected common case), we can
+	 * just copy_to_user. Otherwise, we have to create a new bitmap to pass.
+	 *
+	 * We do not lock against concurrent vCPUs mapping new memory on any of
+	 * these operations. Bits are set atomically and never cleared, so any race
+	 * here is indistinguishable from a write happening after this handler
+	 * finishes but before the caller reads the results.
+	 */
+	coarseness = log->granule_shift - KVM_EVER_MAPPED_SHIFT;
+	if (coarseness == 0 && !(log->first_granule & 7) && !(log->num_granules & 7)) {
+		if (copy_to_user(log->bitmap,
+				 (u8 *)kvm->arch.ever_mapped_bitmap + log->first_granule / 8,
+				 log->num_granules / 8))
+			return -EFAULT;
+		return 0;
+	}
+
+	bitmap = kvzalloc(DIV_ROUND_UP(log->num_granules, 8), GFP_KERNEL_ACCOUNT);
+	if (!bitmap)
+		return -ENOMEM;
+
+	for (u64 gran = log->first_granule;
+	     gran < log->first_granule + log->num_granules;
+	     gran++) {
+		unsigned long start = gran << coarseness;
+		unsigned long end = start + (1UL << coarseness);
+
+		if (find_next_bit(kvm->arch.ever_mapped_bitmap, end, start) < end)
+			__set_bit(gran - log->first_granule, bitmap);
+	}
+
+	if (copy_to_user(log->bitmap, bitmap, DIV_ROUND_UP(log->num_granules, 8))) {
+		r = -EFAULT;
+		goto out_free;
+	}
+
+	r = 0;
+
+out_free:
+	kvfree(bitmap);
+	return r;
+}
+
 #ifdef CONFIG_KVM_COMPAT
 /* for KVM_X86_SET_MSR_FILTER */
 struct kvm_msr_filter_range_compat {
@@ -4710,6 +4811,15 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
 		r = kvm_vm_ioctl_set_msr_filter(kvm, &filter);
 		break;
 	}
+	case KVM_GET_EVER_MAPPED_LOG: {
+		struct kvm_ever_mapped_log mapped_log;
+
+		if (copy_from_user(&mapped_log, argp, sizeof(mapped_log)))
+			return -EFAULT;
+
+		r = kvm_vm_ioctl_get_ever_mapped_log(kvm, &mapped_log);
+		break;
+	}
 	default:
 		r = -ENOTTY;
 	}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 419011097fa8e..d0be94946a77c 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -997,6 +997,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_S390_KEYOP 247
 #define KVM_CAP_S390_VSIE_ESAMODE 248
 #define KVM_CAP_S390_HPAGE_2G 249
+#define KVM_CAP_EVER_MAPPED 250
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
@@ -1670,4 +1671,18 @@ struct kvm_pre_fault_memory {
 	__u64 padding[5];
 };
 
+#define KVM_GET_EVER_MAPPED_LOG  _IOW(KVMIO,  0xd6, struct kvm_ever_mapped_log)
+
+struct kvm_ever_mapped_log {
+	__u64 first_granule;
+	__u64 num_granules;
+	__u32 granule_shift;
+	__u32 flags;
+	union {
+		void __user *bitmap;
+		__u64 padding;
+	};
+	__u64 reserved[4];
+};
+
 #endif /* __LINUX_KVM_H */
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 4ace12606e937..1eb0bac1920dc 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -162,6 +162,7 @@ TEST_GEN_PROGS_x86 += rseq_test
 TEST_GEN_PROGS_x86 += steal_time
 TEST_GEN_PROGS_x86 += system_counter_offset_test
 TEST_GEN_PROGS_x86 += pre_fault_memory_test
+TEST_GEN_PROGS_x86 += ever_mapped_test
 
 # Compiled outputs used by test targets
 TEST_GEN_PROGS_EXTENDED_x86 += x86/nx_huge_pages_test
diff --git a/tools/testing/selftests/kvm/ever_mapped_test.c b/tools/testing/selftests/kvm/ever_mapped_test.c
new file mode 100644
index 0000000000000..76723f0c9ee2c
--- /dev/null
+++ b/tools/testing/selftests/kvm/ever_mapped_test.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KVM ever-mapped bitmap test
+ *
+ * Copyright (C) 2026, Nutanix, Inc.
+ */
+
+#include <test_util.h>
+#include <kvm_util.h>
+#include <processor.h>
+
+#define KiB 1024u
+#define MiB (1024 * KiB)
+
+static void guest_code(uint64_t base_gpa, size_t len)
+{
+	GUEST_DONE();
+}
+
+static void assert_bitmaps_equal(u8 expected[], u8 actual[], size_t len)
+{
+	for (size_t i = 0; i < len; i++) {
+		TEST_ASSERT(expected[i] == actual[i],
+			    "byte %ld, expected 0x%02x, got 0x%02x",
+			    i, expected[i], actual[i]);
+	}
+}
+
+static void pre_fault(struct kvm_vcpu *vcpu, u64 start, u64 len)
+{
+	struct kvm_pre_fault_memory range = {
+		.gpa = start,
+		.size = len,
+		.flags = 0,
+	};
+	vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, &range);
+}
+
+static void test_one_page(void)
+{
+	struct kvm_vm *vm;
+	struct kvm_vcpu *vcpu;
+	struct kvm_pre_fault_memory range = {
+		.gpa = 0x0,
+		.size = PAGE_SIZE,
+		.flags = 0,
+	};
+	unsigned char mapped_bitmap;
+	struct kvm_ever_mapped_log log = {
+		.first_granule = 0,
+		.num_granules = 1,
+		.granule_shift = 21,
+		.flags = 0,
+		.bitmap = &mapped_bitmap,
+	};
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+	vm_enable_cap(vm, KVM_CAP_EVER_MAPPED, PAGE_SIZE);
+	vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, &range);
+
+	vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	TEST_ASSERT(mapped_bitmap == 0x1, "expected 0x1, got 0x%x", mapped_bitmap);
+}
+
+/*
+ * Add 64MB or memory at GPA 16MB ( --> [16MB, 80MB) ),
+ * pre-fault [16MB, 48MB), request and check bitmap for [16MB, 80MB).
+ */
+static void test_one_block(void)
+{
+	int ret;
+	struct kvm_vm *vm;
+	struct kvm_vcpu *vcpu;
+	const uint64_t map_start = 0x1000000;
+	const uint64_t map_len = 0x4000000;
+	u8 mapped_bitmap[4] = { 0xa5, 0xa5, 0xa5, 0xa5 };
+	u8 expected_bitmap[4] = { 0xff, 0xff, 0x00, 0x00 };
+	struct kvm_ever_mapped_log log = {
+		.first_granule = 0x8,
+		.num_granules = 0x20,
+		.granule_shift = 21,
+		.flags = 0,
+		.bitmap = mapped_bitmap,
+	};
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, map_start, 1, map_len / PAGE_SIZE, 0);
+
+	ret = __vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	TEST_ASSERT(ret && errno == ENOENT,
+		    "expected ENOENT when querying ever-mapped log before enablement, got %d",
+		    errno);
+	vm_enable_cap(vm, KVM_CAP_EVER_MAPPED, map_start + map_len);
+	pre_fault(vcpu, 16 * MiB, 32 * MiB);
+
+	ret = __vm_enable_cap(vm, KVM_CAP_EVER_MAPPED, PAGE_SIZE);
+	TEST_ASSERT(ret && errno == EEXIST,
+		    "expected EEXIST when enabling KVM_CAP_EVER_MAPPED twice, got %d",
+		    errno);
+
+	vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	assert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);
+
+	log.granule_shift = 22;
+	log.first_granule = 0x4;
+	log.num_granules = 0x10;
+	memcpy(mapped_bitmap, (u8[]){ 0xa5, 0xa5, 0xa5, 0xa5 }, 4);
+	memcpy(expected_bitmap, (u8[]){ 0xff, 0x00, 0xa5, 0xa5 }, 4);
+	vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	assert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);
+
+	log.granule_shift = 23;
+	log.first_granule = 0x2;
+	log.num_granules = 0x8;
+	memcpy(mapped_bitmap, (u8[]){ 0xa5, 0xa5, 0xa5, 0xa5 }, 4);
+	memcpy(expected_bitmap, (u8[]){ 0x0f, 0xa5, 0xa5, 0xa5 }, 4);
+	vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	assert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);
+
+	log.num_granules = 0xff;
+	ret = __vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	TEST_ASSERT(ret && errno == EINVAL,
+		    "expected EINVAL when querying beyond range, got %d",
+		    errno);
+
+	log.num_granules = 0x10;
+	log.granule_shift = 1;
+	ret = __vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	TEST_ASSERT(ret && errno == EINVAL,
+		    "expected EINVAL with too small grnaule shift, got %d",
+		    errno);
+}
+
+/*
+ * Add 128MB or memory at GPA 32MB ( --> [32MB, 160MB) ),
+ * pre-fault [32MB, 64MB), and [90MB, 94MB),
+ * request and check bitmap for [16MB, 120MB).
+ */
+static void test_two_blocks(void)
+{
+	struct kvm_vm *vm;
+	struct kvm_vcpu *vcpu;
+	const uint64_t map_start = 0x2000000;
+	const uint64_t map_len = 0x8000000;
+	u8 mapped_bitmap[7] = { 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5 };
+	u8 expected_bitmap[7] = { 0x00, 0xff, 0xff, 0x00, 0x60, 0x00, 0x00 };
+	struct kvm_ever_mapped_log log = {
+		.first_granule = 0x8,
+		.num_granules = 0x34,
+		.granule_shift = 21,
+		.flags = 0,
+		.bitmap = mapped_bitmap,
+	};
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, map_start, 1, map_len / PAGE_SIZE, 0);
+
+	vm_enable_cap(vm, KVM_CAP_EVER_MAPPED, map_start + map_len);
+	pre_fault(vcpu, 32 * MiB, 32 * MiB);
+	pre_fault(vcpu, 90 * MiB, 4 * MiB);
+
+	vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	assert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);
+
+	log.granule_shift = 22;
+	log.first_granule = 0x4;
+	log.num_granules = 0x1a;
+	memcpy(mapped_bitmap, (u8[]){ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5}, 7);
+	memcpy(expected_bitmap, (u8[]){ 0xf0, 0x0f, 0x0c, 0x00, 0xa5, 0xa5, 0xa5 }, 7);
+	vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	assert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);
+
+	log.granule_shift = 23;
+	log.first_granule = 0x2;
+	log.num_granules = 0xd;
+	memcpy(mapped_bitmap, (u8[]){ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5 }, 7);
+	memcpy(expected_bitmap, (u8[]){ 0x3c, 0x02, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5 }, 7);
+	vm_ioctl(vm, KVM_GET_EVER_MAPPED_LOG, &log);
+	assert_bitmaps_equal(expected_bitmap, mapped_bitmap, 4);
+}
+
+int main(int argc, char *argv[])
+{
+	TEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY));
+	TEST_REQUIRE(kvm_check_cap(KVM_CAP_EVER_MAPPED));
+
+	test_one_page();
+	test_one_block();
+	test_two_blocks();
+}

3/2 2026/08/01 16:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 9659
							output: 28
							thoughts: 628
						

Thoughts:
**Analyzing the KVM Ever-Mapped Patch Series**

Okay, so I'm looking at this patch series introducing `KVM_CAP_EVER_MAPPED` and the `KVM_GET_EVER_MAPPED_LOG` ioctl for x86 KVM. It seems like it's designed to track which guest pages have *ever* been mapped, which is a neat capability.

First, let's make sure this is functional and reachable. Yep, new ioctl, new capability – that screams direct user-space interaction. QEMU, syzkaller, all those tools will be able to utilize this. Good.

Now, where are the critical symbols? Let's see... I've got:

*   `kvm_ever_mapped_set_range` - sounds like the workhorse setting ever-mapped status, inlined into `__handle_changed_spte` within `tdp_mmu.c`.
*   `kvm_vm_ioctl_get_ever_mapped_log` - static function, but called from `kvm_arch_vm_ioctl`
*   `kvm_vm_ioctl_enable_cap` - modified to handle the new `KVM_CAP_EVER_MAPPED`
*   `kvm_arch_vm_ioctl` - modified to handle the new `KVM_GET_EVER_MAPPED_LOG`

Since `kvm_vm_ioctl_get_ever_mapped_log` is static, I need to confirm whether it is actually used. Ah, yes, it is. The focus symbols are definitely `kvm_arch_vm_ioctl` and `kvm_vm_ioctl_enable_cap`. They are the entry points.

Let's check `arch/x86/kvm/x86.c` for `kvm_vm_ioctl_get_ever_mapped_log`.



4/2 2026/08/01 16:18 tool grepper
0m Args:
{
  "Expression": "kvm_vm_ioctl_get_ever_mapped_log"
}

Results:
{
  "Output": "arch/x86/kvm/x86.c=3931=int kvm_vm_ioctl_enable_cap(struct kvm *kvm,\n--\narch/x86/kvm/x86.c-4233-\narch/x86/kvm/x86.c:4234:static int kvm_vm_ioctl_get_ever_mapped_log(struct kvm *kvm,\narch/x86/kvm/x86.c-4235-\t\t\t\t\t    struct kvm_ever_mapped_log *log)\n--\narch/x86/kvm/x86.c=4455=int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)\n--\narch/x86/kvm/x86.c-4819-\narch/x86/kvm/x86.c:4820:\t\tr = kvm_vm_ioctl_get_ever_mapped_log(kvm, \u0026mapped_log);\narch/x86/kvm/x86.c-4821-\t\tbreak;\n"
}

5/2 2026/08/01 16:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11025
							output: 21
							thoughts: 100
						

Thoughts:
**Analyzing KVM Architecture for Potential Callers**

Okay, so I'm digging into this KVM code and trying to trace how this `__handle_changed_spte` function, which is, importantly, *static*, is used in the `tdp_mmu.c` file. My initial focus is on the *non-static* functions - I know `kvm_arch_vm_ioctl` and `kvm_vm_ioctl_enable_cap` are the ones to start with. But really what I'm trying to figure out is, does a *non-static* function *in this file*, `tdp_mmu.c`, call this internal `__handle_changed_spte` function? That's the critical question. If it's only called internally, that narrows the scope of investigation significantly.



6/2 2026/08/01 16:18 tool grepper
0m Args:
{
  "Expression": "__handle_changed_spte"
}

Results:
{
  "Output": "arch/x86/kvm/mmu/tdp_mmu.c=386=static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared)\n--\narch/x86/kvm/mmu/tdp_mmu.c-471-/**\narch/x86/kvm/mmu/tdp_mmu.c:472: * __handle_changed_spte - handle bookkeeping associated with an SPTE change\narch/x86/kvm/mmu/tdp_mmu.c-473- * @kvm: kvm instance\n--\narch/x86/kvm/mmu/tdp_mmu.c-486- */\narch/x86/kvm/mmu/tdp_mmu.c:487:static int __handle_changed_spte(struct kvm *kvm, struct kvm_mmu_page *sp,\narch/x86/kvm/mmu/tdp_mmu.c-488-\t\t\t\t gfn_t gfn, u64 old_spte, u64 new_spte,\n--\narch/x86/kvm/mmu/tdp_mmu.c=597=static void handle_changed_spte(struct kvm *kvm, struct kvm_mmu_page *sp,\n--\narch/x86/kvm/mmu/tdp_mmu.c-600-{\narch/x86/kvm/mmu/tdp_mmu.c:601:\tKVM_BUG_ON(__handle_changed_spte(kvm, sp, gfn, old_spte, new_spte,\narch/x86/kvm/mmu/tdp_mmu.c-602-\t\t\t\t\t level, shared), kvm);\n--\narch/x86/kvm/mmu/tdp_mmu.c=647=static inline int __must_check tdp_mmu_set_spte_atomic(struct kvm *kvm,\n--\narch/x86/kvm/mmu/tdp_mmu.c-680-\t */\narch/x86/kvm/mmu/tdp_mmu.c:681:\tret = __handle_changed_spte(kvm, sp, iter-\u003egfn, iter-\u003eold_spte,\narch/x86/kvm/mmu/tdp_mmu.c-682-\t\t\t\t    new_spte, iter-\u003elevel, true);\n"
}

7/2 2026/08/01 16:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 11952
							output: 24
							thoughts: 58
						

Thoughts:
**Focusing on Potential Key Functions in `tdp_mmu.c`**

Okay, so `handle_changed_spte` and `tdp_mmu_set_spte_atomic` both ultimately funnel into `__handle_changed_spte`. That's a clear starting point for understanding how SPTE changes are managed in this TDP MMU context. My task now is to identify other non-static functions within `tdp_mmu.c` that might provide additional insights, serving as potential "focus symbols" to build a more comprehensive picture. Finding the right functions will help me grasp the broader implications of SPTE modifications within this module. I need to look for functions that either interact with SPTEs directly or that control related aspects of the TDP MMU.



8/2 2026/08/01 16:18 tool grepper
0m Args:
{
  "Expression": "^int kvm_tdp_mmu_"
}

Results:
{
  "Output": "arch/x86/kvm/mmu.h=331=static inline bool kvm_shadow_root_allocated(struct kvm *kvm)\n--\narch/x86/kvm/mmu.h-341-\narch/x86/kvm/mmu.h:342:int kvm_tdp_mmu_map_private_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn);\narch/x86/kvm/mmu.h-343-\n--\narch/x86/kvm/mmu/mmu.c=5135=static void kvm_assert_gmem_invalidate_lock_held(struct kvm_memory_slot *slot)\n--\narch/x86/kvm/mmu/mmu.c-5146-\narch/x86/kvm/mmu/mmu.c:5147:int kvm_tdp_mmu_map_private_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)\narch/x86/kvm/mmu/mmu.c-5148-{\n--\narch/x86/kvm/mmu/tdp_mmu.c=1222=static int tdp_mmu_split_huge_page(struct kvm *kvm, struct tdp_iter *iter,\n--\narch/x86/kvm/mmu/tdp_mmu.c-1228- */\narch/x86/kvm/mmu/tdp_mmu.c:1229:int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)\narch/x86/kvm/mmu/tdp_mmu.c-1230-{\n--\narch/x86/kvm/mmu/tdp_mmu.c=1891=bool kvm_tdp_mmu_write_protect_gfn(struct kvm *kvm,\n--\narch/x86/kvm/mmu/tdp_mmu.c-1910- */\narch/x86/kvm/mmu/tdp_mmu.c:1911:int kvm_tdp_mmu_get_walk(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes,\narch/x86/kvm/mmu/tdp_mmu.c-1912-\t\t\t int *root_level)\n--\narch/x86/kvm/mmu/tdp_mmu.h=72=void kvm_tdp_mmu_zap_invalidated_roots(struct kvm *kvm, bool shared);\narch/x86/kvm/mmu/tdp_mmu.h-73-\narch/x86/kvm/mmu/tdp_mmu.h:74:int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault);\narch/x86/kvm/mmu/tdp_mmu.h-75-\n--\narch/x86/kvm/mmu/tdp_mmu.h=106=static inline void kvm_tdp_mmu_walk_lockless_end(void)\n--\narch/x86/kvm/mmu/tdp_mmu.h-110-\narch/x86/kvm/mmu/tdp_mmu.h:111:int kvm_tdp_mmu_get_walk(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes,\narch/x86/kvm/mmu/tdp_mmu.h-112-\t\t\t int *root_level);\n"
}

9/2 2026/08/01 16:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13164
							output: 17
							thoughts: 241
						

Thoughts:
**My Initial Assessment of the Code**

Okay, so I'm diving into this KVM code, and immediately I see a few key functions to zero in on. `kvm_tdp_mmu_map` seems like a good starting point for understanding the page fault path, but the real entry points for these capabilities are `kvm_arch_vm_ioctl` for `KVM_GET_EVER_MAPPED_LOG` and `kvm_vm_ioctl_enable_cap` for `KVM_CAP_EVER_MAPPED`. Those two are definitely worth prioritizing in my analysis, along with the `tdp_mmu_map` function, which appears central to the TDP MMU operations.

Now, before I dig deeper, I want to make sure I understand any configuration dependencies. The patch touches `arch/x86/kvm/x86.c` and `arch/x86/kvm/mmu/tdp_mmu.c`, which makes me think this is specific to x86 KVM. The presence of `tdp_enabled` confirms that. I know `CONFIG_KVM` is a given, but I need to make sure I don't miss anything else. Let's check the `arch/x86/kvm/Kconfig` file to be completely thorough.



10/2 2026/08/01 16:18 tool grepper
0m Args:
{
  "Expression": "config KVM"
}

Results:
{
  "Output": "arch/arm64/kvm/Kconfig=18=if VIRTUALIZATION\narch/arm64/kvm/Kconfig-19-\narch/arm64/kvm/Kconfig:20:menuconfig KVM\narch/arm64/kvm/Kconfig-21-\tbool \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/loongarch/kvm/Kconfig=18=if VIRTUALIZATION\narch/loongarch/kvm/Kconfig-19-\narch/loongarch/kvm/Kconfig:20:config KVM\narch/loongarch/kvm/Kconfig-21-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/mips/kvm/Kconfig=16=if VIRTUALIZATION\narch/mips/kvm/Kconfig-17-\narch/mips/kvm/Kconfig:18:config KVM\narch/mips/kvm/Kconfig-19-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/mips/kvm/Kconfig-30-\narch/mips/kvm/Kconfig:31:config KVM_MIPS_DEBUG_COP0_COUNTERS\narch/mips/kvm/Kconfig-32-\tbool \"Maintain counters for COP0 accesses\"\n--\narch/powerpc/kvm/Kconfig=18=if VIRTUALIZATION\narch/powerpc/kvm/Kconfig-19-\narch/powerpc/kvm/Kconfig:20:config KVM\narch/powerpc/kvm/Kconfig-21-\tbool\n--\narch/powerpc/kvm/Kconfig-25-\narch/powerpc/kvm/Kconfig:26:config KVM_BOOK3S_HANDLER\narch/powerpc/kvm/Kconfig-27-\tbool\narch/powerpc/kvm/Kconfig-28-\narch/powerpc/kvm/Kconfig:29:config KVM_BOOK3S_32_HANDLER\narch/powerpc/kvm/Kconfig-30-\tbool\n--\narch/powerpc/kvm/Kconfig-33-\narch/powerpc/kvm/Kconfig:34:config KVM_BOOK3S_64_HANDLER\narch/powerpc/kvm/Kconfig-35-\tbool\n--\narch/powerpc/kvm/Kconfig-37-\narch/powerpc/kvm/Kconfig:38:config KVM_BOOK3S_PR_POSSIBLE\narch/powerpc/kvm/Kconfig-39-\tbool\n--\narch/powerpc/kvm/Kconfig-41-\narch/powerpc/kvm/Kconfig:42:config KVM_BOOK3S_HV_POSSIBLE\narch/powerpc/kvm/Kconfig-43-\tbool\narch/powerpc/kvm/Kconfig-44-\narch/powerpc/kvm/Kconfig:45:config KVM_BOOK3S_32\narch/powerpc/kvm/Kconfig-46-\ttristate \"KVM support for PowerPC book3s_32 processors\"\n--\narch/powerpc/kvm/Kconfig-61-\narch/powerpc/kvm/Kconfig:62:config KVM_BOOK3S_64\narch/powerpc/kvm/Kconfig-63-\ttristate \"KVM support for PowerPC book3s_64 processors\"\n--\narch/powerpc/kvm/Kconfig-78-\narch/powerpc/kvm/Kconfig:79:config KVM_BOOK3S_64_HV\narch/powerpc/kvm/Kconfig-80-\ttristate \"KVM for POWER7 and later using hypervisor mode in host\"\n--\narch/powerpc/kvm/Kconfig-99-\narch/powerpc/kvm/Kconfig:100:config KVM_BOOK3S_64_PR\narch/powerpc/kvm/Kconfig-101-\ttristate \"KVM support without using hypervisor mode in host\"\n--\narch/powerpc/kvm/Kconfig-125-\narch/powerpc/kvm/Kconfig:126:config KVM_BOOK3S_HV_EXIT_TIMING\narch/powerpc/kvm/Kconfig-127-\tbool\narch/powerpc/kvm/Kconfig-128-\narch/powerpc/kvm/Kconfig:129:config KVM_BOOK3S_HV_P9_TIMING\narch/powerpc/kvm/Kconfig-130-\tbool \"Detailed timing for the P9 entry point\"\n--\narch/powerpc/kvm/Kconfig-141-\narch/powerpc/kvm/Kconfig:142:config KVM_BOOK3S_HV_P8_TIMING\narch/powerpc/kvm/Kconfig-143-\tbool \"Detailed timing for hypervisor real-mode code (for POWER8)\"\n--\narch/powerpc/kvm/Kconfig-156-\narch/powerpc/kvm/Kconfig:157:config KVM_BOOK3S_HV_NESTED_PMU_WORKAROUND\narch/powerpc/kvm/Kconfig-158-\tbool \"Nested L0 host workaround for L1 KVM host PMU handling bug\" if EXPERT\n--\narch/powerpc/kvm/Kconfig-171-\narch/powerpc/kvm/Kconfig:172:config KVM_BOOK3S_HV_PMU\narch/powerpc/kvm/Kconfig-173-\ttristate \"Hypervisor Perf events for KVM Book3s-HV\"\n--\narch/powerpc/kvm/Kconfig-183-\narch/powerpc/kvm/Kconfig:184:config KVM_BOOKE_HV\narch/powerpc/kvm/Kconfig-185-\tbool\narch/powerpc/kvm/Kconfig-186-\narch/powerpc/kvm/Kconfig:187:config KVM_EXIT_TIMING\narch/powerpc/kvm/Kconfig-188-\tbool \"Detailed exit timing\"\n--\narch/powerpc/kvm/Kconfig-197-\narch/powerpc/kvm/Kconfig:198:config KVM_E500V2\narch/powerpc/kvm/Kconfig-199-\tbool \"KVM support for PowerPC E500v2 processors\"\n--\narch/powerpc/kvm/Kconfig-212-\narch/powerpc/kvm/Kconfig:213:config KVM_E500MC\narch/powerpc/kvm/Kconfig-214-\tbool \"KVM support for PowerPC E500MC/E5500/E6500 processors\"\n--\narch/powerpc/kvm/Kconfig-228-\narch/powerpc/kvm/Kconfig:229:config KVM_MPIC\narch/powerpc/kvm/Kconfig-230-\tbool \"KVM in-kernel MPIC emulation\"\n--\narch/powerpc/kvm/Kconfig-240-\narch/powerpc/kvm/Kconfig:241:config KVM_XICS\narch/powerpc/kvm/Kconfig-242-\tbool \"KVM in-kernel XICS emulation\"\n--\narch/powerpc/kvm/Kconfig-250-\narch/powerpc/kvm/Kconfig:251:config KVM_XIVE\narch/powerpc/kvm/Kconfig-252-\tbool\n--\narch/powerpc/platforms/Kconfig=22=source \"arch/powerpc/platforms/microwatt/Kconfig\"\narch/powerpc/platforms/Kconfig-23-\narch/powerpc/platforms/Kconfig:24:config KVM_GUEST\narch/powerpc/platforms/Kconfig-25-\tbool \"KVM Guest support\"\n--\narch/riscv/kvm/Kconfig=18=if VIRTUALIZATION\narch/riscv/kvm/Kconfig-19-\narch/riscv/kvm/Kconfig:20:config KVM\narch/riscv/kvm/Kconfig-21-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/s390/kvm/Kconfig=17=if VIRTUALIZATION\narch/s390/kvm/Kconfig-18-\narch/s390/kvm/Kconfig:19:config KVM\narch/s390/kvm/Kconfig-20-\tdef_tristate y\n--\narch/s390/kvm/Kconfig-46-\narch/s390/kvm/Kconfig:47:config KVM_S390_UCONTROL\narch/s390/kvm/Kconfig-48-\tbool \"Userspace controlled virtual machines\"\n--\narch/x86/Kconfig=839=source \"arch/x86/xen/Kconfig\"\narch/x86/Kconfig-840-\narch/x86/Kconfig:841:config KVM_GUEST\narch/x86/Kconfig-842-\tbool \"KVM Guest support (including kvmclock)\"\n--\narch/x86/kvm/Kconfig=18=if VIRTUALIZATION\narch/x86/kvm/Kconfig-19-\narch/x86/kvm/Kconfig:20:config KVM_X86\narch/x86/kvm/Kconfig-21-\tdef_tristate KVM if (KVM_INTEL != n || KVM_AMD != n)\n--\narch/x86/kvm/Kconfig-51-\narch/x86/kvm/Kconfig:52:config KVM\narch/x86/kvm/Kconfig-53-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/x86/kvm/Kconfig-68-\narch/x86/kvm/Kconfig:69:config KVM_WERROR\narch/x86/kvm/Kconfig-70-\tbool \"Compile KVM with -Werror\"\n--\narch/x86/kvm/Kconfig-82-\narch/x86/kvm/Kconfig:83:config KVM_SW_PROTECTED_VM\narch/x86/kvm/Kconfig-84-\tbool \"Enable support for KVM software-protected VMs\"\n--\narch/x86/kvm/Kconfig-95-\narch/x86/kvm/Kconfig:96:config KVM_INTEL\narch/x86/kvm/Kconfig-97-\ttristate \"KVM for Intel (and compatible) processors support\"\n--\narch/x86/kvm/Kconfig-106-\narch/x86/kvm/Kconfig:107:config KVM_INTEL_PROVE_VE\narch/x86/kvm/Kconfig-108-        bool \"Check that guests do not receive #VE exceptions\"\n--\narch/x86/kvm/Kconfig=122=config X86_SGX_KVM\n--\narch/x86/kvm/Kconfig-133-\narch/x86/kvm/Kconfig:134:config KVM_INTEL_TDX\narch/x86/kvm/Kconfig-135-\tbool \"Intel Trust Domain Extensions (TDX) support\"\n--\narch/x86/kvm/Kconfig-145-\narch/x86/kvm/Kconfig:146:config KVM_AMD\narch/x86/kvm/Kconfig-147-\ttristate \"KVM for AMD processors support\"\n--\narch/x86/kvm/Kconfig-155-\narch/x86/kvm/Kconfig:156:config KVM_AMD_SEV\narch/x86/kvm/Kconfig-157-\tbool \"AMD Secure Encrypted Virtualization (SEV) support\"\n--\narch/x86/kvm/Kconfig-171-\narch/x86/kvm/Kconfig:172:config KVM_IOAPIC\narch/x86/kvm/Kconfig-173-\tbool \"I/O APIC, PIC, and PIT emulation\"\n--\narch/x86/kvm/Kconfig-181-\narch/x86/kvm/Kconfig:182:config KVM_SMM\narch/x86/kvm/Kconfig-183-\tbool \"System Management Mode emulation\"\n--\narch/x86/kvm/Kconfig-192-\narch/x86/kvm/Kconfig:193:config KVM_HYPERV\narch/x86/kvm/Kconfig-194-\tbool \"Support for Microsoft Hyper-V emulation\"\n--\narch/x86/kvm/Kconfig-206-\narch/x86/kvm/Kconfig:207:config KVM_XEN\narch/x86/kvm/Kconfig-208-\tbool \"Support for Xen hypercall interface\"\n--\narch/x86/kvm/Kconfig-215-\narch/x86/kvm/Kconfig:216:config KVM_PROVE_MMU\narch/x86/kvm/Kconfig-217-\tbool \"Prove KVM MMU correctness\"\n--\narch/x86/kvm/Kconfig-228-\narch/x86/kvm/Kconfig:229:config KVM_EXTERNAL_WRITE_TRACKING\narch/x86/kvm/Kconfig-230-\tbool\narch/x86/kvm/Kconfig-231-\narch/x86/kvm/Kconfig:232:config KVM_MAX_NR_VCPUS\narch/x86/kvm/Kconfig-233-\tint \"Maximum number of vCPUs per KVM guest\"\n--\nvirt/kvm/Kconfig-3-\nvirt/kvm/Kconfig:4:config KVM_COMMON\nvirt/kvm/Kconfig-5-       bool\n--\nvirt/kvm/Kconfig=39=config NEED_KVM_DIRTY_RING_WITH_BITMAP\n--\nvirt/kvm/Kconfig-42-\nvirt/kvm/Kconfig:43:config KVM_MMIO\nvirt/kvm/Kconfig-44-       bool\nvirt/kvm/Kconfig-45-\nvirt/kvm/Kconfig:46:config KVM_ASYNC_PF\nvirt/kvm/Kconfig-47-       bool\n--\nvirt/kvm/Kconfig-49-# Toggle to switch between direct notification and batch job\nvirt/kvm/Kconfig:50:config KVM_ASYNC_PF_SYNC\nvirt/kvm/Kconfig-51-       bool\n--\nvirt/kvm/Kconfig=59=config HAVE_KVM_CPU_RELAX_INTERCEPT\n--\nvirt/kvm/Kconfig-61-\nvirt/kvm/Kconfig:62:config KVM_VFIO\nvirt/kvm/Kconfig-63-       bool\n--\nvirt/kvm/Kconfig=65=config HAVE_KVM_INVALID_WAKEUPS\n--\nvirt/kvm/Kconfig-67-\nvirt/kvm/Kconfig:68:config KVM_GENERIC_DIRTYLOG_READ_PROTECT\nvirt/kvm/Kconfig-69-       bool\nvirt/kvm/Kconfig-70-\nvirt/kvm/Kconfig:71:config KVM_GENERIC_PRE_FAULT_MEMORY\nvirt/kvm/Kconfig-72-       bool\nvirt/kvm/Kconfig-73-\nvirt/kvm/Kconfig:74:config KVM_COMPAT\nvirt/kvm/Kconfig-75-       def_bool y\n--\nvirt/kvm/Kconfig=91=config HAVE_KVM_PM_NOTIFIER\n--\nvirt/kvm/Kconfig-93-\nvirt/kvm/Kconfig:94:config KVM_GENERIC_HARDWARE_ENABLING\nvirt/kvm/Kconfig-95-       bool\nvirt/kvm/Kconfig-96-\nvirt/kvm/Kconfig:97:config KVM_ELIDE_TLB_FLUSH_IF_YOUNG\nvirt/kvm/Kconfig-98-       bool\nvirt/kvm/Kconfig-99-\nvirt/kvm/Kconfig:100:config KVM_MMU_LOCKLESS_AGING\nvirt/kvm/Kconfig-101-       bool\nvirt/kvm/Kconfig-102-\nvirt/kvm/Kconfig:103:config KVM_GENERIC_MEMORY_ATTRIBUTES\nvirt/kvm/Kconfig-104-       bool\nvirt/kvm/Kconfig-105-\nvirt/kvm/Kconfig:106:config KVM_GUEST_MEMFD\nvirt/kvm/Kconfig-107-       select XARRAY_MULTI\n"
}

11/2 2026/08/01 16:18 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 17995
							output: 171
							thoughts: 933
						

Thoughts:
**Analyzing KVM Ever-Mapped Tracking Implementation**

Okay, so I'm looking at this KVM functionality – the "ever-mapped" feature. My initial thought is to zero in on the configuration requirements. It looks like `KVM` is the primary one, and `X86_64` is implicitly required due to the `tdp_enabled` check, which seems to require the 64-bit architecture. So, primarily, `KVM` is what we need to focus on.

I checked `kvm_vm_ioctl_enable_cap` in `arch/x86/kvm/x86.c`. I confirmed that `tdp_enabled` is required, which is true by default for Intel EPT and AMD NPT. This confirms the importance of KVM being enabled.

Now, let's get into the code flow. I want to highlight some key symbols that reveal how this new tracking works. I figured `kvm_arch_vm_ioctl`, `kvm_vm_ioctl_enable_cap`, and `kvm_tdp_mmu_map` are relevant entry points. I'm focusing on `kvm_tdp_mmu_map` because it's where the TDP MMU page fault handling occurs and where we'll find the logic for setting the ever-mapped bits.

I confirmed that `kvm_tdp_mmu_map` is the main entry point for TDP MMU page faults in `arch/x86/kvm/mmu/tdp_mmu.c`. I checked for other related functions like `kvm_tdp_mmu_zap_invalidated_roots`, but `kvm_tdp_mmu_map` is the crucial one because it's responsible for setting new SPTEs, which then triggers the ever-mapped tracking logic.

Revisiting the focus symbols: `kvm_arch_vm_ioctl`, `kvm_vm_ioctl_enable_cap`, and especially `kvm_tdp_mmu_map`.

The reasoning is solid: The new KVM capability `KVM_CAP_EVER_MAPPED` and its corresponding `KVM_GET_EVER_MAPPED_LOG` ioctl allow us to track guest pages that have been mapped. This is accessed through KVM ioctls, so we're looking at a user-space-accessible feature. The patch requires both `CONFIG_KVM` and `CONFIG_X86_64`, with KVM being the critical one. The core of this tracking occurs within the ioctl entry points and the TDP MMU page fault handler.

Let's double-check `kvm_tdp_mmu_map`. Yes, it's called during page faults and SPTE creation. Looking at the code:

```c
	if (unlikely(kvm->arch.ever_mapped_bitmap) &&
	    is_leaf && !was_leaf) {
		kvm_ever_mapped_set_range(kvm, gfn, KVM_PAGES_PER_HPAGE(level));
	}
```

This snippet inside `__handle_changed_spte` is what we're looking for, confirming that `kvm_tdp_mmu_map` is the right place.
Specifically, `__handle_changed_spte` is called by `tdp_mmu_set_spte_atomic`, which is in turn called by `kvm_tdp_mmu_map`. This confirms we're on the right track! Time to run the tool.



12/2 2026/08/01 16:19 tool set-results
0m Args:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvm_arch_vm_ioctl",
    "kvm_vm_ioctl_enable_cap",
    "kvm_tdp_mmu_map"
  ],
  "Reasoning": "The patch introduces a new KVM capability `KVM_CAP_EVER_MAPPED` and a new ioctl `KVM_GET_EVER_MAPPED_LOG` to track which guest pages have ever been mapped. This is functional and reachable from userspace via KVM ioctls. The feature requires `CONFIG_KVM` and is specific to x86. We focus on the ioctl entry points and the TDP MMU page fault handler where the tracking is updated.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "KVM"
  ],
  "FocusSymbols": [
    "kvm_arch_vm_ioctl",
    "kvm_vm_ioctl_enable_cap",
    "kvm_tdp_mmu_map"
  ],
  "Reasoning": "The patch introduces a new KVM capability `KVM_CAP_EVER_MAPPED` and a new ioctl `KVM_GET_EVER_MAPPED_LOG` to track which guest pages have ever been mapped. This is functional and reachable from userspace via KVM ioctls. The feature requires `CONFIG_KVM` and is specific to x86. We focus on the ioctl entry points and the TDP MMU page fault handler where the tracking is updated.",
  "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)