tools/testing/selftests/kvm/set_memory_region_test.c

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/set_memory_region_test.c
Extension
.c
Size
19175 bytes
Lines
672
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 (run->exit_reason == KVM_EXIT_IO) {
			cmd = get_ucall(vcpu, &uc);
			if (cmd != UCALL_SYNC)
				break;

			sem_post(&vcpu_ready);
			continue;
		}

		if (run->exit_reason != KVM_EXIT_MMIO)
			break;

		TEST_ASSERT(!run->mmio.is_write, "Unexpected exit mmio write");
		TEST_ASSERT(run->mmio.len == 8,
			    "Unexpected exit mmio size = %u", run->mmio.len);

		TEST_ASSERT(run->mmio.phys_addr == MEM_REGION_GPA,
			    "Unexpected exit mmio address = 0x%llx",
			    run->mmio.phys_addr);
		memcpy(run->mmio.data, &MMIO_VAL, 8);
	}

	if (run->exit_reason == KVM_EXIT_IO && cmd == UCALL_ABORT)
		REPORT_GUEST_ASSERT(uc);

	return NULL;
}

static void wait_for_vcpu(void)
{
	struct timespec ts;

	TEST_ASSERT(!clock_gettime(CLOCK_REALTIME, &ts),
		    "clock_gettime() failed: %d", errno);

	ts.tv_sec += 2;
	TEST_ASSERT(!sem_timedwait(&vcpu_ready, &ts),
		    "sem_timedwait() failed: %d", errno);

	/* Wait for the vCPU thread to reenter the guest. */
	usleep(100000);
}

static struct kvm_vm *spawn_vm(struct kvm_vcpu **vcpu, pthread_t *vcpu_thread,
			       void *guest_code)
{
	struct kvm_vm *vm;
	u64 *hva;
	gpa_t gpa;

	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);

	/*
	 * 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);
	TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc\n");

	virt_map(vm, MEM_REGION_GPA, MEM_REGION_GPA, 2);

	/* Ditto for the host mapping so that both pages can be zeroed. */
	hva = addr_gpa2hva(vm, MEM_REGION_GPA);
	memset(hva, 0, 2 * 4096);

	pthread_create(vcpu_thread, NULL, vcpu_worker, *vcpu);

	/* Ensure the guest thread is spun up. */
	wait_for_vcpu();

	return vm;
}


static void guest_code_move_memory_region(void)
{
	u64 val;

	GUEST_SYNC(0);

	/*
	 * Spin until the memory region starts getting moved to a
	 * misaligned address.
	 * Every region move may or may not trigger MMIO, as the
	 * window where the memslot is invalid is usually quite small.
	 */

Annotation

Implementation Notes