VirtualBox

Changeset 24120 in vbox for trunk


Ignore:
Timestamp:
Oct 27, 2009 9:46:51 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
54027
Message:

#3987: Virtio: Save/restore state.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DevVirtioNet.cpp

    r23979 r24120  
    114114    uint16_t uNextAvailIndex;
    115115    uint16_t uNextUsedIndex;
    116     uint16_t uPageNumber;
     116    uint32_t uPageNumber;
    117117    void   (*pfnCallback)(void *pvState, struct VQueue *pQueue);
    118118};
     
    499499}
    500500
    501 /**
    502  * Arm a timer.
    503  *
    504  * @param   pState      Pointer to the device state structure.
    505  * @param   pTimer      Pointer to the timer.
    506  * @param   uExpireIn   Expiration interval in microseconds.
    507  */
    508 DECLINLINE(void) vpciArmTimer(VPCISTATE *pState, PTMTIMER pTimer, uint32_t uExpireIn)
    509 {
    510     Log2(("%s Arming timer to fire in %d usec...\n",
    511           INSTANCE(pState), uExpireIn));
    512     TMTimerSet(pTimer, TMTimerFromMicro(pTimer, uExpireIn) +
    513                TMTimerGet(pTimer));
    514 }
    515 
    516501
    517502DECLINLINE(int) vpciCsEnter(VPCISTATE *pState, int iBusyRc)
     
    904889
    905890
     891#ifdef DEBUG
     892static void vpciDumpState(PVPCISTATE pState, const char *pcszCaller)
     893{
     894    Log2(("vpciDumpState: (called from %s)\n"
     895          "  uGuestFeatures = 0x%08x\n"
     896          "  uQueueSelector = 0x%04x\n"
     897          "  uStatus        = 0x%02x\n"
     898          "  uISR           = 0x%02x\n",
     899          pcszCaller,
     900          pState->uGuestFeatures,
     901          pState->uQueueSelector,
     902          pState->uStatus,
     903          pState->uISR));
     904
     905    for (unsigned i = 0; i < g_VPCIDevices[pState->enmDevType].nQueues; i++)
     906        Log2((" %s queue:\n"
     907              "  VRing.uSize           = %u\n"
     908              "  VRing.addrDescriptors = %p\n"
     909              "  VRing.addrAvail       = %p\n"
     910              "  VRing.addrUsed        = %p\n"
     911              "  uNextAvailIndex       = %u\n"
     912              "  uNextUsedIndex        = %u\n"
     913              "  uPageNumber           = %x\n",
     914              g_VPCIDevices[pState->enmDevType].pfnGetQueueName(pState, &pState->pQueues[i]),
     915              pState->pQueues[i].VRing.uSize,
     916              pState->pQueues[i].VRing.addrDescriptors,
     917              pState->pQueues[i].VRing.addrAvail,
     918              pState->pQueues[i].VRing.addrUsed,
     919              pState->pQueues[i].uNextAvailIndex,
     920              pState->pQueues[i].uNextUsedIndex,
     921              pState->pQueues[i].uPageNumber));
     922             
     923}
     924#else
     925#define vpciDumpState(x, s)
     926#endif
     927
     928/**
     929 * Saves the state of device.
     930 *
     931 * @returns VBox status code.
     932 * @param   pDevIns     The device instance.
     933 * @param   pSSM        The handle to the saved state.
     934 */
     935static DECLCALLBACK(int) vpciSaveExec(PVPCISTATE pState, PSSMHANDLE pSSM)
     936{
     937    int rc;
     938
     939    vpciDumpState(pState, "vpciSaveExec");
     940
     941    rc = SSMR3PutU32(pSSM, pState->uGuestFeatures);
     942    AssertRCReturn(rc, rc);
     943    rc = SSMR3PutU16(pSSM, pState->uQueueSelector);
     944    AssertRCReturn(rc, rc);
     945    rc = SSMR3PutU8( pSSM, pState->uStatus);
     946    AssertRCReturn(rc, rc);
     947    rc = SSMR3PutU8( pSSM, pState->uISR);
     948    AssertRCReturn(rc, rc);
     949
     950    /* Save queue states */
     951    for (unsigned i = 0; i < g_VPCIDevices[pState->enmDevType].nQueues; i++)
     952    {
     953        rc = SSMR3PutU16(pSSM, pState->pQueues[i].VRing.uSize);
     954        AssertRCReturn(rc, rc);
     955        rc = SSMR3PutU32(pSSM, pState->pQueues[i].uPageNumber);
     956        AssertRCReturn(rc, rc);
     957        rc = SSMR3PutU16(pSSM, pState->pQueues[i].uNextAvailIndex);
     958        AssertRCReturn(rc, rc);
     959        rc = SSMR3PutU16(pSSM, pState->pQueues[i].uNextUsedIndex);
     960        AssertRCReturn(rc, rc);
     961    }
     962
     963    return VINF_SUCCESS;
     964}
     965
     966/**
     967 * Loads a saved device state.
     968 *
     969 * @returns VBox status code.
     970 * @param   pDevIns     The device instance.
     971 * @param   pSSM        The handle to the saved state.
     972 * @param   uVersion    The data unit version number.
     973 * @param   uPass       The data pass.
     974 */
     975static DECLCALLBACK(int) vpciLoadExec(PVPCISTATE pState, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
     976{
     977    int rc;
     978
     979    if (uPass == SSM_PASS_FINAL)
     980    {
     981        /* Restore state data */
     982        rc = SSMR3GetU32(pSSM, &pState->uGuestFeatures);
     983        AssertRCReturn(rc, rc);
     984        rc = SSMR3GetU16(pSSM, &pState->uQueueSelector);
     985        AssertRCReturn(rc, rc);
     986        rc = SSMR3GetU8( pSSM, &pState->uStatus);
     987        AssertRCReturn(rc, rc);
     988        rc = SSMR3GetU8( pSSM, &pState->uISR);
     989        AssertRCReturn(rc, rc);
     990
     991        /* Restore queues */
     992        for (unsigned i = 0; i < g_VPCIDevices[pState->enmDevType].nQueues; i++)
     993        {
     994            rc = SSMR3GetU16(pSSM, &pState->pQueues[i].VRing.uSize);
     995            AssertRCReturn(rc, rc);
     996            rc = SSMR3GetU32(pSSM, &pState->pQueues[i].uPageNumber);
     997            AssertRCReturn(rc, rc);
     998
     999            if (pState->pQueues[i].uPageNumber)
     1000                vqueueInit(&pState->pQueues[i], pState->pQueues[i].uPageNumber);
     1001
     1002            rc = SSMR3GetU16(pSSM, &pState->pQueues[i].uNextAvailIndex);
     1003            AssertRCReturn(rc, rc);
     1004            rc = SSMR3GetU16(pSSM, &pState->pQueues[i].uNextUsedIndex);
     1005            AssertRCReturn(rc, rc);
     1006        }
     1007    }
     1008
     1009    vpciDumpState(pState, "vpciLoadExec");
     1010
     1011    return VINF_SUCCESS;
     1012}
     1013
    9061014/**
    9071015 * Set PCI configuration space registers.
     
    11251233    /** PCI config area holding MAC address as well as TBD. */
    11261234    struct VNetPCIConfig config;
     1235    /** MAC address obtained from the configuration. */
     1236    RTMAC       macConfigured;
    11271237    /** True if physical cable is attached in configuration. */
    11281238    bool        fCableConnected;
     
    11981308#endif /* DEBUG */
    11991309
     1310DECLINLINE(int) vnetCsEnter(PVNETSTATE pState, int rcBusy)
     1311{
     1312    return vpciCsEnter(&pState->VPCI, rcBusy);
     1313}
     1314
     1315DECLINLINE(void) vnetCsLeave(PVNETSTATE pState)
     1316{
     1317    vpciCsLeave(&pState->VPCI);
     1318}
     1319
     1320
    12001321PDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pvState)
    12011322{
     
    12831404    STATUS |= VNET_S_LINK_UP;
    12841405    vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
     1406    vnetWakeupReceive(pDevIns);
    12851407}
    12861408
     
    13301452 * @returns VERR_NET_NO_BUFFER_SPACE if it cannot.
    13311453 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1332  * @thread  EMT
     1454 * @thread  RX
    13331455 */
    13341456static int vnetCanReceive(VNETSTATE *pState)
    13351457{
    1336     int rc;
     1458    int rc = vpciCsEnter(&pState->VPCI, VERR_SEM_BUSY);
    13371459    LogFlow(("%s vnetCanReceive\n", INSTANCE(pState)));
    13381460    if (!(pState->VPCI.uStatus & VPCI_STATUS_DRV_OK))
     
    13521474
    13531475    LogFlow(("%s vnetCanReceive -> %Vrc\n", INSTANCE(pState), rc));
     1476    vpciCsLeave(&pState->VPCI);
    13541477    return rc;
    13551478}
     
    14401563 * @param   pvBuf           The available data.
    14411564 * @param   cb              Number of bytes available in the buffer.
     1565 * @thread  RX
    14421566 */
    14431567static int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb)
     
    15001624 * @param   pvBuf           The available data.
    15011625 * @param   cb              Number of bytes available in the buffer.
    1502  * @thread  ???
     1626 * @thread  RX
    15031627 */
    15041628static DECLCALLBACK(int) vnetReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
     
    16571781}
    16581782
     1783/**
     1784 * Saves the configuration.
     1785 *
     1786 * @param   pState      The VNET state.
     1787 * @param   pSSM        The handle to the saved state.
     1788 */
     1789static void vnetSaveConfig(VNETSTATE *pState, PSSMHANDLE pSSM)
     1790{
     1791    SSMR3PutMem(pSSM, &pState->macConfigured, sizeof(pState->macConfigured));
     1792}
     1793
     1794/**
     1795 * Live save - save basic configuration.
     1796 *
     1797 * @returns VBox status code.
     1798 * @param   pDevIns     The device instance.
     1799 * @param   pSSM        The handle to the saved state.
     1800 * @param   uPass
     1801 */
     1802static DECLCALLBACK(int) vnetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
     1803{
     1804    VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
     1805    vnetSaveConfig(pState, pSSM);
     1806    return VINF_SSM_DONT_CALL_AGAIN;
     1807}
     1808
     1809/**
     1810 * Prepares for state saving.
     1811 *
     1812 * @returns VBox status code.
     1813 * @param   pDevIns     The device instance.
     1814 * @param   pSSM        The handle to the saved state.
     1815 */
     1816static DECLCALLBACK(int) vnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     1817{
     1818    VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
     1819
     1820    int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
     1821    if (RT_UNLIKELY(rc != VINF_SUCCESS))
     1822        return rc;
     1823    vnetCsLeave(pState);
     1824    return VINF_SUCCESS;
     1825}
     1826
     1827/**
     1828 * Saves the state of device.
     1829 *
     1830 * @returns VBox status code.
     1831 * @param   pDevIns     The device instance.
     1832 * @param   pSSM        The handle to the saved state.
     1833 */
     1834static DECLCALLBACK(int) vnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     1835{
     1836    VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
     1837
     1838    /* Save config first */
     1839    vnetSaveConfig(pState, pSSM);
     1840
     1841    /* Save the common part */
     1842    int rc = vpciSaveExec(&pState->VPCI, pSSM);
     1843    AssertRCReturn(rc, rc);
     1844    /* Save device-specific part */
     1845    rc = SSMR3PutMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
     1846    AssertRCReturn(rc, rc);
     1847    Log(("%s State has been saved\n", INSTANCE(pState)));
     1848    return VINF_SUCCESS;
     1849}
     1850
     1851
     1852/**
     1853 * Serializes the receive thread, it may be working inside the critsect.
     1854 *
     1855 * @returns VBox status code.
     1856 * @param   pDevIns     The device instance.
     1857 * @param   pSSM        The handle to the saved state.
     1858 */
     1859static DECLCALLBACK(int) vnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     1860{
     1861    VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
     1862
     1863    int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
     1864    if (RT_UNLIKELY(rc != VINF_SUCCESS))
     1865        return rc;
     1866    vnetCsLeave(pState);
     1867    return VINF_SUCCESS;
     1868}
     1869
     1870/* Takes down the link temporarily if it's current status is up.
     1871 *
     1872 * This is used during restore and when replumbing the network link.
     1873 *
     1874 * The temporary link outage is supposed to indicate to the OS that all network
     1875 * connections have been lost and that it for instance is appropriate to
     1876 * renegotiate any DHCP lease.
     1877 *
     1878 * @param  pThis        The PCNet instance data.
     1879 */
     1880static void vnetTempLinkDown(PVNETSTATE pState)
     1881{
     1882    if (STATUS & VNET_S_LINK_UP)
     1883    {
     1884        STATUS &= ~VNET_S_LINK_UP;
     1885        vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
     1886        /* Restore the link back in 5 seconds. */
     1887        int rc = TMTimerSetMillies(pState->pLinkUpTimer, 5000);
     1888        AssertRC(rc);
     1889    }
     1890}
     1891
     1892
     1893/**
     1894 * Restore previously saved state of device.
     1895 *
     1896 * @returns VBox status code.
     1897 * @param   pDevIns     The device instance.
     1898 * @param   pSSM        The handle to the saved state.
     1899 * @param   uVersion    The data unit version number.
     1900 * @param   uPass       The data pass.
     1901 */
     1902static DECLCALLBACK(int) vnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
     1903{
     1904    VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
     1905    int       rc;
     1906
     1907    /* config checks */
     1908    RTMAC macConfigured;
     1909    rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
     1910    AssertRCReturn(rc, rc);
     1911    if (   memcmp(&macConfigured, &pState->macConfigured, sizeof(macConfigured))
     1912           && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
     1913        LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
     1914
     1915    rc = vpciLoadExec(&pState->VPCI, pSSM, uVersion, uPass);
     1916    AssertRCReturn(rc, rc);
     1917
     1918    if (uPass == SSM_PASS_FINAL)
     1919    {
     1920        rc = SSMR3GetMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
     1921        AssertRCReturn(rc, rc);
     1922        /* Indicate link down to the guest OS that all network connections have
     1923           been lost, unless we've been teleported here. */
     1924        if (!PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
     1925            vnetTempLinkDown(pState);
     1926    }
     1927
     1928    return rc;
     1929}
    16591930
    16601931/**
     
    16961967
    16971968    /* Get config params */
    1698     rc = CFGMR3QueryBytes(pCfgHandle, "MAC", pState->config.mac.au8,
    1699                           sizeof(pState->config.mac.au8));
     1969    rc = CFGMR3QueryBytes(pCfgHandle, "MAC", pState->macConfigured.au8,
     1970                          sizeof(pState->macConfigured));
    17001971    if (RT_FAILURE(rc))
    17011972        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    17061977                                N_("Configuration error: Failed to get the value of 'CableConnected'"));
    17071978
     1979    /* Initialize PCI config space */
     1980    memcpy(pState->config.mac.au8, pState->macConfigured.au8, sizeof(pState->config.mac.au8));
     1981    pState->config.uStatus = 0;
     1982
    17081983    /* Initialize state structure */
    17091984    pState->fLocked      = false;
     
    17181993
    17191994    /* Register save/restore state handlers. */
    1720     // TODO:
    1721     /*
    1722     rc = PDMDevHlpSSMRegisterEx(pDevIns, VVNET_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
    1723                                 NULL, NULL, NULL,
    1724                                 NULL, vnetSaveExec, NULL,
    1725                                 NULL, vnetLoadExec, vnetLoadDone);
     1995    rc = PDMDevHlpSSMRegisterEx(pDevIns, VNET_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
     1996                                NULL,         vnetLiveExec, NULL,
     1997                                vnetSavePrep, vnetSaveExec, NULL,
     1998                                vnetLoadPrep, vnetLoadExec, NULL);
    17261999    if (RT_FAILURE(rc))
    1727     return rc;*/
     2000    return rc;
    17282001
    17292002    /* Create the RX notifier signaller. */
     
    19242197     * network card
    19252198     */
    1926     if ((STATUS & VNET_S_LINK_UP) && RT_SUCCESS(rc))
    1927     {
    1928         STATUS &= ~VNET_S_LINK_UP;
    1929         vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
    1930         /* Restore the link back in 5 seconds. */
    1931         vpciArmTimer(&pState->VPCI, pState->pLinkUpTimer, 5000000);
    1932     }
     2199    if (RT_SUCCESS(rc))
     2200        vnetTempLinkDown(pState);
    19332201
    19342202    vpciCsLeave(&pState->VPCI);
Note: See TracChangeset for help on using the changeset viewer.

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