예제 #1
0
/**
 * Implements the SUPDRV component factor interface query method.
 *
 * @returns Pointer to an interface. NULL if not supported.
 *
 * @param   pSupDrvFactory      Pointer to the component factory registration structure.
 * @param   pSession            The session - unused.
 * @param   pszInterfaceUuid    The factory interface id.
 */
static DECLCALLBACK(void *) vboxNetAdpQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
{
    PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));

    /*
     * Convert the UUID strings and compare them.
     */
    RTUUID UuidReq;
    int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
    if (RT_SUCCESS(rc))
    {
        if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
        {
            ASMAtomicIncS32(&pGlobals->cFactoryRefs);
            return &pGlobals->TrunkFactory;
        }
#ifdef LOG_ENABLED
        else
            Log(("VBoxNetAdp: unknown factory interface query (%s)\n", pszInterfaceUuid));
#endif
    }
    else
        Log(("VBoxNetAdp: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));

    return NULL;
}
예제 #2
0
/**
 * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue)
 */
DECLCALLBACK(int) drvNvram_pfnLoadNvramValue(PPDMINVRAM pInterface,
                                             int idxVariable,
                                             RTUUID *pVendorUuid,
                                             char *pcszVariableName,
                                             size_t *pcbVariableName,
                                             uint8_t *pu8Value,
                                             size_t *pcbValue)
{
    int rc = VINF_SUCCESS;
    char szExtraDataKey[256];
    Bstr bstrValue;
    HRESULT hrc;
    LogFlowFunc(("ENTER: idxVariable:%d, *pcbVariableName:%d, *pcbValue:%d\n",
                        idxVariable,
                        *pcbVariableName,
                        *pcbValue));
    PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram);
    if (!pThis->fPermanentSave)
    {
        rc = VERR_NOT_FOUND;
        LogFlowFuncLeaveRC(rc);
        return rc;
    }


    RT_ZERO(szExtraDataKey);
    RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableName", idxVariable);
    hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
    if (!SUCCEEDED(hrc))
        return VERR_NOT_FOUND;
    *pcbVariableName = RTStrCopy(pcszVariableName, 1024, Utf8Str(bstrValue).c_str());

    RT_ZERO(szExtraDataKey);
    RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VendorGuid", idxVariable);
    hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
    RTUuidFromStr(pVendorUuid, Utf8Str(bstrValue).c_str());

#if 0
    RT_ZERO(szExtraDataKey);
    RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValueLength", idxVariable);
    hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
    *pcbValue = Utf8Str(bstrValue).toUInt32();
#endif

    RT_ZERO(szExtraDataKey);
    RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValue", idxVariable);
    hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
    rc = RTBase64Decode(Utf8Str(bstrValue).c_str(), pu8Value, 1024, pcbValue, NULL);
    AssertRCReturn(rc, rc);

    pThis->cLoadedVariables++;
    LogFlowFuncLeaveRC(rc);
    return rc;
}
예제 #3
0
파일: uuid-win.cpp 프로젝트: bayasist/vbox
RTDECL(int)  RTUuidCompare2Strs(const char *pszString1, const char *pszString2)
{
    RTUUID Uuid1;
    RTUUID Uuid2;
    int rc;

    /* check params */
    AssertPtrReturn(pszString1, -1);
    AssertPtrReturn(pszString2, 1);

    /*
     * Try convert the strings to UUIDs and then compare them.
     */
    rc = RTUuidFromStr(&Uuid1, pszString1);
    AssertRCReturn(rc, -1);

    rc = RTUuidFromStr(&Uuid2, pszString2);
    AssertRCReturn(rc, 1);

    return RTUuidCompare(&Uuid1, &Uuid2);
}
예제 #4
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;
}
예제 #5
0
파일: uuid-win.cpp 프로젝트: bayasist/vbox
RTDECL(int)  RTUuidCompareStr(PCRTUUID pUuid1, const char *pszString2)
{
    /* check params */
    AssertPtrReturn(pUuid1, -1);
    AssertPtrReturn(pszString2, 1);

    /*
     * Try convert the string to a UUID and then compare the two.
     */
    RTUUID Uuid2;
    int rc = RTUuidFromStr(&Uuid2, pszString2);
    AssertRCReturn(rc, 1);

    return RTUuidCompare(pUuid1, &Uuid2);
}
예제 #6
0
/**
 * Implements the SUPDRV component factor interface query method.
 *
 * @returns Pointer to an interface. NULL if not supported.
 *
 * @param   pSupDrvFactory      Pointer to the component factory registration structure.
 * @param   pSession            The session - unused.
 * @param   pszInterfaceUuid    The factory interface id.
 */
static DECLCALLBACK(void *) vboxPciQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
{
    PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, SupDrvFactory));

    /*
     * Convert the UUID strings and compare them.
     */
    RTUUID UuidReq;
    int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
    if (RT_SUCCESS(rc))
    {
        if (!RTUuidCompareStr(&UuidReq, RAWPCIFACTORY_UUID_STR))
        {
            ASMAtomicIncS32(&pGlobals->cFactoryRefs);
            return &pGlobals->RawPciFactory;
        }
    }
    else
        Log(("VBoxRawPci: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));

    return NULL;
}
int main(int argc, char **argv)
{
    RTTEST hTest;
    int rc = RTTestInitAndCreate("tstRTUuid", &hTest);
    if (rc)
        return rc;
    RTTestBanner(hTest);


#define CHECK_RC() \
    do { if (RT_FAILURE(rc)) { RTTestFailed(hTest, "line %d: rc=%Rrc", __LINE__, rc); } } while (0)

    RTTestSub(hTest, "RTUuidClear & RTUuisIsNull");
    RTUUID UuidNull;
    rc = RTUuidClear(&UuidNull); CHECK_RC();

    RTTEST_CHECK(hTest, RTUuidIsNull(&UuidNull));
    RTTEST_CHECK(hTest, RTUuidCompare(&UuidNull, &UuidNull) == 0);

    RTTestSub(hTest, "RTUuidCreate");
    RTUUID Uuid;
    rc = RTUuidCreate(&Uuid); CHECK_RC();
    RTTEST_CHECK(hTest, !RTUuidIsNull(&Uuid));
    RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid) == 0);
    RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &UuidNull) > 0);
    RTTEST_CHECK(hTest, RTUuidCompare(&UuidNull, &Uuid) < 0);

    RTTestSub(hTest, "RTUuidToStr");
    char sz[RTUUID_STR_LENGTH];
    rc = RTUuidToStr(&Uuid, sz, sizeof(sz)); CHECK_RC();
    RTTEST_CHECK(hTest, strlen(sz) == RTUUID_STR_LENGTH - 1);
    RTTestPrintf(hTest, RTTESTLVL_INFO, "UUID=%s\n", sz);

    RTTestSub(hTest, "RTUuidFromStr");
    RTUUID Uuid2;
    rc = RTUuidFromStr(&Uuid2, sz); CHECK_RC();
    RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid2) == 0);

    char *psz = (char *)RTTestGuardedAllocTail(hTest, RTUUID_STR_LENGTH);
    if (psz)
    {
        RTStrPrintf(psz, RTUUID_STR_LENGTH, "%s", sz);
        RTTESTI_CHECK_RC(RTUuidFromStr(&Uuid2, psz), VINF_SUCCESS);
        RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid2) == 0);
        for (unsigned off = 1; off < RTUUID_STR_LENGTH; off++)
        {
            char *psz2 = psz + off;
            RTStrPrintf(psz2, RTUUID_STR_LENGTH - off, "%s", sz);
            RTTESTI_CHECK_RC(RTUuidFromStr(&Uuid2, psz2), VERR_INVALID_UUID_FORMAT);
        }
        RTTestGuardedFree(hTest, psz);
    }

    RTUuidClear(&Uuid2);
    char sz2[RTUUID_STR_LENGTH + 2];
    RTStrPrintf(sz2, sizeof(sz2), "{%s}", sz);
    rc = RTUuidFromStr(&Uuid2, sz2); CHECK_RC();
    RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid2) == 0);

    psz = (char *)RTTestGuardedAllocTail(hTest, RTUUID_STR_LENGTH + 2);
    if (psz)
    {
        RTStrPrintf(psz, RTUUID_STR_LENGTH + 2, "{%s}", sz);
        RTTESTI_CHECK_RC(RTUuidFromStr(&Uuid2, psz), VINF_SUCCESS);
        RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid2) == 0);
        for (unsigned off = 1; off < RTUUID_STR_LENGTH + 2; off++)
        {
            char *psz2 = psz + off;
            RTStrPrintf(psz2, RTUUID_STR_LENGTH + 2 - off, "{%s}", sz);
            RTTESTI_CHECK_RC(RTUuidFromStr(&Uuid2, psz2), VERR_INVALID_UUID_FORMAT);
        }
        RTTestGuardedFree(hTest, psz);
    }

    RTTestSub(hTest, "RTUuidToUtf16");
    RTUTF16 wsz[RTUUID_STR_LENGTH];
    rc = RTUuidToUtf16(&Uuid, wsz, sizeof(wsz)); CHECK_RC();
    RTTEST_CHECK(hTest, RTUtf16Len(wsz) == RTUUID_STR_LENGTH - 1);

    RTTestSub(hTest, "RTUuidFromUtf16");
    rc = RTUuidFromUtf16(&Uuid2, wsz); CHECK_RC();
    RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid2) == 0);

    RTUTF16 *pwsz;
    rc = RTStrToUtf16(sz2, &pwsz);
    RTTEST_CHECK(hTest, rc == VINF_SUCCESS);
    if (RT_SUCCESS(rc))
    {
        RTTESTI_CHECK_RC(RTUuidFromUtf16(&Uuid2, pwsz), VINF_SUCCESS);
        RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid2) == 0);
        RTUTF16 *pwsz2 = (RTUTF16*)RTTestGuardedAllocTail(hTest, 2 * (RTUUID_STR_LENGTH + 2));
        if (pwsz2)
        {
            memcpy(pwsz2, pwsz, 2 * (RTUUID_STR_LENGTH + 2));
            RTTESTI_CHECK_RC(RTUuidFromUtf16(&Uuid2, pwsz2), VINF_SUCCESS);
            RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid2) == 0);
            for (unsigned off = 1; off < RTUUID_STR_LENGTH + 2; off++)
            {
                RTUTF16 *pwsz3 = pwsz2 + off;
                memcpy(pwsz3, pwsz, 2 * (RTUUID_STR_LENGTH + 1 - off));
                pwsz3[RTUUID_STR_LENGTH + 1 - off] = 0;
                RTTESTI_CHECK_RC(RTUuidFromUtf16(&Uuid2, pwsz3), VERR_INVALID_UUID_FORMAT);
            }
            RTTestGuardedFree(hTest, pwsz2);
        }
        RTUtf16Free(pwsz);
    }

    RTTestSub(hTest, "RTUuidCompareStr");
    RTTEST_CHECK(hTest, RTUuidCompareStr(&Uuid, sz) == 0);
    RTTEST_CHECK(hTest, RTUuidCompareStr(&Uuid, "00000000-0000-0000-0000-000000000000") > 0);
    RTTEST_CHECK(hTest, RTUuidCompareStr(&UuidNull, "00000000-0000-0000-0000-000000000000") == 0);

    RTTestSub(hTest, "RTUuidCompare2Strs");
    RTTEST_CHECK(hTest, RTUuidCompare2Strs(sz, sz) == 0);
    RTTEST_CHECK(hTest, RTUuidCompare2Strs(sz, "00000000-0000-0000-0000-000000000000") > 0);
    RTTEST_CHECK(hTest, RTUuidCompare2Strs("00000000-0000-0000-0000-000000000000", sz) < 0);
    RTTEST_CHECK(hTest, RTUuidCompare2Strs("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000") == 0);
    RTTEST_CHECK(hTest, RTUuidCompare2Strs("d95d883b-f91d-4ce5-a5c5-d08bb6a85dec", "a56193c7-3e0b-4c03-9d66-56efb45082f7") > 0);
    RTTEST_CHECK(hTest, RTUuidCompare2Strs("a56193c7-3e0b-4c03-9d66-56efb45082f7", "d95d883b-f91d-4ce5-a5c5-d08bb6a85dec") < 0);

    /*
     * Check the binary representation.
     */
    RTTestSub(hTest, "Binary representation");
    RTUUID Uuid3;
    Uuid3.au8[0]  = 0x01;
    Uuid3.au8[1]  = 0x23;
    Uuid3.au8[2]  = 0x45;
    Uuid3.au8[3]  = 0x67;
    Uuid3.au8[4]  = 0x89;
    Uuid3.au8[5]  = 0xab;
    Uuid3.au8[6]  = 0xcd;
    Uuid3.au8[7]  = 0x4f;
    Uuid3.au8[8]  = 0x10;
    Uuid3.au8[9]  = 0xb2;
    Uuid3.au8[10] = 0x54;
    Uuid3.au8[11] = 0x76;
    Uuid3.au8[12] = 0x98;
    Uuid3.au8[13] = 0xba;
    Uuid3.au8[14] = 0xdc;
    Uuid3.au8[15] = 0xfe;
    Uuid3.Gen.u8ClockSeqHiAndReserved = (Uuid3.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
    Uuid3.Gen.u16TimeHiAndVersion = (Uuid3.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
    const char *pszUuid3 = "67452301-ab89-4fcd-90b2-547698badcfe";
    rc = RTUuidToStr(&Uuid3, sz, sizeof(sz)); CHECK_RC();
    RTTEST_CHECK(hTest, strcmp(sz, pszUuid3) == 0);
    rc = RTUuidFromStr(&Uuid, pszUuid3); CHECK_RC();
    RTTEST_CHECK(hTest, RTUuidCompare(&Uuid, &Uuid3) == 0);
    RTTEST_CHECK(hTest, memcmp(&Uuid3, &Uuid, sizeof(Uuid)) == 0);

    /*
     * checking the clock seq and time hi and version bits...
     */
    RTTestSub(hTest, "Clock seq, time hi, version bits");
    RTUUID Uuid4Changes;
    Uuid4Changes.au64[0] = 0;
    Uuid4Changes.au64[1] = 0;

    RTUUID Uuid4Prev;
    RTUuidCreate(&Uuid4Prev);

    for (unsigned i = 0; i < 1024; i++)
    {
        RTUUID Uuid4;
        RTUuidCreate(&Uuid4);

        Uuid4Changes.au64[0] |= Uuid4.au64[0] ^ Uuid4Prev.au64[0];
        Uuid4Changes.au64[1] |= Uuid4.au64[1] ^ Uuid4Prev.au64[1];

#if 0   /** @todo make a bit string/dumper similar to %Rhxs/d. */
        RTPrintf("tstUuid: %d %d %d %d-%d %d %d %d  %d %d %d %d-%d %d %d %d ; %d %d %d %d-%d %d %d %d  %d %d %d %d-%d %d %d %d\n",
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(0)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(1)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(2)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(3)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(4)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(5)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(6)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(7)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(8)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(9)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(10)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(11)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(12)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(13)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(14)),
                 !!(Uuid4.Gen.u16ClockSeq & RT_BIT(15)),

                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(0)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(1)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(2)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(3)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(4)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(5)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(6)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(7)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(8)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(9)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(10)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(11)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(12)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(13)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(14)),
                 !!(Uuid4.Gen.u16TimeHiAndVersion & RT_BIT(15))
                 );
#endif
        Uuid4Prev = Uuid4;
    }

    RTUUID Uuid4Fixed;
    Uuid4Fixed.au64[0] = ~Uuid4Changes.au64[0];
    Uuid4Fixed.au64[1] = ~Uuid4Changes.au64[1];
    RTTestPrintf(hTest, RTTESTLVL_INFO, "fixed bits: %RTuuid (mask)\n", &Uuid4Fixed);
    RTTestPrintf(hTest, RTTESTLVL_INFO, "tstUuid:        raw: %.*Rhxs\n", sizeof(Uuid4Fixed), &Uuid4Fixed);

    Uuid4Prev.au64[0] &= Uuid4Fixed.au64[0];
    Uuid4Prev.au64[1] &= Uuid4Fixed.au64[1];
    RTTestPrintf(hTest, RTTESTLVL_INFO, "tstUuid: fixed bits: %RTuuid (value)\n", &Uuid4Prev);
    RTTestPrintf(hTest, RTTESTLVL_INFO, "tstUuid:        raw: %.*Rhxs\n", sizeof(Uuid4Prev), &Uuid4Prev);

    /*
     * Summary.
     */
    return RTTestSummaryAndDestroy(hTest);
}
예제 #8
0
파일: getopt.cpp 프로젝트: miguelinux/vbox
/**
 * Value string -> Value union.
 *
 * @returns IPRT status code.
 * @param   fFlags              The value flags.
 * @param   pszValue            The value string.
 * @param   pValueUnion         Where to return the processed value.
 */
static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion)
{
    /*
     * Transform into a option value as requested.
     * If decimal conversion fails, we'll check for "0x<xdigit>" and
     * try a 16 based conversion. We will not interpret any of the
     * generic ints as octals.
     */
    switch (fFlags & (  RTGETOPT_REQ_MASK
                      | RTGETOPT_FLAG_HEX
                      | RTGETOPT_FLAG_DEC
                      | RTGETOPT_FLAG_OCT))
    {
        case RTGETOPT_REQ_STRING:
            pValueUnion->psz = pszValue;
            break;

        case RTGETOPT_REQ_BOOL:
            if (   !RTStrICmp(pszValue, "true")
                || !RTStrICmp(pszValue, "t")
                || !RTStrICmp(pszValue, "yes")
                || !RTStrICmp(pszValue, "y")
                || !RTStrICmp(pszValue, "enabled")
                || !RTStrICmp(pszValue, "enable")
                || !RTStrICmp(pszValue, "en")
                || !RTStrICmp(pszValue, "e")
                || !RTStrICmp(pszValue, "on")
                || !RTStrCmp(pszValue, "1")
                )
                pValueUnion->f = true;
            else if (   !RTStrICmp(pszValue, "false")
                     || !RTStrICmp(pszValue, "f")
                     || !RTStrICmp(pszValue, "no")
                     || !RTStrICmp(pszValue, "n")
                     || !RTStrICmp(pszValue, "disabled")
                     || !RTStrICmp(pszValue, "disable")
                     || !RTStrICmp(pszValue, "dis")
                     || !RTStrICmp(pszValue, "d")
                     || !RTStrICmp(pszValue, "off")
                     || !RTStrCmp(pszValue, "0")
                     )
                pValueUnion->f = false;
            else
            {
                pValueUnion->psz = pszValue;
                return VERR_GETOPT_UNKNOWN_OPTION;
            }
            break;

        case RTGETOPT_REQ_BOOL_ONOFF:
            if (!RTStrICmp(pszValue, "on"))
                pValueUnion->f = true;
            else if (!RTStrICmp(pszValue, "off"))
                pValueUnion->f = false;
            else
            {
                pValueUnion->psz = pszValue;
                return VERR_GETOPT_UNKNOWN_OPTION;
            }
            break;

#define MY_INT_CASE(req, type, memb, convfn) \
            case req: \
            { \
                type Value; \
                if (    convfn(pszValue, 10, &Value) != VINF_SUCCESS \
                    &&  (   pszValue[0] != '0' \
                         || (pszValue[1] != 'x' && pszValue[1] != 'X') \
                         || !RT_C_IS_XDIGIT(pszValue[2]) \
                         || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \
                    return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
                pValueUnion->memb = Value; \
                break; \
            }
#define MY_BASE_INT_CASE(req, type, memb, convfn, base) \
            case req: \
            { \
                type Value; \
                if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \
                    return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
                pValueUnion->memb = Value; \
                break; \
            }

        MY_INT_CASE(RTGETOPT_REQ_INT8,   int8_t,   i8,  RTStrToInt8Full)
        MY_INT_CASE(RTGETOPT_REQ_INT16,  int16_t,  i16, RTStrToInt16Full)
        MY_INT_CASE(RTGETOPT_REQ_INT32,  int32_t,  i32, RTStrToInt32Full)
        MY_INT_CASE(RTGETOPT_REQ_INT64,  int64_t,  i64, RTStrToInt64Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT8,  uint8_t,  u8,  RTStrToUInt8Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_HEX, int8_t,   i8,  RTStrToInt8Full,   16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_HEX, int16_t,  i16, RTStrToInt16Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_HEX, int32_t,  i32, RTStrToInt32Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_HEX, int64_t,  i64, RTStrToInt64Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_HEX, uint8_t,  u8,  RTStrToUInt8Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_DEC, int8_t,   i8,  RTStrToInt8Full,   10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_DEC, int16_t,  i16, RTStrToInt16Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_DEC, int32_t,  i32, RTStrToInt32Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_DEC, int64_t,  i64, RTStrToInt64Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_DEC, uint8_t,  u8,  RTStrToUInt8Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_OCT, int8_t,   i8,  RTStrToInt8Full,   8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_OCT, int16_t,  i16, RTStrToInt16Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_OCT, int32_t,  i32, RTStrToInt32Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_OCT, int64_t,  i64, RTStrToInt64Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_OCT, uint8_t,  u8,  RTStrToUInt8Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8)

#undef MY_INT_CASE
#undef MY_BASE_INT_CASE

        case RTGETOPT_REQ_IPV4ADDR:
        {
            RTNETADDRIPV4 Addr;
            if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->IPv4Addr = Addr;
            break;
        }

        case RTGETOPT_REQ_IPV4CIDR:
        {
            RTNETADDRIPV4 network;
            RTNETADDRIPV4 netmask;
            if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask)))
              return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->CidrIPv4.IPv4Network.u = network.u;
            pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u;
            break;
        }

        case RTGETOPT_REQ_MACADDR:
        {
            RTMAC Addr;
            if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->MacAddr = Addr;
            break;
        }

        case RTGETOPT_REQ_UUID:
        {
            RTUUID Uuid;
            if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->Uuid = Uuid;
            break;
        }

        default:
            AssertMsgFailed(("f=%#x\n", fFlags));
            return VERR_INTERNAL_ERROR;
    }

    return VINF_SUCCESS;
}
/**
 * Value string -> Value union.
 *
 * @returns IPRT status code.
 * @param   fFlags              The value flags.
 * @param   pszValue            The value string.
 * @param   pValueUnion         Where to return the processed value.
 */
static int rtGetOptProcessValue(uint32_t fFlags, const char *pszValue, PRTGETOPTUNION pValueUnion)
{
    /*
     * Transform into a option value as requested.
     * If decimal conversion fails, we'll check for "0x<xdigit>" and
     * try a 16 based conversion. We will not interpret any of the
     * generic ints as octals.
     */
    uint32_t const fSwitchValue =  fFlags & (  RTGETOPT_REQ_MASK
                                             | RTGETOPT_FLAG_HEX
                                             | RTGETOPT_FLAG_DEC
                                             | RTGETOPT_FLAG_OCT);
    switch (fSwitchValue)
    {
        case RTGETOPT_REQ_STRING:
            pValueUnion->psz = pszValue;
            break;

        case RTGETOPT_REQ_BOOL:
            if (   !RTStrICmp(pszValue, "true")
                || !RTStrICmp(pszValue, "t")
                || !RTStrICmp(pszValue, "yes")
                || !RTStrICmp(pszValue, "y")
                || !RTStrICmp(pszValue, "enabled")
                || !RTStrICmp(pszValue, "enable")
                || !RTStrICmp(pszValue, "en")
                || !RTStrICmp(pszValue, "e")
                || !RTStrICmp(pszValue, "on")
                || !RTStrCmp(pszValue, "1")
                )
                pValueUnion->f = true;
            else if (   !RTStrICmp(pszValue, "false")
                     || !RTStrICmp(pszValue, "f")
                     || !RTStrICmp(pszValue, "no")
                     || !RTStrICmp(pszValue, "n")
                     || !RTStrICmp(pszValue, "disabled")
                     || !RTStrICmp(pszValue, "disable")
                     || !RTStrICmp(pszValue, "dis")
                     || !RTStrICmp(pszValue, "d")
                     || !RTStrICmp(pszValue, "off")
                     || !RTStrCmp(pszValue, "0")
                     )
                pValueUnion->f = false;
            else
            {
                pValueUnion->psz = pszValue;
                return VERR_GETOPT_UNKNOWN_OPTION;
            }
            break;

        case RTGETOPT_REQ_BOOL_ONOFF:
            if (!RTStrICmp(pszValue, "on"))
                pValueUnion->f = true;
            else if (!RTStrICmp(pszValue, "off"))
                pValueUnion->f = false;
            else
            {
                pValueUnion->psz = pszValue;
                return VERR_GETOPT_UNKNOWN_OPTION;
            }
            break;

#define MY_INT_CASE(req, type, memb, convfn) \
            case req: \
            { \
                type Value; \
                if (    convfn(pszValue, 10, &Value) != VINF_SUCCESS \
                    &&  (   pszValue[0] != '0' \
                         || (pszValue[1] != 'x' && pszValue[1] != 'X') \
                         || !RT_C_IS_XDIGIT(pszValue[2]) \
                         || convfn(pszValue, 16, &Value) != VINF_SUCCESS ) ) \
                    return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
                pValueUnion->memb = Value; \
                break; \
            }
#define MY_BASE_INT_CASE(req, type, memb, convfn, base) \
            case req: \
            { \
                type Value; \
                if (convfn(pszValue, base, &Value) != VINF_SUCCESS) \
                    return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
                pValueUnion->memb = Value; \
                break; \
            }

        MY_INT_CASE(RTGETOPT_REQ_INT8,   int8_t,   i8,  RTStrToInt8Full)
        MY_INT_CASE(RTGETOPT_REQ_INT16,  int16_t,  i16, RTStrToInt16Full)
        MY_INT_CASE(RTGETOPT_REQ_INT32,  int32_t,  i32, RTStrToInt32Full)
        MY_INT_CASE(RTGETOPT_REQ_INT64,  int64_t,  i64, RTStrToInt64Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT8,  uint8_t,  u8,  RTStrToUInt8Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT16, uint16_t, u16, RTStrToUInt16Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT32, uint32_t, u32, RTStrToUInt32Full)
        MY_INT_CASE(RTGETOPT_REQ_UINT64, uint64_t, u64, RTStrToUInt64Full)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_HEX, int8_t,   i8,  RTStrToInt8Full,   16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_HEX, int16_t,  i16, RTStrToInt16Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_HEX, int32_t,  i32, RTStrToInt32Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_HEX, int64_t,  i64, RTStrToInt64Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_HEX, uint8_t,  u8,  RTStrToUInt8Full,  16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_HEX, uint16_t, u16, RTStrToUInt16Full, 16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX, uint32_t, u32, RTStrToUInt32Full, 16)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX, uint64_t, u64, RTStrToUInt64Full, 16)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_DEC, int8_t,   i8,  RTStrToInt8Full,   10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_DEC, int16_t,  i16, RTStrToInt16Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_DEC, int32_t,  i32, RTStrToInt32Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_DEC, int64_t,  i64, RTStrToInt64Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_DEC, uint8_t,  u8,  RTStrToUInt8Full,  10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_DEC, uint16_t, u16, RTStrToUInt16Full, 10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_DEC, uint32_t, u32, RTStrToUInt32Full, 10)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_DEC, uint64_t, u64, RTStrToUInt64Full, 10)

        MY_BASE_INT_CASE(RTGETOPT_REQ_INT8   | RTGETOPT_FLAG_OCT, int8_t,   i8,  RTStrToInt8Full,   8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT16  | RTGETOPT_FLAG_OCT, int16_t,  i16, RTStrToInt16Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT32  | RTGETOPT_FLAG_OCT, int32_t,  i32, RTStrToInt32Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_INT64  | RTGETOPT_FLAG_OCT, int64_t,  i64, RTStrToInt64Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT8  | RTGETOPT_FLAG_OCT, uint8_t,  u8,  RTStrToUInt8Full,  8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT16 | RTGETOPT_FLAG_OCT, uint16_t, u16, RTStrToUInt16Full, 8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_OCT, uint32_t, u32, RTStrToUInt32Full, 8)
        MY_BASE_INT_CASE(RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_OCT, uint64_t, u64, RTStrToUInt64Full, 8)

#undef MY_INT_CASE
#undef MY_BASE_INT_CASE

        case RTGETOPT_REQ_IPV4ADDR:
        {
            RTNETADDRIPV4 Addr;
            if (rtgetoptConvertIPv4Addr(pszValue, &Addr) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->IPv4Addr = Addr;
            break;
        }

        case RTGETOPT_REQ_IPV4CIDR:
        {
            RTNETADDRIPV4 network;
            RTNETADDRIPV4 netmask;
            if (RT_FAILURE(RTCidrStrToIPv4(pszValue, &network, &netmask)))
              return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->CidrIPv4.IPv4Network.u = network.u;
            pValueUnion->CidrIPv4.IPv4Netmask.u = netmask.u;
            break;
        }

        case RTGETOPT_REQ_MACADDR:
        {
            RTMAC Addr;
            if (rtgetoptConvertMacAddr(pszValue, &Addr) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->MacAddr = Addr;
            break;
        }

        case RTGETOPT_REQ_UUID:
        {
            RTUUID Uuid;
            if (RTUuidFromStr(&Uuid, pszValue) != VINF_SUCCESS)
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT;
            pValueUnion->Uuid = Uuid;
            break;
        }

#define MY_INT_PAIR_CASE(a_fReqValue, a_fReqValueOptional, a_Type, a_MemberPrefix, a_fnConv, a_ConvBase, a_DefaultValue) \
            case a_fReqValue: \
            case a_fReqValueOptional: \
            { \
                /* First value: */ \
                a_Type Value1; \
                char *pszNext = NULL; \
                unsigned uBase =   pszValue[0] == '0' \
                                && (pszValue[1] == 'x' || pszValue[1] == 'X') \
                                && RT_C_IS_XDIGIT(pszValue[2]) \
                              ? 16 : a_ConvBase; \
                int rc = a_fnConv(pszValue, &pszNext, uBase, &Value1); \
                if (rc == VINF_SUCCESS || rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES) \
                { \
                    /* The second value, could be optional: */ \
                    a_Type Value2 = a_DefaultValue; \
                    pszValue = pszNext;\
                    if (pszValue) \
                    { \
                        while (RT_C_IS_BLANK(*pszValue)) \
                            pszValue++; \
                        if (*pszValue == ':' || *pszValue == '/' || *pszValue == '|') \
                            do pszValue++; \
                            while (RT_C_IS_BLANK(*pszValue)); \
                        if (pszValue != pszNext) \
                        { \
                            uBase =    pszValue[0] == '0' \
                                    && (pszValue[1] == 'x' || pszValue[1] == 'X') \
                                    && RT_C_IS_XDIGIT(pszValue[2]) \
                                  ? 16 : a_ConvBase; \
                            rc = a_fnConv(pszValue, &pszNext, uBase, &Value2); \
                            if (rc == VINF_SUCCESS) \
                            { /* likely */ } \
                            else \
                               { RTAssertMsg2("z rc=%Rrc: '%s' '%s' uBase=%d\n", rc, pszValue, pszNext, uBase); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \
                        } \
                        else if (fSwitchValue != (a_fReqValueOptional)) \
                        { RTAssertMsg2("x\n"); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \
                    } \
                    else if (fSwitchValue != (a_fReqValueOptional)) \
                        { RTAssertMsg2("y\n"); return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; } \
                    pValueUnion->a_MemberPrefix##Second = Value2; \
                    pValueUnion->a_MemberPrefix##First  = Value1; \
                    break; \
                } \
                return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; \
            }

        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR,                      RTGETOPT_REQ_UINT32_OPTIONAL_PAIR,
                         uint32_t, PairU32.u, RTStrToUInt32Ex, 10, UINT32_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_DEC,  RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_DEC,
                         uint32_t, PairU32.u, RTStrToUInt32Ex, 10, UINT32_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_HEX,  RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX,
                         uint32_t, PairU32.u, RTStrToUInt32Ex, 16, UINT32_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT32_PAIR | RTGETOPT_FLAG_OCT,  RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_OCT,
                         uint32_t, PairU32.u, RTStrToUInt32Ex,  8, UINT32_MAX)

        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR,                      RTGETOPT_REQ_UINT64_OPTIONAL_PAIR,
                         uint64_t, PairU64.u, RTStrToUInt64Ex, 10, UINT64_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_DEC,  RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_DEC,
                         uint64_t, PairU64.u, RTStrToUInt64Ex, 10, UINT64_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_HEX,  RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX,
                         uint64_t, PairU64.u, RTStrToUInt64Ex, 16, UINT64_MAX)
        MY_INT_PAIR_CASE(RTGETOPT_REQ_UINT64_PAIR | RTGETOPT_FLAG_OCT,  RTGETOPT_REQ_UINT64_OPTIONAL_PAIR | RTGETOPT_FLAG_OCT,
                         uint64_t, PairU64.u, RTStrToUInt64Ex,  8, UINT64_MAX)

        default:
            AssertMsgFailed(("f=%#x\n", fFlags));
            return VERR_INTERNAL_ERROR;
    }

    return VINF_SUCCESS;
}
예제 #10
0
/**
 * Construct the DMI table.
 *
 * @returns VBox status code.
 * @param   pDevIns             The device instance.
 * @param   pTable              Where to create the DMI table.
 * @param   cbMax               The maximum size of the DMI table.
 * @param   pUuid               Pointer to the UUID to use if the DmiUuid
 *                              configuration string isn't present.
 * @param   pCfg                The handle to our config node.
 * @param   cCpus               Number of VCPUs.
 * @param   pcbDmiTables        Size of DMI data in bytes.
 * @param   pcNumDmiTables      Number of DMI tables.
 */
int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PCRTUUID pUuid, PCFGMNODE pCfg, uint16_t cCpus, uint16_t *pcbDmiTables, uint16_t *pcNumDmiTables)
{
#define CHECKSIZE(cbWant) \
    { \
        size_t cbNeed = (size_t)(pszStr + cbWant - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \
        if (cbNeed > cbMax) \
        { \
            if (fHideErrors) \
            { \
                LogRel(("One of the DMI strings is too long -- using default DMI data!\n")); \
                continue; \
            } \
            return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \
                                       N_("One of the DMI strings is too long. Check all bios/Dmi* configuration entries. At least %zu bytes are needed but there is no space for more than %d bytes"), cbNeed, cbMax); \
        } \
    }

#define READCFGSTRDEF(variable, name, default_value) \
    { \
        if (fForceDefault) \
            pszTmp = default_value; \
        else \
        { \
            rc = CFGMR3QueryStringDef(pCfg, name, szBuf, sizeof(szBuf), default_value); \
            if (RT_FAILURE(rc)) \
            { \
                if (fHideErrors) \
                { \
                    LogRel(("Configuration error: Querying \"" name "\" as a string failed -- using default DMI data!\n")); \
                    continue; \
                } \
                return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
                                           N_("Configuration error: Querying \"" name "\" as a string failed")); \
            } \
            else if (!strcmp(szBuf, "<EMPTY>")) \
                pszTmp = ""; \
            else \
                pszTmp = szBuf; \
        } \
        if (!pszTmp[0]) \
            variable = 0; /* empty string */ \
        else \
        { \
            variable = iStrNr++; \
            size_t cStr = strlen(pszTmp) + 1; \
            CHECKSIZE(cStr); \
            memcpy(pszStr, pszTmp, cStr); \
            pszStr += cStr ; \
        } \
    }

#define READCFGSTR(variable, name) \
    READCFGSTRDEF(variable, # name, s_szDef ## name)

#define READCFGINT(variable, name) \
    { \
        if (fForceDefault) \
            variable = s_iDef ## name; \
        else \
        { \
            rc = CFGMR3QueryS32Def(pCfg, # name, & variable, s_iDef ## name); \
            if (RT_FAILURE(rc)) \
            { \
                if (fHideErrors) \
                { \
                    LogRel(("Configuration error: Querying \"" # name "\" as an int failed -- using default DMI data!\n")); \
                    continue; \
                } \
                return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
                                           N_("Configuration error: Querying \"" # name "\" as an int failed")); \
            } \
        } \
    }

#define START_STRUCT(tbl)                                       \
        pszStr                       = (char *)(tbl + 1);       \
        iStrNr                       = 1;

#define TERM_STRUCT \
    { \
        *pszStr++                    = '\0'; /* terminate set of text strings */ \
        if (iStrNr == 1) \
            *pszStr++                = '\0'; /* terminate a structure without strings */ \
    }

    bool fForceDefault = false;
#ifdef VBOX_BIOS_DMI_FALLBACK
    /*
     * There will be two passes. If an error occurs during the first pass, a
     * message will be written to the release log and we fall back to default
     * DMI data and start a second pass.
     */
    bool fHideErrors = true;
#else
    /*
     * There will be one pass, every error is fatal and will prevent the VM
     * from starting.
     */
    bool fHideErrors = false;
#endif

    uint8_t fDmiUseHostInfo;
    int rc = CFGMR3QueryU8Def(pCfg, "DmiUseHostInfo", &fDmiUseHostInfo, 0);
    if (RT_FAILURE (rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("Configuration error: Failed to read \"DmiUseHostInfo\""));

    /* Sync up with host default DMI values */
    if (fDmiUseHostInfo)
        fwCommonUseHostDMIStrings();

    uint8_t fDmiExposeMemoryTable;
    rc = CFGMR3QueryU8Def(pCfg, "DmiExposeMemoryTable", &fDmiExposeMemoryTable, 0);
    if (RT_FAILURE (rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("Configuration error: Failed to read \"DmiExposeMemoryTable\""));
    uint8_t fDmiExposeProcessorInf;
    rc = CFGMR3QueryU8Def(pCfg, "DmiExposeProcInf", &fDmiExposeProcessorInf, 0);
    if (RT_FAILURE (rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("Configuration error: Failed to read \"DmiExposeProcInf\""));

    for  (;; fForceDefault = true, fHideErrors = false)
    {
        int  iStrNr;
        char szBuf[256];
        char *pszStr = (char *)pTable;
        char szDmiSystemUuid[64];
        char *pszDmiSystemUuid;
        const char *pszTmp;

        if (fForceDefault)
            pszDmiSystemUuid = NULL;
        else
        {
            rc = CFGMR3QueryString(pCfg, "DmiSystemUuid", szDmiSystemUuid, sizeof(szDmiSystemUuid));
            if (rc == VERR_CFGM_VALUE_NOT_FOUND)
                pszDmiSystemUuid = NULL;
            else if (RT_FAILURE(rc))
            {
                if (fHideErrors)
                {
                    LogRel(("Configuration error: Querying \"DmiSystemUuid\" as a string failed, using default DMI data\n"));
                    continue;
                }
                return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                           N_("Configuration error: Querying \"DmiSystemUuid\" as a string failed"));
            }
            else
                pszDmiSystemUuid = szDmiSystemUuid;
        }

        /*********************************
         * DMI BIOS information (Type 0) *
         *********************************/
        PDMIBIOSINF pBIOSInf         = (PDMIBIOSINF)pszStr;
        CHECKSIZE(sizeof(*pBIOSInf));

        pszStr                       = (char *)&pBIOSInf->u8ReleaseMajor;
        pBIOSInf->header.u8Length    = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);

        /* don't set these fields by default for legacy compatibility */
        int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor;
        READCFGINT(iDmiBIOSReleaseMajor, DmiBIOSReleaseMajor);
        READCFGINT(iDmiBIOSReleaseMinor, DmiBIOSReleaseMinor);
        if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
        {
            pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
            pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
            pBIOSInf->u8ReleaseMajor  = iDmiBIOSReleaseMajor;
            pBIOSInf->u8ReleaseMinor  = iDmiBIOSReleaseMinor;

            int iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor;
            READCFGINT(iDmiBIOSFirmwareMajor, DmiBIOSFirmwareMajor);
            READCFGINT(iDmiBIOSFirmwareMinor, DmiBIOSFirmwareMinor);
            if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
            {
                pszStr = (char *)(pBIOSInf + 1);
                pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
                pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
                pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
            }
        }

        iStrNr                       = 1;
        pBIOSInf->header.u8Type      = 0; /* BIOS Information */
        pBIOSInf->header.u16Handle   = 0x0000;
        READCFGSTR(pBIOSInf->u8Vendor,  DmiBIOSVendor);
        READCFGSTR(pBIOSInf->u8Version, DmiBIOSVersion);
        pBIOSInf->u16Start           = 0xE000;
        READCFGSTR(pBIOSInf->u8Release, DmiBIOSReleaseDate);
        pBIOSInf->u8ROMSize          = 1; /* 128K */
        pBIOSInf->u64Characteristics = RT_BIT(4)   /* ISA is supported */
                                     | RT_BIT(7)   /* PCI is supported */
                                     | RT_BIT(15)  /* Boot from CD is supported */
                                     | RT_BIT(16)  /* Selectable Boot is supported */
                                     | RT_BIT(27)  /* Int 9h, 8042 Keyboard services supported */
                                     | RT_BIT(30)  /* Int 10h, CGA/Mono Video Services supported */
                                     /* any more?? */
                                     ;
        pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0)   /* ACPI is supported */
                                         /* any more?? */
                                         ;
        pBIOSInf->u8CharacteristicsByte2 = 0
                                         /* any more?? */
                                         ;
        TERM_STRUCT;

        /***********************************
         * DMI system information (Type 1) *
         ***********************************/
        PDMISYSTEMINF pSystemInf     = (PDMISYSTEMINF)pszStr;
        CHECKSIZE(sizeof(*pSystemInf));
        START_STRUCT(pSystemInf);
        pSystemInf->header.u8Type    = 1; /* System Information */
        pSystemInf->header.u8Length  = sizeof(*pSystemInf);
        pSystemInf->header.u16Handle = 0x0001;
        READCFGSTR(pSystemInf->u8Manufacturer, DmiSystemVendor);
        READCFGSTR(pSystemInf->u8ProductName,  DmiSystemProduct);
        READCFGSTR(pSystemInf->u8Version,      DmiSystemVersion);
        READCFGSTR(pSystemInf->u8SerialNumber, DmiSystemSerial);

        RTUUID uuid;
        if (pszDmiSystemUuid)
        {
            rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
            if (RT_FAILURE(rc))
            {
                if (fHideErrors)
                {
                    LogRel(("Configuration error: Invalid UUID for DMI tables specified, using default DMI data\n"));
                    continue;
                }
                return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                           N_("Configuration error: Invalid UUID for DMI tables specified"));
            }
            uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
            uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
            uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
            pUuid = &uuid;
        }
        memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));

        pSystemInf->u8WakeupType     = 6; /* Power Switch */
        READCFGSTR(pSystemInf->u8SKUNumber, DmiSystemSKU);
        READCFGSTR(pSystemInf->u8Family, DmiSystemFamily);
        TERM_STRUCT;

        /**********************************
         * DMI board information (Type 2) *
         **********************************/
        PDMIBOARDINF pBoardInf       = (PDMIBOARDINF)pszStr;
        CHECKSIZE(sizeof(*pBoardInf));
        START_STRUCT(pBoardInf);
        int iDmiBoardBoardType;
        pBoardInf->header.u8Type     = 2; /* Board Information */
        pBoardInf->header.u8Length   = sizeof(*pBoardInf);
        pBoardInf->header.u16Handle  = 0x0008;
        READCFGSTR(pBoardInf->u8Manufacturer, DmiBoardVendor);
        READCFGSTR(pBoardInf->u8Product,      DmiBoardProduct);
        READCFGSTR(pBoardInf->u8Version,      DmiBoardVersion);
        READCFGSTR(pBoardInf->u8SerialNumber, DmiBoardSerial);
        READCFGSTR(pBoardInf->u8AssetTag,     DmiBoardAssetTag);
        pBoardInf->u8FeatureFlags    = RT_BIT(0) /* hosting board, e.g. motherboard */
                                     ;
        READCFGSTR(pBoardInf->u8LocationInChass, DmiBoardLocInChass);
        pBoardInf->u16ChassisHandle  = 0x0003; /* see type 3 */
        READCFGINT(iDmiBoardBoardType, DmiBoardBoardType);
        pBoardInf->u8BoardType = iDmiBoardBoardType;
        pBoardInf->u8cObjectHandles  = 0;

        TERM_STRUCT;

        /********************************************
         * DMI System Enclosure or Chassis (Type 3) *
         ********************************************/
        PDMICHASSIS pChassis         = (PDMICHASSIS)pszStr;
        CHECKSIZE(sizeof(*pChassis));
        pszStr                       = (char*)&pChassis->u32OEMdefined;
        iStrNr                       = 1;
#ifdef VBOX_WITH_DMI_CHASSIS
        pChassis->header.u8Type      = 3; /* System Enclosure or Chassis */
#else
        pChassis->header.u8Type      = 0x7e; /* inactive */
#endif
        pChassis->header.u8Length    = RT_OFFSETOF(DMICHASSIS, u32OEMdefined);
        pChassis->header.u16Handle   = 0x0003;
        READCFGSTR(pChassis->u8Manufacturer, DmiChassisVendor);
        int iDmiChassisType;
        READCFGINT(iDmiChassisType, DmiChassisType);
        pChassis->u8Type             = iDmiChassisType;
        READCFGSTR(pChassis->u8Version, DmiChassisVersion);
        READCFGSTR(pChassis->u8SerialNumber, DmiChassisSerial);
        READCFGSTR(pChassis->u8AssetTag, DmiChassisAssetTag);
        pChassis->u8BootupState      = 0x03; /* safe */
        pChassis->u8PowerSupplyState = 0x03; /* safe */
        pChassis->u8ThermalState     = 0x03; /* safe */
        pChassis->u8SecurityStatus   = 0x03; /* none XXX */
# if 0
        /* v2.3+, currently not supported */
        pChassis->u32OEMdefined      = 0;
        pChassis->u8Height           = 0; /* unspecified */
        pChassis->u8NumPowerChords   = 0; /* unspecified */
        pChassis->u8ContElems        = 0; /* no contained elements */
        pChassis->u8ContElemRecLen   = 0; /* no contained elements */
# endif
        TERM_STRUCT;

        /**************************************
         * DMI Processor Information (Type 4) *
         **************************************/

        /*
         * This is just a dummy processor. Should we expose the real guest CPU features
         * here? Accessing this information at this point is difficult.
         */
        char szSocket[32];
        PDMIPROCESSORINF pProcessorInf = (PDMIPROCESSORINF)pszStr;
        CHECKSIZE(sizeof(*pProcessorInf));
        START_STRUCT(pProcessorInf);
        if (fDmiExposeProcessorInf)
            pProcessorInf->header.u8Type   = 4; /* Processor Information */
        else
            pProcessorInf->header.u8Type   = 126; /* inactive structure */
        pProcessorInf->header.u8Length     = sizeof(*pProcessorInf);
        pProcessorInf->header.u16Handle    = 0x0007;
        RTStrPrintf(szSocket, sizeof(szSocket), "Socket #%u", 0);
        pProcessorInf->u8SocketDesignation = iStrNr++;
        {
            size_t cStr = strlen(szSocket) + 1;
            CHECKSIZE(cStr);
            memcpy(pszStr, szSocket, cStr);
            pszStr += cStr;
        }
        pProcessorInf->u8ProcessorType     = 0x03; /* Central Processor */
        pProcessorInf->u8ProcessorFamily   = 0xB1; /* Pentium III with Intel SpeedStep(TM) */
        READCFGSTR(pProcessorInf->u8ProcessorManufacturer, DmiProcManufacturer);

        pProcessorInf->u64ProcessorID      = UINT64_C(0x0FEBFBFF00010676);
                                             /* Ext Family ID  = 0
                                              * Ext Model ID   = 2
                                              * Processor Type = 0
                                              * Family ID      = 6
                                              * Model          = 7
                                              * Stepping       = 6
                                              * Features: FPU, VME, DE, PSE, TSC, MSR, PAE, MCE, CX8,
                                              *           APIC, SEP, MTRR, PGE, MCA, CMOV, PAT, PSE-36,
                                              *           CFLSH, DS, ACPI, MMX, FXSR, SSE, SSE2, SS */
        READCFGSTR(pProcessorInf->u8ProcessorVersion, DmiProcVersion);
        pProcessorInf->u8Voltage           = 0x02;   /* 3.3V */
        pProcessorInf->u16ExternalClock    = 0x00;   /* unknown */
        pProcessorInf->u16MaxSpeed         = 3000;   /* 3GHz */
        pProcessorInf->u16CurrentSpeed     = 3000;   /* 3GHz */
        pProcessorInf->u8Status            = RT_BIT(6)  /* CPU socket populated */
                                           | RT_BIT(0)  /* CPU enabled */
                                           ;
        pProcessorInf->u8ProcessorUpgrade  = 0x04;   /* ZIF Socket */
        pProcessorInf->u16L1CacheHandle    = 0xFFFF; /* not specified */
        pProcessorInf->u16L2CacheHandle    = 0xFFFF; /* not specified */
        pProcessorInf->u16L3CacheHandle    = 0xFFFF; /* not specified */
        pProcessorInf->u8SerialNumber      = 0;      /* not specified */
        pProcessorInf->u8AssetTag          = 0;      /* not specified */
        pProcessorInf->u8PartNumber        = 0;      /* not specified */
        pProcessorInf->u8CoreCount         = cCpus;  /*  */
        pProcessorInf->u8CoreEnabled       = cCpus;
        pProcessorInf->u8ThreadCount       = 1;
        pProcessorInf->u16ProcessorCharacteristics 
                                           = RT_BIT(2); /* 64-bit capable */
        pProcessorInf->u16ProcessorFamily2 = 0;
        TERM_STRUCT;

        /***************************************
         * DMI Physical Memory Array (Type 16) *
         ***************************************/
        uint64_t u64RamSize;
        rc = CFGMR3QueryU64(pCfg, "RamSize", &u64RamSize);
        if (RT_FAILURE (rc))
            return PDMDEV_SET_ERROR(pDevIns, rc,
                                    N_("Configuration error: Failed to read \"RamSize\""));

        PDMIRAMARRAY pMemArray = (PDMIRAMARRAY)pszStr;
        CHECKSIZE(sizeof(*pMemArray));
        START_STRUCT(pMemArray);
        if (fDmiExposeMemoryTable)
            pMemArray->header.u8Type     = 16;     /* Physical Memory Array */
        else
            pMemArray->header.u8Type     = 126;    /* inactive structure */
        pMemArray->header.u8Length       = sizeof(*pMemArray);
        pMemArray->header.u16Handle      = 0x0005;
        pMemArray->u8Location            = 0x03;   /* Motherboard */
        pMemArray->u8Use                 = 0x03;   /* System memory */
        pMemArray->u8MemErrorCorrection  = 0x01;   /* Other */
        pMemArray->u32MaxCapacity        = (uint32_t)(u64RamSize / _1K); /* RAM size in K */
        pMemArray->u16MemErrorHandle     = 0xfffe; /* No error info structure */
        pMemArray->u16NumberOfMemDevices = 1;
        TERM_STRUCT;

        /***************************************
         * DMI Memory Device (Type 17)         *
         ***************************************/
        PDMIMEMORYDEV pMemDev = (PDMIMEMORYDEV)pszStr;
        CHECKSIZE(sizeof(*pMemDev));
        START_STRUCT(pMemDev);
        if (fDmiExposeMemoryTable)
            pMemDev->header.u8Type       = 17;     /* Memory Device */
        else
            pMemDev->header.u8Type       = 126;    /* inactive structure */
        pMemDev->header.u8Length         = sizeof(*pMemDev);
        pMemDev->header.u16Handle        = 0x0006;
        pMemDev->u16PhysMemArrayHandle   = 0x0005; /* handle of array we belong to */
        pMemDev->u16MemErrHandle         = 0xfffe; /* system doesn't provide this information */
        pMemDev->u16TotalWidth           = 0xffff; /* Unknown */
        pMemDev->u16DataWidth            = 0xffff; /* Unknown */
        int16_t u16RamSizeM = (uint16_t)(u64RamSize / _1M);
        if (u16RamSizeM == 0)
            u16RamSizeM = 0x400; /* 1G */
        pMemDev->u16Size                 = u16RamSizeM; /* RAM size */
        pMemDev->u8FormFactor            = 0x09; /* DIMM */
        pMemDev->u8DeviceSet             = 0x00; /* Not part of a device set */
        READCFGSTRDEF(pMemDev->u8DeviceLocator, " ", "DIMM 0");
        READCFGSTRDEF(pMemDev->u8BankLocator, " ", "Bank 0");
        pMemDev->u8MemoryType            = 0x03; /* DRAM */
        pMemDev->u16TypeDetail           = 0;    /* Nothing special */
        pMemDev->u16Speed                = 1600; /* Unknown, shall be speed in MHz */
        READCFGSTR(pMemDev->u8Manufacturer, DmiSystemVendor);
        READCFGSTRDEF(pMemDev->u8SerialNumber, " ", "00000000");
        READCFGSTRDEF(pMemDev->u8AssetTag, " ", "00000000");
        READCFGSTRDEF(pMemDev->u8PartNumber, " ", "00000000");
        pMemDev->u8Attributes            = 0; /* Unknown */
        TERM_STRUCT;

        /*****************************
         * DMI OEM strings (Type 11) *
         *****************************/
        PDMIOEMSTRINGS pOEMStrings    = (PDMIOEMSTRINGS)pszStr;
        CHECKSIZE(sizeof(*pOEMStrings));
        START_STRUCT(pOEMStrings);
#ifdef VBOX_WITH_DMI_OEMSTRINGS
        pOEMStrings->header.u8Type    = 0xb; /* OEM Strings */
#else
        pOEMStrings->header.u8Type    = 126; /* inactive structure */
#endif
        pOEMStrings->header.u8Length  = sizeof(*pOEMStrings);
        pOEMStrings->header.u16Handle = 0x0002;
        pOEMStrings->u8Count          = 2;

        char szTmp[64];
        RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u",
                    RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
        READCFGSTRDEF(pOEMStrings->u8VBoxVersion, "DmiOEMVBoxVer", szTmp);
        RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision());
        READCFGSTRDEF(pOEMStrings->u8VBoxRevision, "DmiOEMVBoxRev", szTmp);
        TERM_STRUCT;

        /*************************************
         * DMI OEM specific table (Type 128) *
         ************************************/
        PDMIOEMSPECIFIC pOEMSpecific = (PDMIOEMSPECIFIC)pszStr;
        CHECKSIZE(sizeof(*pOEMSpecific));
        START_STRUCT(pOEMSpecific);
        pOEMSpecific->header.u8Type    = 0x80; /* OEM specific */
        pOEMSpecific->header.u8Length  = sizeof(*pOEMSpecific);
        pOEMSpecific->header.u16Handle = 0x0008; /* Just next free handle */
        pOEMSpecific->u32CpuFreqKHz    = RT_H2LE_U32((uint32_t)((uint64_t)TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns)) / 1000));
        TERM_STRUCT;

        /* End-of-table marker - includes padding to account for fixed table size. */
        PDMIHDR pEndOfTable          = (PDMIHDR)pszStr;
        pszStr                       = (char *)(pEndOfTable + 1);
        pEndOfTable->u8Type          = 0x7f;

        pEndOfTable->u8Length        = sizeof(*pEndOfTable);
        pEndOfTable->u16Handle       = 0xFEFF;
        *pcbDmiTables = ((uintptr_t)pszStr - (uintptr_t)pTable) + 2;

        /* We currently plant 10 DMI tables. Update this if tables number changed. */
        *pcNumDmiTables = 10;

        /* If more fields are added here, fix the size check in READCFGSTR */

        /* Success! */
        break;
    }

#undef READCFGSTR
#undef READCFGINT
#undef CHECKSIZE
    return VINF_SUCCESS;
}
예제 #11
0
/** entry point */
int main(int argc, char *argv[])
{
    const char *uuid = NULL;
    int c;
    int listHostModes = 0;
    int quit = 0;
    const struct option options[] =
    {
        { "help",          no_argument,       NULL, 'h' },
        { "startvm",       required_argument, NULL, 's' },
        { "fixedres",      required_argument, NULL, 'f' },
        { "listhostmodes", no_argument,       NULL, 'l' },
        { "scale",         no_argument,       NULL, 'c' }
    };

    printf("VirtualBox DirectFB GUI built %s %s\n"
           "(C) 2004-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
           "(C) 2004-2005 secunet Security Networks AG\n", __DATE__, __TIME__);

    for (;;)
    {
        c = getopt_long(argc, argv, "s:", options, NULL);
        if (c == -1)
            break;
        switch (c)
        {
            case 'h':
            {
                showusage();
                exit(0);
                break;
            }
            case 's':
            {
                // UUID as string, parse it
                RTUUID buuid;
                if (!RT_SUCCESS(RTUuidFromStr((PRTUUID)&buuid, optarg)))
                {
                    printf("Error, invalid UUID format given!\n");
                    showusage();
                    exit(-1);
                }
                uuid = optarg;
                break;
            }
            case 'f':
            {
                if (sscanf(optarg, "%ux%ux%u", &fixedVideoMode.width, &fixedVideoMode.height,
                           &fixedVideoMode.bpp) != 3)
                {
                    printf("Error, invalid resolution argument!\n");
                    showusage();
                    exit(-1);
                }
                useFixedVideoMode = 1;
                break;
            }
            case 'l':
            {
                listHostModes = 1;
                break;
            }
            case 'c':
            {
                scaleGuest = 1;
                break;
            }
            default:
                break;
        }
    }

    // check if we got a UUID
    if (!uuid)
    {
        printf("Error, no UUID given!\n");
        showusage();
        exit(-1);
    }


    /**
     * XPCOM setup
     */

    nsresult rc;
    /*
     * Note that we scope all nsCOMPtr variables in order to have all XPCOM
     * objects automatically released before we call NS_ShutdownXPCOM at the
     * end. This is an XPCOM requirement.
     */
    {
        nsCOMPtr<nsIServiceManager> serviceManager;
        rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull);
        if (NS_FAILED(rc))
        {
            printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
            exit(-1);
        }

        // register our component
        nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager);
        if (!registrar)
        {
            printf("Error: could not query nsIComponentRegistrar interface!\n");
            exit(-1);
        }
        registrar->AutoRegister(nsnull);

        /*
         * Make sure the main event queue is created. This event queue is
         * responsible for dispatching incoming XPCOM IPC messages. The main
         * thread should run this event queue's loop during lengthy non-XPCOM
         * operations to ensure messages from the VirtualBox server and other
         * XPCOM IPC clients are processed. This use case doesn't perform such
         * operations so it doesn't run the event loop.
         */
        nsCOMPtr<nsIEventQueue> eventQ;
        rc = NS_GetMainEventQ(getter_AddRefs (eventQ));
        if (NS_FAILED(rc))
        {
            printf("Error: could not get main event queue! rc=%08X\n", rc);
            return -1;
        }

        /*
         * Now XPCOM is ready and we can start to do real work.
         * IVirtualBox is the root interface of VirtualBox and will be
         * retrieved from the XPCOM component manager. We use the
         * XPCOM provided smart pointer nsCOMPtr for all objects because
         * that's very convenient and removes the need deal with reference
         * counting and freeing.
         */
        nsCOMPtr<nsIComponentManager> manager;
        rc = NS_GetComponentManager (getter_AddRefs (manager));
        if (NS_FAILED(rc))
        {
            printf("Error: could not get component manager! rc=%08X\n", rc);
            exit(-1);
        }

        nsCOMPtr<IVirtualBox> virtualBox;
        rc = manager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID,
                                                 nsnull,
                                                 NS_GET_IID(IVirtualBox),
                                                 getter_AddRefs(virtualBox));
        if (NS_FAILED(rc))
        {
            printf("Error, could not instantiate object! rc=0x%x\n", rc);
            exit(-1);
        }

        nsCOMPtr<ISession> session;
        rc = manager->CreateInstance(CLSID_Session,
                                     nsnull,
                                     NS_GET_IID(ISession),
                                     getter_AddRefs(session));
        if (NS_FAILED(rc))
        {
            printf("Error: could not instantiate Session object! rc = %08X\n", rc);
            exit(-1);
        }

        // open session for this VM
        rc = virtualBox->OpenSession(session, NS_ConvertUTF8toUTF16(uuid).get());
        if (NS_FAILED(rc))
        {
            printf("Error: given machine not found!\n");
            exit(-1);
        }
        nsCOMPtr<IMachine> machine;
        session->GetMachine(getter_AddRefs(machine));
        if (!machine)
        {
            printf("Error: given machine not found!\n");
            exit(-1);
        }
        nsCOMPtr<IConsole> console;
        session->GetConsole(getter_AddRefs(console));
        if (!console)
        {
            printf("Error: cannot get console!\n");
            exit(-1);
        }

        nsCOMPtr<IDisplay> display;
        console->GetDisplay(getter_AddRefs(display));
        if (!display)
        {
            printf("Error: could not get display object!\n");
            exit(-1);
        }

        nsCOMPtr<IKeyboard> keyboard;
        nsCOMPtr<IMouse> mouse;
        VBoxDirectFB *frameBuffer = NULL;

        /**
         * Init DirectFB
         */
        IDirectFB *dfb = NULL;
        IDirectFBSurface *surface = NULL;
        IDirectFBInputDevice *dfbKeyboard = NULL;
        IDirectFBInputDevice *dfbMouse = NULL;
        IDirectFBEventBuffer *dfbEventBuffer = NULL;
        DFBSurfaceDescription dsc;
        int screen_width, screen_height;

        DFBCHECK(DirectFBInit(&argc, &argv));
        DFBCHECK(DirectFBCreate(&dfb));
        DFBCHECK(dfb->SetCooperativeLevel(dfb, DFSCL_FULLSCREEN));
        // populate our structure of supported video modes
        DFBCHECK(dfb->EnumVideoModes(dfb, enumVideoModesHandler, NULL));

        if (listHostModes)
        {
            printf("*****************************************************\n");
            printf("Number of available host video modes: %u\n", numVideoModes);
            for (uint32_t i = 0; i < numVideoModes; i++)
            {
                printf("Mode %u: xres = %u, yres = %u, bpp = %u\n", i,
                       videoModes[i].width, videoModes[i].height, videoModes[i].bpp);
            }
            printf("Note: display modes with bpp < have been filtered out\n");
            printf("*****************************************************\n");
            goto Leave;
        }

        if (useFixedVideoMode)
        {
            int32_t bestVideoMode = getBestVideoMode(fixedVideoMode.width,
                                                     fixedVideoMode.height,
                                                     fixedVideoMode.bpp);
            // validate the fixed mode
            if ((bestVideoMode == -1) ||
                ((fixedVideoMode.width  != videoModes[bestVideoMode].width) ||
                (fixedVideoMode.height != videoModes[bestVideoMode].height) ||
                (fixedVideoMode.bpp    != videoModes[bestVideoMode].bpp)))
            {
                printf("Error: the specified fixed video mode is not available!\n");
                exit(-1);
            }
        } else
        {
            initialVideoMode = getBestVideoMode(640, 480, 16);
            if (initialVideoMode == -1)
            {
                printf("Error: initial video mode 640x480x16 is not available!\n");
                exit(-1);
            }
        }

        dsc.flags = DSDESC_CAPS;
        dsc.caps = DSCAPS_PRIMARY;
        DFBCHECK(dfb->CreateSurface(dfb, &dsc, &surface));
        DFBCHECK(surface->Clear(surface, 0, 0, 0, 0));
        DFBCHECK(surface->GetSize(surface, &screen_width, &screen_height));
        DFBCHECK(dfb->GetInputDevice(dfb, DIDID_KEYBOARD, &dfbKeyboard));
        DFBCHECK(dfbKeyboard->CreateEventBuffer(dfbKeyboard, &dfbEventBuffer));
        DFBCHECK(dfb->GetInputDevice(dfb, DIDID_MOUSE, &dfbMouse));
        DFBCHECK(dfbMouse->AttachEventBuffer(dfbMouse, dfbEventBuffer));


        if (useFixedVideoMode)
        {
            printf("Information: setting video mode to %ux%ux%u\n", fixedVideoMode.width,
                   fixedVideoMode.height, fixedVideoMode.bpp);
            DFBCHECK(dfb->SetVideoMode(dfb, fixedVideoMode.width,
                                       fixedVideoMode.height, fixedVideoMode.bpp));
        } else
        {
            printf("Information: starting with default video mode %ux%ux%u\n",
                   videoModes[initialVideoMode].width, videoModes[initialVideoMode].height,
                   videoModes[initialVideoMode].bpp);
            DFBCHECK(dfb->SetVideoMode(dfb, videoModes[initialVideoMode].width,
                                            videoModes[initialVideoMode].height,
                                            videoModes[initialVideoMode].bpp));
        }

        // register our framebuffer
        frameBuffer = new VBoxDirectFB(dfb, surface);
        display->SetFramebuffer(0, frameBuffer);

        /**
         * Start the VM execution thread
         */
        console->PowerUp(NULL);

        console->GetKeyboard(getter_AddRefs(keyboard));
        console->GetMouse(getter_AddRefs(mouse));

        /**
         * Main event loop
         */
        #define MAX_KEYEVENTS 10
        PRInt32 keyEvents[MAX_KEYEVENTS];
        int numKeyEvents;

        while (!quit)
        {
            DFBInputEvent event;

            numKeyEvents = 0;
            DFBCHECK(dfbEventBuffer->WaitForEvent(dfbEventBuffer));
            while (dfbEventBuffer->GetEvent(dfbEventBuffer, DFB_EVENT(&event)) == DFB_OK)
            {
                int mouseXDelta = 0;
                int mouseYDelta = 0;
                int mouseZDelta = 0;
                switch (event.type)
                {
                    #define QUEUEEXT() keyEvents[numKeyEvents++] = 0xe0
                    #define QUEUEKEY(scan) keyEvents[numKeyEvents++] = scan | (event.type == DIET_KEYRELEASE ? 0x80 : 0x00)
                    #define QUEUEKEYRAW(scan) keyEvents[numKeyEvents++] = scan
                    case DIET_KEYPRESS:
                    case DIET_KEYRELEASE:
                    {
                        // @@@AH development hack to get out of it!
                        if ((event.key_id == DIKI_ESCAPE) && (event.modifiers & (DIMM_CONTROL | DIMM_ALT)))
                            quit = 1;

                        if (numKeyEvents < MAX_KEYEVENTS)
                        {
                            //printf("%s: key_code: 0x%x\n", event.type == DIET_KEYPRESS ? "DIET_KEYPRESS" : "DIET_KEYRELEASE", event.key_code);
                            switch ((uint32_t)event.key_id)
                            {
                                case DIKI_CONTROL_R:
                                    QUEUEEXT();
                                    QUEUEKEY(0x1d);
                                    break;
                                case DIKI_INSERT:
                                    QUEUEEXT();
                                    QUEUEKEY(0x52);
                                    break;
                                case DIKI_DELETE:
                                    QUEUEEXT();
                                    QUEUEKEY(0x53);
                                    break;
                                case DIKI_HOME:
                                    QUEUEEXT();
                                    QUEUEKEY(0x47);
                                    break;
                                case DIKI_END:
                                    QUEUEEXT();
                                    QUEUEKEY(0x4f);
                                    break;
                                case DIKI_PAGE_UP:
                                    QUEUEEXT();
                                    QUEUEKEY(0x49);
                                    break;
                                case DIKI_PAGE_DOWN:
                                    QUEUEEXT();
                                    QUEUEKEY(0x51);
                                    break;
                                case DIKI_LEFT:
                                    QUEUEEXT();
                                    QUEUEKEY(0x4b);
                                    break;
                                case DIKI_RIGHT:
                                    QUEUEEXT();
                                    QUEUEKEY(0x4d);
                                    break;
                                case DIKI_UP:
                                    QUEUEEXT();
                                    QUEUEKEY(0x48);
                                    break;
                                case DIKI_DOWN:
                                    QUEUEEXT();
                                    QUEUEKEY(0x50);
                                    break;
                                case DIKI_KP_DIV:
                                    QUEUEEXT();
                                    QUEUEKEY(0x35);
                                    break;
                                case DIKI_KP_ENTER:
                                    QUEUEEXT();
                                    QUEUEKEY(0x1c);
                                    break;
                                case DIKI_PRINT:
                                    // the break code is inverted!
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEEXT();
                                        QUEUEKEY(0x2a);
                                        QUEUEEXT();
                                        QUEUEKEY(0x37);
                                    } else
                                    {
                                        QUEUEEXT();
                                        QUEUEKEY(0x37);
                                        QUEUEEXT();
                                        QUEUEKEY(0x2a);
                                    }
                                    break;
                                case DIKI_PAUSE:
                                    // This is a super weird key. No break code and a 6 byte
                                    // combination.
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEKEY(0xe1);
                                        QUEUEKEY(0x1d);
                                        QUEUEKEY(0x45);
                                        QUEUEKEY(0xe1);
                                        QUEUEKEY(0x9d);
                                        QUEUEKEY(0xc5);
                                    }
                                    break;
                                case DIKI_META_L:
                                    // the left Windows logo is a bit different
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0x1f);
                                    } else
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0xf0);
                                        QUEUEKEYRAW(0x1f);
                                    }
                                    break;
                                case DIKI_META_R:
                                    // the right Windows logo is a bit different
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0x27);
                                    } else
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0xf0);
                                        QUEUEKEYRAW(0x27);
                                    }
                                    break;
                                case DIKI_SUPER_R:
                                    // the popup menu is a bit different
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0x2f);
                                    } else
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0xf0);
                                        QUEUEKEYRAW(0x2f);
                                    }
                                    break;

                                default:
                                    // check if we got a hardware scancode
                                    if (event.key_code != -1)
                                    {
                                        // take the scancode from DirectFB as is
                                        QUEUEKEY(event.key_code);
                                    } else
                                    {
                                        // XXX need extra handling!
                                    }
                            }
                        }
                        break;
                    }
                    #undef QUEUEEXT
                    #undef QUEUEKEY
                    #undef QUEUEKEYRAW

                    case DIET_AXISMOTION:
                    {
                        switch (event.axis)
                        {
                            case DIAI_X:
                                mouseXDelta += event.axisrel;
                                break;
                            case DIAI_Y:
                                mouseYDelta += event.axisrel;
                                break;
                            case DIAI_Z:
                                mouseZDelta += event.axisrel;
                                break;
                            default:
                                break;
                        }
                        // fall through
                    }
                    case DIET_BUTTONPRESS:
                        // fall through;
                    case DIET_BUTTONRELEASE:
                    {
                        int buttonState = 0;
                        if (event.buttons & DIBM_LEFT)
                            buttonState |= MouseButtonState::LeftButton;
                        if (event.buttons & DIBM_RIGHT)
                            buttonState |= MouseButtonState::RightButton;
                        if (event.buttons & DIBM_MIDDLE)
                            buttonState |= MouseButtonState::MiddleButton;
                        mouse->PutMouseEvent(mouseXDelta, mouseYDelta, mouseZDelta,
                                             buttonState);
                        break;
                    }
                    default:
                        break;
                }
            }
            // did we get any keyboard events?
            if (numKeyEvents > 0)
            {
                uint32_t codesStored;
                if (numKeyEvents > 1)
                {
                    keyboard->PutScancodes(numKeyEvents, keyEvents,
                                           &codesStored);
                } else
                {
                    keyboard->PutScancode(keyEvents[0]);
                }
            }
        }
        {
            nsCOMPtr<IProgress> progress;
            console->PowerDown(getter_AddRefs(progress));
            progress->WaitForCompletion(-1);
        }
    }

Leave:
    /*
     * Perform the standard XPCOM shutdown procedure.
     */
    NS_ShutdownXPCOM(nsnull);

    return 0;
}
예제 #12
0
/**
 * Construct the DMI table.
 *
 * @returns VBox status code.
 * @param   pDevIns             The device instance.
 * @param   pTable              Where to create the DMI table.
 * @param   cbMax               The maximum size of the DMI table.
 * @param   pUuid               Pointer to the UUID to use if the DmiUuid
 *                              configuration string isn't present.
 * @param   pCfg                The handle to our config node.
 */
int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PCRTUUID pUuid, PCFGMNODE pCfg)
{
#define CHECKSIZE(cbWant) \
    { \
        size_t cbNeed = (size_t)(pszStr + cbWant - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \
        if (cbNeed > cbMax) \
        { \
            if (fHideErrors) \
            { \
                LogRel(("One of the DMI strings is too long -- using default DMI data!\n")); \
                continue; \
            } \
            return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \
                                       N_("One of the DMI strings is too long. Check all bios/Dmi* configuration entries. At least %zu bytes are needed but there is no space for more than %d bytes"), cbNeed, cbMax); \
        } \
    }

#define READCFGSTRDEF(variable, name, default_value) \
    { \
        if (fForceDefault) \
            pszTmp = default_value; \
        else \
        { \
            rc = CFGMR3QueryStringDef(pCfg, name, szBuf, sizeof(szBuf), default_value); \
            if (RT_FAILURE(rc)) \
            { \
                if (fHideErrors) \
                { \
                    LogRel(("Configuration error: Querying \"" name "\" as a string failed -- using default DMI data!\n")); \
                    continue; \
                } \
                return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
                                           N_("Configuration error: Querying \"" name "\" as a string failed")); \
            } \
            else if (!strcmp(szBuf, "<EMPTY>")) \
                pszTmp = ""; \
            else \
                pszTmp = szBuf; \
        } \
        if (!pszTmp[0]) \
            variable = 0; /* empty string */ \
        else \
        { \
            variable = iStrNr++; \
            size_t cStr = strlen(pszTmp) + 1; \
            CHECKSIZE(cStr); \
            memcpy(pszStr, pszTmp, cStr); \
            pszStr += cStr ; \
        } \
    }

#define READCFGSTR(variable, name) \
    READCFGSTRDEF(variable, # name, s_szDef ## name)

#define READCFGINT(variable, name) \
    { \
        if (fForceDefault) \
            variable = s_iDef ## name; \
        else \
        { \
            rc = CFGMR3QueryS32Def(pCfg, # name, & variable, s_iDef ## name); \
            if (RT_FAILURE(rc)) \
            { \
                if (fHideErrors) \
                { \
                    LogRel(("Configuration error: Querying \"" # name "\" as an int failed -- using default DMI data!\n")); \
                    continue; \
                } \
                return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
                                           N_("Configuration error: Querying \"" # name "\" as an int failed")); \
            } \
        } \
    }

#define START_STRUCT(tbl)                                       \
        pszStr                       = (char *)(tbl + 1);       \
        iStrNr                       = 1;

#define TERM_STRUCT \
    { \
        *pszStr++                    = '\0'; /* terminate set of text strings */ \
        if (iStrNr == 1) \
            *pszStr++                = '\0'; /* terminate a structure without strings */ \
    }

    bool fForceDefault = false;
#ifdef VBOX_BIOS_DMI_FALLBACK
    /*
     * There will be two passes. If an error occurs during the first pass, a
     * message will be written to the release log and we fall back to default
     * DMI data and start a second pass.
     */
    bool fHideErrors = true;
#else
    /*
     * There will be one pass, every error is fatal and will prevent the VM
     * from starting.
     */
    bool fHideErrors = false;
#endif

    uint8_t fDmiUseHostInfo;
    int rc = CFGMR3QueryU8Def(pCfg, "DmiUseHostInfo", &fDmiUseHostInfo, 0);
    if (RT_FAILURE (rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("Configuration error: Failed to read \"DmiUseHostInfo\""));

    /* Sync up with host default DMI values */
    if (fDmiUseHostInfo)
        fwCommonUseHostDMIStrings();

    uint8_t fDmiExposeMemoryTable;
    rc = CFGMR3QueryU8Def(pCfg, "DmiExposeMemoryTable", &fDmiExposeMemoryTable, 0);
    if (RT_FAILURE (rc))
        return PDMDEV_SET_ERROR(pDevIns, rc,
                                N_("Configuration error: Failed to read \"DmiExposeMemoryTable\""));

    for  (;; fForceDefault = true, fHideErrors = false)
    {
        int  iStrNr;
        char szBuf[256];
        char *pszStr = (char *)pTable;
        char szDmiSystemUuid[64];
        char *pszDmiSystemUuid;
        const char *pszTmp;

        if (fForceDefault)
            pszDmiSystemUuid = NULL;
        else
        {
            rc = CFGMR3QueryString(pCfg, "DmiSystemUuid", szDmiSystemUuid, sizeof(szDmiSystemUuid));
            if (rc == VERR_CFGM_VALUE_NOT_FOUND)
                pszDmiSystemUuid = NULL;
            else if (RT_FAILURE(rc))
            {
                if (fHideErrors)
                {
                    LogRel(("Configuration error: Querying \"DmiSystemUuid\" as a string failed, using default DMI data\n"));
                    continue;
                }
                return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                           N_("Configuration error: Querying \"DmiSystemUuid\" as a string failed"));
            }
            else
                pszDmiSystemUuid = szDmiSystemUuid;
        }

        /*********************************
         * DMI BIOS information (Type 0) *
         *********************************/
        PDMIBIOSINF pBIOSInf         = (PDMIBIOSINF)pszStr;
        CHECKSIZE(sizeof(*pBIOSInf));

        pszStr                       = (char *)&pBIOSInf->u8ReleaseMajor;
        pBIOSInf->header.u8Length    = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);

        /* don't set these fields by default for legacy compatibility */
        int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor;
        READCFGINT(iDmiBIOSReleaseMajor, DmiBIOSReleaseMajor);
        READCFGINT(iDmiBIOSReleaseMinor, DmiBIOSReleaseMinor);
        if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
        {
            pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
            pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
            pBIOSInf->u8ReleaseMajor  = iDmiBIOSReleaseMajor;
            pBIOSInf->u8ReleaseMinor  = iDmiBIOSReleaseMinor;

            int iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor;
            READCFGINT(iDmiBIOSFirmwareMajor, DmiBIOSFirmwareMajor);
            READCFGINT(iDmiBIOSFirmwareMinor, DmiBIOSFirmwareMinor);
            if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
            {
                pszStr = (char *)(pBIOSInf + 1);
                pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
                pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
                pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
            }
        }

        iStrNr                       = 1;
        pBIOSInf->header.u8Type      = 0; /* BIOS Information */
        pBIOSInf->header.u16Handle   = 0x0000;
        READCFGSTR(pBIOSInf->u8Vendor,  DmiBIOSVendor);
        READCFGSTR(pBIOSInf->u8Version, DmiBIOSVersion);
        pBIOSInf->u16Start           = 0xE000;
        READCFGSTR(pBIOSInf->u8Release, DmiBIOSReleaseDate);
        pBIOSInf->u8ROMSize          = 1; /* 128K */
        pBIOSInf->u64Characteristics = RT_BIT(4)   /* ISA is supported */
                                     | RT_BIT(7)   /* PCI is supported */
                                     | RT_BIT(15)  /* Boot from CD is supported */
                                     | RT_BIT(16)  /* Selectable Boot is supported */
                                     | RT_BIT(27)  /* Int 9h, 8042 Keyboard services supported */
                                     | RT_BIT(30)  /* Int 10h, CGA/Mono Video Services supported */
                                     /* any more?? */
                                     ;
        pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0)   /* ACPI is supported */
                                         /* any more?? */
                                         ;
        pBIOSInf->u8CharacteristicsByte2 = 0
                                         /* any more?? */
                                         ;
        TERM_STRUCT;

        /***********************************
         * DMI system information (Type 1) *
         ***********************************/
        PDMISYSTEMINF pSystemInf     = (PDMISYSTEMINF)pszStr;
        CHECKSIZE(sizeof(*pSystemInf));
        pszStr                       = (char *)(pSystemInf + 1);
        iStrNr                       = 1;
        pSystemInf->header.u8Type    = 1; /* System Information */
        pSystemInf->header.u8Length  = sizeof(*pSystemInf);
        pSystemInf->header.u16Handle = 0x0001;
        READCFGSTR(pSystemInf->u8Manufacturer, DmiSystemVendor);
        READCFGSTR(pSystemInf->u8ProductName,  DmiSystemProduct);
        READCFGSTR(pSystemInf->u8Version,      DmiSystemVersion);
        READCFGSTR(pSystemInf->u8SerialNumber, DmiSystemSerial);

        RTUUID uuid;
        if (pszDmiSystemUuid)
        {
            rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
            if (RT_FAILURE(rc))
            {
                if (fHideErrors)
                {
                    LogRel(("Configuration error: Invalid UUID for DMI tables specified, using default DMI data\n"));
                    continue;
                }
                return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
                                           N_("Configuration error: Invalid UUID for DMI tables specified"));
            }
            uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
            uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
            uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
            pUuid = &uuid;
        }
        memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));

        pSystemInf->u8WakeupType     = 6; /* Power Switch */
        READCFGSTR(pSystemInf->u8SKUNumber, DmiSystemSKU);
        READCFGSTR(pSystemInf->u8Family, DmiSystemFamily);
        TERM_STRUCT;

        /********************************************
         * DMI System Enclosure or Chassis (Type 3) *
         ********************************************/
        PDMICHASSIS pChassis         = (PDMICHASSIS)pszStr;
        CHECKSIZE(sizeof(*pChassis));
        pszStr                       = (char*)&pChassis->u32OEMdefined;
        iStrNr                       = 1;
#ifdef VBOX_WITH_DMI_CHASSIS
        pChassis->header.u8Type      = 3; /* System Enclosure or Chassis */
#else
        pChassis->header.u8Type      = 0x7e; /* inactive */
#endif
        pChassis->header.u8Length    = RT_OFFSETOF(DMICHASSIS, u32OEMdefined);
        pChassis->header.u16Handle   = 0x0003;
        READCFGSTR(pChassis->u8Manufacturer, DmiChassisVendor);
        pChassis->u8Type             = 0x01; /* ''other'', no chassis lock present */
        READCFGSTR(pChassis->u8Version, DmiChassisVersion);
        READCFGSTR(pChassis->u8SerialNumber, DmiChassisSerial);
        READCFGSTR(pChassis->u8AssetTag, DmiChassisAssetTag);
        pChassis->u8BootupState      = 0x03; /* safe */
        pChassis->u8PowerSupplyState = 0x03; /* safe */
        pChassis->u8ThermalState     = 0x03; /* safe */
        pChassis->u8SecurityStatus   = 0x03; /* none XXX */
# if 0
        /* v2.3+, currently not supported */
        pChassis->u32OEMdefined      = 0;
        pChassis->u8Height           = 0; /* unspecified */
        pChassis->u8NumPowerChords   = 0; /* unspecified */
        pChassis->u8ContElems        = 0; /* no contained elements */
        pChassis->u8ContElemRecLen   = 0; /* no contained elements */
# endif
        TERM_STRUCT;

        if (fDmiExposeMemoryTable)
        {
            /***************************************
             * DMI Physical Memory Array (Type 16) *
             ***************************************/
            uint64_t u64RamSize;
            rc = CFGMR3QueryU64(pCfg, "RamSize", &u64RamSize);
            if (RT_FAILURE (rc))
                return PDMDEV_SET_ERROR(pDevIns, rc,
                                        N_("Configuration error: Failed to read \"RamSize\""));

            PDMIRAMARRAY pMemArray = (PDMIRAMARRAY)pszStr;
            CHECKSIZE(sizeof(*pMemArray));

            START_STRUCT(pMemArray);
            pMemArray->header.u8Type    = 16; /* Physical Memory Array */
            pMemArray->header.u8Length  = sizeof(*pMemArray);
            pMemArray->header.u16Handle = 0x0005;
            pMemArray->u8Location = 0x03; /* Motherboard */
            pMemArray->u8Use = 0x03; /* System memory */
            pMemArray->u8MemErrorCorrection = 0x01; /* Other */
            uint32_t u32RamSizeK = (uint32_t)(u64RamSize / _1K);
            pMemArray->u32MaxCapacity = u32RamSizeK; /* RAM size in K */
            pMemArray->u16MemErrorHandle = 0xfffe; /* No error info structure */
            pMemArray->u16NumberOfMemDevices = 1;
            TERM_STRUCT;

            /***************************************
             * DMI Memory Device (Type 17)         *
             ***************************************/
            PDMIMEMORYDEV pMemDev = (PDMIMEMORYDEV)pszStr;
            CHECKSIZE(sizeof(*pMemDev));

            START_STRUCT(pMemDev);
            pMemDev->header.u8Type    = 17; /* Memory Device */
            pMemDev->header.u8Length  = sizeof(*pMemDev);
            pMemDev->header.u16Handle = 0x0006;
            pMemDev->u16PhysMemArrayHandle = 0x0005; /* handle of array we belong to */
            pMemDev->u16MemErrHandle = 0xfffe; /* system doesn't provide this information */
            pMemDev->u16TotalWidth = 0xffff; /* Unknown */
            pMemDev->u16DataWidth = 0xffff;  /* Unknown */
            int16_t u16RamSizeM = (uint16_t)(u64RamSize / _1M);
            if (u16RamSizeM == 0)
                u16RamSizeM = 0x400; /* 1G */
            pMemDev->u16Size = u16RamSizeM; /* RAM size */
            pMemDev->u8FormFactor = 0x09; /* DIMM */
            pMemDev->u8DeviceSet = 0x00; /* Not part of a device set */
            READCFGSTRDEF(pMemDev->u8DeviceLocator, " ", "DIMM 0");
            READCFGSTRDEF(pMemDev->u8BankLocator, " ", "Bank 0");
            pMemDev->u8MemoryType = 0x03; /* DRAM */
            pMemDev->u16TypeDetail = 0; /* Nothing special */
            pMemDev->u16Speed = 1600; /* Unknown, shall be speed in MHz */
            READCFGSTR(pMemDev->u8Manufacturer, DmiSystemVendor);
            READCFGSTRDEF(pMemDev->u8SerialNumber, " ", "00000000");
            READCFGSTRDEF(pMemDev->u8AssetTag, " ", "00000000");
            READCFGSTRDEF(pMemDev->u8PartNumber, " ", "00000000");
            pMemDev->u8Attributes = 0; /* Unknown */
            TERM_STRUCT;
        }

        /*****************************
         * DMI OEM strings (Type 11) *
         *****************************/
        PDMIOEMSTRINGS pOEMStrings    = (PDMIOEMSTRINGS)pszStr;
        CHECKSIZE(sizeof(*pOEMStrings));
        pszStr                        = (char *)(pOEMStrings + 1);
        iStrNr                        = 1;
#ifdef VBOX_WITH_DMI_OEMSTRINGS
        pOEMStrings->header.u8Type    = 0xb; /* OEM Strings */
#else
        pOEMStrings->header.u8Type    = 0x7e; /* inactive */
#endif
        pOEMStrings->header.u8Length  = sizeof(*pOEMStrings);
        pOEMStrings->header.u16Handle = 0x0002;
        pOEMStrings->u8Count          = 2;

        char szTmp[64];
        RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u",
                    RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
        READCFGSTRDEF(pOEMStrings->u8VBoxVersion, "DmiOEMVBoxVer", szTmp);
        RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision());
        READCFGSTRDEF(pOEMStrings->u8VBoxRevision, "DmiOEMVBoxRev", szTmp);
        TERM_STRUCT;

        /* End-of-table marker - includes padding to account for fixed table size. */
        PDMIHDR pEndOfTable          = (PDMIHDR)pszStr;
        pEndOfTable->u8Type          = 0x7f;
        pEndOfTable->u8Length        = cbMax - ((char *)pszStr - (char *)pTable) - 2;
        pEndOfTable->u16Handle       = 0xFEFF;

        /* If more fields are added here, fix the size check in READCFGSTR */

        /* Success! */
        break;
    }

#undef READCFGSTR
#undef READCFGINT
#undef CHECKSIZE
    return VINF_SUCCESS;
}