+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