VirtualBox

Ignore:
Timestamp:
May 14, 2020 10:38:14 AM (5 years ago)
Author:
vboxsync
Message:

AMD IOMMU: bugref:9654 Asynchronous IOMMU command processing.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp

    r84301 r84302  
    803803    /** The 64-bit unsigned integer view. */
    804804    uint64_t    au64[2];
    805 } CMD_COMPLETION_WAIT_T;
    806 AssertCompileSize(CMD_COMPLETION_WAIT_T, 16);
     805} CMD_COMWAIT_T;
     806AssertCompileSize(CMD_COMWAIT_T, 16);
     807/** Pointer to a completion wait command. */
     808typedef CMD_COMWAIT_T *PCMD_COMWAIT_T;
     809/** Pointer to a const completion wait command. */
     810typedef CMD_COMWAIT_T const *PCCMD_COMWAIT_T;
     811#define IOMMU_CMD_COM_WAIT_QWORD_0_VALID_MASK        UINT64_C(0xf00fffffffffffff)
    807812
    808813/**
     
    21662171
    21672172/**
    2168  * DEV_TAB_HARDWARE_ERROR, PAGE_TAB_HARDWARE_ERROR and COMMAND_HARDWARE_ERROR Event
    2169  * Types.
    2170  * In accordance with the AMD spec.
    2171  */
    2172 typedef enum EVT_HW_ERR_TYPE_T
    2173 {
    2174     kHwErrType_MasterAbort = 0,
    2175     kHwErrType_TargetAbort,
    2176     kHwErrType_PoisonedData
    2177 } EVT_HW_ERR_TYPE_T;
    2178 
    2179 /**
    21802173 * ILLEGAL_COMMAND_ERROR Event Types.
    21812174 * In accordance with the AMD spec.
     
    25862579
    25872580
    2588 DECLINLINE(IOMMU_STATUS_T) iommuAmdGetStatus(PCIOMMU pThis)
     2581DECL_FORCE_INLINE(IOMMU_STATUS_T) iommuAmdGetStatus(PCIOMMU pThis)
    25892582{
    25902583    IOMMU_STATUS_T Status;
     
    25942587
    25952588
    2596 DECLINLINE(IOMMU_CTRL_T) iommuAmdGetCtrl(PCIOMMU pThis)
     2589DECL_FORCE_INLINE(IOMMU_CTRL_T) iommuAmdGetCtrl(PCIOMMU pThis)
    25972590{
    25982591    IOMMU_CTRL_T Ctrl;
     
    36553648 * @param   enmOp               The IOMMU operation being performed.
    36563649 * @param   pEvtPageTabHwErr    The page table hardware error event.
    3657  * @param   enmEvtType          The hardware error event type.
    36583650 *
    36593651 * @thread  Any.
    36603652 */
    3661 static void iommuAmdRaisePageTabHwErrorEvent(PPDMDEVINS pDevIns, IOMMUOP enmOp, PEVT_PAGE_TAB_HW_ERR_T pEvtPageTabHwErr,
    3662                                              EVT_HW_ERR_TYPE_T enmEvtType)
     3653static void iommuAmdRaisePageTabHwErrorEvent(PPDMDEVINS pDevIns, IOMMUOP enmOp, PEVT_PAGE_TAB_HW_ERR_T pEvtPageTabHwErr)
    36633654{
    36643655    AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_PAGE_TAB_HW_ERR_T));
     
    36743665    IOMMU_UNLOCK(pDevIns);
    36753666
    3676     Log((IOMMU_LOG_PFX ": Raised PAGE_TAB_HARDWARE_ERROR. uDevId=%#x uDomainId=%#x GCPhysPtEntity=%#RGp enmOp=%u enmType=%u\n",
    3677          pEvtPageTabHwErr->n.u16DevId, pEvtPageTabHwErr->n.u16DomainOrPasidLo, pEvtPageTabHwErr->n.u64Addr, enmOp, enmEvtType));
    3678     NOREF(enmEvtType);
     3667    Log((IOMMU_LOG_PFX ": Raised PAGE_TAB_HARDWARE_ERROR. uDevId=%#x uDomainId=%#x GCPhysPtEntity=%#RGp enmOp=%u u2Type=%u\n",
     3668         pEvtPageTabHwErr->n.u16DevId, pEvtPageTabHwErr->n.u16DomainOrPasidLo, pEvtPageTabHwErr->n.u64Addr, enmOp,
     3669         pEvtPageTabHwErr->n.u2Type));
    36793670}
    36803671
     
    36833674 * Initializes a COMMAND_HARDWARE_ERROR event.
    36843675 *
    3685  * @param   GCPhysCmd       The system physical address of the command that caused
    3686  *                          the error.
     3676 * @param   GCPhysAddr      The system physical address the IOMMU attempted to access.
    36873677 * @param   pEvtCmdHwErr    Where to store the initialized event.
    36883678 */
    3689 static void iommuAmdInitCmdHwErrorEvent(RTGCPHYS GCPhysCmd, HWEVTTYPE enmHwErrType, PEVT_CMD_HW_ERR_T pEvtCmdHwErr)
     3679static void iommuAmdInitCmdHwErrorEvent(RTGCPHYS GCPhysAddr, PEVT_CMD_HW_ERR_T pEvtCmdHwErr)
    36903680{
    36913681    memset(pEvtCmdHwErr, 0, sizeof(*pEvtCmdHwErr));
    3692     pEvtCmdHwErr->n.u2Type    = enmHwErrType;
     3682    pEvtCmdHwErr->n.u2Type    = HWEVTTYPE_DATA_ERROR;
    36933683    pEvtCmdHwErr->n.u4EvtCode = IOMMU_EVT_COMMAND_HW_ERROR;
    3694     pEvtCmdHwErr->n.u64Addr   = GCPhysCmd;
     3684    pEvtCmdHwErr->n.u64Addr   = GCPhysAddr;
    36953685}
    36963686
     
    37013691 * @param   pDevIns         The IOMMU device instance.
    37023692 * @param   pEvtCmdHwErr    The command hardware error event.
    3703  * @param   enmEvtType      The hardware error event type.
    37043693 *
    37053694 * @thread  Any.
    37063695 */
    3707 static void iommuAmdRaiseCmdHwErrorEvent(PPDMDEVINS pDevIns, PCEVT_CMD_HW_ERR_T pEvtCmdHwErr, EVT_HW_ERR_TYPE_T enmEvtType)
     3696static void iommuAmdRaiseCmdHwErrorEvent(PPDMDEVINS pDevIns, PCEVT_CMD_HW_ERR_T pEvtCmdHwErr)
    37083697{
    37093698    AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_CMD_HW_ERR_T));
     
    37183707    IOMMU_UNLOCK(pDevIns);
    37193708
    3720     Log((IOMMU_LOG_PFX ": Raised COMMAND_HARDWARE_ERROR. GCPhysCmd=%#RGp enmType=%u\n", pEvtCmdHwErr->n.u64Addr, enmEvtType));
    3721     NOREF(enmEvtType);
     3709    Log((IOMMU_LOG_PFX ": Raised COMMAND_HARDWARE_ERROR. GCPhysCmd=%#RGp u2Type=%u\n", pEvtCmdHwErr->n.u64Addr,
     3710         pEvtCmdHwErr->n.u2Type));
    37223711}
    37233712
     
    37533742 * @param   enmOp               The IOMMU operation being performed.
    37543743 * @param   pEvtDevTabHwErr     The device table hardware error event.
    3755  * @param   enmEvtType          The hardware error event type.
    37563744 *
    37573745 * @thread  Any.
    37583746 */
    3759 static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, IOMMUOP enmOp, PEVT_DEV_TAB_HW_ERROR_T pEvtDevTabHwErr,
    3760                                             EVT_HW_ERR_TYPE_T enmEvtType)
     3747static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, IOMMUOP enmOp, PEVT_DEV_TAB_HW_ERROR_T pEvtDevTabHwErr)
    37613748{
    37623749    AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_DEV_TAB_HW_ERROR_T));
     
    37723759    IOMMU_UNLOCK(pDevIns);
    37733760
    3774     Log((IOMMU_LOG_PFX ": Raised DEV_TAB_HARDWARE_ERROR. uDevId=%#x GCPhysDte=%#RGp enmOp=%u enmType=%u\n",
    3775          pEvtDevTabHwErr->n.u16DevId, pEvtDevTabHwErr->n.u64Addr, enmOp, enmEvtType));
    3776     NOREF(enmEvtType);
     3761    Log((IOMMU_LOG_PFX ": Raised DEV_TAB_HARDWARE_ERROR. uDevId=%#x GCPhysDte=%#RGp enmOp=%u u2Type=%u\n",
     3762         pEvtDevTabHwErr->n.u16DevId, pEvtDevTabHwErr->n.u64Addr, enmOp, pEvtDevTabHwErr->n.u2Type));
    37773763}
    37783764
     
    41424128        EVT_DEV_TAB_HW_ERROR_T EvtDevTabHwErr;
    41434129        iommuAmdInitDevTabHwErrorEvent(uDevId, GCPhysDte, enmOp, &EvtDevTabHwErr);
    4144         iommuAmdRaiseDevTabHwErrorEvent(pDevIns, enmOp, &EvtDevTabHwErr, kHwErrType_TargetAbort);
     4130        iommuAmdRaiseDevTabHwErrorEvent(pDevIns, enmOp, &EvtDevTabHwErr);
    41454131        return VERR_IOMMU_IPE_1;
    41464132    }
     
    42784264                EVT_PAGE_TAB_HW_ERR_T EvtPageTabHwErr;
    42794265                iommuAmdInitPageTabHwErrorEvent(uDevId, pDte->n.u16DomainId, GCPhysPtEntity, enmOp, &EvtPageTabHwErr);
    4280                 iommuAmdRaisePageTabHwErrorEvent(pDevIns, enmOp, &EvtPageTabHwErr, kHwErrType_TargetAbort);
     4266                iommuAmdRaisePageTabHwErrorEvent(pDevIns, enmOp, &EvtPageTabHwErr);
    42814267                return VERR_IOMMU_IPE_2;
    42824268            }
     
    46234609 * @returns VBox status code.
    46244610 * @param   pDevIns         The IOMMU device instance.
     4611 * @param   GCPhysCmd       The system physical address of the command.
    46254612 * @param   pCmd            The command to process.
    4626  * @param   penmEvtType     Where to store the illegal command error event type in
    4627  *                          case of failures.
    4628  */
    4629 static int iommuAmdR3ProcessCmd(PPDMDEVINS pDevIns, PCCMD_GENERIC_T pCmd, PEVT_ILLEGAL_CMD_ERR_TYPE_T penmEvtType)
     4613 *
     4614 * @thread  Command thread.
     4615 */
     4616static int iommuAmdR3ProcessCmd(PPDMDEVINS pDevIns, RTGCPHYS GCPhysCmd, PCCMD_GENERIC_T pCmd)
    46304617{
    46314618    IOMMU_ASSERT_NOT_LOCKED(pDevIns);
     4619
     4620    EVT_ILLEGAL_CMD_ERR_T EvtIllegalCmdErr;
    46324621
    46334622    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     
    46364625    {
    46374626        case IOMMU_CMD_COMPLETION_WAIT:
     4627        {
     4628            PCCMD_COMWAIT_T pCmdComWait = (PCCMD_COMWAIT_T)pCmd;
     4629            AssertCompile(sizeof(*pCmdComWait) == sizeof(*pCmd));
     4630
     4631            /* Validate reserved bits in the command. */
     4632            if (!(pCmdComWait->au64[0] & ~IOMMU_CMD_COM_WAIT_QWORD_0_VALID_MASK))
     4633            {
     4634                /* If Completion Store is requested, write the Store Data to the specified Store Address.*/
     4635                if (pCmdComWait->n.u1Store)
     4636                {
     4637                    RTGCPHYS const GCPhysStore = RT_MAKE_U64(pCmdComWait->n.u29StoreAddrLo << 3, pCmdComWait->n.u20StoreAddrHi);
     4638                    uint64_t const u64Data     = pCmdComWait->n.u64StoreData;
     4639
     4640                    int rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhysStore, &u64Data, sizeof(u64Data));
     4641                    if (RT_FAILURE(rc))
     4642                    {
     4643                        EVT_CMD_HW_ERR_T EvtCmdHwErr;
     4644                        iommuAmdInitCmdHwErrorEvent(GCPhysStore, &EvtCmdHwErr);
     4645                        iommuAmdRaiseCmdHwErrorEvent(pDevIns, &EvtCmdHwErr);
     4646                        Log((IOMMU_LOG_PFX ": Failed to write StoreData (%#RX64) to %#RGp. rc=%Rrc\n", u64Data, GCPhysStore, rc));
     4647                        return rc;
     4648                    }
     4649                }
     4650
     4651                /* If command completion interrupt is requested, honor it. */
     4652                if (pCmdComWait->n.u1Interrupt)
     4653                {
     4654                    IOMMU_LOCK(pDevIns);
     4655                    IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis);
     4656                    if (Ctrl.n.u1CompWaitIntrEn)
     4657                    {
     4658                        /* Indicate that this command completed. */
     4659                        ASMAtomicOrU64(&pThis->Status.u64, IOMMU_STATUS_COMPLETION_WAIT_INTR);
     4660
     4661                        /* Check and signal an interrupt if software wants to receive one when this command completes. */
     4662                        IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis);
     4663                        if (Ctrl.n.u1CompWaitIntrEn)
     4664                            iommuAmdRaiseMsiInterrupt(pDevIns);
     4665                    }
     4666                    IOMMU_UNLOCK(pDevIns);
     4667                }
     4668                return VINF_SUCCESS;
     4669            }
     4670
     4671            iommuAmdInitIllegalCmdEvent(GCPhysCmd, &EvtIllegalCmdErr);
     4672            iommuAmdRaiseIllegalCmdEvent(pDevIns, &EvtIllegalCmdErr, kIllegalCmdErrType_RsvdNotZero);
     4673            return VERR_INVALID_FUNCTION;
     4674        }
     4675
    46384676        case IOMMU_CMD_INV_DEV_TAB_ENTRY:
    46394677        case IOMMU_CMD_INV_IOMMU_PAGES:
     
    46524690    }
    46534691
    4654     Log((IOMMU_LOG_PFX ": Invalid/Unrecognized command opcode %u (%#x)\n", bCmd, bCmd));
    4655     *penmEvtType = kIllegalCmdErrType_CmdNotSupported;
    4656     return VERR_INVALID_FUNCTION;
     4692    Log((IOMMU_LOG_PFX ": Unrecognized or unsupported command opcode %u (%#x)\n", bCmd, bCmd));
     4693    return VERR_NOT_SUPPORTED;
    46574694}
    46584695
     
    47014738         *        number of calls to PGM. In the longer run we could lock the memory and
    47024739         *        mappings and accessing them directly. */
    4703         IOMMU_STATUS_T Status = iommuAmdGetStatus(pThis);
     4740        IOMMU_LOCK(pDevIns);
     4741
     4742        IOMMU_STATUS_T const Status = iommuAmdGetStatus(pThis);
    47044743        if (Status.u64 & IOMMU_STATUS_CMD_BUF_RUNNING)
    47054744        {
    4706             IOMMU_LOCK(pDevIns);
    4707 
    47084745            /* Get the offset we need to read the command from memory (circular buffer offset). */
    47094746            uint32_t const cbCmdBuf = iommuAmdGetTotalBufLength(pThis->CmdBufBaseAddr.n.u4Len);
     
    47244761
    47254762                    /* Process the fetched command. */
    4726                     EVT_ILLEGAL_CMD_ERR_TYPE_T enmEvtType;
    47274763                    IOMMU_UNLOCK(pDevIns);
    4728                     rc = iommuAmdR3ProcessCmd(pDevIns, &Cmd, &enmEvtType);
     4764                    rc = iommuAmdR3ProcessCmd(pDevIns, GCPhysCmd, &Cmd);
    47294765                    IOMMU_LOCK(pDevIns);
    4730                     if (RT_SUCCESS(rc))
    4731                     { /* likely */ }
    4732                     else
    4733                     {
    4734                         EVT_ILLEGAL_CMD_ERR_T EvtIllegalCmdErr;
    4735                         iommuAmdInitIllegalCmdEvent(GCPhysCmd, &EvtIllegalCmdErr);
    4736                         iommuAmdRaiseIllegalCmdEvent(pDevIns, &EvtIllegalCmdErr, enmEvtType);
     4766                    if (RT_FAILURE(rc))
    47374767                        break;
    4738                     }
    47394768                }
    47404769                else
    47414770                {
    4742                     /* Reporting this as a "data error". Maybe target abort is more appropriate? */
    47434771                    EVT_CMD_HW_ERR_T EvtCmdHwErr;
    4744                     iommuAmdInitCmdHwErrorEvent(GCPhysCmd, HWEVTTYPE_DATA_ERROR, &EvtCmdHwErr);
    4745                     iommuAmdRaiseCmdHwErrorEvent(pDevIns, &EvtCmdHwErr, kHwErrType_PoisonedData);
     4772                    iommuAmdInitCmdHwErrorEvent(GCPhysCmd, &EvtCmdHwErr);
     4773                    iommuAmdRaiseCmdHwErrorEvent(pDevIns, &EvtCmdHwErr);
    47464774                    break;
    47474775                }
    47484776            }
    4749 
    4750             IOMMU_UNLOCK(pDevIns);
    4751         }
    4752     }
     4777        }
     4778
     4779        IOMMU_UNLOCK(pDevIns);
     4780    }
     4781
     4782    LogFlow((IOMMU_LOG_PFX ": Command thread terminating\n"));
     4783    return VINF_SUCCESS;
    47534784}
    47544785
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette