>+static void guest_code(void) >+{ >+ uint32_t icr_val; >+ int i; >+ >+ xapic_enable(); >+ >+ icr_val = (APIC_DEST_SELF | APIC_INT_ASSERT | VINTR_VECTOR); >+ >+ for (i = 0; i < NUM_ITERATIONS; i++) { >+ cli(); >+ xapic_write_reg(APIC_ICR, icr_val); >+ safe_halt(); >+ GUEST_ASSERT(READ_ONCE(irq_received)); >+ WRITE_ONCE(irq_received, false); any reason to use READ/WRITE_ONCE here? >+ } >+ GUEST_DONE(); >+} >+ >+static void guest_vintr_handler(struct ex_regs *regs) >+{ >+ WRITE_ONCE(irq_received, true); >+ xapic_write_reg(APIC_EOI, 0x00); >+} >+ >+int main(int argc, char *argv[]) >+{ >+ struct kvm_vm *vm; >+ struct kvm_vcpu *vcpu; >+ struct ucall uc; >+ uint64_t halt_exits, vintr_exits; >+ >+ /* Check the extension for binary stats */ >+ TEST_REQUIRE(this_cpu_has(X86_FEATURE_IDLE_HLT)); IIUC, this test assumes that the IDLE_HLT feature is enabled for guests if it is supported by the CPU. But this isn't true in some cases: 1. an old KVM runs on new hardware 2. the feature bit is somehow cleared, e.g., by "clearcpuid" cmdline >+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_BINARY_STATS_FD)); >+ >+ vm = vm_create_with_one_vcpu(&vcpu, guest_code); >+ >+ vm_install_exception_handler(vm, VINTR_VECTOR, guest_vintr_handler); >+ virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); >+ >+ vcpu_run(vcpu); >+ TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); >+ >+ halt_exits = vcpu_get_stat(vcpu, HALT_EXITS); >+ vintr_exits = vcpu_get_stat(vcpu, IRQ_WINDOW_EXITS); >+ >+ switch (get_ucall(vcpu, &uc)) { >+ case UCALL_ABORT: >+ REPORT_GUEST_ASSERT(uc); >+ /* NOT REACHED */ >+ case UCALL_DONE: >+ break; >+ >+ default: >+ TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd); >+ } >+ >+ TEST_ASSERT_EQ(halt_exits, 0); >+ pr_debug("Guest executed VINTR followed by halts: %d times.\n" >+ "The guest exited due to halt: %ld times and number\n" >+ "of vintr exits: %ld.\n", >+ NUM_ITERATIONS, halt_exits, vintr_exits); >+ >+ kvm_vm_free(vm); >+ return 0; >+} >-- >2.34.1 > >