VirtualBox

Changeset 65301 in vbox for trunk


Ignore:
Timestamp:
Jan 15, 2017 6:07:07 PM (8 years ago)
Author:
vboxsync
Message:

PCI: Save and restore I/O region sizes and types so we can callback devices to deal with changes.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/pdmpcidev.h

    r64455 r65301  
    8181 * @param   pDevIns         Pointer to the device instance the PCI device
    8282 *                          belongs to.
    83  * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
     83 * @param   pPciDev         Pointer to the PCI device.
    8484 * @param   iRegion         The region number.
    8585 * @param   GCPhysAddress   Physical address of the region. If enmType is PCI_ADDRESS_SPACE_IO, this
     
    100100/** Pointer to a FNPCIIOREGIONMAP() function. */
    101101typedef FNPCIIOREGIONMAP *PFNPCIIOREGIONMAP;
     102
     103
     104/**
     105 * Sets the size and type for old saved states from within a
     106 * PDMPCIDEV::pfnRegionLoadChangeHookR3 callback.
     107 *
     108 * @returns VBox status code.
     109 * @param   pPciDev         Pointer to the PCI device.
     110 * @param   iRegion         The region number.
     111 * @param   cbRegion        The region size.
     112 * @param   enmType         Combination of the PCI_ADDRESS_SPACE_* values.
     113 */
     114typedef DECLCALLBACK(int) FNPCIIOREGIONOLDSETTER(PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion, PCIADDRESSSPACE enmType);
     115/** Pointer to a FNPCIIOREGIONOLDSETTER() function. */
     116typedef FNPCIIOREGIONOLDSETTER *PFNPCIIOREGIONOLDSETTER;
     117
    102118
    103119
     
    142158    /** Device name. */
    143159    R3PTRTYPE(const char *) pszNameR3;
    144     /** Reserved. */
    145     RTR3PTR                 pvReserved;
    146160    /** @} */
     161
     162    /**
     163     * Callback for dealing with size changes.
     164     *
     165     * This is set by the PCI device when needed.  It is only needed if any changes
     166     * in the PCI resources have been made that may be incompatible with saved state
     167     * (i.e. does not reflect configuration, but configuration defaults changed).
     168     *
     169     * The implementation can use PDMDevHlpMMIOExReduce to adjust the resource
     170     * allocation down in size.  There is currently no way of growing resources.
     171     * Dropping a resource is automatic.
     172     *
     173     * @returns VBox status code.
     174     * @param   pDevIns         Pointer to the device instance the PCI device
     175     *                          belongs to.
     176     * @param   pPciDev         Pointer to the PCI device.
     177     * @param   iRegion         The region number or UINT32_MAX if old saved state call.
     178     * @param   cbRegion        The size being loaded, RTGCPHYS_MAX if old saved state
     179     *                          call, or 0 for dummy 64-bit top half region.
     180     * @param   enmType         The type being loaded, -1 if old saved state call, or
     181     *                          0xff if dummy 64-bit top half region.
     182     * @param   pfnOldSetter    Callback for setting size and type for call
     183     *                          regarding old saved states.  NULL otherwise.
     184     */
     185    DECLR3CALLBACKMEMBER(int, pfnRegionLoadChangeHookR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
     186                                                         uint64_t cbRegion, PCIADDRESSSPACE enmType,
     187                                                         PFNPCIIOREGIONOLDSETTER pfnOldSetter));
    147188} PDMPCIDEV;
    148189#ifdef PDMPCIDEVINT_DECLARED
  • trunk/src/VBox/Devices/Bus/DevPCI.cpp

    r65283 r65301  
    6868*   Defined Constants And Macros                                                                                                 *
    6969*********************************************************************************************************************************/
    70 /** @def VBOX_PCI_SAVED_STATE_VERSION
    71  * Saved state version of the PCI bus device.
    72  */
    73 #define VBOX_PCI_SAVED_STATE_VERSION 3
     70/** Saved state version of the PCI bus device. */
     71#define VBOX_PCI_SAVED_STATE_VERSION                VBOX_PCI_SAVED_STATE_VERSION_REGION_SIZES
     72/** Adds I/O region types and sizes for dealing changes in resource regions. */
     73#define VBOX_PCI_SAVED_STATE_VERSION_REGION_SIZES   4
     74/** Before region sizes, the first named one.
     75 * Looking at the code though, we support even older version.  */
     76#define VBOX_PCI_SAVED_STATE_VERSION_IRQ_STATES     3
     77/** Notes whether we use the I/O APIC. */
     78#define VBOX_PCI_SAVED_STATE_VERSION_USE_IO_APIC    2
    7479
    7580
     
    886891            SSMR3PutMem(pSSM, pDev->abConfig, sizeof(pDev->abConfig));
    887892
    888             int rc = SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
    889             if (RT_FAILURE(rc))
    890                 return rc;
     893            SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
     894
     895            /* Save the type an size of all the regions. */
     896            for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
     897            {
     898                SSMR3PutU8(pSSM, pDev->Int.s.aIORegions[iRegion].type);
     899                SSMR3PutU64(pSSM, pDev->Int.s.aIORegions[iRegion].size);
     900            }
    891901        }
    892902    }
     
    971981    for (i = 0;; i++)
    972982    {
    973         PDMPCIDEV   DevTmp;
    974         PPDMPCIDEV  pDev;
    975 
    976983        /* index / terminator */
    977984        rc = SSMR3GetU32(pSSM, &u32);
    978985        if (RT_FAILURE(rc))
    979986            return rc;
    980         if (u32 == (uint32_t)~0)
     987        if (u32 == UINT32_MAX)
    981988            break;
    982989        if (    u32 >= RT_ELEMENTS(pBus->apDevices)
     
    10011008
    10021009        /* get the data */
     1010        PDMPCIDEV DevTmp;
     1011        RT_ZERO(DevTmp);
    10031012        DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
    10041013        SSMR3GetMem(pSSM, DevTmp.abConfig, sizeof(DevTmp.abConfig));
    1005         if (uVersion < 3)
     1014        if (uVersion < VBOX_PCI_SAVED_STATE_VERSION_IRQ_STATES)
    10061015        {
    10071016            int32_t i32Temp;
     
    10181027        }
    10191028
     1029        /* Load the region types and sizes. */
     1030        if (uVersion >= VBOX_PCI_SAVED_STATE_VERSION_REGION_SIZES)
     1031        {
     1032            for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
     1033            {
     1034                SSMR3GetU8(pSSM, &DevTmp.Int.s.aIORegions[iRegion].type);
     1035                rc = SSMR3GetU64(pSSM, &DevTmp.Int.s.aIORegions[iRegion].size);
     1036                AssertLogRelRCReturn(rc, rc);
     1037            }
     1038        }
     1039
    10201040        /* check that it's still around. */
    1021         pDev = pBus->apDevices[i];
     1041        PPDMPCIDEV pDev = pBus->apDevices[i];
    10221042        if (!pDev)
    10231043        {
     
    10331053        if (   DevTmp.abConfig[0] != pDev->abConfig[0]
    10341054            || DevTmp.abConfig[1] != pDev->abConfig[1])
    1035             return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
     1055            return SSMR3SetCfgError(pSSM, RT_SRC_POS,
     1056                                    N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
    10361057                                    i, pDev->pszNameR3, DevTmp.abConfig, pDev->abConfig);
    10371058
    10381059        /* commit the loaded device config. */
     1060        rc = devpciR3CommonRestoreRegions(pSSM, pDev, DevTmp.Int.s.aIORegions,
     1061                                          uVersion >= VBOX_PCI_SAVED_STATE_VERSION_REGION_SIZES);
     1062        if (RT_FAILURE(rc))
     1063            break;
    10391064        devpciR3CommonRestoreConfig(pDev, &DevTmp.abConfig[0]);
    10401065
     
    10671092     */
    10681093    SSMR3GetU32(pSSM, &pThis->uConfigReg);
    1069     if (uVersion > 1)
     1094    if (uVersion >= VBOX_PCI_SAVED_STATE_VERSION_USE_IO_APIC)
    10701095        SSMR3GetBool(pSSM, &pThis->fUseIoApic);
    10711096
    10721097    /* Load IRQ states. */
    1073     if (uVersion > 2)
     1098    if (uVersion >= VBOX_PCI_SAVED_STATE_VERSION_IRQ_STATES)
    10741099    {
    10751100        for (uint8_t i = 0; i < RT_ELEMENTS(pThis->Piix3.auPciLegacyIrqLevels); i++)
     
    10861111    if (RT_FAILURE(rc))
    10871112        return rc;
    1088     if (u32 != (uint32_t)~0)
     1113    if (u32 != UINT32_MAX)
    10891114        AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
    10901115
  • trunk/src/VBox/Devices/Bus/DevPciIch9.cpp

    r65292 r65301  
    7474*   Defined Constants And Macros                                                                                                 *
    7575*********************************************************************************************************************************/
    76 /** @def VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT
    77  * Saved state version of the ICH9 PCI bus device.
    78  */
    79 #define VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI 1
    80 #define VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI   2
    81 #define VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI
     76/** Saved state version of the ICH9 PCI bus device. */
     77#define VBOX_ICH9PCI_SAVED_STATE_VERSION                VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES
     78/** Adds I/O region types and sizes for dealing changes in resource regions. */
     79#define VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES   3
     80/** This appears to be the first state we need to care about. */
     81#define VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI            2
     82/** This is apparently not supported or has a grossly incomplete state, juding
     83 * from hints in the code. */
     84#define VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI          1
    8285
    8386/** Invalid PCI region mapping address. */
     
    918921            if (RT_FAILURE(rc))
    919922                return rc;
     923
    920924            /* Save MSI-X page state */
    921925            if (pDev->Int.s.u8MsixCapOffset != 0)
     
    925929                if (RT_FAILURE(rc))
    926930                    return rc;
     931            }
     932
     933            /* Save the type an size of all the regions. */
     934            for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
     935            {
     936                SSMR3PutU8(pSSM, pDev->Int.s.aIORegions[iRegion].type);
     937                rc = SSMR3PutU64(pSSM, pDev->Int.s.aIORegions[iRegion].size);
     938                AssertRCReturn(rc, rc);
    927939            }
    928940        }
     
    11981210}
    11991211
     1212
     1213/**
     1214 * @callback_method_impl{FNPCIIOREGIONOLDSETTER}
     1215 */
     1216static DECLCALLBACK(int) devpciR3CommonRestoreOldSetRegion(PPDMPCIDEV pPciDev, uint32_t iRegion,
     1217                                                           RTGCPHYS cbRegion, PCIADDRESSSPACE enmType)
     1218{
     1219    AssertLogRelReturn(iRegion < RT_ELEMENTS(pPciDev->Int.s.aIORegions), VERR_INVALID_PARAMETER);
     1220    pPciDev->Int.s.aIORegions[iRegion].type = enmType;
     1221    pPciDev->Int.s.aIORegions[iRegion].size = cbRegion;
     1222    return VINF_SUCCESS;
     1223}
     1224
     1225
     1226/**
     1227 * Checks for and deals with changes in resource sizes and types.
     1228 *
     1229 * @returns VBox status code.
     1230 * @param   pSSM                The Saved state handle.
     1231 * @param   pPciDev             The PCI device in question.
     1232 * @param   paIoRegions         I/O regions with the size and type fields from
     1233 *                              the saved state.
     1234 * @param   fNewState           Set if this is a new state with I/O region sizes
     1235 *                              and types, clear if old one.
     1236 */
     1237int devpciR3CommonRestoreRegions(PSSMHANDLE pSSM, PPDMPCIDEV pPciDev, PPCIIOREGION paIoRegions, bool fNewState)
     1238{
     1239    int rc;
     1240    if (fNewState)
     1241    {
     1242        for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
     1243        {
     1244            if (   pPciDev->Int.s.aIORegions[iRegion].type != paIoRegions[iRegion].type
     1245                || pPciDev->Int.s.aIORegions[iRegion].size != paIoRegions[iRegion].size)
     1246            {
     1247                AssertLogRelMsgFailed(("PCI: %8s/%u: region #%u size/type load change: %#RGp/%#x -> %#RGp/%#x\n",
     1248                                       pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance,
     1249                                       pPciDev->Int.s.aIORegions[iRegion].size, pPciDev->Int.s.aIORegions[iRegion].type,
     1250                                       paIoRegions[iRegion].size, paIoRegions[iRegion].type));
     1251                if (pPciDev->pfnRegionLoadChangeHookR3)
     1252                {
     1253                    rc = pPciDev->pfnRegionLoadChangeHookR3(pPciDev->Int.s.pDevInsR3, pPciDev, iRegion, paIoRegions[iRegion].size,
     1254                                                            (PCIADDRESSSPACE)paIoRegions[iRegion].type, NULL /*pfnOldSetter*/);
     1255                    if (RT_FAILURE(rc))
     1256                        return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
     1257                                                 N_("Device %s/%u failed to respond to region #%u size/type changing from %#RGp/%#x to %#RGp/%#x: %Rrc"),
     1258                                                 pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, iRegion,
     1259                                                 pPciDev->Int.s.aIORegions[iRegion].size, pPciDev->Int.s.aIORegions[iRegion].type,
     1260                                                 paIoRegions[iRegion].size, paIoRegions[iRegion].type, rc);
     1261                }
     1262                pPciDev->Int.s.aIORegions[iRegion].type = paIoRegions[iRegion].type;
     1263                pPciDev->Int.s.aIORegions[iRegion].size = paIoRegions[iRegion].size;
     1264            }
     1265        }
     1266    }
     1267    /* Old saved state without sizes and types.  Do a special hook call to give
     1268       devices with changes a chance to adjust resources back to old values. */
     1269    else if (pPciDev->pfnRegionLoadChangeHookR3)
     1270    {
     1271        rc = pPciDev->pfnRegionLoadChangeHookR3(pPciDev->Int.s.pDevInsR3, pPciDev, UINT32_MAX, RTGCPHYS_MAX, (PCIADDRESSSPACE)-1,
     1272                                                devpciR3CommonRestoreOldSetRegion);
     1273        if (RT_FAILURE(rc))
     1274            return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,  N_("Device %s/%u failed to resize its resources: %Rrc"),
     1275                                     pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, rc);
     1276    }
     1277    return VINF_SUCCESS;
     1278}
     1279
     1280
    12001281/**
    12011282 * Common worker for ich9pciR3LoadExec and ich9pcibridgeR3LoadExec.
     
    12141295
    12151296    Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
    1216     if (uVersion != VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT)
     1297    if (   uVersion < VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI
     1298        || uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION)
    12171299        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    12181300
     
    12481330    for (i = 0;; i++)
    12491331    {
    1250         PPDMPCIDEV  pDev;
    1251         PDMPCIDEV   DevTmp;
    1252 
    12531332        /* index / terminator */
    12541333        rc = SSMR3GetU32(pSSM, &u32);
     
    12601339
    12611340        /* skip forward to the device checking that no new devices are present. */
     1341        PPDMPCIDEV pDev;
    12621342        for (; i < u32; i++)
    12631343        {
     
    12811361
    12821362        /* get the data */
     1363        PDMPCIDEV DevTmp;
     1364        RT_ZERO(DevTmp);
    12831365        DevTmp.Int.s.fFlags = 0;
    12841366        DevTmp.Int.s.u8MsiCapOffset = 0;
     
    13071389        }
    13081390
    1309         /* check that it's still around. */
     1391        /* Load the region types and sizes. */
     1392        if (uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES)
     1393        {
     1394            for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
     1395            {
     1396                SSMR3GetU8(pSSM, &DevTmp.Int.s.aIORegions[iRegion].type);
     1397                rc = SSMR3GetU64(pSSM, &DevTmp.Int.s.aIORegions[iRegion].size);
     1398                AssertLogRelRCReturn(rc, rc);
     1399            }
     1400        }
     1401
     1402        /*
     1403         * Check that it's still around.
     1404         */
    13101405        pDev = pBus->apDevices[i];
    13111406        if (!pDev)
     
    13351430
    13361431        /* commit the loaded device config. */
     1432        rc = devpciR3CommonRestoreRegions(pSSM, pDev, DevTmp.Int.s.aIORegions,
     1433                                          uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES);
     1434        if (RT_FAILURE(rc))
     1435            break;
    13371436        Assert(!pciDevIsPassthrough(pDev));
    13381437        devpciR3CommonRestoreConfig(pDev, &DevTmp.abConfig[0]);
     
    13631462
    13641463    /* We ignore this version as there's no saved state with it anyway */
    1365     if (uVersion == VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI)
     1464    if (uVersion <= VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI)
    13661465        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    1367     if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
     1466    if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION)
    13681467        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    13691468
     
    13921491{
    13931492    PDEVPCIBUS pThis = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
    1394     if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
    1395         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    13961493    return ich9pciR3CommonLoadExec(pThis, pSSM, uVersion, uPass);
    13971494}
     
    27302827    }
    27312828
    2732     rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
     2829    rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
    27332830                                sizeof(*pBus) + 16*128, "pgm",
    27342831                                NULL, NULL, NULL,
     
    29723069     * to make changes easier.
    29733070     */
    2974     rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
     3071    rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
    29753072                                sizeof(*pBus) + 16*128,
    29763073                                "pgm" /* before */,
  • trunk/src/VBox/Devices/Bus/DevPciInternal.h

    r65283 r65301  
    194194                                                        uint32_t uAddress, uint32_t u32Value, unsigned cb);
    195195void devpciR3CommonRestoreConfig(PPDMPCIDEV pDev, uint8_t const *pbSrcConfig);
     196int  devpciR3CommonRestoreRegions(PSSMHANDLE pSSM, PPDMPCIDEV pPciDev, PPCIIOREGION paIoRegions, bool fNewState);
    196197
    197198#endif
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r65294 r65301  
    148148    GEN_CHECK_OFF(PDMPCIDEV, uDevFn);
    149149    GEN_CHECK_OFF(PDMPCIDEV, pszNameR3);
    150     GEN_CHECK_OFF(PDMPCIDEV, pvReserved);
     150    GEN_CHECK_OFF(PDMPCIDEV, pfnRegionLoadChangeHookR3);
    151151    GEN_CHECK_OFF(PDMPCIDEV, Int);
    152152    GEN_CHECK_OFF(PDMPCIDEV, Int.s.aIORegions);
Note: See TracChangeset for help on using the changeset viewer.

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