AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/26 23:12 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch only modifies userspace testing tools (KVM selftests) in tools/testing/selftests/kvm/. It does not make any functional changes to the core kernel logic, drivers, or architectures.",
  "WorthFuzzing": false
}

1/1 2026/08/26 23:12 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 220a59c810ce6afc4c5cd7e313b1242003d92f23\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Aug 26 23:12:02 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/tools/testing/selftests/kvm/arm64/page_fault_test.c b/tools/testing/selftests/kvm/arm64/page_fault_test.c\nindex 6bb3d82906b22..b0e3fc8cd76ac 100644\n--- a/tools/testing/selftests/kvm/arm64/page_fault_test.c\n+++ b/tools/testing/selftests/kvm/arm64/page_fault_test.c\n@@ -597,18 +597,16 @@ static void setup_memslots(struct kvm_vm *vm, struct test_params *p)\n \n \tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0,\n \t\t\t\t    CODE_AND_DATA_MEMSLOT, code_npages, 0);\n-\tvm-\u003ememslots[MEM_REGION_CODE] = CODE_AND_DATA_MEMSLOT;\n-\tvm-\u003ememslots[MEM_REGION_DATA] = CODE_AND_DATA_MEMSLOT;\n-\n-\tvm_userspace_mem_region_add(vm, p-\u003esrc_type, data_gpa - pt_size,\n-\t\t\t\t    PAGE_TABLE_MEMSLOT, pt_size / guest_page_size,\n-\t\t\t\t    p-\u003etest_desc-\u003ept_memslot_flags);\n-\tvm-\u003ememslots[MEM_REGION_PT] = PAGE_TABLE_MEMSLOT;\n-\n-\tvm_userspace_mem_region_add(vm, p-\u003esrc_type, data_gpa, TEST_DATA_MEMSLOT,\n-\t\t\t\t    data_size / guest_page_size,\n-\t\t\t\t    p-\u003etest_desc-\u003edata_memslot_flags);\n-\tvm-\u003ememslots[MEM_REGION_TEST_DATA] = TEST_DATA_MEMSLOT;\n+\t____vm_override_mem_region(vm, MEM_REGION_CODE, CODE_AND_DATA_MEMSLOT);\n+\t____vm_override_mem_region(vm, MEM_REGION_DATA, CODE_AND_DATA_MEMSLOT);\n+\n+\t__vm_override_mem_region(vm, MEM_REGION_PT, p-\u003esrc_type, data_gpa - pt_size,\n+\t\t\t\t PAGE_TABLE_MEMSLOT, pt_size / guest_page_size,\n+\t\t\t\t p-\u003etest_desc-\u003ept_memslot_flags);\n+\n+\t__vm_override_mem_region(vm, MEM_REGION_TEST_DATA, p-\u003esrc_type, data_gpa,\n+\t\t\t\t TEST_DATA_MEMSLOT, data_size / guest_page_size,\n+\t\t\t\t p-\u003etest_desc-\u003edata_memslot_flags);\n }\n \n static void setup_ucall(struct kvm_vm *vm)\ndiff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c\nindex 9a69c439a0f8f..b4c651ea385d8 100644\n--- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c\n+++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c\n@@ -164,8 +164,8 @@ static void setup_memslot(void)\n \n \tpages = sz / vm-\u003epage_size;\n \tgpa_base = ((vm_compute_max_gfn(vm) + 1) * vm-\u003epage_size) - sz;\n-\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, gpa_base,\n-\t\t\t\t    TEST_MEMSLOT_INDEX, pages, 0);\n+\tvm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS,\n+\t\t\t       gpa_base, TEST_MEMSLOT_INDEX, pages);\n }\n \n #define LPI_PROP_DEFAULT_PRIO\t0xa0\n@@ -191,28 +191,25 @@ static void setup_test_data(void)\n \tgpa_t cmdq_base;\n \n \ttest_data.device_table = vm_phy_pages_alloc(vm, pages_per_64k,\n-\t\t\t\t\t\t    gpa_base,\n-\t\t\t\t\t\t    TEST_MEMSLOT_INDEX);\n+\t\t\t\t\t\t    MEM_REGION_TEST_EXTRA);\n \n \ttest_data.collection_table = vm_phy_pages_alloc(vm, pages_per_64k,\n-\t\t\t\t\t\t\tgpa_base,\n-\t\t\t\t\t\t\tTEST_MEMSLOT_INDEX);\n+\t\t\t\t\t\t\tMEM_REGION_TEST_EXTRA);\n \n-\tcmdq_base = vm_phy_pages_alloc(vm, pages_per_64k, gpa_base,\n-\t\t\t\t       TEST_MEMSLOT_INDEX);\n+\tcmdq_base = vm_phy_pages_alloc(vm, pages_per_64k, MEM_REGION_TEST_EXTRA);\n \tvirt_map(vm, cmdq_base, cmdq_base, pages_per_64k);\n \ttest_data.cmdq_base = cmdq_base;\n \ttest_data.cmdq_base_va = (void *)cmdq_base;\n \n \ttest_data.itt_tables = vm_phy_pages_alloc(vm, pages_per_64k * nr_devices,\n-\t\t\t\t\t\t  gpa_base, TEST_MEMSLOT_INDEX);\n+\t\t\t\t\t\t  MEM_REGION_TEST_EXTRA);\n \n \ttest_data.lpi_prop_table = vm_phy_pages_alloc(vm, pages_per_64k,\n-\t\t\t\t\t\t      gpa_base, TEST_MEMSLOT_INDEX);\n+\t\t\t\t\t\t      MEM_REGION_TEST_EXTRA);\n \tconfigure_lpis();\n \n \ttest_data.lpi_pend_tables = vm_phy_pages_alloc(vm, pages_per_64k * nr_cpus,\n-\t\t\t\t\t\t       gpa_base, TEST_MEMSLOT_INDEX);\n+\t\t\t\t\t\t       MEM_REGION_TEST_EXTRA);\n \n \tsync_global_to_guest(vm, test_data);\n }\ndiff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h\nindex 5a7a455b53875..ffd4cf740d7fa 100644\n--- a/tools/testing/selftests/kvm/include/kvm_util.h\n+++ b/tools/testing/selftests/kvm/include/kvm_util.h\n@@ -33,6 +33,8 @@\n \n #define NSEC_PER_SEC 1000000000L\n \n+#define KVM_INVALID_MEMSLOT UINT_MAX\n+\n struct userspace_mem_region {\n \tstruct kvm_userspace_memory_region2 region;\n \tstruct sparsebit *unused_phy_pages;\n@@ -80,11 +82,43 @@ struct userspace_mem_regions {\n \tDECLARE_HASHTABLE(slot_hash, 9);\n };\n \n+/*\n+ * Memory region types are passed to various page allocators to communicate\n+ * various properties and metadata related to the allocation.  Note, the\n+ * descriptions below described the primary usage of each type.  Individual\n+ * tests may allocate memory for other purposes.\n+ *\n+ * By default, all regions are mapped to memslot '0'.  Tests can override the\n+ * memslot for any or all types, e.g. so that all test data is allocated from a\n+ * curated memslot.\n+ */\n enum kvm_mem_region_type {\n+\t/*\n+\t * The CODE region is used by lib/elf when loading the test's code into\n+\t * guest memory.\n+\t */\n \tMEM_REGION_CODE,\n+\t/*\n+\t * The DATA region is used to allocate core data structures, e.g. vCPU\n+\t * stacks, VM exception tables, x86's TSS, etc.\n+\t */\n \tMEM_REGION_DATA,\n+\t/*\n+\t * The PT region, a.k.a. Page Table region, is used to allocate page\n+\t * table pages.\n+\t */\n \tMEM_REGION_PT,\n+\t/*\n+\t * The TEST_DATA region is used for allocating test data that is either\n+\t * test specific, and/or isn't considered a \"core\" data structure.\n+\t */\n \tMEM_REGION_TEST_DATA,\n+\t/*\n+\t * The TEST_EXTRA region is for special snowflakes, where a test wants\n+\t * to create and use a one-off memslot, without impacting \"normal\" test\n+\t * data allocations.\n+\t */\n+\tMEM_REGION_TEST_EXTRA,\n \tNR_MEM_REGIONS,\n };\n \n@@ -127,11 +161,6 @@ struct kvm_vm {\n \n \tstruct kvm_binary_stats stats;\n \n-\t/*\n-\t * KVM region slots. These are the default memslots used by page\n-\t * allocators, e.g., lib/elf uses the memslots[MEM_REGION_CODE]\n-\t * memslot.\n-\t */\n \tu32 memslots[NR_MEM_REGIONS];\n };\n \n@@ -169,13 +198,14 @@ memslot2region(struct kvm_vm *vm, u32 memslot);\n static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm,\n \t\t\t\t\t\t\t     enum kvm_mem_region_type type)\n {\n-\tassert(type \u003c NR_MEM_REGIONS);\n+\tTEST_ASSERT(type \u003c NR_MEM_REGIONS,\n+\t\t    \"Invalid memory region type '%u'\", type);\n \treturn memslot2region(vm, vm-\u003ememslots[type]);\n }\n \n /* Minimum allocated guest virtual and physical addresses */\n #define KVM_UTIL_MIN_VADDR\t\t0x2000\n-#define KVM_GUEST_PAGE_TABLE_MIN_PADDR\t0x180000\n+#define KVM_GUEST_PAGE_TABLE_MIN_PADDR\t0x200000\n \n #define DEFAULT_GUEST_STACK_VADDR_MIN\t0xab6000\n #define DEFAULT_STACK_PGS\t\t5\n@@ -702,6 +732,36 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,\n \t\tgpa_t gpa, u32 slot, u64 npages, u32 flags,\n \t\tint guest_memfd_fd, u64 guest_memfd_offset);\n \n+\n+static inline void ____vm_override_mem_region(struct kvm_vm *vm,\n+\t\t\t\t\t      enum kvm_mem_region_type type,\n+\t\t\t\t\t      u32 slot)\n+{\n+\tTEST_ASSERT(vm-\u003ememslots[type] == KVM_INVALID_MEMSLOT,\n+\t\t    \"Memory region type '%u' was already overridden with slot=%u\",\n+\t\t    type, vm-\u003ememslots[type]);\n+\n+\tvm-\u003ememslots[type] = slot;\n+}\n+\n+static inline void __vm_override_mem_region(struct kvm_vm *vm,\n+\t\t\t\t\t    enum kvm_mem_region_type type,\n+\t\t\t\t\t    enum vm_mem_backing_src_type src_type,\n+\t\t\t\t\t    gpa_t gpa, u32 slot, u64 npages,\n+\t\t\t\t\t    u32 flags)\n+{\n+\t____vm_override_mem_region(vm, type, slot);\n+\tvm_userspace_mem_region_add(vm, src_type, gpa, slot, npages, flags);\n+}\n+\n+static inline void vm_override_mem_region(struct kvm_vm *vm,\n+\t\t\t\t\t  enum kvm_mem_region_type type,\n+\t\t\t\t\t  enum vm_mem_backing_src_type src_type,\n+\t\t\t\t\t  gpa_t gpa, u32 slot, u64 npages)\n+{\n+\t__vm_override_mem_region(vm, type, src_type, gpa, slot, npages, 0);\n+}\n+\n #ifndef vm_arch_has_protected_memory\n static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm)\n {\n@@ -990,23 +1050,41 @@ void kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *routing);\n \n const char *exit_reason_str(unsigned int exit_reason);\n \n-gpa_t vm_phy_page_alloc(struct kvm_vm *vm, gpa_t min_gpa, u32 memslot);\n-gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, gpa_t min_gpa,\n-\t\t\t   u32 memslot, bool protected);\n-gpa_t vm_alloc_page_table(struct kvm_vm *vm);\n+bool kvm_arch_needs_naturally_aligned_page_tables(void);\n+\n+gpa_t ____vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, gpa_t min_gpa,\n+\t\t\t     u32 memslot, bool protected, bool naturally_aligned);\n+gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages,\n+\t\t\t   enum kvm_mem_region_type type, bool protected);\n \n-static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,\n-\t\t\t\t       gpa_t min_gpa, u32 memslot)\n+static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages,\n+\t\t\t\t       enum kvm_mem_region_type type)\n {\n \t/*\n \t * By default, allocate memory as protected for VMs that support\n \t * protected memory, as the majority of memory for such VMs is\n \t * protected, i.e. using shared memory is effectively opt-in.\n \t */\n-\treturn __vm_phy_pages_alloc(vm, num, min_gpa, memslot,\n+\treturn __vm_phy_pages_alloc(vm, nr_pages, type,\n \t\t\t\t    vm_arch_has_protected_memory(vm));\n }\n \n+static inline gpa_t vm_phy_page_alloc(struct kvm_vm *vm,\n+\t\t\t\t      enum kvm_mem_region_type type)\n+{\n+\treturn vm_phy_pages_alloc(vm, 1, type);\n+}\n+\n+static inline gpa_t vm_alloc_page_table_pages(struct kvm_vm *vm, size_t nr_pages)\n+{\n+\treturn vm_phy_pages_alloc(vm, nr_pages, MEM_REGION_PT);\n+}\n+\n+static inline gpa_t vm_alloc_page_table(struct kvm_vm *vm)\n+{\n+\treturn vm_alloc_page_table_pages(vm, 1);\n+}\n+\n /*\n  * ____vm_create() does KVM_CREATE_VM and little else.  __vm_create() also\n  * loads the test binary into guest memory and creates an IRQ chip (x86 only).\ndiff --git a/tools/testing/selftests/kvm/include/x86/smm.h b/tools/testing/selftests/kvm/include/x86/smm.h\nindex 2d1afa09819b0..15faaa0601262 100644\n--- a/tools/testing/selftests/kvm/include/x86/smm.h\n+++ b/tools/testing/selftests/kvm/include/x86/smm.h\n@@ -8,7 +8,7 @@\n #define SMRAM_MEMSLOT\t((1 \u003c\u003c 16) | 1)\n #define SMRAM_PAGES\t(SMRAM_SIZE / PAGE_SIZE)\n \n-void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, u64 smram_gpa,\n+void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, gpa_t smram_gpa,\n \t\t const void *smi_handler, size_t handler_size);\n \n void inject_smi(struct kvm_vcpu *vcpu);\ndiff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c\nindex 01325bf4d36fc..2dcaa2c4a0383 100644\n--- a/tools/testing/selftests/kvm/lib/arm64/processor.c\n+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c\n@@ -115,9 +115,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)\n \tif (vm-\u003emmu.pgd_created)\n \t\treturn;\n \n-\tvm-\u003emmu.pgd = vm_phy_pages_alloc(vm, nr_pages,\n-\t\t\t\t\t KVM_GUEST_PAGE_TABLE_MIN_PADDR,\n-\t\t\t\t\t vm-\u003ememslots[MEM_REGION_PT]);\n+\tvm-\u003emmu.pgd = vm_alloc_page_table_pages(vm, nr_pages);\n \tvm-\u003emmu.pgd_created = true;\n }\n \ndiff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c\nindex 9ddc047d5c275..57b653fbd0b1f 100644\n--- a/tools/testing/selftests/kvm/lib/kvm_util.c\n+++ b/tools/testing/selftests/kvm/lib/kvm_util.c\n@@ -17,6 +17,7 @@\n #include \u003csys/stat.h\u003e\n #include \u003ctime.h\u003e\n #include \u003cunistd.h\u003e\n+#include \u003clinux/align.h\u003e\n #include \u003clinux/kernel.h\u003e\n \n #define KVM_UTIL_MIN_PFN\t2\n@@ -287,6 +288,7 @@ __weak void vm_populate_gva_bitmap(struct kvm_vm *vm)\n struct kvm_vm *____vm_create(struct vm_shape shape)\n {\n \tstruct kvm_vm *vm;\n+\tint i;\n \n \tvm = calloc(1, sizeof(*vm));\n \tTEST_ASSERT(vm != NULL, \"Insufficient Memory\");\n@@ -295,6 +297,8 @@ struct kvm_vm *____vm_create(struct vm_shape shape)\n \tvm-\u003eregions.gpa_tree = RB_ROOT;\n \tvm-\u003eregions.hva_tree = RB_ROOT;\n \thash_init(vm-\u003eregions.slot_hash);\n+\tfor (i = 0; i \u003c NR_MEM_REGIONS; i++)\n+\t\tvm-\u003ememslots[i] = KVM_INVALID_MEMSLOT;\n \n \tvm-\u003emode = shape.mode;\n \tvm-\u003etype = shape.type;\n@@ -491,7 +495,7 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,\n \t\t\t\t\t\t nr_extra_pages);\n \tstruct userspace_mem_region *slot0;\n \tstruct kvm_vm *vm;\n-\tint i, flags;\n+\tint flags;\n \n \tkvm_set_files_rlimit(nr_runnable_vcpus);\n \n@@ -509,8 +513,10 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,\n \t\tflags |= KVM_MEM_GUEST_MEMFD;\n \n \tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, nr_pages, flags);\n-\tfor (i = 0; i \u003c NR_MEM_REGIONS; i++)\n-\t\tvm-\u003ememslots[i] = 0;\n+\t____vm_override_mem_region(vm, MEM_REGION_CODE, 0);\n+\t____vm_override_mem_region(vm, MEM_REGION_PT, 0);\n+\t____vm_override_mem_region(vm, MEM_REGION_DATA, 0);\n+\t____vm_override_mem_region(vm, MEM_REGION_TEST_DATA, 0);\n \n \tkvm_vm_elf_load(vm, program_invocation_name);\n \n@@ -1189,6 +1195,8 @@ memslot2region(struct kvm_vm *vm, u32 memslot)\n {\n \tstruct userspace_mem_region *region;\n \n+\tTEST_ASSERT(memslot != KVM_INVALID_MEMSLOT, \"vm-\u003ememslots[] unpopulated?\");\n+\n \thash_for_each_possible(vm-\u003eregions.slot_hash, region, slot_node,\n \t\t\t       memslot)\n \t\tif (region-\u003eregion.slot == memslot)\n@@ -1465,9 +1473,7 @@ static gva_t ____vm_alloc(struct kvm_vm *vm, size_t sz, gva_t min_gva,\n \tu64 pages = (sz \u003e\u003e vm-\u003epage_shift) + ((sz % vm-\u003epage_size) != 0);\n \n \tvirt_pgd_alloc(vm);\n-\tgpa_t gpa = __vm_phy_pages_alloc(vm, pages,\n-\t\t\t\t\t   KVM_UTIL_MIN_PFN * vm-\u003epage_size,\n-\t\t\t\t\t   vm-\u003ememslots[type], protected);\n+\tgpa_t gpa = __vm_phy_pages_alloc(vm, pages, type, protected);\n \n \t/*\n \t * Find an unused range of virtual page addresses of at least\n@@ -2025,33 +2031,21 @@ const char *exit_reason_str(unsigned int exit_reason)\n }\n \n /*\n- * Physical Contiguous Page Allocator\n- *\n- * Input Args:\n- *   vm - Virtual Machine\n- *   num - number of pages\n- *   min_gpa - Physical address minimum\n- *   memslot - Memory region to allocate page from\n- *   protected - True if the pages will be used as protected/private memory\n+ * Allocate contiguous (guest) physical pages in a given memory region, at or\n+ * the minimum specific GPA.  If the memory is protected/private, also add the\n+ * allocate pages to the region's set of protected pages, e.g. so that arch\n+ * code knows which pages need to be encrypted when launching the VM.\n  *\n- * Output Args: None\n- *\n- * Return:\n- *   Starting physical address\n- *\n- * Within the VM specified by vm, locates a range of available physical\n- * pages at or above min_gpa. If found, the pages are marked as in use\n- * and their base address is returned. A TEST_ASSERT failure occurs if\n- * not enough pages are available at or above min_gpa.\n+ * Note, success is guaranteed!\n  */\n-gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,\n-\t\t\t   gpa_t min_gpa, u32 memslot,\n-\t\t\t   bool protected)\n+gpa_t ____vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, gpa_t min_gpa,\n+\t\t\t     u32 memslot, bool protected, bool naturally_aligned)\n {\n+\tsize_t alignment = naturally_aligned ? nr_pages : 1;\n \tstruct userspace_mem_region *region;\n \tsparsebit_idx_t pg, base;\n \n-\tTEST_ASSERT(num \u003e 0, \"Must allocate at least one page\");\n+\tTEST_ASSERT(nr_pages, \"Must allocate at least one page\");\n \n \tTEST_ASSERT((min_gpa % vm-\u003epage_size) == 0, \"Min physical address \"\n \t\t\"not divisible by page size.\\n\"\n@@ -2062,43 +2056,78 @@ gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,\n \tTEST_ASSERT(!protected || region-\u003eprotected_phy_pages,\n \t\t    \"Region doesn't support protected memory\");\n \n-\tbase = pg = min_gpa \u003e\u003e vm-\u003epage_shift;\n-\tdo {\n-\t\tfor (; pg \u003c base + num; ++pg) {\n-\t\t\tif (!sparsebit_is_set(region-\u003eunused_phy_pages, pg)) {\n-\t\t\t\tbase = pg = sparsebit_next_set(region-\u003eunused_phy_pages, pg);\n-\t\t\t\tbreak;\n-\t\t\t}\n+\tbase = min_gpa \u003e\u003e vm-\u003epage_shift;\n+again:\n+\tbase = ALIGN(base, alignment);\n+\tfor (pg = base; pg \u003c base + nr_pages; ++pg) {\n+\t\tif (!sparsebit_is_set(region-\u003eunused_phy_pages, pg)) {\n+\t\t\tbase = sparsebit_next_set(region-\u003eunused_phy_pages, pg);\n+\t\t\tif (!base)\n+\t\t\t\tgoto enomem;\n+\t\t\tgoto again;\n \t\t}\n-\t} while (pg \u0026\u0026 pg != base + num);\n-\n-\tif (pg == 0) {\n-\t\tfprintf(stderr, \"No guest physical page available, \"\n-\t\t\t\"min_gpa: 0x%lx page_size: 0x%x memslot: %u\\n\",\n-\t\t\tmin_gpa, vm-\u003epage_size, memslot);\n-\t\tfputs(\"---- vm dump ----\\n\", stderr);\n-\t\tvm_dump(stderr, vm, 2);\n-\t\tabort();\n \t}\n \n-\tfor (pg = base; pg \u003c base + num; ++pg) {\n+\tfor (pg = base; pg \u003c base + nr_pages; ++pg) {\n \t\tsparsebit_clear(region-\u003eunused_phy_pages, pg);\n \t\tif (protected)\n \t\t\tsparsebit_set(region-\u003eprotected_phy_pages, pg);\n \t}\n \n \treturn base * vm-\u003epage_size;\n+\n+enomem:\n+\tfprintf(stderr, \"No guest physical page available, min_gpa: 0x%lx page_size: 0x%x memslot: %u\\n\",\n+\t\tmin_gpa, vm-\u003epage_size, memslot);\n+\tfputs(\"---- vm dump ----\\n\", stderr);\n+\tvm_dump(stderr, vm, 2);\n+\tabort();\n+\t__builtin_unreachable();\n }\n \n-gpa_t vm_phy_page_alloc(struct kvm_vm *vm, gpa_t min_gpa, u32 memslot)\n+__weak bool kvm_arch_needs_naturally_aligned_page_tables(void)\n {\n-\treturn vm_phy_pages_alloc(vm, 1, min_gpa, memslot);\n+\treturn false;\n }\n \n-gpa_t vm_alloc_page_table(struct kvm_vm *vm)\n+gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages,\n+\t\t\t   enum kvm_mem_region_type type, bool protected)\n {\n-\treturn vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR,\n-\t\t\t\t vm-\u003ememslots[MEM_REGION_PT]);\n+\tstruct userspace_mem_region *region = vm_get_mem_region(vm, type);\n+\tbool naturally_aligned = false;\n+\tgpa_t min_gpa;\n+\n+\tTEST_ASSERT(region, \"No region for type '%u', memslot '%u'\",\n+\t\t    type, vm-\u003ememslots[type]);\n+\n+\tswitch (type) {\n+\tcase MEM_REGION_CODE:\n+\tcase MEM_REGION_DATA:\n+\tcase MEM_REGION_TEST_DATA:\n+\t\t/*\n+\t\t * If the region is backed by the default memslot (id=0), use\n+\t\t * selftests' hardcoded minimum PFN, otherwise use the base of\n+\t\t * the custom memory slot that backs the region.\n+\t\t */\n+\t\tif (!vm-\u003ememslots[type])\n+\t\t\tmin_gpa = KVM_UTIL_MIN_PFN * vm-\u003epage_size;\n+\t\telse\n+\t\t\tmin_gpa = region-\u003eregion.guest_phys_addr;\n+\t\tbreak;\n+\tcase MEM_REGION_PT:\n+\t\tmin_gpa = KVM_GUEST_PAGE_TABLE_MIN_PADDR;\n+\t\tnaturally_aligned = kvm_arch_needs_naturally_aligned_page_tables();\n+\t\tbreak;\n+\tcase MEM_REGION_TEST_EXTRA:\n+\t\tmin_gpa = region-\u003eregion.guest_phys_addr;\n+\t\tbreak;\n+\tdefault:\n+\t\tTEST_FAIL(\"Invalid memory region type '%u'\", type);\n+\t\tbreak;\n+\t}\n+\n+\treturn ____vm_phy_pages_alloc(vm, nr_pages, min_gpa, vm-\u003ememslots[type],\n+\t\t\t\t      protected, naturally_aligned);\n }\n \n /*\ndiff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/testing/selftests/kvm/lib/loongarch/processor.c\nindex 47bbde3e205a0..fcd41bc6fbdae 100644\n--- a/tools/testing/selftests/kvm/lib/loongarch/processor.c\n+++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c\n@@ -9,7 +9,6 @@\n #include \"processor.h\"\n #include \"ucall_common.h\"\n \n-#define LOONGARCH_PAGE_TABLE_PHYS_MIN\t\t0x200000\n #define LOONGARCH_GUEST_STACK_VADDR_MIN\t\t0x200000\n \n static gpa_t invalid_pgtable[4];\n@@ -57,9 +56,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)\n \tchild = table = 0;\n \tfor (i = 0; i \u003c vm-\u003emmu.pgtable_levels; i++) {\n \t\tinvalid_pgtable[i] = child;\n-\t\ttable = vm_phy_page_alloc(vm, LOONGARCH_PAGE_TABLE_PHYS_MIN,\n-\t\t\t\tvm-\u003ememslots[MEM_REGION_PT]);\n-\t\tTEST_ASSERT(table, \"Fail to allocate page tale at level %d\\n\", i);\n+\t\ttable = vm_alloc_page_table(vm);\n \t\tvirt_set_pgtable(vm, table, child);\n \t\tchild = table;\n \t}\ndiff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c\nindex ded5429f34483..c175dcd141144 100644\n--- a/tools/testing/selftests/kvm/lib/riscv/processor.c\n+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c\n@@ -69,9 +69,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)\n \tif (vm-\u003emmu.pgd_created)\n \t\treturn;\n \n-\tvm-\u003emmu.pgd = vm_phy_pages_alloc(vm, nr_pages,\n-\t\t\t\t\t KVM_GUEST_PAGE_TABLE_MIN_PADDR,\n-\t\t\t\t\t vm-\u003ememslots[MEM_REGION_PT]);\n+\tvm-\u003emmu.pgd = vm_alloc_page_table_pages(vm, nr_pages);\n \tvm-\u003emmu.pgd_created = true;\n }\n \ndiff --git a/tools/testing/selftests/kvm/lib/s390/processor.c b/tools/testing/selftests/kvm/lib/s390/processor.c\nindex a9adb3782b352..33f49d743b5fd 100644\n--- a/tools/testing/selftests/kvm/lib/s390/processor.c\n+++ b/tools/testing/selftests/kvm/lib/s390/processor.c\n@@ -20,9 +20,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)\n \tif (vm-\u003emmu.pgd_created)\n \t\treturn;\n \n-\tgpa = vm_phy_pages_alloc(vm, PAGES_PER_REGION,\n-\t\t\t\t   KVM_GUEST_PAGE_TABLE_MIN_PADDR,\n-\t\t\t\t   vm-\u003ememslots[MEM_REGION_PT]);\n+\tgpa = vm_alloc_page_table_pages(vm, PAGES_PER_REGION);\n \tmemset(addr_gpa2hva(vm, gpa), 0xff, PAGES_PER_REGION * vm-\u003epage_size);\n \n \tvm-\u003emmu.pgd = gpa;\n@@ -38,8 +36,7 @@ static u64 virt_alloc_region(struct kvm_vm *vm, int ri)\n {\n \tu64 taddr;\n \n-\ttaddr = vm_phy_pages_alloc(vm,  ri \u003c 4 ? PAGES_PER_REGION : 1,\n-\t\t\t\t   KVM_GUEST_PAGE_TABLE_MIN_PADDR, 0);\n+\ttaddr = vm_alloc_page_table_pages(vm, ri \u003c 4 ? PAGES_PER_REGION : 1);\n \tmemset(addr_gpa2hva(vm, taddr), 0xff, PAGES_PER_REGION * vm-\u003epage_size);\n \n \treturn (taddr \u0026 REGION_ENTRY_ORIGIN)\ndiff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c\nindex d31fa81ea0756..479e9a481687d 100644\n--- a/tools/testing/selftests/kvm/lib/x86/processor.c\n+++ b/tools/testing/selftests/kvm/lib/x86/processor.c\n@@ -529,7 +529,10 @@ void tdp_identity_map_default_memslots(struct kvm_vm *vm)\n \n \t/* Only memslot 0 is mapped here, ensure it's the only one being used */\n \tfor (s = 0; s \u003c NR_MEM_REGIONS; s++)\n-\t\tTEST_ASSERT_EQ(vm-\u003ememslots[s], 0);\n+\t\tTEST_ASSERT(!vm-\u003ememslots[s] ||\n+\t\t\t    vm-\u003ememslots[s] == KVM_INVALID_MEMSLOT,\n+\t\t\t    \"Unhandled memslot '%u' for type '%u'\",\n+\t\t\t    vm-\u003ememslots[s], s);\n \n \ti = (region-\u003eregion.guest_phys_addr \u003e\u003e vm-\u003epage_shift) - 1;\n \tlast = i + (region-\u003eregion.memory_size \u003e\u003e vm-\u003epage_shift);\n@@ -1465,13 +1468,13 @@ bool kvm_arch_has_default_irqchip(void)\n \treturn true;\n }\n \n-void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, u64 smram_gpa,\n+void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, gpa_t smram_gpa,\n \t\t const void *smi_handler, size_t handler_size)\n {\n-\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, smram_gpa,\n-\t\t\t\t    SMRAM_MEMSLOT, SMRAM_PAGES, 0);\n-\tTEST_ASSERT(vm_phy_pages_alloc(vm, SMRAM_PAGES, smram_gpa,\n-\t\t\t\t       SMRAM_MEMSLOT) == smram_gpa,\n+\tvm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS,\n+\t\t\t       smram_gpa, SMRAM_MEMSLOT, SMRAM_PAGES);\n+\n+\tTEST_ASSERT(vm_phy_pages_alloc(vm, SMRAM_PAGES, MEM_REGION_TEST_EXTRA) == smram_gpa,\n \t\t    \"Could not allocate guest physical addresses for SMRAM\");\n \n \tmemset(addr_gpa2hva(vm, smram_gpa), 0x0, SMRAM_SIZE);\ndiff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c\nindex e1299611be322..844ea9b7bb41c 100644\n--- a/tools/testing/selftests/kvm/memslot_perf_test.c\n+++ b/tools/testing/selftests/kvm/memslot_perf_test.c\n@@ -339,7 +339,8 @@ static bool prepare_vm(struct vm_data *data, int nslots, u64 *maxslots,\n \t\tif (slot == data-\u003enslots)\n \t\t\tnpages += rempages;\n \n-\t\tgpa = vm_phy_pages_alloc(data-\u003evm, npages, guest_addr, slot);\n+\t\tgpa = ____vm_phy_pages_alloc(data-\u003evm, npages, guest_addr, slot,\n+\t\t\t\t\t     false, false);\n \t\tTEST_ASSERT(gpa == guest_addr,\n \t\t\t    \"vm_phy_pages_alloc() failed\");\n \ndiff --git a/tools/testing/selftests/kvm/s390/cmma_test.c b/tools/testing/selftests/kvm/s390/cmma_test.c\nindex 15d81b2ed7ad3..73387cc3bca76 100644\n--- a/tools/testing/selftests/kvm/s390/cmma_test.c\n+++ b/tools/testing/selftests/kvm/s390/cmma_test.c\n@@ -102,24 +102,17 @@ static void guest_dirty_test_data(void)\n \n static void create_main_memslot(struct kvm_vm *vm)\n {\n-\tint i;\n-\n \tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, MAIN_PAGE_COUNT, 0);\n-\t/* set the array of memslots to zero like __vm_create does */\n-\tfor (i = 0; i \u003c NR_MEM_REGIONS; i++)\n-\t\tvm-\u003ememslots[i] = 0;\n+\t____vm_override_mem_region(vm, MEM_REGION_CODE, 0);\n+\t____vm_override_mem_region(vm, MEM_REGION_PT, 0);\n+\t____vm_override_mem_region(vm, MEM_REGION_DATA, 0);\n }\n \n static void create_test_memslot(struct kvm_vm *vm)\n {\n-\tvm_userspace_mem_region_add(vm,\n-\t\t\t\t    VM_MEM_SRC_ANONYMOUS,\n-\t\t\t\t    TEST_DATA_START_GFN \u003c\u003c vm-\u003epage_shift,\n-\t\t\t\t    TEST_DATA_MEMSLOT,\n-\t\t\t\t    TEST_DATA_PAGE_COUNT,\n-\t\t\t\t    0\n-\t\t\t\t   );\n-\tvm-\u003ememslots[MEM_REGION_TEST_DATA] = TEST_DATA_MEMSLOT;\n+\tvm_override_mem_region(vm, MEM_REGION_TEST_DATA, VM_MEM_SRC_ANONYMOUS,\n+\t\t\t       TEST_DATA_START_GFN \u003c\u003c vm-\u003epage_shift,\n+\t\t\t       TEST_DATA_MEMSLOT, TEST_DATA_PAGE_COUNT);\n }\n \n static void create_memslots(struct kvm_vm *vm)\ndiff --git a/tools/testing/selftests/kvm/s390/irq_routing.c b/tools/testing/selftests/kvm/s390/irq_routing.c\nindex f3839284ac081..cd26cc1aed803 100644\n--- a/tools/testing/selftests/kvm/s390/irq_routing.c\n+++ b/tools/testing/selftests/kvm/s390/irq_routing.c\n@@ -36,7 +36,7 @@ static void test(void)\n \t};\n \n \tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n-\tmem = vm_phy_pages_alloc(vm, 2, 4096 * 42, 0);\n+\tmem = ____vm_phy_pages_alloc(vm, 2, 4096 * 42, 0, false, false);\n \n \trouting = kvm_gsi_routing_create();\n \trouting-\u003enr = 1;\ndiff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c\nindex dffe9654f45bd..bfa5ac8ce0295 100644\n--- a/tools/testing/selftests/kvm/set_memory_region_test.c\n+++ b/tools/testing/selftests/kvm/set_memory_region_test.c\n@@ -116,15 +116,15 @@ static struct kvm_vm *spawn_vm(struct kvm_vcpu **vcpu, pthread_t *vcpu_thread,\n \n \tvm = vm_create_with_one_vcpu(vcpu, guest_code);\n \n-\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS_THP,\n-\t\t\t\t    MEM_REGION_GPA, MEM_REGION_SLOT,\n-\t\t\t\t    MEM_REGION_SIZE / getpagesize(), 0);\n+\tvm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS_THP,\n+\t\t\t       MEM_REGION_GPA, MEM_REGION_SLOT,\n+\t\t\t       MEM_REGION_SIZE / getpagesize());\n \n \t/*\n \t * Allocate and map two pages so that the GPA accessed by guest_code()\n \t * stays valid across the memslot move.\n \t */\n-\tgpa = vm_phy_pages_alloc(vm, 2, MEM_REGION_GPA, MEM_REGION_SLOT);\n+\tgpa = vm_phy_pages_alloc(vm, 2, MEM_REGION_TEST_EXTRA);\n \tTEST_ASSERT(gpa == MEM_REGION_GPA, \"Failed vm_phy_pages_alloc\\n\");\n \n \tvirt_map(vm, MEM_REGION_GPA, MEM_REGION_GPA, 2);\ndiff --git a/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c b/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c\nindex 3dca85e954781..8d1822717abdc 100644\n--- a/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c\n+++ b/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c\n@@ -62,11 +62,12 @@ int main(int argc, char *argv[])\n \tTEST_ASSERT(rc, \"KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable\");\n \tvm_enable_cap(vm, KVM_CAP_EXIT_ON_EMULATION_FAILURE, 1);\n \n-\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,\n-\t\t\t\t    MEM_REGION_GPA, MEM_REGION_SLOT,\n-\t\t\t\t    MEM_REGION_SIZE / PAGE_SIZE, 0);\n+\tvm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS,\n+\t\t\t       MEM_REGION_GPA, MEM_REGION_SLOT,\n+\t\t\t       MEM_REGION_SIZE / PAGE_SIZE);\n+\n \tgpa = vm_phy_pages_alloc(vm, MEM_REGION_SIZE / PAGE_SIZE,\n-\t\t\t\t MEM_REGION_GPA, MEM_REGION_SLOT);\n+\t\t\t\t MEM_REGION_TEST_EXTRA);\n \tTEST_ASSERT(gpa == MEM_REGION_GPA, \"Failed vm_phy_pages_alloc\");\n \tvirt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1);\n \thva = addr_gpa2hva(vm, MEM_REGION_GPA);\n"
}

2/1 2026/08/26 23:12 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies userspace testing tools (KVM selftests) in tools/testing/selftests/kvm/. It does not make any functional changes to the core kernel logic, drivers, or architectures.",
  "WorthFuzzing": false
}

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 220a59c810ce6afc4c5cd7e313b1242003d92f23
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Aug 26 23:12:02 2026 +0000

    syz-cluster: applied patch under review

diff --git a/tools/testing/selftests/kvm/arm64/page_fault_test.c b/tools/testing/selftests/kvm/arm64/page_fault_test.c
index 6bb3d82906b22..b0e3fc8cd76ac 100644
--- a/tools/testing/selftests/kvm/arm64/page_fault_test.c
+++ b/tools/testing/selftests/kvm/arm64/page_fault_test.c
@@ -597,18 +597,16 @@ static void setup_memslots(struct kvm_vm *vm, struct test_params *p)
 
 	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0,
 				    CODE_AND_DATA_MEMSLOT, code_npages, 0);
-	vm->memslots[MEM_REGION_CODE] = CODE_AND_DATA_MEMSLOT;
-	vm->memslots[MEM_REGION_DATA] = CODE_AND_DATA_MEMSLOT;
-
-	vm_userspace_mem_region_add(vm, p->src_type, data_gpa - pt_size,
-				    PAGE_TABLE_MEMSLOT, pt_size / guest_page_size,
-				    p->test_desc->pt_memslot_flags);
-	vm->memslots[MEM_REGION_PT] = PAGE_TABLE_MEMSLOT;
-
-	vm_userspace_mem_region_add(vm, p->src_type, data_gpa, TEST_DATA_MEMSLOT,
-				    data_size / guest_page_size,
-				    p->test_desc->data_memslot_flags);
-	vm->memslots[MEM_REGION_TEST_DATA] = TEST_DATA_MEMSLOT;
+	____vm_override_mem_region(vm, MEM_REGION_CODE, CODE_AND_DATA_MEMSLOT);
+	____vm_override_mem_region(vm, MEM_REGION_DATA, CODE_AND_DATA_MEMSLOT);
+
+	__vm_override_mem_region(vm, MEM_REGION_PT, p->src_type, data_gpa - pt_size,
+				 PAGE_TABLE_MEMSLOT, pt_size / guest_page_size,
+				 p->test_desc->pt_memslot_flags);
+
+	__vm_override_mem_region(vm, MEM_REGION_TEST_DATA, p->src_type, data_gpa,
+				 TEST_DATA_MEMSLOT, data_size / guest_page_size,
+				 p->test_desc->data_memslot_flags);
 }
 
 static void setup_ucall(struct kvm_vm *vm)
diff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
index 9a69c439a0f8f..b4c651ea385d8 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
@@ -164,8 +164,8 @@ static void setup_memslot(void)
 
 	pages = sz / vm->page_size;
 	gpa_base = ((vm_compute_max_gfn(vm) + 1) * vm->page_size) - sz;
-	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, gpa_base,
-				    TEST_MEMSLOT_INDEX, pages, 0);
+	vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS,
+			       gpa_base, TEST_MEMSLOT_INDEX, pages);
 }
 
 #define LPI_PROP_DEFAULT_PRIO	0xa0
@@ -191,28 +191,25 @@ static void setup_test_data(void)
 	gpa_t cmdq_base;
 
 	test_data.device_table = vm_phy_pages_alloc(vm, pages_per_64k,
-						    gpa_base,
-						    TEST_MEMSLOT_INDEX);
+						    MEM_REGION_TEST_EXTRA);
 
 	test_data.collection_table = vm_phy_pages_alloc(vm, pages_per_64k,
-							gpa_base,
-							TEST_MEMSLOT_INDEX);
+							MEM_REGION_TEST_EXTRA);
 
-	cmdq_base = vm_phy_pages_alloc(vm, pages_per_64k, gpa_base,
-				       TEST_MEMSLOT_INDEX);
+	cmdq_base = vm_phy_pages_alloc(vm, pages_per_64k, MEM_REGION_TEST_EXTRA);
 	virt_map(vm, cmdq_base, cmdq_base, pages_per_64k);
 	test_data.cmdq_base = cmdq_base;
 	test_data.cmdq_base_va = (void *)cmdq_base;
 
 	test_data.itt_tables = vm_phy_pages_alloc(vm, pages_per_64k * nr_devices,
-						  gpa_base, TEST_MEMSLOT_INDEX);
+						  MEM_REGION_TEST_EXTRA);
 
 	test_data.lpi_prop_table = vm_phy_pages_alloc(vm, pages_per_64k,
-						      gpa_base, TEST_MEMSLOT_INDEX);
+						      MEM_REGION_TEST_EXTRA);
 	configure_lpis();
 
 	test_data.lpi_pend_tables = vm_phy_pages_alloc(vm, pages_per_64k * nr_cpus,
-						       gpa_base, TEST_MEMSLOT_INDEX);
+						       MEM_REGION_TEST_EXTRA);
 
 	sync_global_to_guest(vm, test_data);
 }
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 5a7a455b53875..ffd4cf740d7fa 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -33,6 +33,8 @@
 
 #define NSEC_PER_SEC 1000000000L
 
+#define KVM_INVALID_MEMSLOT UINT_MAX
+
 struct userspace_mem_region {
 	struct kvm_userspace_memory_region2 region;
 	struct sparsebit *unused_phy_pages;
@@ -80,11 +82,43 @@ struct userspace_mem_regions {
 	DECLARE_HASHTABLE(slot_hash, 9);
 };
 
+/*
+ * Memory region types are passed to various page allocators to communicate
+ * various properties and metadata related to the allocation.  Note, the
+ * descriptions below described the primary usage of each type.  Individual
+ * tests may allocate memory for other purposes.
+ *
+ * By default, all regions are mapped to memslot '0'.  Tests can override the
+ * memslot for any or all types, e.g. so that all test data is allocated from a
+ * curated memslot.
+ */
 enum kvm_mem_region_type {
+	/*
+	 * The CODE region is used by lib/elf when loading the test's code into
+	 * guest memory.
+	 */
 	MEM_REGION_CODE,
+	/*
+	 * The DATA region is used to allocate core data structures, e.g. vCPU
+	 * stacks, VM exception tables, x86's TSS, etc.
+	 */
 	MEM_REGION_DATA,
+	/*
+	 * The PT region, a.k.a. Page Table region, is used to allocate page
+	 * table pages.
+	 */
 	MEM_REGION_PT,
+	/*
+	 * The TEST_DATA region is used for allocating test data that is either
+	 * test specific, and/or isn't considered a "core" data structure.
+	 */
 	MEM_REGION_TEST_DATA,
+	/*
+	 * The TEST_EXTRA region is for special snowflakes, where a test wants
+	 * to create and use a one-off memslot, without impacting "normal" test
+	 * data allocations.
+	 */
+	MEM_REGION_TEST_EXTRA,
 	NR_MEM_REGIONS,
 };
 
@@ -127,11 +161,6 @@ struct kvm_vm {
 
 	struct kvm_binary_stats stats;
 
-	/*
-	 * KVM region slots. These are the default memslots used by page
-	 * allocators, e.g., lib/elf uses the memslots[MEM_REGION_CODE]
-	 * memslot.
-	 */
 	u32 memslots[NR_MEM_REGIONS];
 };
 
@@ -169,13 +198,14 @@ memslot2region(struct kvm_vm *vm, u32 memslot);
 static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm,
 							     enum kvm_mem_region_type type)
 {
-	assert(type < NR_MEM_REGIONS);
+	TEST_ASSERT(type < NR_MEM_REGIONS,
+		    "Invalid memory region type '%u'", type);
 	return memslot2region(vm, vm->memslots[type]);
 }
 
 /* Minimum allocated guest virtual and physical addresses */
 #define KVM_UTIL_MIN_VADDR		0x2000
-#define KVM_GUEST_PAGE_TABLE_MIN_PADDR	0x180000
+#define KVM_GUEST_PAGE_TABLE_MIN_PADDR	0x200000
 
 #define DEFAULT_GUEST_STACK_VADDR_MIN	0xab6000
 #define DEFAULT_STACK_PGS		5
@@ -702,6 +732,36 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
 		gpa_t gpa, u32 slot, u64 npages, u32 flags,
 		int guest_memfd_fd, u64 guest_memfd_offset);
 
+
+static inline void ____vm_override_mem_region(struct kvm_vm *vm,
+					      enum kvm_mem_region_type type,
+					      u32 slot)
+{
+	TEST_ASSERT(vm->memslots[type] == KVM_INVALID_MEMSLOT,
+		    "Memory region type '%u' was already overridden with slot=%u",
+		    type, vm->memslots[type]);
+
+	vm->memslots[type] = slot;
+}
+
+static inline void __vm_override_mem_region(struct kvm_vm *vm,
+					    enum kvm_mem_region_type type,
+					    enum vm_mem_backing_src_type src_type,
+					    gpa_t gpa, u32 slot, u64 npages,
+					    u32 flags)
+{
+	____vm_override_mem_region(vm, type, slot);
+	vm_userspace_mem_region_add(vm, src_type, gpa, slot, npages, flags);
+}
+
+static inline void vm_override_mem_region(struct kvm_vm *vm,
+					  enum kvm_mem_region_type type,
+					  enum vm_mem_backing_src_type src_type,
+					  gpa_t gpa, u32 slot, u64 npages)
+{
+	__vm_override_mem_region(vm, type, src_type, gpa, slot, npages, 0);
+}
+
 #ifndef vm_arch_has_protected_memory
 static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm)
 {
@@ -990,23 +1050,41 @@ void kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *routing);
 
 const char *exit_reason_str(unsigned int exit_reason);
 
-gpa_t vm_phy_page_alloc(struct kvm_vm *vm, gpa_t min_gpa, u32 memslot);
-gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, gpa_t min_gpa,
-			   u32 memslot, bool protected);
-gpa_t vm_alloc_page_table(struct kvm_vm *vm);
+bool kvm_arch_needs_naturally_aligned_page_tables(void);
+
+gpa_t ____vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, gpa_t min_gpa,
+			     u32 memslot, bool protected, bool naturally_aligned);
+gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages,
+			   enum kvm_mem_region_type type, bool protected);
 
-static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
-				       gpa_t min_gpa, u32 memslot)
+static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages,
+				       enum kvm_mem_region_type type)
 {
 	/*
 	 * By default, allocate memory as protected for VMs that support
 	 * protected memory, as the majority of memory for such VMs is
 	 * protected, i.e. using shared memory is effectively opt-in.
 	 */
-	return __vm_phy_pages_alloc(vm, num, min_gpa, memslot,
+	return __vm_phy_pages_alloc(vm, nr_pages, type,
 				    vm_arch_has_protected_memory(vm));
 }
 
+static inline gpa_t vm_phy_page_alloc(struct kvm_vm *vm,
+				      enum kvm_mem_region_type type)
+{
+	return vm_phy_pages_alloc(vm, 1, type);
+}
+
+static inline gpa_t vm_alloc_page_table_pages(struct kvm_vm *vm, size_t nr_pages)
+{
+	return vm_phy_pages_alloc(vm, nr_pages, MEM_REGION_PT);
+}
+
+static inline gpa_t vm_alloc_page_table(struct kvm_vm *vm)
+{
+	return vm_alloc_page_table_pages(vm, 1);
+}
+
 /*
  * ____vm_create() does KVM_CREATE_VM and little else.  __vm_create() also
  * loads the test binary into guest memory and creates an IRQ chip (x86 only).
diff --git a/tools/testing/selftests/kvm/include/x86/smm.h b/tools/testing/selftests/kvm/include/x86/smm.h
index 2d1afa09819b0..15faaa0601262 100644
--- a/tools/testing/selftests/kvm/include/x86/smm.h
+++ b/tools/testing/selftests/kvm/include/x86/smm.h
@@ -8,7 +8,7 @@
 #define SMRAM_MEMSLOT	((1 << 16) | 1)
 #define SMRAM_PAGES	(SMRAM_SIZE / PAGE_SIZE)
 
-void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, u64 smram_gpa,
+void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, gpa_t smram_gpa,
 		 const void *smi_handler, size_t handler_size);
 
 void inject_smi(struct kvm_vcpu *vcpu);
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index 01325bf4d36fc..2dcaa2c4a0383 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -115,9 +115,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	if (vm->mmu.pgd_created)
 		return;
 
-	vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages,
-					 KVM_GUEST_PAGE_TABLE_MIN_PADDR,
-					 vm->memslots[MEM_REGION_PT]);
+	vm->mmu.pgd = vm_alloc_page_table_pages(vm, nr_pages);
 	vm->mmu.pgd_created = true;
 }
 
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 9ddc047d5c275..57b653fbd0b1f 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -17,6 +17,7 @@
 #include <sys/stat.h>
 #include <time.h>
 #include <unistd.h>
+#include <linux/align.h>
 #include <linux/kernel.h>
 
 #define KVM_UTIL_MIN_PFN	2
@@ -287,6 +288,7 @@ __weak void vm_populate_gva_bitmap(struct kvm_vm *vm)
 struct kvm_vm *____vm_create(struct vm_shape shape)
 {
 	struct kvm_vm *vm;
+	int i;
 
 	vm = calloc(1, sizeof(*vm));
 	TEST_ASSERT(vm != NULL, "Insufficient Memory");
@@ -295,6 +297,8 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
 	vm->regions.gpa_tree = RB_ROOT;
 	vm->regions.hva_tree = RB_ROOT;
 	hash_init(vm->regions.slot_hash);
+	for (i = 0; i < NR_MEM_REGIONS; i++)
+		vm->memslots[i] = KVM_INVALID_MEMSLOT;
 
 	vm->mode = shape.mode;
 	vm->type = shape.type;
@@ -491,7 +495,7 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,
 						 nr_extra_pages);
 	struct userspace_mem_region *slot0;
 	struct kvm_vm *vm;
-	int i, flags;
+	int flags;
 
 	kvm_set_files_rlimit(nr_runnable_vcpus);
 
@@ -509,8 +513,10 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,
 		flags |= KVM_MEM_GUEST_MEMFD;
 
 	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, nr_pages, flags);
-	for (i = 0; i < NR_MEM_REGIONS; i++)
-		vm->memslots[i] = 0;
+	____vm_override_mem_region(vm, MEM_REGION_CODE, 0);
+	____vm_override_mem_region(vm, MEM_REGION_PT, 0);
+	____vm_override_mem_region(vm, MEM_REGION_DATA, 0);
+	____vm_override_mem_region(vm, MEM_REGION_TEST_DATA, 0);
 
 	kvm_vm_elf_load(vm, program_invocation_name);
 
@@ -1189,6 +1195,8 @@ memslot2region(struct kvm_vm *vm, u32 memslot)
 {
 	struct userspace_mem_region *region;
 
+	TEST_ASSERT(memslot != KVM_INVALID_MEMSLOT, "vm->memslots[] unpopulated?");
+
 	hash_for_each_possible(vm->regions.slot_hash, region, slot_node,
 			       memslot)
 		if (region->region.slot == memslot)
@@ -1465,9 +1473,7 @@ static gva_t ____vm_alloc(struct kvm_vm *vm, size_t sz, gva_t min_gva,
 	u64 pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0);
 
 	virt_pgd_alloc(vm);
-	gpa_t gpa = __vm_phy_pages_alloc(vm, pages,
-					   KVM_UTIL_MIN_PFN * vm->page_size,
-					   vm->memslots[type], protected);
+	gpa_t gpa = __vm_phy_pages_alloc(vm, pages, type, protected);
 
 	/*
 	 * Find an unused range of virtual page addresses of at least
@@ -2025,33 +2031,21 @@ const char *exit_reason_str(unsigned int exit_reason)
 }
 
 /*
- * Physical Contiguous Page Allocator
- *
- * Input Args:
- *   vm - Virtual Machine
- *   num - number of pages
- *   min_gpa - Physical address minimum
- *   memslot - Memory region to allocate page from
- *   protected - True if the pages will be used as protected/private memory
+ * Allocate contiguous (guest) physical pages in a given memory region, at or
+ * the minimum specific GPA.  If the memory is protected/private, also add the
+ * allocate pages to the region's set of protected pages, e.g. so that arch
+ * code knows which pages need to be encrypted when launching the VM.
  *
- * Output Args: None
- *
- * Return:
- *   Starting physical address
- *
- * Within the VM specified by vm, locates a range of available physical
- * pages at or above min_gpa. If found, the pages are marked as in use
- * and their base address is returned. A TEST_ASSERT failure occurs if
- * not enough pages are available at or above min_gpa.
+ * Note, success is guaranteed!
  */
-gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
-			   gpa_t min_gpa, u32 memslot,
-			   bool protected)
+gpa_t ____vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, gpa_t min_gpa,
+			     u32 memslot, bool protected, bool naturally_aligned)
 {
+	size_t alignment = naturally_aligned ? nr_pages : 1;
 	struct userspace_mem_region *region;
 	sparsebit_idx_t pg, base;
 
-	TEST_ASSERT(num > 0, "Must allocate at least one page");
+	TEST_ASSERT(nr_pages, "Must allocate at least one page");
 
 	TEST_ASSERT((min_gpa % vm->page_size) == 0, "Min physical address "
 		"not divisible by page size.\n"
@@ -2062,43 +2056,78 @@ gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
 	TEST_ASSERT(!protected || region->protected_phy_pages,
 		    "Region doesn't support protected memory");
 
-	base = pg = min_gpa >> vm->page_shift;
-	do {
-		for (; pg < base + num; ++pg) {
-			if (!sparsebit_is_set(region->unused_phy_pages, pg)) {
-				base = pg = sparsebit_next_set(region->unused_phy_pages, pg);
-				break;
-			}
+	base = min_gpa >> vm->page_shift;
+again:
+	base = ALIGN(base, alignment);
+	for (pg = base; pg < base + nr_pages; ++pg) {
+		if (!sparsebit_is_set(region->unused_phy_pages, pg)) {
+			base = sparsebit_next_set(region->unused_phy_pages, pg);
+			if (!base)
+				goto enomem;
+			goto again;
 		}
-	} while (pg && pg != base + num);
-
-	if (pg == 0) {
-		fprintf(stderr, "No guest physical page available, "
-			"min_gpa: 0x%lx page_size: 0x%x memslot: %u\n",
-			min_gpa, vm->page_size, memslot);
-		fputs("---- vm dump ----\n", stderr);
-		vm_dump(stderr, vm, 2);
-		abort();
 	}
 
-	for (pg = base; pg < base + num; ++pg) {
+	for (pg = base; pg < base + nr_pages; ++pg) {
 		sparsebit_clear(region->unused_phy_pages, pg);
 		if (protected)
 			sparsebit_set(region->protected_phy_pages, pg);
 	}
 
 	return base * vm->page_size;
+
+enomem:
+	fprintf(stderr, "No guest physical page available, min_gpa: 0x%lx page_size: 0x%x memslot: %u\n",
+		min_gpa, vm->page_size, memslot);
+	fputs("---- vm dump ----\n", stderr);
+	vm_dump(stderr, vm, 2);
+	abort();
+	__builtin_unreachable();
 }
 
-gpa_t vm_phy_page_alloc(struct kvm_vm *vm, gpa_t min_gpa, u32 memslot)
+__weak bool kvm_arch_needs_naturally_aligned_page_tables(void)
 {
-	return vm_phy_pages_alloc(vm, 1, min_gpa, memslot);
+	return false;
 }
 
-gpa_t vm_alloc_page_table(struct kvm_vm *vm)
+gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages,
+			   enum kvm_mem_region_type type, bool protected)
 {
-	return vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR,
-				 vm->memslots[MEM_REGION_PT]);
+	struct userspace_mem_region *region = vm_get_mem_region(vm, type);
+	bool naturally_aligned = false;
+	gpa_t min_gpa;
+
+	TEST_ASSERT(region, "No region for type '%u', memslot '%u'",
+		    type, vm->memslots[type]);
+
+	switch (type) {
+	case MEM_REGION_CODE:
+	case MEM_REGION_DATA:
+	case MEM_REGION_TEST_DATA:
+		/*
+		 * If the region is backed by the default memslot (id=0), use
+		 * selftests' hardcoded minimum PFN, otherwise use the base of
+		 * the custom memory slot that backs the region.
+		 */
+		if (!vm->memslots[type])
+			min_gpa = KVM_UTIL_MIN_PFN * vm->page_size;
+		else
+			min_gpa = region->region.guest_phys_addr;
+		break;
+	case MEM_REGION_PT:
+		min_gpa = KVM_GUEST_PAGE_TABLE_MIN_PADDR;
+		naturally_aligned = kvm_arch_needs_naturally_aligned_page_tables();
+		break;
+	case MEM_REGION_TEST_EXTRA:
+		min_gpa = region->region.guest_phys_addr;
+		break;
+	default:
+		TEST_FAIL("Invalid memory region type '%u'", type);
+		break;
+	}
+
+	return ____vm_phy_pages_alloc(vm, nr_pages, min_gpa, vm->memslots[type],
+				      protected, naturally_aligned);
 }
 
 /*
diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/testing/selftests/kvm/lib/loongarch/processor.c
index 47bbde3e205a0..fcd41bc6fbdae 100644
--- a/tools/testing/selftests/kvm/lib/loongarch/processor.c
+++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c
@@ -9,7 +9,6 @@
 #include "processor.h"
 #include "ucall_common.h"
 
-#define LOONGARCH_PAGE_TABLE_PHYS_MIN		0x200000
 #define LOONGARCH_GUEST_STACK_VADDR_MIN		0x200000
 
 static gpa_t invalid_pgtable[4];
@@ -57,9 +56,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	child = table = 0;
 	for (i = 0; i < vm->mmu.pgtable_levels; i++) {
 		invalid_pgtable[i] = child;
-		table = vm_phy_page_alloc(vm, LOONGARCH_PAGE_TABLE_PHYS_MIN,
-				vm->memslots[MEM_REGION_PT]);
-		TEST_ASSERT(table, "Fail to allocate page tale at level %d\n", i);
+		table = vm_alloc_page_table(vm);
 		virt_set_pgtable(vm, table, child);
 		child = table;
 	}
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index ded5429f34483..c175dcd141144 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -69,9 +69,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	if (vm->mmu.pgd_created)
 		return;
 
-	vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages,
-					 KVM_GUEST_PAGE_TABLE_MIN_PADDR,
-					 vm->memslots[MEM_REGION_PT]);
+	vm->mmu.pgd = vm_alloc_page_table_pages(vm, nr_pages);
 	vm->mmu.pgd_created = true;
 }
 
diff --git a/tools/testing/selftests/kvm/lib/s390/processor.c b/tools/testing/selftests/kvm/lib/s390/processor.c
index a9adb3782b352..33f49d743b5fd 100644
--- a/tools/testing/selftests/kvm/lib/s390/processor.c
+++ b/tools/testing/selftests/kvm/lib/s390/processor.c
@@ -20,9 +20,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	if (vm->mmu.pgd_created)
 		return;
 
-	gpa = vm_phy_pages_alloc(vm, PAGES_PER_REGION,
-				   KVM_GUEST_PAGE_TABLE_MIN_PADDR,
-				   vm->memslots[MEM_REGION_PT]);
+	gpa = vm_alloc_page_table_pages(vm, PAGES_PER_REGION);
 	memset(addr_gpa2hva(vm, gpa), 0xff, PAGES_PER_REGION * vm->page_size);
 
 	vm->mmu.pgd = gpa;
@@ -38,8 +36,7 @@ static u64 virt_alloc_region(struct kvm_vm *vm, int ri)
 {
 	u64 taddr;
 
-	taddr = vm_phy_pages_alloc(vm,  ri < 4 ? PAGES_PER_REGION : 1,
-				   KVM_GUEST_PAGE_TABLE_MIN_PADDR, 0);
+	taddr = vm_alloc_page_table_pages(vm, ri < 4 ? PAGES_PER_REGION : 1);
 	memset(addr_gpa2hva(vm, taddr), 0xff, PAGES_PER_REGION * vm->page_size);
 
 	return (taddr & REGION_ENTRY_ORIGIN)
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index d31fa81ea0756..479e9a481687d 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -529,7 +529,10 @@ void tdp_identity_map_default_memslots(struct kvm_vm *vm)
 
 	/* Only memslot 0 is mapped here, ensure it's the only one being used */
 	for (s = 0; s < NR_MEM_REGIONS; s++)
-		TEST_ASSERT_EQ(vm->memslots[s], 0);
+		TEST_ASSERT(!vm->memslots[s] ||
+			    vm->memslots[s] == KVM_INVALID_MEMSLOT,
+			    "Unhandled memslot '%u' for type '%u'",
+			    vm->memslots[s], s);
 
 	i = (region->region.guest_phys_addr >> vm->page_shift) - 1;
 	last = i + (region->region.memory_size >> vm->page_shift);
@@ -1465,13 +1468,13 @@ bool kvm_arch_has_default_irqchip(void)
 	return true;
 }
 
-void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, u64 smram_gpa,
+void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, gpa_t smram_gpa,
 		 const void *smi_handler, size_t handler_size)
 {
-	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, smram_gpa,
-				    SMRAM_MEMSLOT, SMRAM_PAGES, 0);
-	TEST_ASSERT(vm_phy_pages_alloc(vm, SMRAM_PAGES, smram_gpa,
-				       SMRAM_MEMSLOT) == smram_gpa,
+	vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS,
+			       smram_gpa, SMRAM_MEMSLOT, SMRAM_PAGES);
+
+	TEST_ASSERT(vm_phy_pages_alloc(vm, SMRAM_PAGES, MEM_REGION_TEST_EXTRA) == smram_gpa,
 		    "Could not allocate guest physical addresses for SMRAM");
 
 	memset(addr_gpa2hva(vm, smram_gpa), 0x0, SMRAM_SIZE);
diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index e1299611be322..844ea9b7bb41c 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -339,7 +339,8 @@ static bool prepare_vm(struct vm_data *data, int nslots, u64 *maxslots,
 		if (slot == data->nslots)
 			npages += rempages;
 
-		gpa = vm_phy_pages_alloc(data->vm, npages, guest_addr, slot);
+		gpa = ____vm_phy_pages_alloc(data->vm, npages, guest_addr, slot,
+					     false, false);
 		TEST_ASSERT(gpa == guest_addr,
 			    "vm_phy_pages_alloc() failed");
 
diff --git a/tools/testing/selftests/kvm/s390/cmma_test.c b/tools/testing/selftests/kvm/s390/cmma_test.c
index 15d81b2ed7ad3..73387cc3bca76 100644
--- a/tools/testing/selftests/kvm/s390/cmma_test.c
+++ b/tools/testing/selftests/kvm/s390/cmma_test.c
@@ -102,24 +102,17 @@ static void guest_dirty_test_data(void)
 
 static void create_main_memslot(struct kvm_vm *vm)
 {
-	int i;
-
 	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, MAIN_PAGE_COUNT, 0);
-	/* set the array of memslots to zero like __vm_create does */
-	for (i = 0; i < NR_MEM_REGIONS; i++)
-		vm->memslots[i] = 0;
+	____vm_override_mem_region(vm, MEM_REGION_CODE, 0);
+	____vm_override_mem_region(vm, MEM_REGION_PT, 0);
+	____vm_override_mem_region(vm, MEM_REGION_DATA, 0);
 }
 
 static void create_test_memslot(struct kvm_vm *vm)
 {
-	vm_userspace_mem_region_add(vm,
-				    VM_MEM_SRC_ANONYMOUS,
-				    TEST_DATA_START_GFN << vm->page_shift,
-				    TEST_DATA_MEMSLOT,
-				    TEST_DATA_PAGE_COUNT,
-				    0
-				   );
-	vm->memslots[MEM_REGION_TEST_DATA] = TEST_DATA_MEMSLOT;
+	vm_override_mem_region(vm, MEM_REGION_TEST_DATA, VM_MEM_SRC_ANONYMOUS,
+			       TEST_DATA_START_GFN << vm->page_shift,
+			       TEST_DATA_MEMSLOT, TEST_DATA_PAGE_COUNT);
 }
 
 static void create_memslots(struct kvm_vm *vm)
diff --git a/tools/testing/selftests/kvm/s390/irq_routing.c b/tools/testing/selftests/kvm/s390/irq_routing.c
index f3839284ac081..cd26cc1aed803 100644
--- a/tools/testing/selftests/kvm/s390/irq_routing.c
+++ b/tools/testing/selftests/kvm/s390/irq_routing.c
@@ -36,7 +36,7 @@ static void test(void)
 	};
 
 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
-	mem = vm_phy_pages_alloc(vm, 2, 4096 * 42, 0);
+	mem = ____vm_phy_pages_alloc(vm, 2, 4096 * 42, 0, false, false);
 
 	routing = kvm_gsi_routing_create();
 	routing->nr = 1;
diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c
index dffe9654f45bd..bfa5ac8ce0295 100644
--- a/tools/testing/selftests/kvm/set_memory_region_test.c
+++ b/tools/testing/selftests/kvm/set_memory_region_test.c
@@ -116,15 +116,15 @@ static struct kvm_vm *spawn_vm(struct kvm_vcpu **vcpu, pthread_t *vcpu_thread,
 
 	vm = vm_create_with_one_vcpu(vcpu, guest_code);
 
-	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS_THP,
-				    MEM_REGION_GPA, MEM_REGION_SLOT,
-				    MEM_REGION_SIZE / getpagesize(), 0);
+	vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS_THP,
+			       MEM_REGION_GPA, MEM_REGION_SLOT,
+			       MEM_REGION_SIZE / getpagesize());
 
 	/*
 	 * Allocate and map two pages so that the GPA accessed by guest_code()
 	 * stays valid across the memslot move.
 	 */
-	gpa = vm_phy_pages_alloc(vm, 2, MEM_REGION_GPA, MEM_REGION_SLOT);
+	gpa = vm_phy_pages_alloc(vm, 2, MEM_REGION_TEST_EXTRA);
 	TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc\n");
 
 	virt_map(vm, MEM_REGION_GPA, MEM_REGION_GPA, 2);
diff --git a/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c b/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c
index 3dca85e954781..8d1822717abdc 100644
--- a/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c
+++ b/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c
@@ -62,11 +62,12 @@ int main(int argc, char *argv[])
 	TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable");
 	vm_enable_cap(vm, KVM_CAP_EXIT_ON_EMULATION_FAILURE, 1);
 
-	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
-				    MEM_REGION_GPA, MEM_REGION_SLOT,
-				    MEM_REGION_SIZE / PAGE_SIZE, 0);
+	vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS,
+			       MEM_REGION_GPA, MEM_REGION_SLOT,
+			       MEM_REGION_SIZE / PAGE_SIZE);
+
 	gpa = vm_phy_pages_alloc(vm, MEM_REGION_SIZE / PAGE_SIZE,
-				 MEM_REGION_GPA, MEM_REGION_SLOT);
+				 MEM_REGION_TEST_EXTRA);
 	TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc");
 	virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1);
 	hva = addr_gpa2hva(vm, MEM_REGION_GPA);

3/2 2026/08/26 23:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 13289
							output: 76
							thoughts: 924
						

Thoughts:
**Determining Fuzzing Worthiness**

Okay, let's break this down. My initial thought is to determine if this patch introduces *functional* changes to the kernel that necessitate fuzzing. The patch touches files within `tools/testing/selftests/kvm/`.  Hang on, that's the selftests directory! I know those are *part* of the kernel source tree, technically, but they're userspace testing tools, not kernel code. They run *on top* of the kernel to verify its behavior.  Changes there won't directly alter kernel logic, drivers, or architectures.

Now, let's consult the provided guidelines. The instructions explicitly list scenarios where we should return `WorthFuzzing=false`. It covers things like documentation, comments, logging, unreachable code in virtualized environments, and vendor-specific hardware drivers that aren't emulated.  It doesn't *explicitly* mention `tools/`, but my experience tells me that changes in the `tools/` directory (e.g., selftests, perf, bpf) generally don't affect the kernel itself; they're user-space tools.

Looking at the opposite case, the guidelines state that if the patch modifies *reachable* core kernel logic, drivers, or architectures, I need to verify that code can be executed, then return `WorthFuzzing=true`. Since we're dealing *only* with `tools/testing/selftests/kvm/`, this condition isn't met. The patch *doesn't* modify core kernel components. Therefore, it's very likely `WorthFuzzing=false`.

Just to be absolutely sure, let's take a quick look at the file list from the patch.  Ah, yes, it's exclusively `tools/testing/selftests/kvm/`:

- `arm64/page_fault_test.c`
- `arm64/vgic_lpi_stress.c`
- `include/kvm_util.h`
- `include/x86/smm.h`
- `lib/arm64/processor.c`
- `lib/kvm_util.c`
- `lib/loongarch/processor.c`
- `lib/riscv/processor.c`
- `lib/s390/processor.c`
- `lib/x86/processor.c`
- `memslot_perf_test.c`
- `s390/cmma_test.c`
- `s390/irq_routing.c`
- `set_memory_region_test.c`
- `x86/smaller_maxphyaddr_emulation_test.c`

Yup, it's all selftests. These are *userspace* test programs, not kernel code. They don't run inside the kernel.  So, based on the analysis of the patch's scope and the guidelines, `WorthFuzzing` is definitively `false`.

I will now call set-results with `WorthFuzzing=false`.



4/2 2026/08/26 23:12 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies userspace testing tools (KVM selftests) in tools/testing/selftests/kvm/. It does not make any functional changes to the core kernel logic, drivers, or architectures.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies userspace testing tools (KVM selftests) in tools/testing/selftests/kvm/. It does not make any functional changes to the core kernel logic, drivers, or architectures.",
  "WorthFuzzing": false
}

5/1 2026/08/26 23:12 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

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)