diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c --- a/sys/amd64/vmm/io/vlapic.c +++ b/sys/amd64/vmm/io/vlapic.c @@ -813,8 +813,8 @@ * or xAPIC (8-bit) destination field. */ static void -vlapic_calcdest(struct vm *vm, cpuset_t *dmask, uint32_t dest, bool phys, - bool lowprio, bool x2apic_dest) +vlapic_calcdest(struct vm *vm, cpuset_t *dmask, uint32_t dest, uint32_t delmode, + bool phys, bool lowprio, bool x2apic_dest) { struct vlapic *vlapic; uint32_t dfr, ldr, ldest, cluster; @@ -834,11 +834,17 @@ if (phys) { /* * Physical mode: destination is APIC ID. + * + * The guest might allocate vCPUs only upon handling + * VM_EXITCODE_SPINUP_AP, so permit an "inactive" destination + * for startup IPIs. */ CPU_ZERO(dmask); vcpuid = vm_apicid2vcpuid(vm, dest); amask = vm_active_cpus(vm); - if (vcpuid < vm_get_maxcpus(vm) && CPU_ISSET(vcpuid, &amask)) + if (vcpuid < vm_get_maxcpus(vm) && (CPU_ISSET(vcpuid, &amask) || + delmode == APIC_DELMODE_INIT || + delmode == APIC_DELMODE_STARTUP)) CPU_SET(vcpuid, dmask); } else { /* @@ -1060,7 +1066,8 @@ switch (shorthand) { case APIC_DEST_DESTFLD: - vlapic_calcdest(vlapic->vm, &dmask, dest, phys, false, x2apic(vlapic)); + vlapic_calcdest(vlapic->vm, &dmask, dest, mode, phys, false, + x2apic(vlapic)); break; case APIC_DEST_SELF: CPU_SETOF(vlapic->vcpuid, &dmask); @@ -1118,22 +1125,6 @@ break; case APIC_DELMODE_INIT: - if (!vlapic->ipi_exit) { - if (!phys) - break; - - i = vm_apicid2vcpuid(vlapic->vm, dest); - if (i >= vm_get_maxcpus(vlapic->vm) || - i == vlapic->vcpuid) - break; - - CPU_SETOF(i, &ipimask); - - break; - } - - CPU_COPY(&dmask, &ipimask); - break; case APIC_DELMODE_STARTUP: if (!vlapic->ipi_exit) { if (!phys) @@ -1185,16 +1176,22 @@ *retu = true; switch (vme->u.ipi.mode) { - case APIC_DELMODE_INIT: - vm_smp_rendezvous(vcpu, *dmask, vlapic_handle_init, - NULL); + case APIC_DELMODE_INIT: { + cpuset_t active, reinit; + + active = vm_active_cpus(vcpu_vm(vcpu)); + CPU_AND(&reinit, &active, dmask); + if (!CPU_EMPTY(&reinit)) { + vm_smp_rendezvous(vcpu, reinit, vlapic_handle_init, + NULL); + } vm_await_start(vcpu_vm(vcpu), dmask); - if (!vlapic->ipi_exit) { + if (!vlapic->ipi_exit) *retu = false; - } break; + } case APIC_DELMODE_STARTUP: /* * Ignore SIPIs in any state other than wait-for-SIPI @@ -1212,13 +1209,13 @@ */ if (!vlapic->ipi_exit) { vme->exitcode = VM_EXITCODE_SPINUP_AP; - vme->u.spinup_ap.vcpu = CPU_FFS(dmask); + vme->u.spinup_ap.vcpu = CPU_FFS(dmask) - 1; vme->u.spinup_ap.rip = vec << PAGE_SHIFT; } break; default: - return (1); + panic("unexpected delivery mode %#x", vme->u.ipi.mode); } return (0); @@ -1707,7 +1704,7 @@ * all interrupts originating from the ioapic or MSI specify the * 'dest' in the legacy xAPIC format. */ - vlapic_calcdest(vm, &dmask, dest, phys, lowprio, false); + vlapic_calcdest(vm, &dmask, dest, delmode, phys, lowprio, false); CPU_FOREACH_ISSET(vcpuid, &dmask) { vcpu = vm_vcpu(vm, vcpuid); @@ -1799,7 +1796,8 @@ } lowprio = (delmode == APIC_DELMODE_LOWPRIO); - vlapic_calcdest(vlapic->vm, &dmask, dest, phys, lowprio, false); + vlapic_calcdest(vlapic->vm, &dmask, dest, delmode, phys, lowprio, + false); if (!CPU_ISSET(vlapic->vcpuid, &dmask)) return; diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -1930,10 +1930,8 @@ * VM_EXITCODE_INST_EMUL could access the apic which could transform the * exit code into VM_EXITCODE_IPI. */ - if (error == 0 && vme->exitcode == VM_EXITCODE_IPI) { - retu = false; + if (error == 0 && vme->exitcode == VM_EXITCODE_IPI) error = vm_handle_ipi(vcpu, vme, &retu); - } if (error == 0 && retu == false) goto restart;