mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 14:51:51 -04:00
Use u8 instead of uint8_t to make the KVM selftests code more concise and more similar to the kernel (since selftests are primarily developed by kernel developers). This commit was generated with the following command: git ls-files tools/testing/selftests/kvm | xargs sed -i 's/uint8_t/u8/g' Then by manually adjusting whitespace to make checkpatch.pl happy. No functional change intended. Signed-off-by: David Matlack <dmatlack@google.com> Link: https://patch.msgid.link/20260420212004.3938325-11-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
143 lines
3.3 KiB
C
143 lines
3.3 KiB
C
// 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)
|
|
{
|
|
struct kvm_run *run = vcpu->run;
|
|
struct ucall uc;
|
|
|
|
vcpu_run(vcpu);
|
|
switch (get_ucall(vcpu, &uc)) {
|
|
case UCALL_SYNC:
|
|
pr_info("%s: %016lx\n", (const char *)uc.args[2], uc.args[3]);
|
|
break;
|
|
case UCALL_DONE:
|
|
return;
|
|
case UCALL_ABORT:
|
|
REPORT_GUEST_ASSERT(uc);
|
|
default:
|
|
TEST_FAIL("Unhandled ucall: %ld\nexit_reason: %u (%s)",
|
|
uc.cmd, run->exit_reason, exit_reason_str(run->exit_reason));
|
|
}
|
|
}
|
|
|
|
static void test_fix_hypercall(struct kvm_vcpu *vcpu, bool disable_quirk)
|
|
{
|
|
struct kvm_vm *vm = vcpu->vm;
|
|
|
|
vm_install_exception_handler(vcpu->vm, UD_VECTOR, guest_ud_handler);
|
|
|
|
if (disable_quirk)
|
|
vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2,
|
|
KVM_X86_QUIRK_FIX_HYPERCALL_INSN);
|
|
|
|
quirk_disabled = disable_quirk;
|
|
sync_global_to_guest(vm, quirk_disabled);
|
|
|
|
virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
|
|
|
|
enter_guest(vcpu);
|
|
}
|
|
|
|
KVM_ONE_VCPU_TEST(fix_hypercall, enable_quirk, guest_main)
|
|
{
|
|
test_fix_hypercall(vcpu, false);
|
|
}
|
|
|
|
KVM_ONE_VCPU_TEST(fix_hypercall, disable_quirk, guest_main)
|
|
{
|
|
test_fix_hypercall(vcpu, true);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
TEST_REQUIRE(kvm_check_cap(KVM_CAP_DISABLE_QUIRKS2) & KVM_X86_QUIRK_FIX_HYPERCALL_INSN);
|
|
|
|
return test_harness_run(argc, argv);
|
|
}
|