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

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
Extension
.c
Size
13574 bytes
Lines
481
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 (size > PAGE_SIZE) {
			memset((void *)gpa, p2, PAGE_SIZE);
			goto skip;
		}

		memset((void *)gpa, p2, size);
		guest_sync_private(gpa, size, p1);

		/*
		 * Verify that the private memory was set to pattern two, and
		 * that shared memory still holds the initial pattern.
		 */
		memcmp_g(gpa, p2, size);
		if (gpa > base_gpa)
			memcmp_g(base_gpa, init_p, gpa - base_gpa);
		if (gpa + size < base_gpa + PER_CPU_DATA_SIZE)
			memcmp_g(gpa + size, init_p,
				 (base_gpa + PER_CPU_DATA_SIZE) - (gpa + size));

		/*
		 * Convert odd-number page frames back to shared to verify KVM
		 * also correctly handles holes in private ranges.
		 */
		for (j = 0; j < size; j += PAGE_SIZE) {
			if ((j >> PAGE_SHIFT) & 1) {
				guest_map_shared(gpa + j, PAGE_SIZE, do_fallocate);
				guest_sync_shared(gpa + j, PAGE_SIZE, p1, p3);

				memcmp_g(gpa + j, p3, PAGE_SIZE);
			} else {
				guest_sync_private(gpa + j, PAGE_SIZE, p1);
			}
		}

skip:
		/*
		 * Convert the entire region back to shared, explicitly write
		 * pattern three to fill in the even-number frames before
		 * asking the host to verify (and write pattern four).
		 */
		guest_map_shared(gpa, size, do_fallocate);
		memset((void *)gpa, p3, size);
		guest_sync_shared(gpa, size, p3, p4);
		memcmp_g(gpa, p4, size);

		/* Reset the shared memory back to the initial pattern. */
		memset((void *)gpa, init_p, size);

		/*
		 * Free (via PUNCH_HOLE) *all* private memory so that the next
		 * iteration starts from a clean slate, e.g. with respect to
		 * whether or not there are pages/folios in guest_mem.
		 */
		guest_map_shared(base_gpa, PER_CPU_DATA_SIZE, true);
	}
}

static void guest_punch_hole(gpa_t gpa, u64 size)
{
	/* "Mapping" memory shared via fallocate() is done via PUNCH_HOLE. */
	u64 flags = MAP_GPA_SHARED | MAP_GPA_DO_FALLOCATE;

	kvm_hypercall_map_gpa_range(gpa, size, flags);
}

/*
 * Test that PUNCH_HOLE actually frees memory by punching holes without doing a
 * proper conversion.  Freeing (PUNCH_HOLE) should zap SPTEs, and reallocating
 * (subsequent fault) should zero memory.
 */
static void guest_test_punch_hole(u64 base_gpa, bool precise)
{
	const u8 init_p = 0xcc;
	int i;

	/*
	 * Convert the entire range to private, this testcase is all about
	 * punching holes in guest_memfd, i.e. shared mappings aren't needed.
	 */
	guest_map_private(base_gpa, PER_CPU_DATA_SIZE, false);

	for (i = 0; i < ARRAY_SIZE(test_ranges); i++) {
		gpa_t gpa = base_gpa + test_ranges[i].offset;
		u64 size = test_ranges[i].size;

		/*
		 * Free all memory before each iteration, even for the !precise
		 * case where the memory will be faulted back in.  Freeing and
		 * reallocating should obviously work, and freeing all memory
		 * minimizes the probability of cross-testcase influence.

Annotation

Implementation Notes