Index: sys/amd64/include/vmm.h =================================================================== --- sys/amd64/include/vmm.h (revision 260410) +++ sys/amd64/include/vmm.h (working copy) @@ -47,7 +47,7 @@ enum x2apic_state; -typedef int (*vmm_init_func_t)(void); +typedef int (*vmm_init_func_t)(int ipinum); typedef int (*vmm_cleanup_func_t)(void); typedef void (*vmm_resume_func_t)(void); typedef void * (*vmi_init_func_t)(struct vm *vm, struct pmap *pmap); Index: sys/amd64/vmm/amd/amdv.c =================================================================== --- sys/amd64/vmm/amd/amdv.c (revision 260410) +++ sys/amd64/vmm/amd/amdv.c (working copy) @@ -38,7 +38,7 @@ #include "io/iommu.h" static int -amdv_init(void) +amdv_init(int ipinum) { printf("amdv_init: not implemented\n"); Index: sys/amd64/vmm/intel/ept.c =================================================================== --- sys/amd64/vmm/intel/ept.c (revision 260410) +++ sys/amd64/vmm/intel/ept.c (working copy) @@ -77,7 +77,7 @@ &ept_pmap_flags, 0, NULL); int -ept_init(void) +ept_init(int ipinum) { int use_hw_ad_bits, use_superpages, use_exec_only; uint64_t cap; @@ -99,7 +99,7 @@ !INVEPT_ALL_TYPES_SUPPORTED(cap)) return (EINVAL); - ept_pmap_flags = vmm_ipinum & PMAP_NESTED_IPIMASK; + ept_pmap_flags = ipinum & PMAP_NESTED_IPIMASK; use_superpages = 1; TUNABLE_INT_FETCH("hw.vmm.ept.use_superpages", &use_superpages); Index: sys/amd64/vmm/intel/ept.h =================================================================== --- sys/amd64/vmm/intel/ept.h (revision 260410) +++ sys/amd64/vmm/intel/ept.h (working copy) @@ -31,7 +31,7 @@ struct vmx; -int ept_init(void); +int ept_init(int ipinum); void ept_invalidate_mappings(u_long eptp); struct vmspace *ept_vmspace_alloc(vm_offset_t min, vm_offset_t max); void ept_vmspace_free(struct vmspace *vmspace); Index: sys/amd64/vmm/intel/vmcs.h =================================================================== --- sys/amd64/vmm/intel/vmcs.h (revision 260410) +++ sys/amd64/vmm/intel/vmcs.h (working copy) @@ -97,6 +97,7 @@ /* 16-bit control fields */ #define VMCS_VPID 0x00000000 +#define VMCS_PIR_VECTOR 0x00000002 /* 16-bit guest-state fields */ #define VMCS_GUEST_ES_SELECTOR 0x00000800 @@ -129,6 +130,7 @@ #define VMCS_TSC_OFFSET 0x00002010 #define VMCS_VIRTUAL_APIC 0x00002012 #define VMCS_APIC_ACCESS 0x00002014 +#define VMCS_PIR_DESC 0x00002016 #define VMCS_EPTP 0x0000201A #define VMCS_EOI_EXIT0 0x0000201C #define VMCS_EOI_EXIT1 0x0000201E Index: sys/amd64/vmm/intel/vmx.c =================================================================== --- sys/amd64/vmm/intel/vmx.c (revision 260410) +++ sys/amd64/vmm/intel/vmx.c (working copy) @@ -45,11 +45,13 @@ #include #include #include +#include #include #include #include #include "vmm_host.h" +#include "vmm_ipi.h" #include "vmm_msr.h" #include "vmm_ktr.h" #include "vmm_stat.h" @@ -93,6 +95,7 @@ #define VM_EXIT_CTLS_ONE_SETTING \ (VM_EXIT_CTLS_ONE_SETTING_NO_PAT | \ + VM_EXIT_ACKNOWLEDGE_INTERRUPT | \ VM_EXIT_SAVE_PAT | \ VM_EXIT_LOAD_PAT) #define VM_EXIT_CTLS_ZERO_SETTING VM_EXIT_SAVE_DEBUG_CONTROLS @@ -171,6 +174,14 @@ SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, virtual_interrupt_delivery, CTLFLAG_RD, &virtual_interrupt_delivery, 0, "APICv virtual interrupt delivery support"); +static int posted_interrupts; +SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, posted_interrupts, CTLFLAG_RD, + &posted_interrupts, 0, "APICv posted interrupt support"); + +static int pirvec; +SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, posted_interrupt_vector, CTLFLAG_RD, + &pirvec, 0, "APICv posted interrupt vector"); + static struct unrhdr *vpid_unr; static u_int vpid_alloc_failed; SYSCTL_UINT(_hw_vmm_vmx, OID_AUTO, vpid_alloc_failed, CTLFLAG_RD, @@ -441,6 +452,9 @@ static int vmx_cleanup(void) { + + if (pirvec != 0) + vmm_ipi_free(pirvec); if (vpid_unr != NULL) { delete_unrhdr(vpid_unr); @@ -474,7 +488,7 @@ } static int -vmx_init(void) +vmx_init(int ipinum) { int error, use_tpr_shadow; uint64_t fixed0, fixed1, feature_control; @@ -636,10 +650,34 @@ procbased_ctls |= PROCBASED_USE_TPR_SHADOW; procbased_ctls2 |= procbased2_vid_bits; procbased_ctls2 &= ~PROCBASED2_VIRTUALIZE_X2APIC_MODE; + + /* + * Check for Posted Interrupts only if Virtual Interrupt + * Delivery is enabled. + */ + error = vmx_set_ctlreg(MSR_VMX_PINBASED_CTLS, + MSR_VMX_TRUE_PINBASED_CTLS, PINBASED_POSTED_INTERRUPT, 0, + &tmp); + if (error == 0) { + pirvec = vmm_ipi_alloc(); + if (pirvec == 0) { + if (bootverbose) { + printf("vmx_init: unable to allocate " + "posted interrupt vector\n"); + } + } else { + posted_interrupts = 1; + TUNABLE_INT_FETCH("hw.vmm.vmx.use_apic_pir", + &posted_interrupts); + } + } } + if (posted_interrupts) + pinbased_ctls |= PINBASED_POSTED_INTERRUPT; + /* Initialize EPT */ - error = ept_init(); + error = ept_init(ipinum); if (error) { printf("vmx_init: ept initialization failed (%d)\n", error); return (error); @@ -822,6 +860,11 @@ error += vmwrite(VMCS_EOI_EXIT2, 0); error += vmwrite(VMCS_EOI_EXIT3, 0); } + if (posted_interrupts) { + error += vmwrite(VMCS_PIR_VECTOR, pirvec); + error += vmwrite(VMCS_PIR_DESC, + vtophys(&vmx->pir_desc[i])); + } VMCLEAR(vmcs); KASSERT(error == 0, ("vmx_vminit: error customizing the vmcs")); @@ -1370,13 +1413,694 @@ return (UNHANDLED); } +static void +vmx_swintr(int vector) +{ + switch (vector) { + case 32: + __asm __volatile("int $32"); + break; + case 33: + __asm __volatile("int $33"); + break; + case 34: + __asm __volatile("int $34"); + break; + case 35: + __asm __volatile("int $35"); + break; + case 36: + __asm __volatile("int $36"); + break; + case 37: + __asm __volatile("int $37"); + break; + case 38: + __asm __volatile("int $38"); + break; + case 39: + __asm __volatile("int $39"); + break; + case 40: + __asm __volatile("int $40"); + break; + case 41: + __asm __volatile("int $41"); + break; + case 42: + __asm __volatile("int $42"); + break; + case 43: + __asm __volatile("int $43"); + break; + case 44: + __asm __volatile("int $44"); + break; + case 45: + __asm __volatile("int $45"); + break; + case 46: + __asm __volatile("int $46"); + break; + case 47: + __asm __volatile("int $47"); + break; + case 48: + __asm __volatile("int $48"); + break; + case 49: + __asm __volatile("int $49"); + break; + case 50: + __asm __volatile("int $50"); + break; + case 51: + __asm __volatile("int $51"); + break; + case 52: + __asm __volatile("int $52"); + break; + case 53: + __asm __volatile("int $53"); + break; + case 54: + __asm __volatile("int $54"); + break; + case 55: + __asm __volatile("int $55"); + break; + case 56: + __asm __volatile("int $56"); + break; + case 57: + __asm __volatile("int $57"); + break; + case 58: + __asm __volatile("int $58"); + break; + case 59: + __asm __volatile("int $59"); + break; + case 60: + __asm __volatile("int $60"); + break; + case 61: + __asm __volatile("int $61"); + break; + case 62: + __asm __volatile("int $62"); + break; + case 63: + __asm __volatile("int $63"); + break; + case 64: + __asm __volatile("int $64"); + break; + case 65: + __asm __volatile("int $65"); + break; + case 66: + __asm __volatile("int $66"); + break; + case 67: + __asm __volatile("int $67"); + break; + case 68: + __asm __volatile("int $68"); + break; + case 69: + __asm __volatile("int $69"); + break; + case 70: + __asm __volatile("int $70"); + break; + case 71: + __asm __volatile("int $71"); + break; + case 72: + __asm __volatile("int $72"); + break; + case 73: + __asm __volatile("int $73"); + break; + case 74: + __asm __volatile("int $74"); + break; + case 75: + __asm __volatile("int $75"); + break; + case 76: + __asm __volatile("int $76"); + break; + case 77: + __asm __volatile("int $77"); + break; + case 78: + __asm __volatile("int $78"); + break; + case 79: + __asm __volatile("int $79"); + break; + case 80: + __asm __volatile("int $80"); + break; + case 81: + __asm __volatile("int $81"); + break; + case 82: + __asm __volatile("int $82"); + break; + case 83: + __asm __volatile("int $83"); + break; + case 84: + __asm __volatile("int $84"); + break; + case 85: + __asm __volatile("int $85"); + break; + case 86: + __asm __volatile("int $86"); + break; + case 87: + __asm __volatile("int $87"); + break; + case 88: + __asm __volatile("int $88"); + break; + case 89: + __asm __volatile("int $89"); + break; + case 90: + __asm __volatile("int $90"); + break; + case 91: + __asm __volatile("int $91"); + break; + case 92: + __asm __volatile("int $92"); + break; + case 93: + __asm __volatile("int $93"); + break; + case 94: + __asm __volatile("int $94"); + break; + case 95: + __asm __volatile("int $95"); + break; + case 96: + __asm __volatile("int $96"); + break; + case 97: + __asm __volatile("int $97"); + break; + case 98: + __asm __volatile("int $98"); + break; + case 99: + __asm __volatile("int $99"); + break; + case 100: + __asm __volatile("int $100"); + break; + case 101: + __asm __volatile("int $101"); + break; + case 102: + __asm __volatile("int $102"); + break; + case 103: + __asm __volatile("int $103"); + break; + case 104: + __asm __volatile("int $104"); + break; + case 105: + __asm __volatile("int $105"); + break; + case 106: + __asm __volatile("int $106"); + break; + case 107: + __asm __volatile("int $107"); + break; + case 108: + __asm __volatile("int $108"); + break; + case 109: + __asm __volatile("int $109"); + break; + case 110: + __asm __volatile("int $110"); + break; + case 111: + __asm __volatile("int $111"); + break; + case 112: + __asm __volatile("int $112"); + break; + case 113: + __asm __volatile("int $113"); + break; + case 114: + __asm __volatile("int $114"); + break; + case 115: + __asm __volatile("int $115"); + break; + case 116: + __asm __volatile("int $116"); + break; + case 117: + __asm __volatile("int $117"); + break; + case 118: + __asm __volatile("int $118"); + break; + case 119: + __asm __volatile("int $119"); + break; + case 120: + __asm __volatile("int $120"); + break; + case 121: + __asm __volatile("int $121"); + break; + case 122: + __asm __volatile("int $122"); + break; + case 123: + __asm __volatile("int $123"); + break; + case 124: + __asm __volatile("int $124"); + break; + case 125: + __asm __volatile("int $125"); + break; + case 126: + __asm __volatile("int $126"); + break; + case 127: + __asm __volatile("int $127"); + break; + case 128: + __asm __volatile("int $128"); + break; + case 129: + __asm __volatile("int $129"); + break; + case 130: + __asm __volatile("int $130"); + break; + case 131: + __asm __volatile("int $131"); + break; + case 132: + __asm __volatile("int $132"); + break; + case 133: + __asm __volatile("int $133"); + break; + case 134: + __asm __volatile("int $134"); + break; + case 135: + __asm __volatile("int $135"); + break; + case 136: + __asm __volatile("int $136"); + break; + case 137: + __asm __volatile("int $137"); + break; + case 138: + __asm __volatile("int $138"); + break; + case 139: + __asm __volatile("int $139"); + break; + case 140: + __asm __volatile("int $140"); + break; + case 141: + __asm __volatile("int $141"); + break; + case 142: + __asm __volatile("int $142"); + break; + case 143: + __asm __volatile("int $143"); + break; + case 144: + __asm __volatile("int $144"); + break; + case 145: + __asm __volatile("int $145"); + break; + case 146: + __asm __volatile("int $146"); + break; + case 147: + __asm __volatile("int $147"); + break; + case 148: + __asm __volatile("int $148"); + break; + case 149: + __asm __volatile("int $149"); + break; + case 150: + __asm __volatile("int $150"); + break; + case 151: + __asm __volatile("int $151"); + break; + case 152: + __asm __volatile("int $152"); + break; + case 153: + __asm __volatile("int $153"); + break; + case 154: + __asm __volatile("int $154"); + break; + case 155: + __asm __volatile("int $155"); + break; + case 156: + __asm __volatile("int $156"); + break; + case 157: + __asm __volatile("int $157"); + break; + case 158: + __asm __volatile("int $158"); + break; + case 159: + __asm __volatile("int $159"); + break; + case 160: + __asm __volatile("int $160"); + break; + case 161: + __asm __volatile("int $161"); + break; + case 162: + __asm __volatile("int $162"); + break; + case 163: + __asm __volatile("int $163"); + break; + case 164: + __asm __volatile("int $164"); + break; + case 165: + __asm __volatile("int $165"); + break; + case 166: + __asm __volatile("int $166"); + break; + case 167: + __asm __volatile("int $167"); + break; + case 168: + __asm __volatile("int $168"); + break; + case 169: + __asm __volatile("int $169"); + break; + case 170: + __asm __volatile("int $170"); + break; + case 171: + __asm __volatile("int $171"); + break; + case 172: + __asm __volatile("int $172"); + break; + case 173: + __asm __volatile("int $173"); + break; + case 174: + __asm __volatile("int $174"); + break; + case 175: + __asm __volatile("int $175"); + break; + case 176: + __asm __volatile("int $176"); + break; + case 177: + __asm __volatile("int $177"); + break; + case 178: + __asm __volatile("int $178"); + break; + case 179: + __asm __volatile("int $179"); + break; + case 180: + __asm __volatile("int $180"); + break; + case 181: + __asm __volatile("int $181"); + break; + case 182: + __asm __volatile("int $182"); + break; + case 183: + __asm __volatile("int $183"); + break; + case 184: + __asm __volatile("int $184"); + break; + case 185: + __asm __volatile("int $185"); + break; + case 186: + __asm __volatile("int $186"); + break; + case 187: + __asm __volatile("int $187"); + break; + case 188: + __asm __volatile("int $188"); + break; + case 189: + __asm __volatile("int $189"); + break; + case 190: + __asm __volatile("int $190"); + break; + case 191: + __asm __volatile("int $191"); + break; + case 192: + __asm __volatile("int $192"); + break; + case 193: + __asm __volatile("int $193"); + break; + case 194: + __asm __volatile("int $194"); + break; + case 195: + __asm __volatile("int $195"); + break; + case 196: + __asm __volatile("int $196"); + break; + case 197: + __asm __volatile("int $197"); + break; + case 198: + __asm __volatile("int $198"); + break; + case 199: + __asm __volatile("int $199"); + break; + case 200: + __asm __volatile("int $200"); + break; + case 201: + __asm __volatile("int $201"); + break; + case 202: + __asm __volatile("int $202"); + break; + case 203: + __asm __volatile("int $203"); + break; + case 204: + __asm __volatile("int $204"); + break; + case 205: + __asm __volatile("int $205"); + break; + case 206: + __asm __volatile("int $206"); + break; + case 207: + __asm __volatile("int $207"); + break; + case 208: + __asm __volatile("int $208"); + break; + case 209: + __asm __volatile("int $209"); + break; + case 210: + __asm __volatile("int $210"); + break; + case 211: + __asm __volatile("int $211"); + break; + case 212: + __asm __volatile("int $212"); + break; + case 213: + __asm __volatile("int $213"); + break; + case 214: + __asm __volatile("int $214"); + break; + case 215: + __asm __volatile("int $215"); + break; + case 216: + __asm __volatile("int $216"); + break; + case 217: + __asm __volatile("int $217"); + break; + case 218: + __asm __volatile("int $218"); + break; + case 219: + __asm __volatile("int $219"); + break; + case 220: + __asm __volatile("int $220"); + break; + case 221: + __asm __volatile("int $221"); + break; + case 222: + __asm __volatile("int $222"); + break; + case 223: + __asm __volatile("int $223"); + break; + case 224: + __asm __volatile("int $224"); + break; + case 225: + __asm __volatile("int $225"); + break; + case 226: + __asm __volatile("int $226"); + break; + case 227: + __asm __volatile("int $227"); + break; + case 228: + __asm __volatile("int $228"); + break; + case 229: + __asm __volatile("int $229"); + break; + case 230: + __asm __volatile("int $230"); + break; + case 231: + __asm __volatile("int $231"); + break; + case 232: + __asm __volatile("int $232"); + break; + case 233: + __asm __volatile("int $233"); + break; + case 234: + __asm __volatile("int $234"); + break; + case 235: + __asm __volatile("int $235"); + break; + case 236: + __asm __volatile("int $236"); + break; + case 237: + __asm __volatile("int $237"); + break; + case 238: + __asm __volatile("int $238"); + break; + case 239: + __asm __volatile("int $239"); + break; + case 240: + __asm __volatile("int $240"); + break; + case 241: + __asm __volatile("int $241"); + break; + case 242: + __asm __volatile("int $242"); + break; + case 243: + __asm __volatile("int $243"); + break; + case 244: + __asm __volatile("int $244"); + break; + case 245: + __asm __volatile("int $245"); + break; + case 246: + __asm __volatile("int $246"); + break; + case 247: + __asm __volatile("int $247"); + break; + case 248: + __asm __volatile("int $248"); + break; + case 249: + __asm __volatile("int $249"); + break; + case 250: + __asm __volatile("int $250"); + break; + case 251: + __asm __volatile("int $251"); + break; + case 252: + __asm __volatile("int $252"); + break; + case 253: + __asm __volatile("int $253"); + break; + case 254: + __asm __volatile("int $254"); + break; + case 255: + __asm __volatile("int $255"); + break; + default: + panic("vmx_swintr: vector %d not implemented", vector); + } +} + static int vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) { int error, handled; struct vmxctx *vmxctx; struct vlapic *vlapic; - uint32_t eax, ecx, edx, idtvec_info, idtvec_err, reason; + uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, reason; uint64_t qual, gpa; bool retu; @@ -1487,6 +2211,10 @@ * host interrupt handler in the VM's softc. We will inject * this virtual interrupt during the subsequent VM enter. */ + intr_info = vmcs_read(VMCS_EXIT_INTERRUPTION_INFO); + KASSERT((intr_info & VMCS_INTERRUPTION_INFO_VALID) != 0, + ("vm-exit interrupt information not valid")); + vmx_swintr(intr_info & 0xff); /* * This is special. We want to treat this as an 'handled' @@ -2101,19 +2829,9 @@ return (retval); } -/* - * Posted Interrupt Descriptor (described in section 29.6 of the Intel SDM). - */ -struct pir_desc { - uint64_t pir[4]; - uint64_t pending; - uint64_t unused[3]; -} __aligned(64); -CTASSERT(sizeof(struct pir_desc) == 64); - struct vlapic_vtx { struct vlapic vlapic; - struct pir_desc pir_desc; + struct pir_desc *pir_desc; }; #define VMX_CTR_PIR(vm, vcpuid, pir_desc, notify, vector, level, msg) \ @@ -2143,7 +2861,7 @@ * XXX need to deal with level triggered interrupts */ vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; /* * Keep track of interrupt requests in the PIR descriptor. This is @@ -2177,7 +2895,7 @@ KASSERT(vecptr == NULL, ("vmx_pending_intr: vecptr must be NULL")); vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; pending = atomic_load_acq_long(&pir_desc->pending); if (!pending) @@ -2215,6 +2933,13 @@ panic("vmx_intr_accepted: not expected to be called"); } +static void +vmx_post_intr(struct vlapic *vlapic, int hostcpu) +{ + + ipi_cpu(hostcpu, pirvec); +} + /* * Transfer the pending interrupts in the PIR descriptor to the IRR * in the virtual APIC page. @@ -2230,7 +2955,7 @@ uint16_t intr_status_old, intr_status_new; vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; if (atomic_cmpset_long(&pir_desc->pending, 1, 0) == 0) { VCPU_CTR0(vlapic->vm, vlapic->vcpuid, "vmx_inject_pir: " "no posted interrupt pending"); @@ -2295,6 +3020,7 @@ { struct vmx *vmx; struct vlapic *vlapic; + struct vlapic_vtx *vlapic_vtx; vmx = arg; @@ -2303,12 +3029,18 @@ vlapic->vcpuid = vcpuid; vlapic->apic_page = (struct LAPIC *)&vmx->apic_page[vcpuid]; + vlapic_vtx = (struct vlapic_vtx *)vlapic; + vlapic_vtx->pir_desc = &vmx->pir_desc[vcpuid]; + if (virtual_interrupt_delivery) { vlapic->ops.set_intr_ready = vmx_set_intr_ready; vlapic->ops.pending_intr = vmx_pending_intr; vlapic->ops.intr_accepted = vmx_intr_accepted; } + if (posted_interrupts) + vlapic->ops.post_intr = vmx_post_intr; + vlapic_init(vlapic); return (vlapic); Index: sys/amd64/vmm/intel/vmx.h =================================================================== --- sys/amd64/vmm/intel/vmx.h (revision 260410) +++ sys/amd64/vmm/intel/vmx.h (working copy) @@ -93,11 +93,20 @@ }; CTASSERT(sizeof(struct apic_page) == PAGE_SIZE); +/* Posted Interrupt Descriptor (described in section 29.6 of the Intel SDM) */ +struct pir_desc { + uint64_t pir[4]; + uint64_t pending; + uint64_t unused[3]; +} __aligned(64); +CTASSERT(sizeof(struct pir_desc) == 64); + /* virtual machine softc */ struct vmx { struct vmcs vmcs[VM_MAXCPU]; /* one vmcs per virtual cpu */ struct apic_page apic_page[VM_MAXCPU]; /* one apic page per vcpu */ char msr_bitmap[PAGE_SIZE]; + struct pir_desc pir_desc[VM_MAXCPU]; struct msr_entry guest_msrs[VM_MAXCPU][GUEST_MSR_MAX_ENTRIES]; struct vmxctx ctx[VM_MAXCPU]; struct vmxcap cap[VM_MAXCPU]; @@ -108,6 +117,7 @@ CTASSERT((offsetof(struct vmx, vmcs) & PAGE_MASK) == 0); CTASSERT((offsetof(struct vmx, msr_bitmap) & PAGE_MASK) == 0); CTASSERT((offsetof(struct vmx, guest_msrs) & 15) == 0); +CTASSERT((offsetof(struct vmx, pir_desc[0]) & 63) == 0); #define VMX_GUEST_VMEXIT 0 #define VMX_VMRESUME_ERROR 1 Index: sys/amd64/vmm/io/vlapic.c =================================================================== --- sys/amd64/vmm/io/vlapic.c (revision 260410) +++ sys/amd64/vmm/io/vlapic.c (working copy) @@ -1430,7 +1430,7 @@ } void -vlapic_post_intr(struct vlapic *vlapic, int hostcpu) +vlapic_post_intr(struct vlapic *vlapic, int hostcpu, int ipinum) { /* * Post an interrupt to the vcpu currently running on 'hostcpu'. @@ -1444,7 +1444,7 @@ if (vlapic->ops.post_intr) (*vlapic->ops.post_intr)(vlapic, hostcpu); else - ipi_cpu(hostcpu, vmm_ipinum); + ipi_cpu(hostcpu, ipinum); } bool Index: sys/amd64/vmm/io/vlapic.h =================================================================== --- sys/amd64/vmm/io/vlapic.h (revision 260410) +++ sys/amd64/vmm/io/vlapic.h (working copy) @@ -65,9 +65,9 @@ /* * Post an interrupt to the vcpu running on 'hostcpu'. This will use a * hardware assist if available (e.g. Posted Interrupt) or fall back to - * sending an IPI to interrupt the 'hostcpu'. + * sending an 'ipinum' to interrupt the 'hostcpu'. */ -void vlapic_post_intr(struct vlapic *vlapic, int hostcpu); +void vlapic_post_intr(struct vlapic *vlapic, int hostcpu, int ipinum); void vlapic_set_error(struct vlapic *vlapic, uint32_t mask); void vlapic_fire_cmci(struct vlapic *vlapic); Index: sys/amd64/vmm/vmm.c =================================================================== --- sys/amd64/vmm/vmm.c (revision 260410) +++ sys/amd64/vmm/vmm.c (working copy) @@ -130,7 +130,7 @@ static int vmm_initialized; static struct vmm_ops *ops; -#define VMM_INIT() (ops != NULL ? (*ops->init)() : 0) +#define VMM_INIT(num) (ops != NULL ? (*ops->init)(num) : 0) #define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) #define VMM_RESUME() (ops != NULL ? (*ops->resume)() : 0) @@ -170,6 +170,12 @@ /* statistics */ static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); +SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); + +static int vmm_ipinum; +SYSCTL_INT(_hw_vmm, OID_AUTO, ipinum, CTLFLAG_RD, &vmm_ipinum, 0, + "IPI vector used for vcpu notifications"); + static void vcpu_cleanup(struct vm *vm, int i) { @@ -222,8 +228,15 @@ int error; vmm_host_state_init(); - vmm_ipi_init(); + vmm_ipinum = vmm_ipi_alloc(); + if (vmm_ipinum == 0) { + vmm_ipinum = IPI_AST; + } else if (bootverbose) { + printf("vmm_init: installing ipi handler to interrupt vcpus " + "at vector %d\n", vmm_ipinum); + } + error = vmm_mem_init(); if (error) return (error); @@ -238,7 +251,7 @@ vmm_msr_init(); vmm_resume_p = vmm_resume; - return (VMM_INIT()); + return (VMM_INIT(vmm_ipinum)); } static int @@ -259,7 +272,8 @@ if (error == 0) { vmm_resume_p = NULL; iommu_cleanup(); - vmm_ipi_cleanup(); + if (vmm_ipinum != IPI_AST) + vmm_ipi_free(vmm_ipinum); error = VMM_CLEANUP(); /* * Something bad happened - prevent new @@ -294,8 +308,6 @@ DECLARE_MODULE(vmm, vmm_kmod, SI_SUB_SMP + 1, SI_ORDER_ANY); MODULE_VERSION(vmm, 1); -SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); - int vm_create(const char *name, struct vm **retvm) { @@ -1379,7 +1391,8 @@ panic("invalid vcpu state %d", vcpu->state); if (hostcpu != curcpu) { if (lapic_intr) - vlapic_post_intr(vcpu->vlapic, hostcpu); + vlapic_post_intr(vcpu->vlapic, hostcpu, + vmm_ipinum); else ipi_cpu(hostcpu, vmm_ipinum); } Index: sys/amd64/vmm/vmm_ipi.c =================================================================== --- sys/amd64/vmm/vmm_ipi.c (revision 260410) +++ sys/amd64/vmm/vmm_ipi.c (working copy) @@ -44,15 +44,10 @@ extern inthand_t IDTVEC(rsvd), IDTVEC(justreturn); -/* - * The default is to use the IPI_AST to interrupt a vcpu. - */ -int vmm_ipinum = IPI_AST; - CTASSERT(APIC_SPURIOUS_INT == 255); -void -vmm_ipi_init(void) +int +vmm_ipi_alloc(void) { int idx; uintptr_t func; @@ -72,22 +67,27 @@ ip = &idt[idx]; func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset); if (func == (uintptr_t)&IDTVEC(rsvd)) { - vmm_ipinum = idx; - setidt(vmm_ipinum, IDTVEC(justreturn), SDT_SYSIGT, + setidt(idx , IDTVEC(justreturn), SDT_SYSIGT, SEL_KPL, 0); - break; + return (idx); } } - - if (vmm_ipinum != IPI_AST && bootverbose) { - printf("vmm_ipi_init: installing ipi handler to interrupt " - "vcpus at vector %d\n", vmm_ipinum); - } + return (0); } void -vmm_ipi_cleanup(void) +vmm_ipi_free(int ipinum) { - if (vmm_ipinum != IPI_AST) - setidt(vmm_ipinum, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0); + uintptr_t func; + struct gate_descriptor *ip; + + KASSERT(ipinum >= APIC_IPI_INTS && ipinum < APIC_SPURIOUS_INT, + ("invalid ipi %d", ipinum)); + + ip = &idt[ipinum]; + func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset); + KASSERT(func == (uintptr_t)&IDTVEC(justreturn), + ("invalid ipi %d", ipinum)); + + setidt(ipinum, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0); } Index: sys/amd64/vmm/vmm_ipi.h =================================================================== --- sys/amd64/vmm/vmm_ipi.h (revision 260410) +++ sys/amd64/vmm/vmm_ipi.h (working copy) @@ -29,11 +29,7 @@ #ifndef _VMM_IPI_H_ #define _VMM_IPI_H_ -struct vm; +int vmm_ipi_alloc(void); +void vmm_ipi_free(int num); -extern int vmm_ipinum; - -void vmm_ipi_init(void); -void vmm_ipi_cleanup(void); - #endif