/** @interface_method_impl{PDMDEVHLPR0,pfnPCISetIrq} */ static DECLCALLBACK(void) pdmR0DevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) { PDMDEV_ASSERT_DEVINS(pDevIns); LogFlow(("pdmR0DevHlp_PCISetIrq: caller=%p/%d: iIrq=%d iLevel=%d\n", pDevIns, pDevIns->iInstance, iIrq, iLevel)); PVM pVM = pDevIns->Internal.s.pVMR0; PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceR0; PPDMPCIBUS pPciBus = pDevIns->Internal.s.pPciBusR0; pdmLock(pVM); uint32_t uTagSrc; if (iLevel & PDM_IRQ_LEVEL_HIGH) { pDevIns->Internal.s.uLastIrqTag = uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing); if (iLevel == PDM_IRQ_LEVEL_HIGH) VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); else VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); } else uTagSrc = pDevIns->Internal.s.uLastIrqTag; if ( pPciDev && pPciBus && pPciBus->pDevInsR0) { pPciBus->pfnSetIrqR0(pPciBus->pDevInsR0, pPciDev, iIrq, iLevel, uTagSrc); pdmUnlock(pVM); if (iLevel == PDM_IRQ_LEVEL_LOW) VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); } else { pdmUnlock(pVM); /* queue for ring-3 execution. */ PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0); AssertReturnVoid(pTask); pTask->enmOp = PDMDEVHLPTASKOP_PCI_SET_IRQ; pTask->pDevInsR3 = PDMDEVINS_2_R3PTR(pDevIns); pTask->u.SetIRQ.iIrq = iIrq; pTask->u.SetIRQ.iLevel = iLevel; pTask->u.SetIRQ.uTagSrc = uTagSrc; PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0); } LogFlow(("pdmR0DevHlp_PCISetIrq: caller=%p/%d: returns void; uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, uTagSrc)); }
/** * Gets the pending interrupt. * * @returns VBox status code. * @param pVCpu Pointer to the VMCPU. * @param pu8Interrupt Where to store the interrupt on success. */ VMMDECL(int) PDMGetInterrupt(PVMCPU pVCpu, uint8_t *pu8Interrupt) { PVM pVM = pVCpu->CTX_SUFF(pVM); pdmLock(pVM); /* * The local APIC has a higher priority than the PIC. */ if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC)) { VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC); Assert(pVM->pdm.s.Apic.CTX_SUFF(pDevIns)); Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetInterrupt)); uint32_t uTagSrc; int i = pVM->pdm.s.Apic.CTX_SUFF(pfnGetInterrupt)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu, &uTagSrc); AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i)); if (i >= 0) { pdmUnlock(pVM); *pu8Interrupt = (uint8_t)i; VBOXVMM_PDM_IRQ_GET(pVCpu, RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc), i); return VINF_SUCCESS; } } /* * Check the PIC. */ if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC)) { VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC); Assert(pVM->pdm.s.Pic.CTX_SUFF(pDevIns)); Assert(pVM->pdm.s.Pic.CTX_SUFF(pfnGetInterrupt)); uint32_t uTagSrc; int i = pVM->pdm.s.Pic.CTX_SUFF(pfnGetInterrupt)(pVM->pdm.s.Pic.CTX_SUFF(pDevIns), &uTagSrc); AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i)); if (i >= 0) { pdmUnlock(pVM); *pu8Interrupt = (uint8_t)i; VBOXVMM_PDM_IRQ_GET(pVCpu, RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc), i); return VINF_SUCCESS; } } /** @todo Figure out exactly why we can get here without anything being set. (REM) */ pdmUnlock(pVM); return VERR_NO_DATA; }
/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSetIrq} */ static DECLCALLBACK(void) pdmR0PciHlp_IoApicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc) { PDMDEV_ASSERT_DEVINS(pDevIns); Log4(("pdmR0PciHlp_IoApicSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc)); PVM pVM = pDevIns->Internal.s.pVMR0; if (pVM->pdm.s.IoApic.pDevInsR0) { pdmLock(pVM); pVM->pdm.s.IoApic.pfnSetIrqR0(pVM->pdm.s.IoApic.pDevInsR0, iIrq, iLevel, uTagSrc); pdmUnlock(pVM); } else if (pVM->pdm.s.IoApic.pDevInsR3) { /* queue for ring-3 execution. */ PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0); if (pTask) { pTask->enmOp = PDMDEVHLPTASKOP_IOAPIC_SET_IRQ; pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */ pTask->u.SetIRQ.iIrq = iIrq; pTask->u.SetIRQ.iLevel = iLevel; pTask->u.SetIRQ.uTagSrc = uTagSrc; PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0); } else AssertMsgFailed(("We're out of devhlp queue items!!!\n")); } }
/** @interface_method_impl{PDMDEVHLPR0,pfnPCISetIrq} */ static DECLCALLBACK(void) pdmR0DevHlp_ISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) { PDMDEV_ASSERT_DEVINS(pDevIns); LogFlow(("pdmR0DevHlp_ISASetIrq: caller=%p/%d: iIrq=%d iLevel=%d\n", pDevIns, pDevIns->iInstance, iIrq, iLevel)); PVM pVM = pDevIns->Internal.s.pVMR0; pdmLock(pVM); uint32_t uTagSrc; if (iLevel & PDM_IRQ_LEVEL_HIGH) { pDevIns->Internal.s.uLastIrqTag = uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing); if (iLevel == PDM_IRQ_LEVEL_HIGH) VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); else VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); } else uTagSrc = pDevIns->Internal.s.uLastIrqTag; bool fRc = pdmR0IsaSetIrq(pVM, iIrq, iLevel, uTagSrc); if (iLevel == PDM_IRQ_LEVEL_LOW && fRc) VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); pdmUnlock(pVM); LogFlow(("pdmR0DevHlp_ISASetIrq: caller=%p/%d: returns void; uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, uTagSrc)); }
/** * Sets an irq on the I/O APIC. * * @param pVM The VM handle. * @param iIrq The irq. * @param iLevel The new level. */ static void pdmRCIoApicSetIrq(PVM pVM, int iIrq, int iLevel) { if (pVM->pdm.s.IoApic.pDevInsRC) { pdmLock(pVM); pVM->pdm.s.IoApic.pfnSetIrqRC(pVM->pdm.s.IoApic.pDevInsRC, iIrq, iLevel); pdmUnlock(pVM); } else if (pVM->pdm.s.IoApic.pDevInsR3) { /* queue for ring-3 execution. */ PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueRC); if (pTask) { pTask->enmOp = PDMDEVHLPTASKOP_IOAPIC_SET_IRQ; pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */ pTask->u.SetIRQ.iIrq = iIrq; pTask->u.SetIRQ.iLevel = iLevel; PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueRC, &pTask->Core, 0); } else AssertMsgFailed(("We're out of devhlp queue items!!!\n")); } }
/** @interface_method_impl{PDMHPETHLPR3,pfnSetIrq} */ static DECLCALLBACK(int) pdmR3HpetHlp_SetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) { PDMDEV_ASSERT_DEVINS(pDevIns); LogFlow(("pdmR3HpetHlp_SetIrq: caller='%s'/%d: iIrq=%d iLevel=%d\n", pDevIns->pReg->szName, pDevIns->iInstance, iIrq, iLevel)); PVM pVM = pDevIns->Internal.s.pVMR3; pdmLock(pVM); uint32_t uTagSrc; if (iLevel & PDM_IRQ_LEVEL_HIGH) { pDevIns->Internal.s.uLastIrqTag = uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing); if (iLevel == PDM_IRQ_LEVEL_HIGH) VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); else VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); } else uTagSrc = pDevIns->Internal.s.uLastIrqTag; PDMIsaSetIrq(pVM, iIrq, iLevel, uTagSrc); /* (The API takes the lock recursively.) */ if (iLevel == PDM_IRQ_LEVEL_LOW) VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); pdmUnlock(pVM); return 0; }
/** @interface_method_impl{PDMDEVHLPRC,pfnPCISetIrq} */ static DECLCALLBACK(void) pdmRCDevHlp_PCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) { PDMDEV_ASSERT_DEVINS(pDevIns); LogFlow(("pdmRCDevHlp_PCISetIrq: caller=%p/%d: iIrq=%d iLevel=%d\n", pDevIns, pDevIns->iInstance, iIrq, iLevel)); PVM pVM = pDevIns->Internal.s.pVMRC; PPCIDEVICE pPciDev = pDevIns->Internal.s.pPciDeviceRC; PPDMPCIBUS pPciBus = pDevIns->Internal.s.pPciBusRC; if ( pPciDev && pPciBus && pPciBus->pDevInsRC) { pdmLock(pVM); pPciBus->pfnSetIrqRC(pPciBus->pDevInsRC, pPciDev, iIrq, iLevel); pdmUnlock(pVM); } else { /* queue for ring-3 execution. */ PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueRC); if (pTask) { pTask->enmOp = PDMDEVHLPTASKOP_PCI_SET_IRQ; pTask->pDevInsR3 = PDMDEVINS_2_R3PTR(pDevIns); pTask->u.SetIRQ.iIrq = iIrq; pTask->u.SetIRQ.iLevel = iLevel; PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueRC, &pTask->Core, 0); } else AssertMsgFailed(("We're out of devhlp queue items!!!\n")); } LogFlow(("pdmRCDevHlp_PCISetIrq: caller=%p/%d: returns void\n", pDevIns, pDevIns->iInstance)); }
/** * Sends an MSI to I/O APIC. * * @param pVM The VM handle. * @param GCAddr Address of the message. * @param uValue Value of the message. */ static void pdmRCIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue) { if (pVM->pdm.s.IoApic.pDevInsRC) { pdmLock(pVM); pVM->pdm.s.IoApic.pfnSendMsiRC(pVM->pdm.s.IoApic.pDevInsRC, GCAddr, uValue); pdmUnlock(pVM); } }
/** @interface_method_impl{PDMPCIHLPR0,pfnIsaSetIrq} */ static DECLCALLBACK(void) pdmR0PciHlp_IsaSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc) { PDMDEV_ASSERT_DEVINS(pDevIns); Log4(("pdmR0PciHlp_IsaSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc)); PVM pVM = pDevIns->Internal.s.pVMR0; pdmLock(pVM); pdmR0IsaSetIrq(pVM, iIrq, iLevel, uTagSrc); pdmUnlock(pVM); }
/** * Check if the APIC has a pending interrupt/if a TPR change would active one. * * @returns VINF_SUCCESS or VERR_PDM_NO_APIC_INSTANCE. * @param pDevIns Device instance of the APIC. * @param pfPending Pending state (out). */ VMMDECL(int) PDMApicHasPendingIrq(PVM pVM, bool *pfPending) { if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR)); pdmLock(pVM); *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns)); pdmUnlock(pVM); return VINF_SUCCESS; } return VERR_PDM_NO_APIC_INSTANCE; }
/** * Sets the pending I/O APIC interrupt. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param u8Irq The IRQ line. * @param u8Level The new level. * @param uTagSrc The IRQ tag and source tracer ID. */ VMM_INT_DECL(int) PDMIoApicSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc) { if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)); pdmLock(pVM); pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Irq, u8Level, uTagSrc); pdmUnlock(pVM); return VINF_SUCCESS; } return VERR_PDM_NO_PIC_INSTANCE; }
/** * Send a MSI to an I/O APIC. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param GCAddr Request address. * @param u8Value Request value. * @param uTagSrc The IRQ tag and source tracer ID. */ VMM_INT_DECL(int) PDMIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue, uint32_t uTagSrc) { if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSendMsi)); pdmLock(pVM); pVM->pdm.s.IoApic.CTX_SUFF(pfnSendMsi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), GCAddr, uValue, uTagSrc); pdmUnlock(pVM); return VINF_SUCCESS; } return VERR_PDM_NO_PIC_INSTANCE; }
/** * Set the APIC base. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param u64Base The new base. */ VMMDECL(int) PDMApicSetBase(PVM pVM, uint64_t u64Base) { if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase)); pdmLock(pVM); pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), u64Base); pdmUnlock(pVM); return VINF_SUCCESS; } return VERR_PDM_NO_APIC_INSTANCE; }
/** * Set the TPR (task priority register?). * * @returns VBox status code. * @param pVCpu Pointer to the VMCPU. * @param u8TPR The new TPR. */ VMMDECL(int) PDMApicSetTPR(PVMCPU pVCpu, uint8_t u8TPR) { PVM pVM = pVCpu->CTX_SUFF(pVM); if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR)); pdmLock(pVM); pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu, u8TPR); pdmUnlock(pVM); return VINF_SUCCESS; } return VERR_PDM_NO_APIC_INSTANCE; }
/** * Get the APIC base from the APIC device. This is slow and involves * taking the PDM lock, this is currently only used by CPUM to cache the APIC * base once (during init./load state), all other callers should use * PDMApicGetBase() and not this function. * * @returns VBox status code. * @param pVM Pointer to the VMCPU. * @param pu64Base Where to store the APIC base. */ VMMDECL(int) PDMApicGetBase(PVMCPU pVCpu, uint64_t *pu64Base) { PVM pVM = pVCpu->CTX_SUFF(pVM); if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase)); pdmLock(pVM); *pu64Base = pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu); pdmUnlock(pVM); return VINF_SUCCESS; } *pu64Base = 0; return VERR_PDM_NO_APIC_INSTANCE; }
/** * Check if the APIC has a pending interrupt/if a TPR change would active one. * * @returns VINF_SUCCESS or VERR_PDM_NO_APIC_INSTANCE. * @param pVCpu Pointer to the VMCPU. * @param pfPending Pending state (out). */ VMM_INT_DECL(int) PDMApicHasPendingIrq(PVMCPU pVCpu, bool *pfPending) { PVM pVM = pVCpu->CTX_SUFF(pVM); if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR)); pdmLock(pVM); *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu, NULL /* pu8PendingIrq */); pdmUnlock(pVM); return VINF_SUCCESS; } return VERR_PDM_NO_APIC_INSTANCE; }
/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSendMsi} */ static DECLCALLBACK(void) pdmR0PciHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc) { PDMDEV_ASSERT_DEVINS(pDevIns); Log4(("pdmR0PciHlp_IoApicSendMsi: GCPhys=%p uValue=%d uTagSrc=%#x\n", GCPhys, uValue, uTagSrc)); PVM pVM = pDevIns->Internal.s.pVMR0; if (pVM->pdm.s.IoApic.pDevInsR0) { pdmLock(pVM); pVM->pdm.s.IoApic.pfnSendMsiR0(pVM->pdm.s.IoApic.pDevInsR0, GCPhys, uValue, uTagSrc); pdmUnlock(pVM); } else { AssertFatalMsgFailed(("Lazy bastards!")); } }
/** * Sets the pending interrupt coming from ISA source or HPET. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param u8Irq The IRQ line. * @param u8Level The new level. * @param uTagSrc The IRQ tag and source tracer ID. */ VMMDECL(int) PDMIsaSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc) { pdmLock(pVM); /** @todo put the IRQ13 code elsewhere to avoid this unnecessary bloat. */ if (!uTagSrc && (u8Level & PDM_IRQ_LEVEL_HIGH)) /* FPU IRQ */ { if (u8Level == PDM_IRQ_LEVEL_HIGH) VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), 0, 0); else VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), 0, 0); } int rc = VERR_PDM_NO_PIC_INSTANCE; if (pVM->pdm.s.Pic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.Pic.CTX_SUFF(pfnSetIrq)); pVM->pdm.s.Pic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.Pic.CTX_SUFF(pDevIns), u8Irq, u8Level, uTagSrc); rc = VINF_SUCCESS; } if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)); /* * Apply Interrupt Source Override rules. * See ACPI 4.0 specification 5.2.12.4 and 5.2.12.5 for details on * interrupt source override. * Shortly, ISA IRQ0 is electically connected to pin 2 on IO-APIC, and some OSes, * notably recent OS X rely upon this configuration. * If changing, also update override rules in MADT and MPS. */ /* ISA IRQ0 routed to pin 2, all others ISA sources are identity mapped */ if (u8Irq == 0) u8Irq = 2; pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Irq, u8Level, uTagSrc); rc = VINF_SUCCESS; } if (!uTagSrc && u8Level == PDM_IRQ_LEVEL_LOW) VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), 0, 0); pdmUnlock(pVM); return rc; }
/** * Set the APIC base. * * @returns VBox status code. * @param pVM Pointer to the VMCPU. * @param u64Base The new base. */ VMMDECL(int) PDMApicSetBase(PVMCPU pVCpu, uint64_t u64Base) { PVM pVM = pVCpu->CTX_SUFF(pVM); if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns)) { Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase)); pdmLock(pVM); pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu, u64Base); /* Update CPUM's copy of the APIC base. */ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu); Assert(pCtx); pCtx->msrApicBase = pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu); pdmUnlock(pVM); return VINF_SUCCESS; } return VERR_PDM_NO_APIC_INSTANCE; }
/** @interface_method_impl{PDMAPICHLPR0,pfnCalcIrqTag} */ static DECLCALLBACK(uint32_t) pdmR0ApicHlp_CalcIrqTag(PPDMDEVINS pDevIns, uint8_t u8Level) { PDMDEV_ASSERT_DEVINS(pDevIns); PVM pVM = pDevIns->Internal.s.pVMR0; pdmLock(pVM); uint32_t uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing); if (u8Level == PDM_IRQ_LEVEL_HIGH) VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); else VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc)); pdmUnlock(pVM); LogFlow(("pdmR0ApicHlp_CalcIrqTag: caller=%p/%d: returns %#x (u8Level=%d)\n", pDevIns, pDevIns->iInstance, uTagSrc, u8Level)); return uTagSrc; }
/** * Destroy a all queues owned by the specified driver. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param pDrvIns Driver instance. * @thread Emulation thread only. */ VMMR3_INT_DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns) { LogFlow(("PDMR3QueueDestroyDriver: pDrvIns=%p\n", pDrvIns)); /* * Validate input. */ if (!pDrvIns) return VERR_INVALID_PARAMETER; PUVM pUVM = pVM->pUVM; pdmLock(pVM); /* * Unlink it. */ PPDMQUEUE pQueueNext = pUVM->pdm.s.pQueuesTimer; PPDMQUEUE pQueue = pUVM->pdm.s.pQueuesForced; do { while (pQueue) { if ( pQueue->enmType == PDMQUEUETYPE_DRV && pQueue->u.Drv.pDrvIns == pDrvIns) { PPDMQUEUE pQueueDestroy = pQueue; pQueue = pQueue->pNext; int rc = PDMR3QueueDestroy(pQueueDestroy); AssertRC(rc); } else pQueue = pQueue->pNext; } /* next queue list */ pQueue = pQueueNext; pQueueNext = NULL; } while (pQueue); pdmUnlock(pVM); return VINF_SUCCESS; }
/** * Destroy a queue. * * @returns VBox status code. * @param pQueue Queue to destroy. * @thread Emulation thread only. */ VMMR3_INT_DECL(int) PDMR3QueueDestroy(PPDMQUEUE pQueue) { LogFlow(("PDMR3QueueDestroy: pQueue=%p\n", pQueue)); /* * Validate input. */ if (!pQueue) return VERR_INVALID_PARAMETER; Assert(pQueue && pQueue->pVMR3); PVM pVM = pQueue->pVMR3; PUVM pUVM = pVM->pUVM; pdmLock(pVM); /* * Unlink it. */ if (pQueue->pTimer) { if (pUVM->pdm.s.pQueuesTimer != pQueue) { PPDMQUEUE pCur = pUVM->pdm.s.pQueuesTimer; while (pCur) { if (pCur->pNext == pQueue) { pCur->pNext = pQueue->pNext; break; } pCur = pCur->pNext; } AssertMsg(pCur, ("Didn't find the queue!\n")); } else pUVM->pdm.s.pQueuesTimer = pQueue->pNext; } else { if (pUVM->pdm.s.pQueuesForced != pQueue) { PPDMQUEUE pCur = pUVM->pdm.s.pQueuesForced; while (pCur) { if (pCur->pNext == pQueue) { pCur->pNext = pQueue->pNext; break; } pCur = pCur->pNext; } AssertMsg(pCur, ("Didn't find the queue!\n")); } else pUVM->pdm.s.pQueuesForced = pQueue->pNext; } pQueue->pNext = NULL; pQueue->pVMR3 = NULL; pdmUnlock(pVM); /* * Deregister statistics. */ STAMR3DeregisterF(pVM->pUVM, "/PDM/Queue/%s/cbItem", pQueue->pszName); /* * Destroy the timer and free it. */ if (pQueue->pTimer) { TMR3TimerDestroy(pQueue->pTimer); pQueue->pTimer = NULL; } if (pQueue->pVMRC) { pQueue->pVMRC = NIL_RTRCPTR; pQueue->pVMR0 = NIL_RTR0PTR; MMHyperFree(pVM, pQueue); } else MMR3HeapFree(pQueue); return VINF_SUCCESS; }
/** * Internal worker for the queue creation apis. * * @returns VBox status. * @param pVM Pointer to the VM. * @param cbItem Item size. * @param cItems Number of items. * @param cMilliesInterval Number of milliseconds between polling the queue. * If 0 then the emulation thread will be notified whenever an item arrives. * @param fRZEnabled Set if the queue will be used from RC/R0 and need to be allocated from the hyper heap. * @param pszName The queue name. Unique. Not copied. * @param ppQueue Where to store the queue handle. */ static int pdmR3QueueCreate(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue) { PUVM pUVM = pVM->pUVM; /* * Validate input. */ AssertMsgReturn(cbItem >= sizeof(PDMQUEUEITEMCORE) && cbItem < _1M, ("cbItem=%zu\n", cbItem), VERR_OUT_OF_RANGE); AssertMsgReturn(cItems >= 1 && cItems <= _64K, ("cItems=%u\n", cItems), VERR_OUT_OF_RANGE); /* * Align the item size and calculate the structure size. */ cbItem = RT_ALIGN(cbItem, sizeof(RTUINTPTR)); size_t cb = cbItem * cItems + RT_ALIGN_Z(RT_OFFSETOF(PDMQUEUE, aFreeItems[cItems + PDMQUEUE_FREE_SLACK]), 16); PPDMQUEUE pQueue; int rc; if (fRZEnabled) rc = MMHyperAlloc(pVM, cb, 0, MM_TAG_PDM_QUEUE, (void **)&pQueue ); else rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_QUEUE, cb, (void **)&pQueue); if (RT_FAILURE(rc)) return rc; /* * Initialize the data fields. */ pQueue->pVMR3 = pVM; pQueue->pVMR0 = fRZEnabled ? pVM->pVMR0 : NIL_RTR0PTR; pQueue->pVMRC = fRZEnabled ? pVM->pVMRC : NIL_RTRCPTR; pQueue->pszName = pszName; pQueue->cMilliesInterval = cMilliesInterval; //pQueue->pTimer = NULL; pQueue->cbItem = (uint32_t)cbItem; pQueue->cItems = cItems; //pQueue->pPendingR3 = NULL; //pQueue->pPendingR0 = NULL; //pQueue->pPendingRC = NULL; pQueue->iFreeHead = cItems; //pQueue->iFreeTail = 0; PPDMQUEUEITEMCORE pItem = (PPDMQUEUEITEMCORE)((char *)pQueue + RT_ALIGN_Z(RT_OFFSETOF(PDMQUEUE, aFreeItems[cItems + PDMQUEUE_FREE_SLACK]), 16)); for (unsigned i = 0; i < cItems; i++, pItem = (PPDMQUEUEITEMCORE)((char *)pItem + cbItem)) { pQueue->aFreeItems[i].pItemR3 = pItem; if (fRZEnabled) { pQueue->aFreeItems[i].pItemR0 = MMHyperR3ToR0(pVM, pItem); pQueue->aFreeItems[i].pItemRC = MMHyperR3ToRC(pVM, pItem); } } /* * Create timer? */ if (cMilliesInterval) { rc = TMR3TimerCreateInternal(pVM, TMCLOCK_REAL, pdmR3QueueTimer, pQueue, "Queue timer", &pQueue->pTimer); if (RT_SUCCESS(rc)) { rc = TMTimerSetMillies(pQueue->pTimer, cMilliesInterval); if (RT_FAILURE(rc)) { AssertMsgFailed(("TMTimerSetMillies failed rc=%Rrc\n", rc)); int rc2 = TMR3TimerDestroy(pQueue->pTimer); AssertRC(rc2); } } else AssertMsgFailed(("TMR3TimerCreateInternal failed rc=%Rrc\n", rc)); if (RT_FAILURE(rc)) { if (fRZEnabled) MMHyperFree(pVM, pQueue); else MMR3HeapFree(pQueue); return rc; } /* * Insert into the queue list for timer driven queues. */ pdmLock(pVM); pQueue->pNext = pUVM->pdm.s.pQueuesTimer; pUVM->pdm.s.pQueuesTimer = pQueue; pdmUnlock(pVM); } else { /* * Insert into the queue list for forced action driven queues. * This is a FIFO, so insert at the end. */ /** @todo we should add a priority to the queues so we don't have to rely on * the initialization order to deal with problems like @bugref{1605} (pgm/pcnet * deadlock caused by the critsect queue to be last in the chain). * - Update, the critical sections are no longer using queues, so this isn't a real * problem any longer. The priority might be a nice feature for later though. */ pdmLock(pVM); if (!pUVM->pdm.s.pQueuesForced) pUVM->pdm.s.pQueuesForced = pQueue; else { PPDMQUEUE pPrev = pUVM->pdm.s.pQueuesForced; while (pPrev->pNext) pPrev = pPrev->pNext; pPrev->pNext = pQueue; } pdmUnlock(pVM); } /* * Register the statistics. */ STAMR3RegisterF(pVM, &pQueue->cbItem, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Item size.", "/PDM/Queue/%s/cbItem", pQueue->pszName); STAMR3RegisterF(pVM, &pQueue->cItems, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Queue size.", "/PDM/Queue/%s/cItems", pQueue->pszName); STAMR3RegisterF(pVM, &pQueue->StatAllocFailures, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "PDMQueueAlloc failures.", "/PDM/Queue/%s/AllocFailures", pQueue->pszName); STAMR3RegisterF(pVM, &pQueue->StatInsert, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Calls to PDMQueueInsert.", "/PDM/Queue/%s/Insert", pQueue->pszName); STAMR3RegisterF(pVM, &pQueue->StatFlush, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Calls to pdmR3QueueFlush.", "/PDM/Queue/%s/Flush", pQueue->pszName); STAMR3RegisterF(pVM, &pQueue->StatFlushLeftovers, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Left over items after flush.", "/PDM/Queue/%s/FlushLeftovers", pQueue->pszName); #ifdef VBOX_WITH_STATISTICS STAMR3RegisterF(pVM, &pQueue->StatFlushPrf, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Profiling pdmR3QueueFlush.", "/PDM/Queue/%s/FlushPrf", pQueue->pszName); STAMR3RegisterF(pVM, (void *)&pQueue->cStatPending, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Pending items.", "/PDM/Queue/%s/Pending", pQueue->pszName); #endif *ppQueue = pQueue; return VINF_SUCCESS; }
/** @interface_method_impl{PDMPCIHLPR3,pfnUnlock} */ static DECLCALLBACK(void) pdmR3PciHlp_Unlock(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); LogFlow(("pdmR3PciHlp_Unlock: caller='%s'/%d:\n", pDevIns->pReg->szName, pDevIns->iInstance)); pdmUnlock(pDevIns->Internal.s.pVMR3); }
/** * Destroy a queue. * * @returns VBox status code. * @param pQueue Queue to destroy. * @thread Emulation thread only. */ VMMR3_INT_DECL(int) PDMR3QueueDestroy(PPDMQUEUE pQueue) { LogFlow(("PDMR3QueueDestroy: pQueue=%p\n", pQueue)); /* * Validate input. */ if (!pQueue) return VERR_INVALID_PARAMETER; Assert(pQueue && pQueue->pVMR3); PVM pVM = pQueue->pVMR3; PUVM pUVM = pVM->pUVM; pdmLock(pVM); /* * Unlink it. */ if (pQueue->pTimer) { if (pUVM->pdm.s.pQueuesTimer != pQueue) { PPDMQUEUE pCur = pUVM->pdm.s.pQueuesTimer; while (pCur) { if (pCur->pNext == pQueue) { pCur->pNext = pQueue->pNext; break; } pCur = pCur->pNext; } AssertMsg(pCur, ("Didn't find the queue!\n")); } else pUVM->pdm.s.pQueuesTimer = pQueue->pNext; } else { if (pUVM->pdm.s.pQueuesForced != pQueue) { PPDMQUEUE pCur = pUVM->pdm.s.pQueuesForced; while (pCur) { if (pCur->pNext == pQueue) { pCur->pNext = pQueue->pNext; break; } pCur = pCur->pNext; } AssertMsg(pCur, ("Didn't find the queue!\n")); } else pUVM->pdm.s.pQueuesForced = pQueue->pNext; } pQueue->pNext = NULL; pQueue->pVMR3 = NULL; pdmUnlock(pVM); /* * Deregister statistics. */ STAMR3Deregister(pVM, &pQueue->cbItem); STAMR3Deregister(pVM, &pQueue->cbItem); STAMR3Deregister(pVM, &pQueue->StatAllocFailures); STAMR3Deregister(pVM, &pQueue->StatInsert); STAMR3Deregister(pVM, &pQueue->StatFlush); STAMR3Deregister(pVM, &pQueue->StatFlushLeftovers); #ifdef VBOX_WITH_STATISTICS STAMR3Deregister(pVM, &pQueue->StatFlushPrf); STAMR3Deregister(pVM, (void *)&pQueue->cStatPending); #endif /* * Destroy the timer and free it. */ if (pQueue->pTimer) { TMR3TimerDestroy(pQueue->pTimer); pQueue->pTimer = NULL; } if (pQueue->pVMRC) { pQueue->pVMRC = NIL_RTRCPTR; pQueue->pVMR0 = NIL_RTR0PTR; MMHyperFree(pVM, pQueue); } else MMR3HeapFree(pQueue); return VINF_SUCCESS; }
/** @interface_method_impl{PDMPCIHLPR0,pfnUnlock} */ static DECLCALLBACK(void) pdmR0PciHlp_Unlock(PPDMDEVINS pDevIns) { PDMDEV_ASSERT_DEVINS(pDevIns); pdmUnlock(pDevIns->Internal.s.pVMR0); }