| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/03 13:16 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "All changes in this patch series are restricted to user-space KVM selftests under tools/testing/selftests/kvm/, which do not modify the compiled kernel image (vmlinux) or kernel modules.",
"WorthFuzzing": false
} |
| 1/1 | 2026/09/03 13:16 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 37a306d7e8699704e16b0bddd75e5a6947d48c29\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Thu Sep 3 13:16:29 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..45a87ba5a737a 100644\n--- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c\n+++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c\n@@ -23,7 +23,6 @@\n #define GIC_LPI_OFFSET\t8192\n \n static size_t nr_iterations = 1000;\n-static gpa_t gpa_base;\n \n static struct kvm_vm *vm;\n static struct kvm_vcpu **vcpus;\n@@ -143,6 +142,7 @@ static void guest_code(size_t nr_lpis)\n \n static void setup_memslot(void)\n {\n+\tgpa_t gpa_base;\n \tsize_t pages;\n \tsize_t sz;\n \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..89b4fc2af7516 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,45 @@ 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 except TEST_EXTRA are mapped to memslot '0'. The\n+ * TEXT_EXTRA region is left unmapped as it's intended to be used only for test\n+ * specific allocations, i.e. should never be used by core/infrastructure code.\n+ * Tests can override the memslot for any or all types, e.g. so that all test\n+ * data is allocated from a 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 +163,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,7 +200,8 @@ 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@@ -702,6 +734,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 +1052,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/09/03 13:16 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "All changes in this patch series are restricted to user-space KVM selftests under tools/testing/selftests/kvm/, which do not modify the compiled kernel image (vmlinux) or kernel modules.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any '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: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 37a306d7e8699704e16b0bddd75e5a6947d48c29
Author: syz-cluster <triage@syzkaller.com>
Date: Thu Sep 3 13:16:29 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..45a87ba5a737a 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
@@ -23,7 +23,6 @@
#define GIC_LPI_OFFSET 8192
static size_t nr_iterations = 1000;
-static gpa_t gpa_base;
static struct kvm_vm *vm;
static struct kvm_vcpu **vcpus;
@@ -143,6 +142,7 @@ static void guest_code(size_t nr_lpis)
static void setup_memslot(void)
{
+ gpa_t gpa_base;
size_t pages;
size_t sz;
@@ -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..89b4fc2af7516 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,45 @@ 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 except TEST_EXTRA are mapped to memslot '0'. The
+ * TEXT_EXTRA region is left unmapped as it's intended to be used only for test
+ * specific allocations, i.e. should never be used by core/infrastructure code.
+ * 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 +163,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,7 +200,8 @@ 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]);
}
@@ -702,6 +734,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 +1052,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/09/03 13:16 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 14259 output: 77 thoughts: 667 Thoughts: **WorthFuzzing Analysis** Okay, let's take a close look at this diff. All the changes are neatly contained within `tools/testing/selftests/kvm/`. This is good, it simplifies the assessment. Now, let's refresh our memory on the fuzzing guidelines. Specifically, section 2: "WHEN TO RETURN WorthFuzzing=false". The key here is the negative criteria. We're looking for modifications that fall *strictly* into a specific category where fuzzing is deemed unnecessary. The guideline specifically calls out "User-space directories, self-tests... that do not affect the compiled kernel image (vmlinux) or kernel modules." Bingo. All the files listed – the `page_fault_test.c`, `vgic_lpi_stress.c`, all the includes and library code, and the various architecture-specific tests – they all reside within `tools/testing/selftests/kvm/`. That's *precisely* user-space self-test code, and it's not going to touch the kernel image or modules. This is straightforward. No kernel modifications, no fuzzing required. Therefore, WorthFuzzing is definitively `false`. Time to call `set-results`. We need to set the parameters like so: * WorthFuzzing: `false` * Reasoning: "All changes in this patch series are restricted to user-space selftests in tools/testing/selftests/kvm/, which do not modify the compiled kernel image (vmlinux) or kernel modules." * FocusSymbols: \[ ] (empty list) * EnableConfigs: \[ ] (empty list) Done. |
| 4/2 | 2026/09/03 13:16 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "All changes in this patch series are restricted to user-space KVM selftests under tools/testing/selftests/kvm/, which do not modify the compiled kernel image (vmlinux) or kernel modules.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "All changes in this patch series are restricted to user-space KVM selftests under tools/testing/selftests/kvm/, which do not modify the compiled kernel image (vmlinux) or kernel modules.",
"WorthFuzzing": false
} |
| 5/1 | 2026/09/03 13:16 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|