Ejemplo n.º 1
0
/**
 * Construct a DHCP server with a default configuration.
 */
VBoxNetDhcp::VBoxNetDhcp():VBoxNetBaseService("VBoxNetDhcp", "VBoxNetDhcp")
{
    /*   m_enmTrunkType          = kIntNetTrunkType_WhateverNone; */
    RTMAC mac;
    mac.au8[0]     = 0x08;
    mac.au8[1]     = 0x00;
    mac.au8[2]     = 0x27;
    mac.au8[3]     = 0x40;
    mac.au8[4]     = 0x41;
    mac.au8[5]     = 0x42;
    setMacAddress(mac);

    RTNETADDRIPV4 address;
    address.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,  5)));
    setIpv4Address(address);

    setSendBufSize(8 * _1K);
    setRecvBufSize(50 * _1K);

    m_uCurMsgType           = UINT8_MAX;
    m_cbCurMsg              = 0;
    m_pCurMsg               = NULL;
    memset(&m_CurHdrs, '\0', sizeof(m_CurHdrs));

    m_fIgnoreCmdLineParameters = true;

    for(unsigned int i = 0; i < RT_ELEMENTS(g_aOptionDefs); ++i)
        addCommandLineOption(&g_aOptionDefs[i]);
}
Ejemplo n.º 2
0
VBoxNetLwipNAT::VBoxNetLwipNAT(SOCKET icmpsock4, SOCKET icmpsock6) : VBoxNetBaseService("VBoxNetNAT", "nat-network")
{
    LogFlowFuncEnter();

    m_ProxyOptions.ipv6_enabled = 0;
    m_ProxyOptions.ipv6_defroute = 0;
    m_ProxyOptions.icmpsock4 = icmpsock4;
    m_ProxyOptions.icmpsock6 = icmpsock6;
    m_ProxyOptions.tftp_root = NULL;
    m_ProxyOptions.src4 = NULL;
    m_ProxyOptions.src6 = NULL;
    RT_ZERO(m_src4);
    RT_ZERO(m_src6);
    m_src4.sin_family = AF_INET;
    m_src6.sin6_family = AF_INET6;
#if HAVE_SA_LEN
    m_src4.sin_len = sizeof(m_src4);
    m_src6.sin6_len = sizeof(m_src6);
#endif
    m_ProxyOptions.nameservers = NULL;

    m_LwipNetIf.name[0] = 'N';
    m_LwipNetIf.name[1] = 'T';

    RTMAC mac;
    mac.au8[0] = 0x52;
    mac.au8[1] = 0x54;
    mac.au8[2] = 0;
    mac.au8[3] = 0x12;
    mac.au8[4] = 0x35;
    mac.au8[5] = 0;
    setMacAddress(mac);

    RTNETADDRIPV4 address;
    address.u     = RT_MAKE_U32_FROM_U8( 10,  0,  2,  2); // NB: big-endian
    setIpv4Address(address);

    address.u     = RT_H2N_U32_C(0xffffff00);
    setIpv4Netmask(address);

    fDontLoadRulesOnStartup = false;

    for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
        addCommandLineOption(&g_aGetOptDef[i]);

    LogFlowFuncLeave();
}
Ejemplo n.º 3
0
RTDECL(uint32_t) ASMByteSwapU32(uint32_t u32)
{
    return RT_MAKE_U32_FROM_U8(RT_BYTE4(u32), RT_BYTE3(u32), RT_BYTE2(u32), RT_BYTE1(u32));
}
Ejemplo n.º 4
0
RTDECL(int) RTCidrStrToIPv4(const char *pszAddress, PRTIPV4ADDR pNetwork, PRTIPV4ADDR pNetmask)
{
    uint8_t cBits;
    uint8_t addr[4];
    uint32_t u32Netmask;
    uint32_t u32Network;
    const char *psz = pszAddress;
    const char *pszNetmask;
    char *pszNext;
    int  rc = VINF_SUCCESS;
    int cDelimiter = 0;
    int cDelimiterLimit = 0;

    AssertPtrReturn(pszAddress, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pNetwork, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pNetmask, VERR_INVALID_PARAMETER);

    pszNetmask = RTStrStr(psz, "/");
    *(uint32_t *)addr = 0;
    if (!pszNetmask)
        cBits = 32;
    else
    {
        rc = RTStrToUInt8Ex(pszNetmask + 1, &pszNext, 10, &cBits);
        if (   RT_FAILURE(rc)
            || cBits > 32
            || rc != VINF_SUCCESS) /* No trailing symbols are acceptable after the digit */
            return VERR_INVALID_PARAMETER;
    }
    u32Netmask = ~(uint32_t)((1<< (32 - cBits)) - 1);

    if (cBits <= 8)
        cDelimiterLimit = 0;
    else if (cBits <= 16)
        cDelimiterLimit = 1;
    else if (cBits <= 24)
        cDelimiterLimit = 2;
    else if (cBits <= 32)
        cDelimiterLimit = 3;

    for (;;)
    {
        rc = RTStrToUInt8Ex(psz, &pszNext, 10, &addr[cDelimiter]);
        if (   RT_FAILURE(rc)
            || rc == VWRN_NUMBER_TOO_BIG)
            return VERR_INVALID_PARAMETER;

        if (*pszNext == '.')
            cDelimiter++;
        else if (   cDelimiter >= cDelimiterLimit
                 && (   *pszNext == '\0'
                     || *pszNext == '/'))
            break;
        else
            return VERR_INVALID_PARAMETER;

        if (cDelimiter > 3)
            /* not more than four octets */
            return VERR_INVALID_PARAMETER;

        psz = pszNext + 1;
    }
    u32Network = RT_MAKE_U32_FROM_U8(addr[3], addr[2], addr[1], addr[0]);

    /* Corner case: see RFC 790 page 2 and RFC 4632 page 6. */
    if (   addr[0] == 0
        && (   *(uint32_t *)addr != 0
            || u32Netmask == (uint32_t)~0))
        return VERR_INVALID_PARAMETER;

    if ((u32Network & ~u32Netmask) != 0)
        return VERR_INVALID_PARAMETER;

    *pNetmask = u32Netmask;
    *pNetwork = u32Network;
    return VINF_SUCCESS;
}
Ejemplo n.º 5
0
int main()
{
    RTTEST hTest;
    int rc = RTTestInitAndCreate("tstRTGetOpt", &hTest);
    if (rc)
        return rc;

    RTGETOPTSTATE GetState;
    RTGETOPTUNION Val;
#define CHECK(expr)  do { if (!(expr)) { RTTestIFailed("error line %d (iNext=%d): %s\n", __LINE__, GetState.iNext, #expr); } } while (0)
#define CHECK2(expr, fmt) \
    do { \
        if (!(expr)) { \
            RTTestIFailed("error line %d (iNext=%d): %s\n", __LINE__, GetState.iNext, #expr); \
            RTTestIFailureDetails fmt; \
         } \
    } while (0)

#define CHECK_pDef(paOpts, i) \
    CHECK2(Val.pDef == &(paOpts)[(i)], ("Got #%d (%p) expected #%d\n", (int)(Val.pDef - &(paOpts)[0]), Val.pDef, i));

#define CHECK_GETOPT(expr, chRet, iInc) \
    do { \
        const int iPrev = GetState.iNext; \
        const int rcGetOpt = (expr); \
        CHECK2(rcGetOpt == (chRet), ("got %d, expected %d\n", rcGetOpt, (chRet))); \
        CHECK2(GetState.iNext == (iInc) + iPrev, ("iNext=%d expected %d\n", GetState.iNext, (iInc) + iPrev)); \
        GetState.iNext = (iInc) + iPrev; \
    } while (0)

#define CHECK_GETOPT_STR(expr, chRet, iInc, str) \
    do { \
        const int iPrev = GetState.iNext; \
        const int rcGetOpt = (expr); \
        CHECK2(rcGetOpt == (chRet), ("got %d, expected %d\n", rcGetOpt, (chRet))); \
        CHECK2(GetState.iNext == (iInc) + iPrev, ("iNext=%d expected %d\n", GetState.iNext, (iInc) + iPrev)); \
        CHECK2(VALID_PTR(Val.psz) && !strcmp(Val.psz, (str)), ("got %s, expected %s\n", Val.psz, (str))); \
        GetState.iNext = (iInc) + iPrev; \
    } while (0)


    /*
     * The basics.
     */
    RTTestSub(hTest, "Basics");
    static const RTGETOPTDEF s_aOpts2[] =
    {
        { "--optwithstring",    's', RTGETOPT_REQ_STRING },
        { "--optwithint",       'i', RTGETOPT_REQ_INT32 },
        { "--verbose",          'v', RTGETOPT_REQ_NOTHING },
        { NULL,                 'q', RTGETOPT_REQ_NOTHING },
        { "--quiet",            384, RTGETOPT_REQ_NOTHING },
        { "-novalue",           385, RTGETOPT_REQ_NOTHING },
        { "-startvm",           386, RTGETOPT_REQ_STRING },
        { "nodash",             387, RTGETOPT_REQ_NOTHING },
        { "nodashval",          388, RTGETOPT_REQ_STRING },
        { "--gateway",          'g', RTGETOPT_REQ_IPV4ADDR },
        { "--mac",              'm', RTGETOPT_REQ_MACADDR },
        { "--strindex",         400, RTGETOPT_REQ_STRING  | RTGETOPT_FLAG_INDEX },
        { "strindex",           400, RTGETOPT_REQ_STRING  | RTGETOPT_FLAG_INDEX },
        { "--intindex",         401, RTGETOPT_REQ_INT32   | RTGETOPT_FLAG_INDEX },
        { "--macindex",         402, RTGETOPT_REQ_MACADDR | RTGETOPT_FLAG_INDEX },
        { "--indexnovalue",     403, RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_INDEX },
        { "--macindexnegative", 404, RTGETOPT_REQ_NOTHING },
        { "--twovalues",        405, RTGETOPT_REQ_STRING },
        { "--twovaluesindex",   406, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_INDEX },
        { "--threevalues",      407, RTGETOPT_REQ_UINT32 },
        { "--boolean",          408, RTGETOPT_REQ_BOOL_ONOFF },
        { "--booleanindex",     409, RTGETOPT_REQ_BOOL_ONOFF | RTGETOPT_FLAG_INDEX },
    };

    const char *argv2[] =
    {
        "-s",               "string1",
        "-sstring2",
        "-s:string3",
        "-s=string4",
        "-s:",
        "-s=",
        "--optwithstring",  "string5",
        "--optwithstring:string6",
        "--optwithstring=string7",
        "--optwithstring:",
        "--optwithstring=",

        "-i",               "-42",
        "-i:-42",
        "-i=-42",

        "--optwithint",     "42",
        "--optwithint:42",
        "--optwithint=42",

        "-v",
        "--verbose",
        "-q",
        "--quiet",

        "-novalue",
        "-startvm",         "myvm",

        "nodash",
        "nodashval",        "string9",

        "filename1",
        "-q",
        "filename2",

        "-vqi999",

        "-g192.168.1.1",

        "-m08:0:27:00:ab:f3",
        "--mac:1:::::c",

        "--strindex786",    "string10",
        "--strindex786:string11",
        "--strindex786=string12",
        "strindex687",      "string13",
        "strindex687:string14",
        "strindex687=string15",
        "strindex688:",
        "strindex689=",
        "--intindex137",    "1000",
        "--macindex138",    "08:0:27:00:ab:f3",
        "--indexnovalue1",
        "--macindexnegative",

        "--twovalues",       "firstvalue", "secondvalue",
        "--twovalues:firstvalue",          "secondvalue",
        "--twovaluesindex4", "1",          "0xA",
        "--twovaluesindex5=2",             "0xB",
        "--threevalues",     "1",          "0xC",          "thirdvalue",

        /* bool on/off */
        "--boolean",         "on",
        "--boolean",         "off",
        "--boolean",         "invalid",
        "--booleanindex2",   "on",
        "--booleanindex7",   "off",
        "--booleanindex9",   "invalid",

        /* standard options */
        "--help",
        "-help",
        "-?",
        "-h",
        "--version",
        "-version",
        "-V",

        /* done */
        NULL
    };
    int argc2 = (int)RT_ELEMENTS(argv2) - 1;

    CHECK(RT_SUCCESS(RTGetOptInit(&GetState, argc2, (char **)argv2, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), 0, 0 /* fFlags */)));

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string1"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string2"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string3"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string4"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, ""));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, ""));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string5"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string6"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string7"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, ""));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 's', 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, ""));
    CHECK(GetState.uIndex == UINT32_MAX);

    /* -i */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 2);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);

    /* --optwithint */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 2);
    CHECK(Val.i32 == 42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == 42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == 42);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 1);
    CHECK_pDef(s_aOpts2, 2);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 1);
    CHECK_pDef(s_aOpts2, 2);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 1);
    CHECK_pDef(s_aOpts2, 3);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 384, 1);
    CHECK_pDef(s_aOpts2, 4);

    /* -novalue / -startvm (single dash long options) */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 385, 1);
    CHECK_pDef(s_aOpts2, 5);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 386, 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "myvm"));

    /* no-dash options */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 387, 1);
    CHECK_pDef(s_aOpts2, 7);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 388, 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string9"));

    /* non-option, option, non-option  */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1);
    CHECK(Val.psz && !strcmp(Val.psz, "filename1"));
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 1);
    CHECK_pDef(s_aOpts2, 3);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1);
    CHECK(Val.psz && !strcmp(Val.psz, "filename2"));

    /* compress short options */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'v', 0);
    CHECK_pDef(s_aOpts2, 2);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'q', 0);
    CHECK_pDef(s_aOpts2, 3);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == 999);

    /* IPv4 */
    RTTestSub(hTest, "RTGetOpt - IPv4");
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'g', 1);
    CHECK(Val.IPv4Addr.u == RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8(192,168,1,1))));

    /* Ethernet MAC address. */
    RTTestSub(hTest, "RTGetOpt - MAC Address");
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'm', 1);
    CHECK(   Val.MacAddr.au8[0] == 0x08
          && Val.MacAddr.au8[1] == 0x00
          && Val.MacAddr.au8[2] == 0x27
          && Val.MacAddr.au8[3] == 0x00
          && Val.MacAddr.au8[4] == 0xab
          && Val.MacAddr.au8[5] == 0xf3);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'm', 1);
    CHECK(   Val.MacAddr.au8[0] == 0x01
          && Val.MacAddr.au8[1] == 0x00
          && Val.MacAddr.au8[2] == 0x00
          && Val.MacAddr.au8[3] == 0x00
          && Val.MacAddr.au8[4] == 0x00
          && Val.MacAddr.au8[5] == 0x0c);

    /* string with indexed argument */
    RTTestSub(hTest, "RTGetOpt - Option w/ Index");
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string10"));
    CHECK(GetState.uIndex == 786);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string11"));
    CHECK(GetState.uIndex == 786);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string12"));
    CHECK(GetState.uIndex == 786);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string13"));
    CHECK(GetState.uIndex == 687);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string14"));
    CHECK(GetState.uIndex == 687);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "string15"));
    CHECK(GetState.uIndex == 687);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, ""));
    CHECK(GetState.uIndex == 688);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 400, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, ""));
    CHECK(GetState.uIndex == 689);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 401, 2);
    CHECK(Val.i32 == 1000);
    CHECK(GetState.uIndex == 137);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 402, 2);
    CHECK(   Val.MacAddr.au8[0] == 0x08
          && Val.MacAddr.au8[1] == 0x00
          && Val.MacAddr.au8[2] == 0x27
          && Val.MacAddr.au8[3] == 0x00
          && Val.MacAddr.au8[4] == 0xab
          && Val.MacAddr.au8[5] == 0xf3);
    CHECK(GetState.uIndex == 138);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 403, 1);
    CHECK(GetState.uIndex == 1);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 404, 1);
    CHECK(GetState.uIndex == UINT32_MAX);

    /* RTGetOptFetchValue tests */
    RTTestSub(hTest, "RTGetOptFetchValue");
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 405, 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "firstvalue"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "secondvalue"));
    CHECK(GetState.uIndex == UINT32_MAX);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 405, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "firstvalue"));
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "secondvalue"));
    CHECK(GetState.uIndex == UINT32_MAX);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 406, 2);
    CHECK(Val.u32 == 1);
    CHECK(GetState.uIndex == 4);
    CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_UINT32), VINF_SUCCESS, 1);
    CHECK(Val.u32 == 10);
    CHECK(GetState.uIndex == 4);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 406, 1);
    CHECK(Val.u32 == 2);
    CHECK(GetState.uIndex == 5);
    CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_UINT32), VINF_SUCCESS, 1);
    CHECK(Val.u32 == 11);
    CHECK(GetState.uIndex == 5);

    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 407, 2);
    CHECK(Val.u32 == 1);
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_UINT32), VINF_SUCCESS, 1);
    CHECK(Val.u32 == 12);
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "thirdvalue"));
    CHECK(GetState.uIndex == UINT32_MAX);

    /* bool on/off tests */
    RTTestSub(hTest, "RTGetOpt - bool on/off");
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 408, 2);
    CHECK(Val.f);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 408, 2);
    CHECK(!Val.f);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), VERR_GETOPT_UNKNOWN_OPTION, 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "invalid"));

    /* bool on/off with indexed argument */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 409, 2);
    CHECK(Val.f);
    CHECK(GetState.uIndex == 2);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 409, 2);
    CHECK(!Val.f);
    CHECK(GetState.uIndex == 7);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), VERR_GETOPT_UNKNOWN_OPTION, 2);
    CHECK(VALID_PTR(Val.psz) && !strcmp(Val.psz, "invalid"));

    /* standard options. */
    RTTestSub(hTest, "Standard options");
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'h', 1);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'h', 1);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'h', 1);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'h', 1);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'V', 1);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'V', 1);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'V', 1);

    /* the end */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 0, 0);
    CHECK(Val.pDef == NULL);
    CHECK(argc2 == GetState.iNext);

    /*
     * Options first.
     */
    RTTestSub(hTest, "Options first");
    const char *argv3[] =
    {
        "foo1",
        "-s",               "string1",
        "foo2",
        "--optwithstring",  "string2",
        "foo3",
        "-i",               "-42",
        "foo4",
        "-i:-42",
        "-i=-42",
        "foo5",
        "foo6",
        "foo7",
        "-i:-42",
        "-i=-42",
        "foo8",
        "--twovalues",       "firstvalue", "secondvalue",
        "foo9",
        "--twovalues:firstvalue",          "secondvalue",
        "foo10",
        "--",
        "--optwithstring",
        "foo11",
        "foo12",

        /* done */
        NULL
    };
    int argc3 = (int)RT_ELEMENTS(argv3) - 1;

    CHECK(RT_SUCCESS(RTGetOptInit(&GetState, argc3, (char **)argv3, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), 0,
                                  RTGETOPTINIT_FLAGS_OPTS_FIRST)));

    /* -s */
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 's', 2, "string1");
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 's', 2, "string2");
    CHECK(GetState.uIndex == UINT32_MAX);

    /* -i */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 2);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);

    /* --twovalues */
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 405, 2, "firstvalue");
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT_STR(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1, "secondvalue");
    CHECK(GetState.uIndex == UINT32_MAX);

    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 405, 1, "firstvalue");
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT_STR(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1, "secondvalue");
    CHECK(GetState.uIndex == UINT32_MAX);

    /* -- */
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 2, "foo1");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo2");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo3");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo4");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo5");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo6");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo7");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo8");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo9");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo10");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "--optwithstring");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo11");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo12");

    /* the end */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 0, 0);
    CHECK(Val.pDef == NULL);
    CHECK(argc3 == GetState.iNext);

    /*
     * Options first, part 2: No dash-dash.
     */
    const char *argv4[] =
    {
        "foo1",
        "-s",               "string1",
        "foo2",
        "--optwithstring",  "string2",
        "foo3",
        "-i",               "-42",
        "foo4",
        "-i:-42",
        "-i=-42",
        "foo5",
        "foo6",
        "foo7",
        "-i:-42",
        "-i=-42",
        "foo8",
        "--twovalues",       "firstvalue", "secondvalue",
        "foo9",
        "--twovalues:firstvalue",          "secondvalue",
        "foo10",
        "foo11",
        "foo12",

        /* done */
        NULL
    };
    int argc4 = (int)RT_ELEMENTS(argv4) - 1;

    CHECK(RT_SUCCESS(RTGetOptInit(&GetState, argc4, (char **)argv4, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), 0,
                                  RTGETOPTINIT_FLAGS_OPTS_FIRST)));

    /* -s */
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 's', 2, "string1");
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 's', 2, "string2");
    CHECK(GetState.uIndex == UINT32_MAX);

    /* -i */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 2);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 'i', 1);
    CHECK(Val.i32 == -42);

    /* --twovalues */
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 405, 2, "firstvalue");
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT_STR(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1, "secondvalue");
    CHECK(GetState.uIndex == UINT32_MAX);

    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), 405, 1, "firstvalue");
    CHECK(GetState.uIndex == UINT32_MAX);
    CHECK_GETOPT_STR(RTGetOptFetchValue(&GetState, &Val, RTGETOPT_REQ_STRING), VINF_SUCCESS, 1, "secondvalue");
    CHECK(GetState.uIndex == UINT32_MAX);

    /* -- */
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo1");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo2");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo3");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo4");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo5");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo6");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo7");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo8");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo9");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo10");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo11");
    CHECK_GETOPT_STR(RTGetOpt(&GetState, &Val), VINF_GETOPT_NOT_OPTION, 1, "foo12");

    /* the end */
    CHECK_GETOPT(RTGetOpt(&GetState, &Val), 0, 0);
    CHECK(Val.pDef == NULL);
    CHECK(argc4 == GetState.iNext);



    /*
     * Summary.
     */
    return RTTestSummaryAndDestroy(hTest);
}
Ejemplo n.º 6
0
/**
 * Initalizes the triple fault / boot hack.
 *
 * Always call vmmR0TripleFaultHackTerm to clean up, even when this call fails.
 *
 * @returns VBox status code.
 */
int vmmR0TripleFaultHackInit(void)
{
    /*
     * Map the first page.
     */
    int rc = RTR0MemObjEnterPhys(&g_hMemPage0, 0, PAGE_SIZE, RTMEM_CACHE_POLICY_DONT_CARE);
    AssertRCReturn(rc, rc);
    rc = RTR0MemObjMapKernel(&g_hMapPage0, g_hMemPage0, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
    AssertRCReturn(rc, rc);
    g_pbPage0 = (uint8_t *)RTR0MemObjAddress(g_hMapPage0);
    LogRel(("0040:0067 = %04x:%04x\n", RT_MAKE_U16(g_pbPage0[0x467+2],  g_pbPage0[0x467+3]),  RT_MAKE_U16(g_pbPage0[0x467+0],  g_pbPage0[0x467+1]) ));

    /*
     * Allocate some "low core" memory.  If that fails, just grab some memory.
     */
    //rc = RTR0MemObjAllocPhys(&g_hMemLowCore, PAGE_SIZE, _1M - 1);
    //__debugbreak();
    rc = RTR0MemObjEnterPhys(&g_hMemLowCore, 0x7000, PAGE_SIZE, RTMEM_CACHE_POLICY_DONT_CARE);
    AssertRCReturn(rc, rc);
    rc = RTR0MemObjMapKernel(&g_hMapLowCore, g_hMemLowCore, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
    AssertRCReturn(rc, rc);
    g_pbLowCore = (uint8_t *)RTR0MemObjAddress(g_hMapLowCore);
    g_HCPhysLowCore = RTR0MemObjGetPagePhysAddr(g_hMapLowCore, 0);
    LogRel(("Low core at %RHp mapped at %p\n", g_HCPhysLowCore, g_pbLowCore));

    /*
     * Save memory we'll be overwriting.
     */
    g_pvSavedLowCore = RTMemAlloc(PAGE_SIZE);
    AssertReturn(g_pvSavedLowCore, VERR_NO_MEMORY);
    memcpy(g_pvSavedLowCore, g_pbLowCore, PAGE_SIZE);

    g_u32SavedVector = RT_MAKE_U32_FROM_U8(g_pbPage0[0x467], g_pbPage0[0x467+1], g_pbPage0[0x467+2], g_pbPage0[0x467+3]);
    g_u16SavedCadIndicator = RT_MAKE_U16(g_pbPage0[0x472], g_pbPage0[0x472+1]);

    /*
     * Install the code.
     */
    size_t cbCode = (uintptr_t)&vmmR0TripleFaultHackEnd - (uintptr_t)&vmmR0TripleFaultHackStart;
    AssertLogRelReturn(cbCode <= PAGE_SIZE, VERR_OUT_OF_RANGE);
    memcpy(g_pbLowCore, &vmmR0TripleFaultHackStart, cbCode);

    g_pbPage0[0x467+0] = 0x00;
    g_pbPage0[0x467+1] = 0x70;
    g_pbPage0[0x467+2] = 0x00;
    g_pbPage0[0x467+3] = 0x00;

    g_pbPage0[0x472+0] = 0x34;
    g_pbPage0[0x472+1] = 0x12;

    /*
     * Configure the status port and cmos shutdown command.
     */
    uint32_t fSaved = ASMIntDisableFlags();

    ASMOutU8(0x70, 0x0f);
    ASMOutU8(0x71, 0x0a);

    ASMOutU8(0x70, 0x05);
    ASMInU8(0x71);

    ASMReloadCR3();
    ASMWriteBackAndInvalidateCaches();

    ASMSetFlags(fSaved);

#if 1 /* For testing & debugging. */
    vmmR0TripleFaultHackTripleFault();
#endif

    return VINF_SUCCESS;
}
Ejemplo n.º 7
0
void UIVMPreviewWindow::sltRecreatePreview()
{
    /* Only do this if we are visible: */
    if (!isVisible())
        return;

    /* Remove preview if any: */
    if (m_pPreviewImg)
    {
        delete m_pPreviewImg;
        m_pPreviewImg = 0;
    }

    /* We are not creating preview for inaccessible VMs: */
    if (m_machineState == KMachineState_Null)
        return;

    if (!m_machine.isNull() && m_vRect.width() > 0 && m_vRect.height() > 0)
    {
        QImage image(size(), QImage::Format_ARGB32);
        image.fill(Qt::transparent);
        QPainter painter(&image);
        bool fDone = false;

        /* Preview enabled? */
        if (m_pUpdateTimer->interval() > 0)
        {
            /* Use the image which may be included in the save state. */
            if (   m_machineState == KMachineState_Saved
                || m_machineState == KMachineState_Restoring)
            {
                ULONG width = 0, height = 0;
                QVector<BYTE> screenData = m_machine.ReadSavedScreenshotPNGToArray(0, width, height);
                if (screenData.size() != 0)
                {
                    QImage shot = QImage::fromData(screenData.data(), screenData.size(), "PNG").scaled(m_vRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
                    dimImage(shot);
                    painter.drawImage(m_vRect.x(), m_vRect.y(), shot);
                    fDone = true;
                }
            }
            /* Use the current VM output. */
            else if (   m_machineState == KMachineState_Running
//                      || m_machineState == KMachineState_Saving /* Not sure if this is valid */
                     || m_machineState == KMachineState_Paused)
            {
                if (m_session.GetState() == KSessionState_Locked)
                {
                    CVirtualBox vbox = vboxGlobal().virtualBox();
                    if (vbox.isOk())
                    {
                        const CConsole& console = m_session.GetConsole();
                        if (!console.isNull())
                        {
                            CDisplay display = console.GetDisplay();
                            /* Todo: correct aspect radio */
//                            ULONG w, h, bpp;
//                            display.GetScreenResolution(0, w, h, bpp);
//                            QImage shot = QImage(w, h, QImage::Format_RGB32);
//                            shot.fill(Qt::black);
//                            display.TakeScreenShot(0, shot.bits(), shot.width(), shot.height());
                            QVector<BYTE> screenData = display.TakeScreenShotToArray(0, m_vRect.width(), m_vRect.height());
                            if (   display.isOk()
                                && screenData.size() != 0)
                            {
                                /* Unfortunately we have to reorder the pixel
                                 * data, cause the VBox API returns RGBA data,
                                 * which is not a format QImage understand.
                                 * Todo: check for 32bit alignment, for both
                                 * the data and the scanlines. Maybe we need to
                                 * copy the data in any case. */
                                uint32_t *d = (uint32_t*)screenData.data();
                                for (int i = 0; i < screenData.size() / 4; ++i)
                                {
                                    uint32_t e = d[i];
                                    d[i] = RT_MAKE_U32_FROM_U8(RT_BYTE3(e), RT_BYTE2(e), RT_BYTE1(e), RT_BYTE4(e));
                                }

                                QImage shot = QImage((uchar*)d, m_vRect.width(), m_vRect.height(), QImage::Format_RGB32);

                                if (m_machineState == KMachineState_Paused)
                                    dimImage(shot);
                                painter.drawImage(m_vRect.x(), m_vRect.y(), shot);
                                fDone = true;
                            }
                        }
                    }
                }
            }
        }
        if (fDone)
            m_pPreviewImg = new QImage(image);
    }
    update();
}
Ejemplo n.º 8
0
/**
 * Deals with complicated MMIO writes.
 *
 * Complicated means unaligned or non-dword/qword sized accesses depending on
 * the MMIO region's access mode flags.
 *
 * @returns Strict VBox status code. Any EM scheduling status code,
 *          VINF_IOM_R3_MMIO_WRITE, VINF_IOM_R3_MMIO_READ_WRITE or
 *          VINF_IOM_R3_MMIO_READ may be returned.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
 * @param   pRange      The range to write to.
 * @param   GCPhys      The physical address to start writing.
 * @param   pvValue     Where to store the value.
 * @param   cbValue     The size of the value to write.
 */
static VBOXSTRICTRC iomMMIODoComplicatedWrite(PVM pVM, PVMCPU pVCpu, PIOMMMIORANGE pRange, RTGCPHYS GCPhys,
                                              void const *pvValue, unsigned cbValue)
{
    AssertReturn(   (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) != IOMMMIO_FLAGS_WRITE_PASSTHRU
                 && (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
                 VERR_IOM_MMIO_IPE_1);
    AssertReturn(cbValue != 0 && cbValue <= 16, VERR_IOM_MMIO_IPE_2);
    RTGCPHYS const GCPhysStart  = GCPhys; NOREF(GCPhysStart);
    bool const     fReadMissing = (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING
                               || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING;

    /*
     * Do debug stop if requested.
     */
    int rc = VINF_SUCCESS; NOREF(pVM);
#ifdef VBOX_STRICT
    if (pRange->fFlags & IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE)
    {
# ifdef IN_RING3
        LogRel(("IOM: Complicated write %#x byte at %RGp to %s, initiating debugger intervention\n", cbValue, GCPhys,
                R3STRING(pRange->pszDesc)));
        rc = DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, RT_SRC_POS,
                            "Complicated write %#x byte at %RGp to %s\n", cbValue, GCPhys, R3STRING(pRange->pszDesc));
        if (rc == VERR_DBGF_NOT_ATTACHED)
            rc = VINF_SUCCESS;
# else
        return VINF_IOM_R3_MMIO_WRITE;
# endif
    }
#endif

    /*
     * Check if we should ignore the write.
     */
    if ((pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD)
    {
        Assert(cbValue != 4 || (GCPhys & 3));
        return VINF_SUCCESS;
    }
    if ((pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD)
    {
        Assert((cbValue != 4 && cbValue != 8) || (GCPhys & (cbValue - 1)));
        return VINF_SUCCESS;
    }

    /*
     * Split and conquer.
     */
    for (;;)
    {
        unsigned const  offAccess  = GCPhys & 3;
        unsigned        cbThisPart = 4 - offAccess;
        if (cbThisPart > cbValue)
            cbThisPart = cbValue;

        /*
         * Get the missing bits (if any).
         */
        uint32_t u32MissingValue = 0;
        if (fReadMissing && cbThisPart != 4)
        {
            int rc2 = pRange->CTX_SUFF(pfnReadCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
                                                        GCPhys & ~(RTGCPHYS)3, &u32MissingValue, sizeof(u32MissingValue));
            switch (rc2)
            {
                case VINF_SUCCESS:
                    break;
                case VINF_IOM_MMIO_UNUSED_FF:
                    u32MissingValue = UINT32_C(0xffffffff);
                    break;
                case VINF_IOM_MMIO_UNUSED_00:
                    u32MissingValue = 0;
                    break;
#ifndef IN_RING3
                case VINF_IOM_R3_MMIO_READ:
                case VINF_IOM_R3_MMIO_READ_WRITE:
                case VINF_IOM_R3_MMIO_WRITE:
                    LogFlow(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
                    rc2 = VBOXSTRICTRC_TODO(iomMmioRing3WritePending(pVCpu, GCPhys, pvValue, cbValue, pRange));
                    if (rc == VINF_SUCCESS || rc2 < rc)
                        rc = rc2;
                    return rc;
#endif
                default:
                    if (RT_FAILURE(rc2))
                    {
                        Log(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [read]\n", GCPhys, GCPhysStart, cbValue, rc2));
                        return rc2;
                    }
                    AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
                    if (rc == VINF_SUCCESS || rc2 < rc)
                        rc = rc2;
                    break;
            }
        }

        /*
         * Merge missing and given bits.
         */
        uint32_t u32GivenMask;
        uint32_t u32GivenValue;
        switch (cbThisPart)
        {
            case 1:
                u32GivenValue = *(uint8_t  const *)pvValue;
                u32GivenMask  = UINT32_C(0x000000ff);
                break;
            case 2:
                u32GivenValue = *(uint16_t const *)pvValue;
                u32GivenMask  = UINT32_C(0x0000ffff);
                break;
            case 3:
                u32GivenValue = RT_MAKE_U32_FROM_U8(((uint8_t const *)pvValue)[0], ((uint8_t const *)pvValue)[1],
                                                    ((uint8_t const *)pvValue)[2], 0);
                u32GivenMask  = UINT32_C(0x00ffffff);
                break;
            case 4:
                u32GivenValue = *(uint32_t const *)pvValue;
                u32GivenMask  = UINT32_C(0xffffffff);
                break;
            default:
                AssertFailedReturn(VERR_IOM_MMIO_IPE_3);
        }
        if (offAccess)
        {
            u32GivenValue <<= offAccess * 8;
            u32GivenMask  <<= offAccess * 8;
        }

        uint32_t u32Value = (u32MissingValue & ~u32GivenMask)
                          | (u32GivenValue & u32GivenMask);

        /*
         * Do DWORD write to the device.
         */
        int rc2 = pRange->CTX_SUFF(pfnWriteCallback)(pRange->CTX_SUFF(pDevIns), pRange->CTX_SUFF(pvUser),
                                                     GCPhys & ~(RTGCPHYS)3, &u32Value, sizeof(u32Value));
        switch (rc2)
        {
            case VINF_SUCCESS:
                break;
#ifndef IN_RING3
            case VINF_IOM_R3_MMIO_READ:
            case VINF_IOM_R3_MMIO_READ_WRITE:
            case VINF_IOM_R3_MMIO_WRITE:
                Log3(("iomMMIODoComplicatedWrite: deferring GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
                AssertReturn(pVCpu->iom.s.PendingMmioWrite.cbValue == 0, VERR_IOM_MMIO_IPE_1);
                AssertReturn(cbValue + (GCPhys & 3) <= sizeof(pVCpu->iom.s.PendingMmioWrite.abValue), VERR_IOM_MMIO_IPE_2);
                pVCpu->iom.s.PendingMmioWrite.GCPhys  = GCPhys & ~(RTGCPHYS)3;
                pVCpu->iom.s.PendingMmioWrite.cbValue = cbValue + (GCPhys & 3);
                *(uint32_t *)pVCpu->iom.s.PendingMmioWrite.abValue = u32Value;
                if (cbValue > cbThisPart)
                    memcpy(&pVCpu->iom.s.PendingMmioWrite.abValue[4],
                           (uint8_t const *)pvValue + cbThisPart, cbValue - cbThisPart);
                VMCPU_FF_SET(pVCpu, VMCPU_FF_IOM);
                if (rc == VINF_SUCCESS)
                    rc = VINF_IOM_R3_MMIO_COMMIT_WRITE;
                return rc2;
#endif
            default:
                if (RT_FAILURE(rc2))
                {
                    Log(("iomMMIODoComplicatedWrite: GCPhys=%RGp GCPhysStart=%RGp cbValue=%u rc=%Rrc [write]\n", GCPhys, GCPhysStart, cbValue, rc2));
                    return rc2;
                }
                AssertMsgReturn(rc2 >= VINF_EM_FIRST && rc2 <= VINF_EM_LAST, ("%Rrc\n", rc2), VERR_IPE_UNEXPECTED_INFO_STATUS);
                if (rc == VINF_SUCCESS || rc2 < rc)
                    rc = rc2;
                break;
        }

        /*
         * Advance.
         */
        cbValue -= cbThisPart;
        if (!cbValue)
            break;
        GCPhys += cbThisPart;
        pvValue = (uint8_t const *)pvValue + cbThisPart;
    }

    return rc;
}