/**
 * Initializes the tracing.
 *
 * @returns VBox status code
 * @param   pVM         The cross context VM structure.
 * @param   cbEntry     The trace entry size.
 * @param   cEntries    The number of entries.
 */
static int dbgfR3TraceEnable(PVM pVM, uint32_t cbEntry, uint32_t cEntries)
{
    /*
     * Don't enable it twice.
     */
    if (pVM->hTraceBufR3 != NIL_RTTRACEBUF)
        return VERR_ALREADY_EXISTS;

    /*
     * Resolve default parameter values.
     */
    int rc;
    if (!cbEntry)
    {
        rc = CFGMR3QueryU32Def(CFGMR3GetChild(CFGMR3GetRoot(pVM), "DBGF"), "TraceBufEntrySize", &cbEntry, 128);
        AssertRCReturn(rc, rc);
    }
    if (!cEntries)
    {
        rc = CFGMR3QueryU32Def(CFGMR3GetChild(CFGMR3GetRoot(pVM), "DBGF"), "TraceBufEntries", &cEntries, 4096);
        AssertRCReturn(rc, rc);
    }

    /*
     * Figure the required size.
     */
    RTTRACEBUF  hTraceBuf;
    size_t      cbBlock = 0;
    rc = RTTraceBufCarve(&hTraceBuf, cEntries, cbEntry, 0 /*fFlags*/, NULL, &cbBlock);
    if (rc != VERR_BUFFER_OVERFLOW)
    {
        AssertReturn(!RT_SUCCESS_NP(rc), VERR_IPE_UNEXPECTED_INFO_STATUS);
        return rc;
    }

    /*
     * Allocate a hyper heap block and carve a trace buffer out of it.
     *
     * Note! We ASSUME that the returned trace buffer handle has the same value
     *       as the heap block.
     */
    cbBlock = RT_ALIGN_Z(cbBlock, PAGE_SIZE);
    void *pvBlock;
    rc = MMR3HyperAllocOnceNoRel(pVM, cbBlock, PAGE_SIZE, MM_TAG_DBGF, &pvBlock);
    if (RT_FAILURE(rc))
        return rc;

    rc = RTTraceBufCarve(&hTraceBuf, cEntries, cbEntry, 0 /*fFlags*/, pvBlock, &cbBlock);
    AssertRCReturn(rc, rc);
    AssertRelease(hTraceBuf == (RTTRACEBUF)pvBlock);
    AssertRelease((void *)hTraceBuf == pvBlock);

    pVM->hTraceBufR3 = hTraceBuf;
    pVM->hTraceBufR0 = MMHyperCCToR0(pVM, hTraceBuf);
    pVM->hTraceBufRC = MMHyperCCToRC(pVM, hTraceBuf);
    return VINF_SUCCESS;
}
Exemple #2
0
/**
 * @interface_method_impl(PDMINVRAMCONNECTOR,pfnVarQueryByIndex)
 */
DECLCALLBACK(int) drvNvram_VarQueryByIndex(PPDMINVRAMCONNECTOR pInterface, uint32_t idxVariable,
                                           PRTUUID pVendorUuid, char *pszName, uint32_t *pcchName,
                                           uint32_t *pfAttributes, uint8_t *pbValue, uint32_t *pcbValue)
{
    PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);

    /*
     * Find the requested variable node.
     */
    PCFGMNODE pVarNode;
    if (pThis->idxLastVar + 1 == idxVariable && pThis->pLastVarNode)
        pVarNode = CFGMR3GetNextChild(pThis->pLastVarNode);
    else
    {
        pVarNode = CFGMR3GetFirstChild(pThis->pCfgVarRoot);
        for (uint32_t i = 0; i < idxVariable && pVarNode; i++)
            pVarNode = CFGMR3GetNextChild(pVarNode);
    }
    if (!pVarNode)
        return VERR_NOT_FOUND;

    /* cache it */
    pThis->pLastVarNode = pVarNode;
    pThis->idxLastVar   = idxVariable;

    /*
     * Read the variable node.
     */
    int rc = CFGMR3QueryString(pVarNode, "Name", pszName, *pcchName);
    AssertRCReturn(rc, rc);
    *pcchName = (uint32_t)strlen(pszName);

    char    szUuid[RTUUID_STR_LENGTH];
    rc = CFGMR3QueryString(pVarNode, "Uuid", szUuid, sizeof(szUuid));
    AssertRCReturn(rc, rc);
    rc = RTUuidFromStr(pVendorUuid, szUuid);
    AssertRCReturn(rc, rc);

    rc = CFGMR3QueryU32Def(pVarNode, "Attribs", pfAttributes, NVRAM_DEFAULT_ATTRIB);
    AssertRCReturn(rc, rc);

    size_t cbValue;
    rc = CFGMR3QuerySize(pVarNode, "Value", &cbValue);
    AssertRCReturn(rc, rc);
    AssertReturn(cbValue <= *pcbValue, VERR_BUFFER_OVERFLOW);
    rc = CFGMR3QueryBytes(pVarNode, "Value", pbValue, cbValue);
    AssertRCReturn(rc, rc);
    *pcbValue = (uint32_t)cbValue;

    return VINF_SUCCESS;
}
/** @interface_method_impl{PDMDEVREG,pfnConstruct} */
static DECLCALLBACK(int) ox958R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
{
    RT_NOREF(iInstance);
    PDEVOX958   pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
    bool        fRCEnabled = true;
    bool        fR0Enabled = true;
    bool        fMsiXSupported = false;
    int         rc;

    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);

    /*
     * Validate and read configuration.
     */
    if (!CFGMR3AreValuesValid(pCfg, "RCEnabled\0"
                                    "R0Enabled\0"
                                    "MsiXSupported\0"
                                    "UartCount\0"))
        return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
                                N_("OXPCIe958 configuration error: Unknown option specified"));

    rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &fRCEnabled, true);
    if (RT_FAILURE(rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("OXPCIe958 configuration error: Failed to read \"RCEnabled\" as boolean"));

    rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
    if (RT_FAILURE(rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("OXPCIe958 configuration error: failed to read \"R0Enabled\" as boolean"));

    rc = CFGMR3QueryBoolDef(pCfg, "MsiXSupported", &fMsiXSupported, true);
    if (RT_FAILURE(rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("OXPCIe958 configuration error: failed to read \"MsiXSupported\" as boolean"));

    rc = CFGMR3QueryU32Def(pCfg, "UartCount", &pThis->cUarts, OX958_UARTS_MAX);
    if (RT_FAILURE(rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("OXPCIe958 configuration error: failed to read \"UartCount\" as unsigned 32bit integer"));

    if (!pThis->cUarts || pThis->cUarts > OX958_UARTS_MAX)
        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                   N_("OXPCIe958 configuration error: \"UartCount\" has invalid value %u (must be in range [1 .. %u]"),
                                   pThis->cUarts, OX958_UARTS_MAX);

    /*
     * Init instance data.
     */
    pThis->fR0Enabled            = fR0Enabled;
    pThis->fRCEnabled            = fRCEnabled;
    pThis->pDevInsR3             = pDevIns;
    pThis->pDevInsR0             = PDMDEVINS_2_R0PTR(pDevIns);
    pThis->pDevInsRC             = PDMDEVINS_2_RCPTR(pDevIns);

    /* Fill PCI config space. */
    PDMPciDevSetVendorId         (&pThis->PciDev, OX958_PCI_VENDOR_ID);
    PDMPciDevSetDeviceId         (&pThis->PciDev, OX958_PCI_DEVICE_ID);
    PDMPciDevSetCommand          (&pThis->PciDev, 0x0000);
#ifdef VBOX_WITH_MSI_DEVICES
    PDMPciDevSetStatus           (&pThis->PciDev, VBOX_PCI_STATUS_CAP_LIST);
    PDMPciDevSetCapabilityList   (&pThis->PciDev, OX958_PCI_MSI_CAP_OFS);
#else
    PDMPciDevSetCapabilityList   (&pThis->PciDev, 0x70);
#endif
    PDMPciDevSetRevisionId       (&pThis->PciDev, 0x00);
    PDMPciDevSetClassBase        (&pThis->PciDev, 0x07); /* Communication controller. */
    PDMPciDevSetClassSub         (&pThis->PciDev, 0x00); /* Serial controller. */
    PDMPciDevSetClassProg        (&pThis->PciDev, 0x02); /* 16550. */

    PDMPciDevSetRevisionId       (&pThis->PciDev, 0x00);
    PDMPciDevSetSubSystemVendorId(&pThis->PciDev, OX958_PCI_VENDOR_ID);
    PDMPciDevSetSubSystemId      (&pThis->PciDev, OX958_PCI_DEVICE_ID);

    PDMPciDevSetInterruptLine       (&pThis->PciDev, 0x00);
    PDMPciDevSetInterruptPin        (&pThis->PciDev, 0x01);
    /** @todo More Capabilities. */

    rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Register PCI device and I/O region.
     */
    rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
    if (RT_FAILURE(rc))
        return rc;

#ifdef VBOX_WITH_MSI_DEVICES
    PDMMSIREG MsiReg;
    RT_ZERO(MsiReg);
    MsiReg.cMsiVectors     = 1;
    MsiReg.iMsiCapOffset   = OX958_PCI_MSI_CAP_OFS;
    MsiReg.iMsiNextOffset  = OX958_PCI_MSIX_CAP_OFS;
    MsiReg.fMsi64bit       = true;
    if (fMsiXSupported)
    {
        MsiReg.cMsixVectors    = VBOX_MSIX_MAX_ENTRIES;
        MsiReg.iMsixCapOffset  = OX958_PCI_MSIX_CAP_OFS;
        MsiReg.iMsixNextOffset = 0x00;
        MsiReg.iMsixBar        = OX958_PCI_MSIX_BAR;
    }
    rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
    if (RT_FAILURE(rc))
    {
        PCIDevSetCapabilityList(&pThis->PciDev, 0x0);
        /* That's OK, we can work without MSI */
    }
#endif

    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, _16K, PCI_ADDRESS_SPACE_MEM, ox958R3Map);
    if (RT_FAILURE(rc))
        return rc;

    PVM pVM = PDMDevHlpGetVM(pDevIns);
    RTR0PTR pfnSerialIrqReqR0 = NIL_RTR0PTR;
    RTRCPTR pfnSerialIrqReqRC = NIL_RTRCPTR;

    if (   fRCEnabled
        && VM_IS_RAW_MODE_ENABLED(pVM))
    {
        rc = PDMR3LdrGetSymbolRC(pVM, pDevIns->pReg->szRCMod, "ox958IrqReq", &pfnSerialIrqReqRC);
        if (RT_FAILURE(rc))
            return rc;
    }

    if (fR0Enabled)
    {
        rc = PDMR3LdrGetSymbolR0(pVM, pDevIns->pReg->szR0Mod, "ox958IrqReq", &pfnSerialIrqReqR0);
        if (RT_FAILURE(rc))
            return rc;
    }

    for (uint32_t i = 0; i < pThis->cUarts; i++)
    {
        POX958UART pUart = &pThis->aUarts[i];
        rc = uartR3Init(&pUart->UartCore, pDevIns, UARTTYPE_16550A, i, 0, ox958IrqReq, pfnSerialIrqReqR0, pfnSerialIrqReqRC);
        if (RT_FAILURE(rc))
            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                       N_("OXPCIe958 configuration error: failed to initialize UART %u"), i);
    }

    ox958R3Reset(pDevIns);
    return VINF_SUCCESS;
}
/**
 * Construct a disk integrity driver instance.
 *
 * @copydoc FNPDMDRVCONSTRUCT
 */
static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
    int rc = VINF_SUCCESS;
    PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
    LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);

    /*
     * Validate configuration.
     */
    if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
                                    "TraceRequests\0"
                                    "CheckIntervalMs\0"
                                    "ExpireIntervalMs\0"
                                    "CheckDoubleCompletions\0"
                                    "HistorySize\0"
                                    "IoLog\0"))
        return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;

    rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
    AssertRC(rc);
    rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
    AssertRC(rc);
    rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
    AssertRC(rc);
    rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
    AssertRC(rc);
    rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
    AssertRC(rc);
    rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
    AssertRC(rc);

    char *pszIoLogFilename = NULL;
    rc = CFGMR3QueryStringAlloc(pCfg, "IoLog", &pszIoLogFilename);
    Assert(RT_SUCCESS(rc) || rc == VERR_CFGM_VALUE_NOT_FOUND);

    /*
     * Initialize most of the data members.
     */
    pThis->pDrvIns                       = pDrvIns;

    /* IBase. */
    pDrvIns->IBase.pfnQueryInterface     = drvdiskintQueryInterface;

    /* IMedia */
    pThis->IMedia.pfnRead                = drvdiskintRead;
    pThis->IMedia.pfnWrite               = drvdiskintWrite;
    pThis->IMedia.pfnFlush               = drvdiskintFlush;
    pThis->IMedia.pfnGetSize             = drvdiskintGetSize;
    pThis->IMedia.pfnIsReadOnly          = drvdiskintIsReadOnly;
    pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
    pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
    pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
    pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
    pThis->IMedia.pfnGetUuid             = drvdiskintGetUuid;

    /* IMediaAsync */
    pThis->IMediaAsync.pfnStartRead      = drvdiskintStartRead;
    pThis->IMediaAsync.pfnStartWrite     = drvdiskintStartWrite;
    pThis->IMediaAsync.pfnStartFlush     = drvdiskintStartFlush;

    /* IMediaAsyncPort. */
    pThis->IMediaAsyncPort.pfnTransferCompleteNotify  = drvdiskintAsyncTransferCompleteNotify;

    /* IMediaPort. */
    pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;

    /* Query the media port interface above us. */
    pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
    if (!pThis->pDrvMediaPort)
        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
                                N_("No media port inrerface above"));

    /* Try to attach async media port interface above.*/
    pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);

    /*
     * Try attach driver below and query it's media interface.
     */
    PPDMIBASE pBase;
    rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
    if (RT_FAILURE(rc))
        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
                                   N_("Failed to attach driver below us! %Rrc"), rc);

    pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
    if (!pThis->pDrvMedia)
        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
                                N_("No media or async media interface below"));

    pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);

    if (pThis->pDrvMedia->pfnDiscard)
        pThis->IMedia.pfnDiscard = drvdiskintDiscard;
    if (   pThis->pDrvMediaAsync
        && pThis->pDrvMediaAsync->pfnStartDiscard)
        pThis->IMediaAsync.pfnStartDiscard = drvdiskintStartDiscard;

    if (pThis->fCheckConsistency)
    {
        /* Create the AVL tree. */
        pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
        if (!pThis->pTreeSegments)
            rc = VERR_NO_MEMORY;
    }

    if (pThis->fTraceRequests)
    {
        for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
        {
            pThis->apReqActive[i].pIoReq  = NULL;
            pThis->apReqActive[i].tsStart = 0;
        }

        pThis->iNextFreeSlot = 0;

        /* Init event semaphore. */
        rc = RTSemEventCreate(&pThis->SemEvent);
        AssertRC(rc);
        pThis->fRunning = true;
        rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
                            0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
        AssertRC(rc);
    }

    if (pThis->fCheckDoubleCompletion)
    {
        pThis->iEntry = 0;
        pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
        AssertPtr(pThis->papIoReq);
    }

    if (pszIoLogFilename)
    {
        rc = VDDbgIoLogCreate(&pThis->hIoLogger, pszIoLogFilename, VDDBG_IOLOG_LOG_DATA);
        MMR3HeapFree(pszIoLogFilename);
    }

    return rc;
}