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

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/x86/hyperv_features.c
Extension
.c
Size
17530 bytes
Lines
701
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

struct msr_data {
	u32 idx;
	bool fault_expected;
	bool write;
	u64 write_val;
	bool reset_expected;
};

struct hcall_data {
	u64 control;
	u64 expect;
	bool ud_expected;
};

static bool is_write_only_msr(u32 msr)
{
	return msr == HV_X64_MSR_EOI;
}

static void guest_msr(struct msr_data *msr)
{
	u8 vector = 0;
	u64 msr_val = 0;

	GUEST_ASSERT(msr->idx);

	if (msr->write)
		vector = wrmsr_safe(msr->idx, msr->write_val);

	if (!vector && (!msr->write || !is_write_only_msr(msr->idx)))
		vector = rdmsr_safe(msr->idx, &msr_val);

	if (msr->fault_expected)
		__GUEST_ASSERT(vector == GP_VECTOR,
			       "Expected #GP on %sMSR(0x%x), got %s",
			       msr->write ? "WR" : "RD", msr->idx, ex_str(vector));
	else
		__GUEST_ASSERT(!vector,
			       "Expected success on %sMSR(0x%x), got %s",
			       msr->write ? "WR" : "RD", msr->idx, ex_str(vector));

	if (vector || is_write_only_msr(msr->idx))
		goto done;

	if (msr->write)
		__GUEST_ASSERT(!vector,
			       "WRMSR(0x%x) to '0x%lx', RDMSR read '0x%lx'",
			       msr->idx, msr->write_val, msr_val);

	/* Invariant TSC bit appears when TSC invariant control MSR is written to */
	if (msr->idx == HV_X64_MSR_TSC_INVARIANT_CONTROL) {
		if (!this_cpu_has(HV_ACCESS_TSC_INVARIANT))
			GUEST_ASSERT(this_cpu_has(X86_FEATURE_INVTSC));
		else
			GUEST_ASSERT(this_cpu_has(X86_FEATURE_INVTSC) ==
				     !!(msr_val & HV_INVARIANT_TSC_EXPOSED));
	}

done:
	GUEST_DONE();
}

static void guest_hcall(gpa_t pgs_gpa, struct hcall_data *hcall)
{
	u64 res, input, output;
	u8 vector;

	GUEST_ASSERT_NE(hcall->control, 0);

	wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID);
	wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa);

	if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) {
		input = pgs_gpa;
		output = pgs_gpa + PAGE_SIZE;
	} else {
		input = output = 0;
	}

	vector = __hyperv_hypercall(hcall->control, input, output, &res);
	if (hcall->ud_expected) {
		__GUEST_ASSERT(vector == UD_VECTOR,
			       "Expected #UD for control '%lu', got %s",
			       hcall->control, ex_str(vector));
	} else {
		__GUEST_ASSERT(!vector,
			       "Expected no exception for control '%lu', got %s",
			       hcall->control, ex_str(vector));
		GUEST_ASSERT_EQ(res, hcall->expect);
	}

Annotation

Implementation Notes