tools/testing/selftests/kvm/x86/nx_huge_pages_test.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/x86/nx_huge_pages_test.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/x86/nx_huge_pages_test.c
Extension
.c
Size
6998 bytes
Lines
267
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

if (reboot_permissions) {
			TEST_ASSERT(!r, "Disabling NX huge pages should succeed if process has reboot permissions");
		} else {
			TEST_ASSERT(r == -1 && errno == EPERM,
				    "This process should not have permission to disable NX huge pages");
			return;
		}
	}

	vcpu = vm_vcpu_add(vm, 0, guest_code);

	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS_HUGETLB,
				    HPAGE_GPA, HPAGE_SLOT,
				    HPAGE_SLOT_NPAGES, 0);

	nr_bytes = HPAGE_SLOT_NPAGES * vm->page_size;

	/*
	 * Ensure that KVM can map HPAGE_SLOT with huge pages by mapping the
	 * region into the guest with 2MiB pages whenever TDP is disabled (i.e.
	 * whenever KVM is shadowing the guest page tables).
	 *
	 * When TDP is enabled, KVM should be able to map HPAGE_SLOT with huge
	 * pages irrespective of the guest page size, so map with 4KiB pages
	 * to test that that is the case.
	 */
	if (kvm_is_tdp_enabled())
		virt_map_level(vm, HPAGE_GVA, HPAGE_GPA, nr_bytes, PG_LEVEL_4K);
	else
		virt_map_level(vm, HPAGE_GVA, HPAGE_GPA, nr_bytes, PG_LEVEL_2M);

	hva = addr_gpa2hva(vm, HPAGE_GPA);
	memset(hva, RETURN_OPCODE, nr_bytes);

	check_2m_page_count(vm, 0);
	check_split_count(vm, 0);

	/*
	 * The guest code will first read from the first hugepage, resulting
	 * in a huge page mapping being created.
	 */
	vcpu_run(vcpu);
	check_2m_page_count(vm, 1);
	check_split_count(vm, 0);

	/*
	 * Then the guest code will read from the second hugepage, resulting
	 * in another huge page mapping being created.
	 */
	vcpu_run(vcpu);
	check_2m_page_count(vm, 2);
	check_split_count(vm, 0);

	/*
	 * Next, the guest will execute from the first huge page, causing it
	 * to be remapped at 4k.
	 *
	 * If NX huge pages are disabled, this should have no effect.
	 */
	vcpu_run(vcpu);
	check_2m_page_count(vm, disable_nx_huge_pages ? 2 : 1);
	check_split_count(vm, disable_nx_huge_pages ? 0 : 1);

	/*
	 * Executing from the third huge page (previously unaccessed) will
	 * cause part to be mapped at 4k.
	 *
	 * If NX huge pages are disabled, it should be mapped at 2M.
	 */
	vcpu_run(vcpu);
	check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1);
	check_split_count(vm, disable_nx_huge_pages ? 0 : 2);

	/* Reading from the first huge page again should have no effect. */
	vcpu_run(vcpu);
	check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1);
	check_split_count(vm, disable_nx_huge_pages ? 0 : 2);

	/* Give recovery thread time to run. */
	wait_for_reclaim(reclaim_period_ms);

	/*
	 * Now that the reclaimer has run, all the split pages should be gone.
	 *
	 * If NX huge pages are disabled, the relaimer will not run, so
	 * nothing should change from here on.
	 */
	check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1);
	check_split_count(vm, 0);

Annotation

Implementation Notes