brintos

brintos / linux-shallow public Read only

0
0
Text · 3.5 KiB · 2b550ef Raw
130 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <fcntl.h>3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6#include <sys/ioctl.h>7 8#include "kvm_util.h"9#include "processor.h"10 11#define CPUID_MWAIT (1u << 3)12 13enum monitor_mwait_testcases {14	MWAIT_QUIRK_DISABLED = BIT(0),15	MISC_ENABLES_QUIRK_DISABLED = BIT(1),16	MWAIT_DISABLED = BIT(2),17};18 19/*20 * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD, in all21 * other scenarios KVM should emulate them as nops.22 */23#define GUEST_ASSERT_MONITOR_MWAIT(insn, testcase, vector)		\24do {									\25	bool fault_wanted = ((testcase) & MWAIT_QUIRK_DISABLED) &&	\26			    ((testcase) & MWAIT_DISABLED);		\27									\28	if (fault_wanted)						\29		__GUEST_ASSERT((vector) == UD_VECTOR,			\30			       "Expected #UD on " insn " for testcase '0x%x', got '0x%x'", \31			       testcase, vector);			\32	else								\33		__GUEST_ASSERT(!(vector),				\34			       "Expected success on " insn " for testcase '0x%x', got '0x%x'", \35			       testcase, vector);			\36} while (0)37 38static void guest_monitor_wait(int testcase)39{40	u8 vector;41 42	GUEST_SYNC(testcase);43 44	/*45	 * Arbitrarily MONITOR this function, SVM performs fault checks before46	 * intercept checks, so the inputs for MONITOR and MWAIT must be valid.47	 */48	vector = kvm_asm_safe("monitor", "a"(guest_monitor_wait), "c"(0), "d"(0));49	GUEST_ASSERT_MONITOR_MWAIT("MONITOR", testcase, vector);50 51	vector = kvm_asm_safe("mwait", "a"(guest_monitor_wait), "c"(0), "d"(0));52	GUEST_ASSERT_MONITOR_MWAIT("MWAIT", testcase, vector);53}54 55static void guest_code(void)56{57	guest_monitor_wait(MWAIT_DISABLED);58 59	guest_monitor_wait(MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);60 61	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED);62	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED);63 64	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);65	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED);66 67	GUEST_DONE();68}69 70int main(int argc, char *argv[])71{72	uint64_t disabled_quirks;73	struct kvm_vcpu *vcpu;74	struct kvm_vm *vm;75	struct ucall uc;76	int testcase;77 78	TEST_REQUIRE(this_cpu_has(X86_FEATURE_MWAIT));79	TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2));80 81	vm = vm_create_with_one_vcpu(&vcpu, guest_code);82	vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT);83 84	while (1) {85		vcpu_run(vcpu);86		TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);87 88		switch (get_ucall(vcpu, &uc)) {89		case UCALL_SYNC:90			testcase = uc.args[1];91			break;92		case UCALL_ABORT:93			REPORT_GUEST_ASSERT(uc);94			goto done;95		case UCALL_DONE:96			goto done;97		default:98			TEST_FAIL("Unknown ucall %lu", uc.cmd);99			goto done;100		}101 102		disabled_quirks = 0;103		if (testcase & MWAIT_QUIRK_DISABLED)104			disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS;105		if (testcase & MISC_ENABLES_QUIRK_DISABLED)106			disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT;107		vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks);108 109		/*110		 * If the MISC_ENABLES quirk (KVM neglects to update CPUID to111		 * enable/disable MWAIT) is disabled, toggle the ENABLE_MWAIT112		 * bit in MISC_ENABLES accordingly.  If the quirk is enabled,113		 * the only valid configuration is MWAIT disabled, as CPUID114		 * can't be manually changed after running the vCPU.115		 */116		if (!(testcase & MISC_ENABLES_QUIRK_DISABLED)) {117			TEST_ASSERT(testcase & MWAIT_DISABLED,118				    "Can't toggle CPUID features after running vCPU");119			continue;120		}121 122		vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE,123			     (testcase & MWAIT_DISABLED) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT);124	}125 126done:127	kvm_vm_free(vm);128	return 0;129}130