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

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/x86/state_test.c
Extension
.c
Size
9847 bytes
Lines
359
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 (supported_xcr0 & XFEATURE_MASK_AVX512) {
			asm volatile ("kmovq %0, %%k1" :: "r" (-1ull));
			asm volatile ("vmovupd %0, %%zmm0" :: "m" (buffer));
			asm volatile ("vmovupd %0, %%zmm16" :: "m" (buffer));
		}

		if (this_cpu_has(X86_FEATURE_MPX)) {
			u64 bounds[2] = { 10, 0xffffffffull };
			u64 output[2] = { };

			GUEST_ASSERT(supported_xcr0 & XFEATURE_MASK_BNDREGS);
			GUEST_ASSERT(supported_xcr0 & XFEATURE_MASK_BNDCSR);

			/*
			 * Don't bother trying to get BNDCSR into the INUSE
			 * state.  MSR_IA32_BNDCFGS doesn't count as it isn't
			 * managed via XSAVE/XRSTOR, and BNDCFGU can only be
			 * modified by XRSTOR.  Stuffing XSTATE_BV in the host
			 * is simpler than doing XRSTOR here in the guest.
			 *
			 * However, temporarily enable MPX in BNDCFGS so that
			 * BNDMOV actually loads BND1.  If MPX isn't *fully*
			 * enabled, all MPX instructions are treated as NOPs.
			 *
			 * Hand encode "bndmov (%rax),%bnd1" as support for MPX
			 * mnemonics/registers has been removed from gcc and
			 * clang (and was never fully supported by clang).
			 */
			wrmsr(MSR_IA32_BNDCFGS, BIT_ULL(0));
			asm volatile (".byte 0x66,0x0f,0x1a,0x08" :: "a" (bounds));
			/*
			 * Hand encode "bndmov %bnd1, (%rax)" to sanity check
			 * that BND1 actually got loaded.
			 */
			asm volatile (".byte 0x66,0x0f,0x1b,0x08" :: "a" (output));
			wrmsr(MSR_IA32_BNDCFGS, 0);

			GUEST_ASSERT_EQ(bounds[0], output[0]);
			GUEST_ASSERT_EQ(bounds[1], output[1]);
		}
		if (this_cpu_has(X86_FEATURE_PKU)) {
			GUEST_ASSERT(supported_xcr0 & XFEATURE_MASK_PKRU);
			set_cr4(get_cr4() | X86_CR4_PKE);
			GUEST_ASSERT(this_cpu_has(X86_FEATURE_OSPKE));

			wrpkru(-1u);
		}
	}

	GUEST_SYNC(2);

	if (arg) {
		if (this_cpu_has(X86_FEATURE_SVM))
			svm_l1_guest_code(arg);
		else
			vmx_l1_guest_code(arg);
	}

	GUEST_DONE();
}

void svm_check_nested_state(int stage, struct kvm_x86_state *state)
{
	struct vmcb *vmcb = (struct vmcb *)state->nested.data.svm;

	if (kvm_cpu_has(X86_FEATURE_VGIF)) {
		if (stage == 4)
			TEST_ASSERT_EQ(!!(vmcb->control.int_ctl & V_GIF_MASK), 1);
		if (stage == 6)
			TEST_ASSERT_EQ(!!(vmcb->control.int_ctl & V_GIF_MASK), 0);
	}

	if (kvm_cpu_has(X86_FEATURE_NRIPS)) {
		/*
		 * GUEST_SYNC() causes IO emulation in KVM, in which case the
		 * RIP is advanced before exiting to userspace. Hence, the RIP
		 * in the saved state should be the same as nRIP saved by the
		 * CPU in the VMCB.
		 */
		if (stage == 6)
			TEST_ASSERT_EQ(vmcb->control.next_rip, state->regs.rip);
	}
}

void check_nested_state(int stage, struct kvm_x86_state *state)
{
	if (kvm_has_cap(KVM_CAP_NESTED_STATE) && kvm_cpu_has(X86_FEATURE_SVM))
		svm_check_nested_state(stage, state);
}

Annotation

Implementation Notes