Index: /trunk/include/VBox/err.h
===================================================================
--- /trunk/include/VBox/err.h	(revision 65298)
+++ /trunk/include/VBox/err.h	(revision 65299)
@@ -1720,4 +1720,6 @@
 /** The display connector is resizing. */
 #define VINF_VGA_RESIZE_IN_PROGRESS                 (3501)
+/** Unexpected PCI region change during VGA saved state loading. */
+#define VERR_VGA_UNEXPECTED_PCI_REGION_LOAD_CHANGE  (-3502)
 /** @} */
 
Index: /trunk/include/VBox/vmm/pdmdev.h
===================================================================
--- /trunk/include/VBox/vmm/pdmdev.h	(revision 65298)
+++ /trunk/include/VBox/vmm/pdmdev.h	(revision 65299)
@@ -1876,6 +1876,7 @@
 
 /** Current PDMDEVHLPR3 version number.
- * @todo Next major revision should add piBus to pfnPCIBusRegister.  */
-#define PDM_DEVHLPR3_VERSION                    PDM_VERSION_MAKE_PP(0xffe7, 19, 1)
+ * @todo Next major revision should add piBus to pfnPCIBusRegister, and move
+ *       pfnMMIOExReduce up to after pfnMMIOExUnmap. */
+#define PDM_DEVHLPR3_VERSION                    PDM_VERSION_MAKE_PP(0xffe7, 19, 2)
 //#define PDM_DEVHLPR3_VERSION                    PDM_VERSION_MAKE_PP(0xffe7, 20, 0)
 
@@ -3265,7 +3266,26 @@
     DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMDEVINS pDevIns));
 
+    /**
+     * Reduces the length of a MMIO2 or pre-registered MMIO range.
+     *
+     * This is for implementations of PDMPCIDEV::pfnRegionLoadChangeHookR3 and will
+     * only work during saved state restore.  It will not call the PCI bus code, as
+     * that is expected to restore the saved resource configuration.
+     *
+     * It just adjusts the mapping length of the region so that when pfnMMIOExMap is
+     * called it will only map @a cbRegion bytes and not the value set during
+     * registration.
+     *
+     * @return VBox status code.
+     * @param   pDevIns             The device owning the range.
+     * @param   pPciDev             The PCI device the region is associated with, or
+     *                              NULL if not associated with any.
+     * @param   iRegion             The region.
+     * @param   cbRegion            The new size, must be smaller.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnMMIOExReduce,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion));
+
     /** Space reserved for future members.
      * @{ */
-    DECLR3CALLBACKMEMBER(void, pfnReserved1,(void));
     DECLR3CALLBACKMEMBER(void, pfnReserved2,(void));
     DECLR3CALLBACKMEMBER(void, pfnReserved3,(void));
@@ -4384,4 +4404,12 @@
 {
     return pDevIns->pHlpR3->pfnMMIOExUnmap(pDevIns, pPciDev, iRegion, GCPhys);
+}
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIOExReduce
+ */
+DECLINLINE(int) PDMDevHlpMMIOExReduce(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion)
+{
+    return pDevIns->pHlpR3->pfnMMIOExReduce(pDevIns, pPciDev, iRegion, cbRegion);
 }
 
Index: /trunk/include/VBox/vmm/pgm.h
===================================================================
--- /trunk/include/VBox/vmm/pgm.h	(revision 65298)
+++ /trunk/include/VBox/vmm/pgm.h	(revision 65299)
@@ -747,4 +747,5 @@
 VMMR3DECL(int)      PGMR3PhysMMIOExMap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS GCPhys);
 VMMR3DECL(int)      PGMR3PhysMMIOExUnmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS GCPhys);
+VMMR3_INT_DECL(int) PGMR3PhysMMIOExReduce(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cbRegion);
 VMMR3DECL(bool)     PGMR3PhysMMIOExIsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys);
 VMMR3_INT_DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys);
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 65298)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevHlp.cpp	(revision 65299)
@@ -591,4 +591,22 @@
 
     LogFlow(("pdmR3DevHlp_MMIOExUnmap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIOExReduce
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIOExReduce(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VM_ASSERT_EMT(pDevIns->Internal.s.pVMR3);
+    LogFlow(("pdmR3DevHlp_MMIOExReduce: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x cbRegion=%RGp\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, cbRegion));
+    AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 != NULL, VERR_INVALID_PARAMETER);
+
+    int rc = PGMR3PhysMMIOExReduce(pDevIns->Internal.s.pVMR3, pDevIns, pPciDev ? pPciDev->Int.s.idxDevCfg : 254, iRegion, cbRegion);
+
+    LogFlow(("pdmR3DevHlp_MMIOExReduce: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
     return rc;
 }
@@ -3678,5 +3696,5 @@
     pdmR3DevHlp_VMGetSuspendReason,
     pdmR3DevHlp_VMGetResumeReason,
-    0,
+    pdmR3DevHlp_MMIOExReduce,
     0,
     0,
@@ -3935,5 +3953,5 @@
     pdmR3DevHlp_VMGetSuspendReason,
     pdmR3DevHlp_VMGetResumeReason,
-    0,
+    pdmR3DevHlp_MMIOExReduce,
     0,
     0,
Index: /trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp	(revision 65298)
+++ /trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp	(revision 65299)
@@ -2698,5 +2698,5 @@
         pNew->RamRange.GCPhysLast   = NIL_RTGCPHYS;
         pNew->RamRange.pszDesc      = pszDesc;
-        pNew->RamRange.cb           = (RTGCPHYS)cPagesTrackedByChunk << X86_PAGE_SHIFT;
+        pNew->RamRange.cb           = pNew->cbReal = (RTGCPHYS)cPagesTrackedByChunk << X86_PAGE_SHIFT;
         pNew->RamRange.fFlags      |= PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO_EX;
         //pNew->RamRange.pvR3       = NULL;
@@ -3163,5 +3163,5 @@
              * Free the memory.
              */
-            uint32_t const cPages = pCur->RamRange.cb >> PAGE_SHIFT;
+            uint32_t const cPages = pCur->cbReal >> PAGE_SHIFT;
             if (pCur->fFlags & PGMREGMMIORANGE_F_MMIO2)
             {
@@ -3674,4 +3674,82 @@
 
     return VINF_SUCCESS;
+}
+
+
+/**
+ * Reduces the mapping size of a MMIO2 or pre-registered MMIO region.
+ *
+ * This is mainly for dealing with old saved states after changing the default
+ * size of a mapping region.  See PGMDevHlpMMIOExReduce and
+ * PDMPCIDEV::pfnRegionLoadChangeHookR3.
+ *
+ * The region must not currently be mapped when making this call.  The VM state
+ * must be state restore or VM construction.
+ *
+ * @returns VBox status code.
+ * @param   pVM             The cross context VM structure.
+ * @param   pDevIns         The device instance owning the region.
+ * @param   iSubDev         The sub-device number of the registered region.
+ * @param   iRegion         The index of the registered region.
+ * @param   cbRegion        The new mapping size.
+ */
+VMMR3_INT_DECL(int) PGMR3PhysMMIOExReduce(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cbRegion)
+{
+    /*
+     * Validate input
+     */
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iSubDev <= UINT8_MAX, VERR_INVALID_PARAMETER);
+    AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
+    AssertReturn(cbRegion >= X86_PAGE_SIZE, VERR_INVALID_PARAMETER);
+    AssertReturn(!(cbRegion & X86_PAGE_OFFSET_MASK), VERR_UNSUPPORTED_ALIGNMENT);
+    VMSTATE enmVmState = VMR3GetState(pVM);
+    AssertLogRelMsgReturn(   enmVmState == VMSTATE_CREATING
+                          || enmVmState == VMSTATE_LOADING,
+                          ("enmVmState=%d (%s)\n", enmVmState, VMR3GetStateName(enmVmState)),
+                          VERR_VM_INVALID_VM_STATE);
+
+    int rc = pgmLock(pVM);
+    AssertRCReturn(rc, rc);
+
+    PPGMREGMMIORANGE pFirstMmio = pgmR3PhysMMIOExFind(pVM, pDevIns, iSubDev, iRegion);
+    if (pFirstMmio)
+    {
+        Assert(pFirstMmio->fFlags & PGMREGMMIORANGE_F_FIRST_CHUNK);
+        if (!(pFirstMmio->fFlags & PGMREGMMIORANGE_F_MAPPED))
+        {
+            /*
+             * NOTE! Current implementation does not support multiple ranges.
+             *       Implement when there is a real world need and thus a testcase.
+             */
+            AssertLogRelMsgStmt(pFirstMmio->fFlags & PGMREGMMIORANGE_F_LAST_CHUNK,
+                                ("%s: %#x\n", pFirstMmio->RamRange.pszDesc, pFirstMmio->fFlags),
+                                rc = VERR_NOT_SUPPORTED);
+            if (RT_SUCCESS(rc))
+            {
+                /*
+                 * Make the change.
+                 */
+                Log(("PGMR3PhysMMIOExReduce: %s changes from %RGp bytes (%RGp) to %RGp bytes.\n",
+                     pFirstMmio->RamRange.pszDesc, pFirstMmio->RamRange.cb, pFirstMmio->cbReal, cbRegion));
+
+                AssertLogRelMsgStmt(cbRegion <= pFirstMmio->cbReal,
+                                    ("%s: cbRegion=%#RGp cbReal=%#RGp\n", pFirstMmio->RamRange.pszDesc, cbRegion, pFirstMmio->cbReal),
+                                    rc = VERR_OUT_OF_RANGE);
+                if (RT_SUCCESS(rc))
+                {
+                    pFirstMmio->RamRange.cb = cbRegion;
+                }
+            }
+        }
+        else
+            rc = VERR_WRONG_ORDER;
+    }
+    else
+        rc = VERR_NOT_FOUND;
+
+    pgmUnlock(pVM);
+    return rc;
 }
 
