brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 762628f Raw
143 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2020, Google LLC.4 *5 * Tests for KVM paravirtual feature disablement6 */7#include <asm/kvm_para.h>8#include <linux/kvm_para.h>9#include <linux/stringify.h>10#include <stdint.h>11 12#include "kvm_test_harness.h"13#include "apic.h"14#include "test_util.h"15#include "kvm_util.h"16#include "processor.h"17 18/* VMCALL and VMMCALL are both 3-byte opcodes. */19#define HYPERCALL_INSN_SIZE	320 21static bool quirk_disabled;22 23static void guest_ud_handler(struct ex_regs *regs)24{25	regs->rax = -EFAULT;26	regs->rip += HYPERCALL_INSN_SIZE;27}28 29static const uint8_t vmx_vmcall[HYPERCALL_INSN_SIZE]  = { 0x0f, 0x01, 0xc1 };30static const uint8_t svm_vmmcall[HYPERCALL_INSN_SIZE] = { 0x0f, 0x01, 0xd9 };31 32extern uint8_t hypercall_insn[HYPERCALL_INSN_SIZE];33static uint64_t do_sched_yield(uint8_t apic_id)34{35	uint64_t ret;36 37	asm volatile("hypercall_insn:\n\t"38		     ".byte 0xcc,0xcc,0xcc\n\t"39		     : "=a"(ret)40		     : "a"((uint64_t)KVM_HC_SCHED_YIELD), "b"((uint64_t)apic_id)41		     : "memory");42 43	return ret;44}45 46static void guest_main(void)47{48	const uint8_t *native_hypercall_insn;49	const uint8_t *other_hypercall_insn;50	uint64_t ret;51 52	if (host_cpu_is_intel) {53		native_hypercall_insn = vmx_vmcall;54		other_hypercall_insn  = svm_vmmcall;55	} else if (host_cpu_is_amd) {56		native_hypercall_insn = svm_vmmcall;57		other_hypercall_insn  = vmx_vmcall;58	} else {59		GUEST_ASSERT(0);60		/* unreachable */61		return;62	}63 64	memcpy(hypercall_insn, other_hypercall_insn, HYPERCALL_INSN_SIZE);65 66	ret = do_sched_yield(GET_APIC_ID_FIELD(xapic_read_reg(APIC_ID)));67 68	/*69	 * If the quirk is disabled, verify that guest_ud_handler() "returned"70	 * -EFAULT and that KVM did NOT patch the hypercall.  If the quirk is71	 * enabled, verify that the hypercall succeeded and that KVM patched in72	 * the "right" hypercall.73	 */74	if (quirk_disabled) {75		GUEST_ASSERT(ret == (uint64_t)-EFAULT);76		GUEST_ASSERT(!memcmp(other_hypercall_insn, hypercall_insn,77			     HYPERCALL_INSN_SIZE));78	} else {79		GUEST_ASSERT(!ret);80		GUEST_ASSERT(!memcmp(native_hypercall_insn, hypercall_insn,81			     HYPERCALL_INSN_SIZE));82	}83 84	GUEST_DONE();85}86 87KVM_ONE_VCPU_TEST_SUITE(fix_hypercall);88 89static void enter_guest(struct kvm_vcpu *vcpu)90{91	struct kvm_run *run = vcpu->run;92	struct ucall uc;93 94	vcpu_run(vcpu);95	switch (get_ucall(vcpu, &uc)) {96	case UCALL_SYNC:97		pr_info("%s: %016lx\n", (const char *)uc.args[2], uc.args[3]);98		break;99	case UCALL_DONE:100		return;101	case UCALL_ABORT:102		REPORT_GUEST_ASSERT(uc);103	default:104		TEST_FAIL("Unhandled ucall: %ld\nexit_reason: %u (%s)",105			  uc.cmd, run->exit_reason, exit_reason_str(run->exit_reason));106	}107}108 109static void test_fix_hypercall(struct kvm_vcpu *vcpu, bool disable_quirk)110{111	struct kvm_vm *vm = vcpu->vm;112 113	vm_install_exception_handler(vcpu->vm, UD_VECTOR, guest_ud_handler);114 115	if (disable_quirk)116		vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2,117			      KVM_X86_QUIRK_FIX_HYPERCALL_INSN);118 119	quirk_disabled = disable_quirk;120	sync_global_to_guest(vm, quirk_disabled);121 122	virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);123 124	enter_guest(vcpu);125}126 127KVM_ONE_VCPU_TEST(fix_hypercall, enable_quirk, guest_main)128{129	test_fix_hypercall(vcpu, false);130}131 132KVM_ONE_VCPU_TEST(fix_hypercall, disable_quirk, guest_main)133{134	test_fix_hypercall(vcpu, true);135}136 137int main(int argc, char *argv[])138{139	TEST_REQUIRE(kvm_check_cap(KVM_CAP_DISABLE_QUIRKS2) & KVM_X86_QUIRK_FIX_HYPERCALL_INSN);140 141	return test_harness_run(argc, argv);142}143