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

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

File Facts

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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2020, Google LLC.
 *
 * Tests for KVM paravirtual feature disablement
 */
#include <asm/kvm_para.h>
#include <linux/kvm_para.h>
#include <linux/stringify.h>
#include <stdint.h>

#include "kvm_test_harness.h"
#include "apic.h"
#include "test_util.h"
#include "kvm_util.h"
#include "processor.h"

/* VMCALL and VMMCALL are both 3-byte opcodes. */
#define HYPERCALL_INSN_SIZE	3

static bool quirk_disabled;

static void guest_ud_handler(struct ex_regs *regs)
{
	regs->rax = -EFAULT;
	regs->rip += HYPERCALL_INSN_SIZE;
}

static const u8 vmx_vmcall[HYPERCALL_INSN_SIZE]  = { 0x0f, 0x01, 0xc1 };
static const u8 svm_vmmcall[HYPERCALL_INSN_SIZE] = { 0x0f, 0x01, 0xd9 };

extern u8 hypercall_insn[HYPERCALL_INSN_SIZE];
static u64 do_sched_yield(u8 apic_id)
{
	u64 ret;

	asm volatile("hypercall_insn:\n\t"
		     ".byte 0xcc,0xcc,0xcc\n\t"
		     : "=a"(ret)
		     : "a"((u64)KVM_HC_SCHED_YIELD), "b"((u64)apic_id)
		     : "memory");

	return ret;
}

static void guest_main(void)
{
	const u8 *native_hypercall_insn;
	const u8 *other_hypercall_insn;
	u64 ret;

	if (host_cpu_is_intel) {
		native_hypercall_insn = vmx_vmcall;
		other_hypercall_insn  = svm_vmmcall;
	} else if (host_cpu_is_amd_compatible) {
		native_hypercall_insn = svm_vmmcall;
		other_hypercall_insn  = vmx_vmcall;
	} else {
		GUEST_ASSERT(0);
		/* unreachable */
		return;
	}

	memcpy(hypercall_insn, other_hypercall_insn, HYPERCALL_INSN_SIZE);

	ret = do_sched_yield(GET_APIC_ID_FIELD(xapic_read_reg(APIC_ID)));

	/*
	 * If the quirk is disabled, verify that guest_ud_handler() "returned"
	 * -EFAULT and that KVM did NOT patch the hypercall.  If the quirk is
	 * enabled, verify that the hypercall succeeded and that KVM patched in
	 * the "right" hypercall.
	 */
	if (quirk_disabled) {
		GUEST_ASSERT(ret == (u64)-EFAULT);
		GUEST_ASSERT(!memcmp(other_hypercall_insn, hypercall_insn,
			     HYPERCALL_INSN_SIZE));
	} else {
		GUEST_ASSERT(!ret);
		GUEST_ASSERT(!memcmp(native_hypercall_insn, hypercall_insn,
			     HYPERCALL_INSN_SIZE));
	}

	GUEST_DONE();
}

KVM_ONE_VCPU_TEST_SUITE(fix_hypercall);

static void enter_guest(struct kvm_vcpu *vcpu)
{

Annotation

Implementation Notes