File Index
Files and directories
Sign in
FILE

svm_int_ctl_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/x86/svm_int_ctl_test.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * svm_int_ctl_test
  4 *
  5 * Copyright (C) 2021, Red Hat, Inc.
  6 *
  7 * Nested SVM testing: test simultaneous use of V_IRQ from L1 and L0.
  8 */
  9
 10#include "test_util.h"
 11#include "kvm_util.h"
 12#include "processor.h"
 13#include "svm_util.h"
 14#include "apic.h"
 15
 16bool vintr_irq_called;
 17bool intr_irq_called;
 18
 19#define VINTR_IRQ_NUMBER 0x20
 20#define INTR_IRQ_NUMBER 0x30
 21
 22static void vintr_irq_handler(struct ex_regs *regs)
 23{
 24	vintr_irq_called = true;
 25}
 26
 27static void intr_irq_handler(struct ex_regs *regs)
 28{
 29	x2apic_write_reg(APIC_EOI, 0x00);
 30	intr_irq_called = true;
 31}
 32
 33static void l2_guest_code(struct svm_test_data *svm)
 34{
 35	/* This code raises interrupt INTR_IRQ_NUMBER in the L1's LAPIC,
 36	 * and since L1 didn't enable virtual interrupt masking,
 37	 * L2 should receive it and not L1.
 38	 *
 39	 * L2 also has virtual interrupt 'VINTR_IRQ_NUMBER' pending in V_IRQ
 40	 * so it should also receive it after the following 'sti'.
 41	 */
 42	x2apic_write_reg(APIC_ICR,
 43		APIC_DEST_SELF | APIC_INT_ASSERT | INTR_IRQ_NUMBER);
 44
 45	sti_nop();
 46
 47	GUEST_ASSERT(vintr_irq_called);
 48	GUEST_ASSERT(intr_irq_called);
 49
 50	__asm__ __volatile__(
 51		"vmcall\n"
 52	);
 53}
 54
 55static void l1_guest_code(struct svm_test_data *svm)
 56{
 57	#define L2_GUEST_STACK_SIZE 64
 58	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
 59	struct vmcb *vmcb = svm->vmcb;
 60
 61	x2apic_enable();
 62
 63	/* Prepare for L2 execution. */
 64	generic_svm_setup(svm, l2_guest_code,
 65			  &l2_guest_stack[L2_GUEST_STACK_SIZE]);
 66
 67	/* No virtual interrupt masking */
 68	vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK;
 69
 70	/* No intercepts for real and virtual interrupts */
 71	vmcb->control.intercept &= ~(BIT(INTERCEPT_INTR) | BIT(INTERCEPT_VINTR));
 72
 73	/* Make a virtual interrupt VINTR_IRQ_NUMBER pending */
 74	vmcb->control.int_ctl |= V_IRQ_MASK | (0x1 << V_INTR_PRIO_SHIFT);
 75	vmcb->control.int_vector = VINTR_IRQ_NUMBER;
 76
 77	run_guest(vmcb, svm->vmcb_gpa);
 78	GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL);
 79	GUEST_DONE();
 80}
 81
 82int main(int argc, char *argv[])
 83{
 84	struct kvm_vcpu *vcpu;
 85	vm_vaddr_t svm_gva;
 86	struct kvm_vm *vm;
 87	struct ucall uc;
 88
 89	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM));
 90
 91	vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
 92
 93	vm_install_exception_handler(vm, VINTR_IRQ_NUMBER, vintr_irq_handler);
 94	vm_install_exception_handler(vm, INTR_IRQ_NUMBER, intr_irq_handler);
 95
 96	vcpu_alloc_svm(vm, &svm_gva);
 97	vcpu_args_set(vcpu, 1, svm_gva);
 98
 99	vcpu_run(vcpu);
100	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
101
102	switch (get_ucall(vcpu, &uc)) {
103	case UCALL_ABORT:
104		REPORT_GUEST_ASSERT(uc);
105		break;
106		/* NOT REACHED */
107	case UCALL_DONE:
108		goto done;
109	default:
110		TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
111	}
112done:
113	kvm_vm_free(vm);
114	return 0;
115}
~/ Read-only file preview.