Index: trunk/include/VBox/mm.h
===================================================================
--- trunk/include/VBox/mm.h	(revision 7634)
+++ trunk/include/VBox/mm.h	(revision 7635)
@@ -293,4 +293,5 @@
 MMDECL(int)         MMHyperAlloc(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv);
 MMDECL(int)         MMHyperFree(PVM pVM, void *pv);
+MMDECL(void)        MMHyperHeapCheck(PVM pVM);
 #ifdef DEBUG
 MMDECL(void)        MMHyperHeapDump(PVM pVM);
@@ -337,5 +338,5 @@
 MMR3DECL(void)      MMR3Reset(PVM pVM);
 MMR3DECL(int)       MMR3IncreaseBaseReservation(PVM pVM, uint64_t cAddBasePages);
-MMR3DECL(int)       MMR3IncreaseFixedReservation(PVM pVM, uint32_t cAddFixedPages);
+MMR3DECL(int)       MMR3AdjustFixedReservation(PVM pVM, int32_t cDeltaFixedPages, const char *pszDesc);
 MMR3DECL(int)       MMR3UpdateShadowReservation(PVM pVM, uint32_t cShadowPages);
 
@@ -351,4 +352,5 @@
 MMR3DECL(int)       MMR3HyperMapHCPhys(PVM pVM, void *pvHC, RTHCPHYS HCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr);
 MMR3DECL(int)       MMR3HyperMapGCPhys(PVM pVM, RTGCPHYS GCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr);
+MMR3DECL(int)       MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTGCPTR pGCPtr);
 MMR3DECL(int)       MMR3HyperMapHCRam(PVM pVM, void *pvHC, size_t cb, bool fFree, const char *pszDesc, PRTGCPTR pGCPtr);
 MMR3DECL(int)       MMR3HyperMapPages(PVM pVM, void *pvR3, RTR0PTR pvR0, size_t cPages, PCSUPPAGE paPages, const char *pszDesc, PRTGCPTR pGCPtr);
@@ -369,5 +371,4 @@
 MMR3DECL(int)       MMR3PhysRegisterEx(PVM pVM, void *pvRam, RTGCPHYS GCPhys, unsigned cb, unsigned fFlags, MMPHYSREG enmType, const char *pszDesc);
 #endif
-MMR3DECL(int)       MMR3PhysRelocate(PVM pVM, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, unsigned cb);
 MMR3DECL(int)       MMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTUINT cbRange, const void *pvBinary, bool fShadow, const char *pszDesc);
 MMR3DECL(int)       MMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTUINT cbRange);
Index: trunk/include/VBox/pci.h
===================================================================
--- trunk/include/VBox/pci.h	(revision 7634)
+++ trunk/include/VBox/pci.h	(revision 7635)
@@ -75,8 +75,14 @@
  * @param   pPciDev         Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
  * @param   iRegion         The region number.
- * @param   GCPhysAddress   Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
- *                          I/O port, else it's a physical address.
- *                          This address is *NOT* relative to pci_mem_base like earlier!
+ * @param   GCPhysAddress   Physical address of the region. If enmType is PCI_ADDRESS_SPACE_IO, this
+ *                          is an I/O port, otherwise it's a physical address.
+ *
+ *                          NIL_RTGCPHYS indicates that a MMIO2 mapping is about to be unmapped and
+ *                          that the device deregister access handlers for it and update its internal
+ *                          state to reflect this.
+ *
  * @param   enmType         One of the PCI_ADDRESS_SPACE_* values.
+ *
+ * @remarks The address is *NOT* relative to pci_mem_base.
  */
 typedef DECLCALLBACK(int) FNPCIIOREGIONMAP(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType);
Index: trunk/include/VBox/pdmdev.h
===================================================================
--- trunk/include/VBox/pdmdev.h	(revision 7634)
+++ trunk/include/VBox/pdmdev.h	(revision 7635)
@@ -644,4 +644,38 @@
     DECLR3CALLBACKMEMBER(void,  pfnIoApicSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
 
+    /**
+     * Checks if the given address is an MMIO2 base address or not.
+     *
+     * @returns true/false accordingly.
+     * @param   pDevIns         The PCI device instance.
+     * @param   pOwner          The owner of the memory, optional.
+     * @param   GCPhys          The address to check.
+     */
+    DECLR3CALLBACKMEMBER(bool,  pfnIsMMIO2Base,(PPDMDEVINS pDevIns, PPDMDEVINS pOwner, RTGCPHYS GCPhys));
+
+    /**
+     * Gets the address of the GC PCI Bus helpers.
+     *
+     * This should be called at both construction and relocation time
+     * to obtain the correct address of the GC helpers.
+     *
+     * @returns GC pointer to the PCI Bus helpers.
+     * @param   pDevIns         Device instance of the PCI Bus.
+     * @thread  EMT only.
+     */
+    DECLR3CALLBACKMEMBER(PCPDMPCIHLPGC, pfnGetGCHelpers,(PPDMDEVINS pDevIns));
+
+    /**
+     * Gets the address of the R0 PCI Bus helpers.
+     *
+     * This should be called at both construction and relocation time
+     * to obtain the correct address of the GC helpers.
+     *
+     * @returns R0 pointer to the PCI Bus helpers.
+     * @param   pDevIns         Device instance of the PCI Bus.
+     * @thread  EMT only.
+     */
+    DECLR3CALLBACKMEMBER(PCPDMPCIHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns));
+
 #ifdef VBOX_WITH_PDM_LOCK
     /**
@@ -662,28 +696,4 @@
     DECLR3CALLBACKMEMBER(void,  pfnUnlock,(PPDMDEVINS pDevIns));
 #endif
-
-    /**
-     * Gets the address of the GC PCI Bus helpers.
-     *
-     * This should be called at both construction and relocation time
-     * to obtain the correct address of the GC helpers.
-     *
-     * @returns GC pointer to the PCI Bus helpers.
-     * @param   pDevIns         Device instance of the PCI Bus.
-     * @thread  EMT only.
-     */
-    DECLR3CALLBACKMEMBER(PCPDMPCIHLPGC, pfnGetGCHelpers,(PPDMDEVINS pDevIns));
-
-    /**
-     * Gets the address of the R0 PCI Bus helpers.
-     *
-     * This should be called at both construction and relocation time
-     * to obtain the correct address of the GC helpers.
-     *
-     * @returns R0 pointer to the PCI Bus helpers.
-     * @param   pDevIns         Device instance of the PCI Bus.
-     * @thread  EMT only.
-     */
-    DECLR3CALLBACKMEMBER(PCPDMPCIHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns));
 
     /** Just a safety precaution. */
@@ -696,5 +706,5 @@
 
 /** Current PDMPCIHLPR3 version number. */
-#define PDM_PCIHLPR3_VERSION  0xf1010000
+#define PDM_PCIHLPR3_VERSION  0xf1020000
 
 
@@ -1709,5 +1719,4 @@
      */
     DECLR3CALLBACKMEMBER(int, pfnIOPortDeregister,(PPDMDEVINS pDevIns, RTIOPORT Port, RTUINT cPorts));
-
 
     /**
@@ -2569,4 +2578,82 @@
     DECLR3CALLBACKMEMBER(int, pfnROMProtectShadow,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTUINT cbRange));
 
+    /**
+     * Allocate and register a MMIO2 region.
+     *
+     * As mentioned elsewhere, MMIO2 is just RAM spelled differently. It's
+     * RAM associated with a device. It is also non-shared memory with a
+     * permanent ring-3 mapping and page backing (presently).
+     *
+     * @returns VBox status.
+     * @param   pDevIns         The device instance.
+     * @param   iRegion         The region number. Use the PCI region number as
+     *                          this must be known to the PCI bus device too. If it's not associated
+     *                          with the PCI device, then any number up to UINT8_MAX is fine.
+     * @param   cb              The size (in bytes) of the region.
+     * @param   ppv             Where to store the address of the ring-3 mapping of the memory.
+     * @param   pszDesc         Pointer to description string. This must not be freed.
+     * @thread  EMT.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnMMIO2Register,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, void **ppv, const char *pszDesc));
+
+    /**
+     * Deregisters and frees a MMIO2 region.
+     *
+     * Any physical (and virtual) access handlers registered for the region must
+     * be deregistered before calling this function.
+     *
+     * @returns VBox status code.
+     * @param   pDevIns         The device instance.
+     * @param   iRegion         The region number used during registration.
+     * @thread  EMT.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnMMIO2Deregister,(PPDMDEVINS pDevIns, uint32_t iRegion));
+
+    /**
+     * Maps a MMIO2 region into the physical memory space.
+     *
+     * A MMIO2 range may overlap with base memory if a lot of RAM
+     * is configured for the VM, in which case we'll drop the base
+     * memory pages. Presently we will make no attempt to preserve
+     * anything that happens to be present in the base memory that
+     * is replaced, this is of course incorrectly but it's too much
+     * effort.
+     *
+     * @returns VBox status code.
+     * @param   pDevIns         The device instance.
+     * @param   iRegion         The region number used during registration.
+     * @param   GCPhys          The physical address to map it at.
+     * @thread  EMT.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnMMIO2Map,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys));
+
+    /**
+     * Unmaps a MMIO2 region previously mapped using pfnMMIO2Map.
+     *
+     * @returns VBox status code.
+     * @param   pDevIns         The device instance.
+     * @param   iRegion         The region number used during registration.
+     * @param   GCPhys          The physical address it's currently mapped at.
+     * @thread  EMT.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnMMIO2Unmap,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys));
+
+    /**
+     * Maps a portion of an MMIO2 region into the hypervisor region.
+     *
+     * Callers of this API must never deregister the MMIO2 region before the
+     * VM is powered off.
+     *
+     * @return VBox status code.
+     * @param   pDevIns     The device owning the MMIO2 memory.
+     * @param   iRegion     The region.
+     * @param   off         The offset into the region. Will be rounded down to closest page boundrary.
+     * @param   cb          The number of bytes to map. Will be rounded up to the closest page boundrary.
+     * @param   pszDesc     Mapping description.
+     * @param   pGCPtr      Where to store the GC address.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnMMHyperMapMMIO2,(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
+                                                  const char *pszDesc, PRTGCPTR pGCPtr));
+
     /** @} */
 
@@ -2581,5 +2668,5 @@
 
 /** Current PDMDEVHLP version number. */
-#define PDM_DEVHLP_VERSION  0xf2050000
+#define PDM_DEVHLP_VERSION  0xf2050001
 
 
@@ -3044,5 +3131,4 @@
     return pDevIns->pDevHlp->pfnROMRegister(pDevIns, GCPhysStart, cbRange, pvBinary, fShadow, pszDesc);
 }
-
 /**
  * @copydoc PDMDEVHLP::pfnROMProtectShadow
@@ -3051,4 +3137,45 @@
 {
     return pDevIns->pDevHlp->pfnROMProtectShadow(pDevIns, GCPhysStart, cbRange);
+}
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMIO2Register
+ */
+DECLINLINE(int) PDMDevHlpMMIO2Register(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, void **ppv, const char *pszDesc)
+{
+    return pDevIns->pDevHlp->pfnMMIO2Register(pDevIns, iRegion, cb, ppv, pszDesc);
+}
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMIO2Deregister
+ */
+DECLINLINE(int) PDMDevHlpMMIO2Deregister(PPDMDEVINS pDevIns, uint32_t iRegion)
+{
+    return pDevIns->pDevHlp->pfnMMIO2Deregister(pDevIns, iRegion);
+}
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMIO2Map
+ */
+DECLINLINE(int) PDMDevHlpMMIO2Map(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    return pDevIns->pDevHlp->pfnMMIO2Map(pDevIns, iRegion, GCPhys);
+}
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMIO2Unmap
+ */
+DECLINLINE(int) PDMDevHlpMMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    return pDevIns->pDevHlp->pfnMMIO2Unmap(pDevIns, iRegion, GCPhys);
+}
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMHyperMapMMIO2
+ */
+DECLINLINE(int) PDMDevHlpMMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
+                                         const char *pszDesc, PRTGCPTR pGCPtr)
+{
+    return pDevIns->pDevHlp->pfnMMHyperMapMMIO2(pDevIns, iRegion, off, cb, pszDesc, pGCPtr);
 }
 
Index: trunk/include/VBox/pgm.h
===================================================================
--- trunk/include/VBox/pgm.h	(revision 7634)
+++ trunk/include/VBox/pgm.h	(revision 7635)
@@ -467,4 +467,10 @@
 #endif /* !VBOX_WITH_NEW_PHYS_CODE */
 PGMR3DECL(int)  PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, const char *pszDesc);
+PDMR3DECL(int)  PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, void **ppv, const char *pszDesc);
+PDMR3DECL(int)  PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion);
+PDMR3DECL(int)  PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys);
+PDMR3DECL(int)  PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys);
+PDMR3DECL(bool) PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys);
+PDMR3DECL(int)  PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys);
 
 /** @group PGMR3PhysRegisterRom flags.
@@ -484,5 +490,4 @@
 PGMR3DECL(int)  PGMR3PhysRegisterChunk(PVM pVM, void *pvRam, RTGCPHYS GCPhys, size_t cb, unsigned fFlags, const SUPPAGE *paPages, const char *pszDesc);
 #endif /* !VBOX_WITH_NEW_PHYS_CODE */
-PGMR3DECL(int)  PGMR3PhysRelocate(PVM pVM, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, size_t cb);
 PGMR3DECL(int)  PGMR3PhysSetFlags(PVM pVM, RTGCPHYS GCPhys, size_t cb, unsigned fFlags, unsigned fMask);
 PGMDECL(void)   PGMR3PhysSetA20(PVM pVM, bool fEnable);
Index: trunk/src/VBox/Devices/Bus/DevPCI.cpp
===================================================================
--- trunk/src/VBox/Devices/Bus/DevPCI.cpp	(revision 7634)
+++ trunk/src/VBox/Devices/Bus/DevPCI.cpp	(revision 7635)
@@ -1,5 +1,5 @@
+/* $Id: $ */
 /** @file
- *
- * PCI Device.
+ * PCI BUS Device.
  */
 
@@ -214,4 +214,5 @@
 static void pci_update_mappings(PCIDevice *d)
 {
+    PPCIBUS pBus = d->Int.s.pBus;
     PCIIORegion *r;
     int cmd, i;
@@ -279,12 +280,16 @@
                         }
                     } else {
-                        int rc = d->pDevIns->pDevHlp->pfnMMIODeregister(d->pDevIns,
-                                                                        r->addr + PCIBUS2PCIGLOBALS(d->Int.s.pBus)->pci_mem_base,
-                                                                        r->size);
-#if 0 /** @todo deal correctly with deregistration of MMIO2 ranges and such like. */
-                        AssertMsg(VBOX_SUCCESS(rc) || !strcmp(d->name, "vga") || !strcmp(d->name, "VMMDev"), ("rc=%Vrc d=%s\n", rc, d->name)); NOREF(rc);
-#else /* less strict check */
-                        AssertMsg(VBOX_SUCCESS(rc) || rc == VERR_IOM_MMIO_RANGE_NOT_FOUND, ("rc=%Vrc d=%s\n", rc, d->name)); NOREF(rc);
-#endif 
+                        RTGCPHYS GCPhysBase = r->addr + PCIBUS2PCIGLOBALS(pBus)->pci_mem_base;
+                        int rc;
+                        if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsHC, d->pDevIns, GCPhysBase))
+                        {
+                            /* unmap it. */
+                            int rc = r->map_func(d, i, NIL_RTGCPHYS, r->size, (PCIADDRESSSPACE)(r->type));
+                            AssertRC(rc);
+                            rc = PDMDevHlpMMIO2Unmap(d->pDevIns, i, GCPhysBase);
+                        }
+                        else
+                            rc = d->pDevIns->pDevHlp->pfnMMIODeregister(d->pDevIns, GCPhysBase, r->size);
+                        AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, d->name, i, GCPhysBase, r->size));
                     }
                 }
@@ -292,5 +297,5 @@
                 if (r->addr != ~0U) {
                     int rc = r->map_func(d, i,
-                                         r->addr + (r->type & PCI_ADDRESS_SPACE_IO ? 0 : PCIBUS2PCIGLOBALS(d->Int.s.pBus)->pci_mem_base),
+                                         r->addr + (r->type & PCI_ADDRESS_SPACE_IO ? 0 : PCIBUS2PCIGLOBALS(pBus)->pci_mem_base),
                                          r->size, (PCIADDRESSSPACE)(r->type));
                     AssertRC(rc);
@@ -772,5 +777,5 @@
     {
     case 0x0101:
-        if (vendor_id == 0x8086 && 
+        if (vendor_id == 0x8086 &&
             (device_id == 0x7010 || device_id == 0x7111)) {
             /* PIIX3 or PIIX4 IDE */
@@ -1083,5 +1088,5 @@
             if (pData->devices[i])
             {
-                LogRel(("New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pData->devices[i]->name, 
+                LogRel(("New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pData->devices[i]->name,
                         PCIDevGetVendorId(pData->devices[i]), PCIDevGetDeviceId(pData->devices[i])));
                 if (SSMR3HandleGetAfter(pSSMHandle) != SSMAFTER_DEBUG_IT)
@@ -1100,5 +1105,5 @@
         if (!pDev)
         {
-            LogRel(("Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i, 
+            LogRel(("Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i,
                     PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
             if (SSMR3HandleGetAfter(pSSMHandle) != SSMAFTER_DEBUG_IT)
@@ -1118,5 +1123,5 @@
         /* commit the loaded device config. */
         memcpy(pDev->config, DevTmp.config, sizeof(pDev->config));
-        if (DevTmp.Int.s.iIrq >= PCI_DEVICES_MAX) 
+        if (DevTmp.Int.s.iIrq >= PCI_DEVICES_MAX)
         {
             LogRel(("Device %s: Too many devices %d (max=%d)\n", pDev->name, DevTmp.Int.s.iIrq, PCI_DEVICES_MAX));
@@ -1326,8 +1331,8 @@
 
 
-/** 
+/**
  * @copydoc PDMPCIBUSREG::pfnSetConfigCallbacksHC
  */
-static DECLCALLBACK(void) pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld, 
+static DECLCALLBACK(void) pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
                                                 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
 {
@@ -1495,4 +1500,8 @@
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Failed to register ourselves as a PCI Bus"));
+    if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
+        return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
+                                   N_("PCI helper version mismatch; got %#x expected %#x"),
+                                   pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION);
 
     pBus->pPciHlpGC = pBus->pPciHlpR3->pfnGetGCHelpers(pDevIns);
Index: trunk/src/VBox/Devices/Graphics/DevVGA.cpp
===================================================================
--- trunk/src/VBox/Devices/Graphics/DevVGA.cpp	(revision 7634)
+++ trunk/src/VBox/Devices/Graphics/DevVGA.cpp	(revision 7635)
@@ -1999,5 +1999,5 @@
     for(y = 0; y < height; y++) {
         addr = addr1;
-        /* CGA/MDA compatibility. Note that these addresses are all 
+        /* CGA/MDA compatibility. Note that these addresses are all
          * shifted left by two compared to VGA specs.
          */
@@ -4108,5 +4108,5 @@
 
 /**
- * Callback function for mapping an PCI I/O region.
+ * Callback function for unmapping and/or mapping the VRAM MMIO2 region (called by the PCI bus).
  *
  * @return VBox status code.
@@ -4121,69 +4121,42 @@
 {
     int         rc;
-    PVGASTATE   pData = PDMINS2DATA(pPciDev->pDevIns, PVGASTATE);
+    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
+    PVGASTATE   pData = PDMINS2DATA(pDevIns, PVGASTATE);
     LogFlow(("vgaR3IORegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
-
-    /*
-     * VRam mapping.
-     */
-    if (iRegion == 0 && enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH)
+    AssertReturn(iRegion == 0 && enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
+
+    if (GCPhysAddress != NIL_RTGCPHYS)
     {
         /*
-         * Register and lock the VRAM.
-         *
-         * Windows usually re-initializes the PCI devices, so we have to check whether the memory was
-         * already registered before trying to do that all over again.
+         * Mapping the VRAM.
          */
-        PVM pVM = PDMDevHlpGetVM(pPciDev->pDevIns);
-        if (pData->GCPhysVRAM)
+        rc = PDMDevHlpMMIO2Map(pDevIns, iRegion, GCPhysAddress);
+        AssertRC(rc);
+        if (RT_SUCCESS(rc))
         {
-            AssertMsg(pData->GCPhysVRAM == GCPhysAddress,
-                      ("The Guest OS relocated our LFB! old GCPhysVRAM=%VGp new GCPhysAddress=%VGp\n",
-                       pData->GCPhysVRAM, GCPhysAddress));
-            rc = VINF_SUCCESS;
-        }
-        else
-        {
-            /*
-             * Register and lock the VRAM.
-             */
-            rc = MMR3PhysRegister(pVM, pData->vram_ptrHC, GCPhysAddress, pData->vram_size, MM_RAM_FLAGS_MMIO2, "VRam");
-            if (VBOX_SUCCESS(rc))
-            {
-                if (!pData->GCPhysVRAM)
-                    rc = PGMR3HandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
-                                                      GCPhysAddress, GCPhysAddress + (pData->vram_size - 1),
-                                                      vgaR3LFBAccessHandler, pData,
-                                                      g_DeviceVga.szR0Mod, "vgaR0LFBAccessHandler", pData->pDevInsHC->pvInstanceDataR0,
-                                                      g_DeviceVga.szGCMod, "vgaGCLFBAccessHandler", pData->pDevInsHC->pvInstanceDataGC,
-                                                      "VGA LFB");
-                if (VBOX_SUCCESS(rc))
-                {
-                    /*
-                     * Map the first 256KB of the VRAM into GC for GC VGA support.
-                     */
-                    RTGCPTR GCPtr;
-                    rc = MMR3HyperMapGCPhys(pVM, GCPhysAddress, VGA_MAPPING_SIZE, "VGA VRam", &GCPtr);
-                    if (VBOX_SUCCESS(rc))
-                    {
-                        MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
-
-                        pData->vram_ptrGC = GCPtr;
-                        pData->GCPhysVRAM = GCPhysAddress;
-                        return VINF_SUCCESS;
-                    }
-                    AssertMsgFailed(("MMR3HyperMapGCPhys failed, rc=%Vrc\n", rc));
-                }
-                else
-                    AssertMsgFailed(("Failed to register write handler for VRAM! rc=%Vrc\n", rc));
-            }
-            else
-                AssertReleaseMsgFailed(("Failed to register VRAM! rc=%Vra\n", rc));
-        }
-        return rc;
+            rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
+                                              PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
+                                              GCPhysAddress, GCPhysAddress + (pData->vram_size - 1),
+                                              vgaR3LFBAccessHandler, pData,
+                                              g_DeviceVga.szR0Mod, "vgaR0LFBAccessHandler", pDevIns->pvInstanceDataR0,
+                                              g_DeviceVga.szGCMod, "vgaGCLFBAccessHandler", pDevIns->pvInstanceDataGC,
+                                              "VGA LFB");
+            AssertRC(rc);
+            if (RT_SUCCESS(rc))
+                pData->GCPhysVRAM = GCPhysAddress;
+        }
     }
     else
-        AssertReleaseMsgFailed(("Huh!?! iRegion=%d enmType=%d\n", iRegion, enmType));
-    return VERR_INTERNAL_ERROR;
+    {
+        /*
+         * Unmapping of the VRAM in progress.
+         * Deregister the access handler so PGM doesn't get upset.
+         */
+        Assert(pData->GCPhysVRAM);
+        rc = PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns), pData->GCPhysVRAM);
+        AssertRC(rc);
+        pData->GCPhysVRAM = 0;
+    }
+    return rc;
 }
 
@@ -4619,4 +4592,13 @@
 
     /*
+     * Allocate the VRAM and map the first 256KB of it into GC so we can speed up VGA support.
+     */
+    rc = PDMDevHlpMMIO2Register(pDevIns, 0 /* iRegion */, pData->vram_size, (void **)&pData->vram_ptrHC, "VRam");
+    AssertMsgRC(rc, ("PDMDevHlpMMIO2Register(%#x,) -> %Rrc\n", pData->vram_size, rc));
+
+    rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, 0 /* iRegion */, 0 /* off */,  VGA_MAPPING_SIZE, "VGA VRam", &pData->vram_ptrGC);
+    AssertMsgRC(rc, ("MMR3HyperMapGCPhys(%#x,) -> %Rrc\n", pData->vram_size, rc));
+
+    /*
      * Register I/O ports, ROM and save state.
      */
@@ -4762,5 +4744,5 @@
     AssertReleaseMsg(g_cbVgaBiosBinary <= _64K && g_cbVgaBiosBinary >= 32*_1K, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
     AssertReleaseMsg(RT_ALIGN_Z(g_cbVgaBiosBinary, PAGE_SIZE) == g_cbVgaBiosBinary, ("g_cbVgaBiosBinary=%#x\n", g_cbVgaBiosBinary));
-    rc = PDMDevHlpROMRegister(pDevIns, 0x000c0000, g_cbVgaBiosBinary, &g_abVgaBiosBinary[0], 
+    rc = PDMDevHlpROMRegister(pDevIns, 0x000c0000, g_cbVgaBiosBinary, &g_abVgaBiosBinary[0],
                               false /* fShadow */, "VGA BIOS");
     if (VBOX_FAILURE(rc))
@@ -4781,5 +4763,6 @@
     if (pData->Dev.devfn != 16 && iInstance == 0)
         Log(("!!WARNING!!: pData->dev.devfn=%d (ignore if testcase or no started by Main)\n", pData->Dev.devfn));
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, pData->vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
+
+    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0 /* iRegion */, pData->vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vgaR3IORegionMap);
     if (VBOX_FAILURE(rc))
         return rc;
@@ -4798,14 +4781,4 @@
     if (VBOX_FAILURE(rc))
         return rc;
-
-    /*
-     * Allocate the VRAM.
-     */
-    rc = SUPPageAlloc(pData->vram_size >> PAGE_SHIFT, (void **)&pData->vram_ptrHC);
-    if (VBOX_FAILURE(rc))
-    {
-        AssertMsgFailed(("SUPPageAlloc(%#x,) -> %d\n", pData->vram_size, rc));
-        return rc;
-    }
 
 #ifdef VBE_NEW_DYN_LIST
Index: trunk/src/VBox/Devices/VMMDev/VBoxDev.cpp
===================================================================
--- trunk/src/VBox/Devices/VMMDev/VBoxDev.cpp	(revision 7634)
+++ trunk/src/VBox/Devices/VMMDev/VBoxDev.cpp	(revision 7635)
@@ -1,6 +1,5 @@
+/* $Id$ */
 /** @file
- *
- * VBox Guest/VMM/host communication:
- * Virtual communication device
+ * VMMDev - Guest <-> VMM/Host communication device.
  */
 
@@ -21,7 +20,4 @@
 /* Enable dev_vmm Log3 statements to get IRQ-related logging. */
 
-#include <stdio.h>
-#include <string.h>
-
 #define LOG_GROUP LOG_GROUP_DEV_VMM
 #include <VBox/log.h>
@@ -36,4 +32,5 @@
 
 #include <iprt/assert.h>
+#include <iprt/string.h>
 #include <iprt/time.h>
 #ifndef IN_GC
@@ -1236,8 +1233,8 @@
                 /* just pass on the information */
                 Log(("VMMDev: returning VRDP status %d level %d\n", pData->fVRDPEnabled, pData->u32VRDPExperienceLevel));
-                
+
                 vrdpChangeRequest->u8VRDPActive = pData->fVRDPEnabled;
                 vrdpChangeRequest->u32VRDPExperienceLevel = pData->u32VRDPExperienceLevel;
-                
+
                 pRequestHeader->rc = VINF_SUCCESS;
             }
@@ -1259,5 +1256,5 @@
                 Log(("VMMDev: returning memory balloon size =%d\n", pData->u32MemoryBalloonSize));
                 memBalloonChangeRequest->u32BalloonSize = pData->u32MemoryBalloonSize;
-                memBalloonChangeRequest->u32PhysMemSize = (pData->u64GuestRAMSize / (uint64_t)_1M);
+                memBalloonChangeRequest->u32PhysMemSize = pData->cbGuestRAM / (uint64_t)_1M;
 
                 if (memBalloonChangeRequest->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
@@ -1381,5 +1378,5 @@
                 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
                     Log(("CPU%d: System cache size      %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/pGuestStats->u32PageSize)));
-    
+
                 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
                     Log(("CPU%d: Page file size         %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/pGuestStats->u32PageSize)));
@@ -1564,62 +1561,29 @@
 static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
 {
-    int         rc;
+    LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
     VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
-    LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
-
-
+    int rc;
+
+    AssertReturn(iRegion == 1 && enmType == PCI_ADDRESS_SPACE_MEM, VERR_INTERNAL_ERROR);
     Assert(pData->pVMMDevRAMHC != NULL);
 
-    memset (pData->pVMMDevRAMHC, 0, sizeof (VMMDevMemory));
-    pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
-    pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
-
-    /*
-     * VMMDev RAM mapping.
-     */
-    if (iRegion == 1 && enmType == PCI_ADDRESS_SPACE_MEM)
+    if (GCPhysAddress != NIL_RTGCPHYS)
     {
         /*
-         * Register and lock the RAM.
-         *
-         * Windows usually re-initializes the PCI devices, so we have to check whether the memory was
-         * already registered before trying to do that all over again.
+         * Map the MMIO2 memory.
          */
-        PVM pVM = PDMDevHlpGetVM(pPciDev->pDevIns);
-
-        if (pData->GCPhysVMMDevRAM)
-        {
-            /*
-             * Relocate the already registered VMMDevRAM.
-             */
-            rc = MMR3PhysRelocate(pVM, pData->GCPhysVMMDevRAM, GCPhysAddress, VMMDEV_RAM_SIZE);
-            if (VBOX_SUCCESS(rc))
-            {
-                pData->GCPhysVMMDevRAM = GCPhysAddress;
-                return VINF_SUCCESS;
-            }
-            AssertReleaseMsgFailed(("Failed to relocate VMMDev RAM from %VGp to %VGp! rc=%Vra\n", pData->GCPhysVMMDevRAM, GCPhysAddress, rc));
-        }
-        else
-        {
-            /*
-             * Register and lock the VMMDevRAM.
-             */
-            /** @todo MM_RAM_FLAGS_MMIO2 seems to be appropriate for a RW memory.
-             * Need to check. May be a RO memory is enough for the device.
-             */
-            rc = MMR3PhysRegister(pVM, pData->pVMMDevRAMHC, GCPhysAddress, VMMDEV_RAM_SIZE, MM_RAM_FLAGS_MMIO2, "VBoxDev");
-            if (VBOX_SUCCESS(rc))
-            {
-                pData->GCPhysVMMDevRAM = GCPhysAddress;
-                return VINF_SUCCESS;
-            }
-            AssertReleaseMsgFailed(("Failed to register VMMDev RAM! rc=%Vra\n", rc));
-        }
-        return rc;
-    }
-
-    AssertReleaseMsgFailed(("VMMDev wrong region type: iRegion=%d enmType=%d\n", iRegion, enmType));
-    return VERR_INTERNAL_ERROR;
+        pData->GCPhysVMMDevRAM = GCPhysAddress;
+        rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
+    }
+    else
+    {
+        /*
+         * It is about to be unmapped, just clean up.
+         */
+        pData->GCPhysVMMDevRAM = NIL_RTGCPHYS;
+        rc = VINF_SUCCESS;
+    }
+
+    return rc;
 }
 
@@ -2096,4 +2060,16 @@
 
     return VINF_SUCCESS;
+}
+
+/**
+ * (Re-)initializes the MMIO2 data.
+ *
+ * @param   pData           Pointer to the VMMDev instance data.
+ */
+static void vmmdevInitRam(VMMDevState *pData)
+{
+    memset(pData->pVMMDevRAMHC, 0, sizeof(VMMDevMemory));
+    pData->pVMMDevRAMHC->u32Size = sizeof(VMMDevMemory);
+    pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
 }
 
@@ -2160,4 +2136,35 @@
 
     /*
+     * Interfaces
+     */
+    /* Base */
+    pData->Base.pfnQueryInterface         = vmmdevPortQueryInterface;
+
+    /* VMMDev port */
+    pData->Port.pfnQueryAbsoluteMouse     = vmmdevQueryAbsoluteMouse;
+    pData->Port.pfnSetAbsoluteMouse       = vmmdevSetAbsoluteMouse;
+    pData->Port.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
+    pData->Port.pfnSetMouseCapabilities   = vmmdevSetMouseCapabilities;
+    pData->Port.pfnRequestDisplayChange   = vmmdevRequestDisplayChange;
+    pData->Port.pfnSetCredentials         = vmmdevSetCredentials;
+    pData->Port.pfnVBVAChange             = vmmdevVBVAChange;
+    pData->Port.pfnRequestSeamlessChange  = vmmdevRequestSeamlessChange;
+    pData->Port.pfnSetMemoryBalloon       = vmmdevSetMemoryBalloon;
+    pData->Port.pfnSetStatisticsInterval  = vmmdevSetStatisticsInterval;
+    pData->Port.pfnVRDPChange             = vmmdevVRDPChange;
+
+    /* Shared folder LED */
+    pData->SharedFolders.Led.u32Magic     = PDMLED_MAGIC;
+    pData->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
+
+#ifdef VBOX_HGCM
+    /* HGCM port */
+    pData->HGCMPort.pfnCompleted          = hgcmCompleted;
+#endif
+
+    /** @todo convert this into a config parameter like we do everywhere else.*/
+    pData->cbGuestRAM = MMR3PhysGetRamSize(PDMDevHlpGetVM(pDevIns));
+
+    /*
      * Register the backdoor logging port
      */
@@ -2172,4 +2179,13 @@
     AssertRCReturn(rc, rc);
 #endif
+
+    /*
+     * Allocate and initialize the MMIO2 memory.
+     */
+    rc = PDMDevHlpMMIO2Register(pDevIns, 1 /*iRegion*/, VMMDEV_RAM_SIZE, (void **)&pData->pVMMDevRAMHC, "VMMDev");
+    if (RT_FAILURE(rc))
+        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
+                                   N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
+    vmmdevInitRam(pData);
 
     /*
@@ -2189,32 +2205,4 @@
 
     /*
-     * Interfaces
-     */
-    /* Base */
-    pData->Base.pfnQueryInterface         = vmmdevPortQueryInterface;
-
-    /* VMMDev port */
-    pData->Port.pfnQueryAbsoluteMouse     = vmmdevQueryAbsoluteMouse;
-    pData->Port.pfnSetAbsoluteMouse       = vmmdevSetAbsoluteMouse;
-    pData->Port.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
-    pData->Port.pfnSetMouseCapabilities   = vmmdevSetMouseCapabilities;
-    pData->Port.pfnRequestDisplayChange   = vmmdevRequestDisplayChange;
-    pData->Port.pfnSetCredentials         = vmmdevSetCredentials;
-    pData->Port.pfnVBVAChange             = vmmdevVBVAChange;
-    pData->Port.pfnRequestSeamlessChange  = vmmdevRequestSeamlessChange;
-    pData->Port.pfnSetMemoryBalloon       = vmmdevSetMemoryBalloon;
-    pData->Port.pfnSetStatisticsInterval  = vmmdevSetStatisticsInterval;
-    pData->Port.pfnVRDPChange             = vmmdevVRDPChange;
-
-    /* Shared folder LED */
-    pData->SharedFolders.Led.u32Magic                 = PDMLED_MAGIC;
-    pData->SharedFolders.ILeds.pfnQueryStatusLed      = vmmdevQueryStatusLed;
-
-#ifdef VBOX_HGCM
-    /* HGCM port */
-    pData->HGCMPort.pfnCompleted          = hgcmCompleted;
-#endif
-
-    /*    
      * Get the corresponding connector interface
      */
@@ -2256,5 +2244,5 @@
     }
 
-    /* 
+    /*
      * Register saved state and init the HGCM CmdList critsect.
      */
@@ -2271,17 +2259,4 @@
 #endif /* VBOX_HGCM */
 
-    /*
-     * Allocate the VMMDev RAM region.
-     */
-    /** @todo freeing of the RAM. */
-    rc = SUPPageAlloc(VMMDEV_RAM_SIZE >> PAGE_SHIFT, (void **)&pData->pVMMDevRAMHC);
-    AssertMsgRCReturn(rc, ("VMMDev SUPPageAlloc(%#x,) -> %Vrc\n", VMMDEV_RAM_SIZE, rc), rc);
-
-    /* initialize the VMMDev memory */
-    pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
-    pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
-
-    PVM pVM = PDMDevHlpGetVM(pDevIns);
-    pData->u64GuestRAMSize = MMR3PhysGetRamSize(pVM);
     return rc;
 }
@@ -2311,11 +2286,7 @@
     pData->u32HostEventFlags = 0;
 
+    /* re-initialize the VMMDev memory */
     if (pData->pVMMDevRAMHC)
-    {
-        /* re-initialize the VMMDev memory */
-        memset (pData->pVMMDevRAMHC, 0, VMMDEV_RAM_SIZE);
-        pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
-        pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
-    }
+        vmmdevInitRam(pData);
 
     /* credentials have to go away */
Index: trunk/src/VBox/Devices/VMMDev/VMMDevState.h
===================================================================
--- trunk/src/VBox/Devices/VMMDev/VMMDevState.h	(revision 7634)
+++ trunk/src/VBox/Devices/VMMDev/VMMDevState.h	(revision 7635)
@@ -1,6 +1,5 @@
+/* $Id$ */
 /** @file
- *
- * VBox Guest/VMM/host communication:
- * HGCM - Host-Guest Communication Manager header
+ * VMMDev - Guest <-> VMM/Host communication device, Internal header.
  */
 
@@ -17,6 +16,6 @@
  */
 
-#ifndef __VMMDevState_h__
-#define __VMMDevState_h__
+#ifndef ___VMMDevState_h___
+#define ___VMMDevState_h___
 
 #include <VBox/cdefs.h>
@@ -72,5 +71,5 @@
     /** Current host side event flags */
     uint32_t u32HostEventFlags;
-    /** Mask of events guest is interested in. Note that the HGCM events 
+    /** Mask of events guest is interested in. Note that the HGCM events
      *  are enabled automatically by the VMMDev device when guest issues
      *  HGCM commands.
@@ -136,5 +135,5 @@
 
     /* guest ram size */
-    uint64_t    u64GuestRAMSize;
+    uint64_t    cbGuestRAM;
 
     /* statistics interval change request */
@@ -146,10 +145,10 @@
     bool fVRDPEnabled;
     uint32_t u32VRDPExperienceLevel;
-        
+
 #ifdef TIMESYNC_BACKDOOR
     bool fTimesyncBackdoorLo;
     uint64_t hostTime;
 #endif
-    /** Set if GetHostTime should fail. 
+    /** Set if GetHostTime should fail.
      * Loaded from the GetHostTimeDisabled configuration value. */
     bool fGetHostTimeDisabled;
@@ -185,3 +184,4 @@
                                   uint32_t u32NotMask);
 
-#endif /* __VMMDevState_h__ */
+#endif /* !___VMMDevState_h___ */
+
Index: trunk/src/VBox/VMM/MM.cpp
===================================================================
--- trunk/src/VBox/VMM/MM.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/MM.cpp	(revision 7635)
@@ -527,4 +527,5 @@
 int mmR3UpdateReservation(PVM pVM)
 {
+    VM_ASSERT_EMT(pVM);
     if (pVM->mm.s.fDoneMMR3InitPaging)
         return GMMR3UpdateReservation(pVM,
@@ -541,5 +542,5 @@
  * This can be called before MMR3InitPaging.
  *
- * @returns VBox status code.
+ * @returns VBox status code. Will set VM error on failure.
  * @param   pVM             The shared VM structure.
  * @param   cAddBasePages   The number of pages to add.
@@ -561,21 +562,23 @@
 
 /**
- * Interface for PGM to increase the reservation of fixed pages.
+ * Interface for PGM to adjust the reservation of fixed pages.
  *
  * This can be called before MMR3InitPaging.
  *
- * @returns VBox status code.
- * @param   pVM             The shared VM structure.
- * @param   cAddFixedPages  The number of pages to add.
- */
-MMR3DECL(int) MMR3IncreaseFixedReservation(PVM pVM, uint32_t cAddFixedPages)
+ * @returns VBox status code. Will set VM error on failure.
+ * @param   pVM                 The shared VM structure.
+ * @param   cDeltaFixedPages    The number of pages to add (positive) or subtract (negative).
+ * @param   pszDesc             Some description associated with the reservation.
+ */
+MMR3DECL(int) MMR3AdjustFixedReservation(PVM pVM, int32_t cDeltaFixedPages, const char *pszDesc)
 {
     const uint32_t cOld = pVM->mm.s.cFixedPages;
-    pVM->mm.s.cFixedPages += cAddFixedPages;
-    LogFlow(("MMR3AddFixedReservation: +%u (%u -> %u)\n", cAddFixedPages, cOld, pVM->mm.s.cFixedPages));
+    pVM->mm.s.cFixedPages += cDeltaFixedPages;
+    LogFlow(("MMR3AdjustFixedReservation: %d (%u -> %u)\n", cDeltaFixedPages, cOld, pVM->mm.s.cFixedPages));
     int rc = mmR3UpdateReservation(pVM);
     if (RT_FAILURE(rc))
     {
-        VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to reserve physical memory (%#x -> %#x)"), cOld, pVM->mm.s.cFixedPages);
+        VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to reserve physical memory (%#x -> %#x; %s)"),
+                   cOld, pVM->mm.s.cFixedPages, pszDesc);
         pVM->mm.s.cFixedPages = cOld;
     }
@@ -589,5 +592,5 @@
  * This can be called before MMR3InitPaging.
  *
- * @returns VBox status code.
+ * @returns VBox status code. Will set VM error on failure.
  * @param   pVM             The shared VM structure.
  * @param   cShadowPages    The new page count.
Index: trunk/src/VBox/VMM/MMHyper.cpp
===================================================================
--- trunk/src/VBox/VMM/MMHyper.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/MMHyper.cpp	(revision 7635)
@@ -183,4 +183,20 @@
             }
 
+            case MMLOOKUPHYPERTYPE_MMIO2:
+            {
+                const RTGCPHYS offEnd = pLookup->u.MMIO2.off + pLookup->cb;
+                for (RTGCPHYS offCur = pLookup->u.MMIO2.off; offCur < offEnd; offCur += PAGE_SIZE)
+                {
+                    RTHCPHYS HCPhys;
+                    rc = PGMR3PhysMMIO2GetHCPhys(pVM, pLookup->u.MMIO2.pDevIns, pLookup->u.MMIO2.iRegion, offCur, &HCPhys);
+                    if (RT_FAILURE(rc))
+                        break;
+                    rc = PGMMap(pVM, GCPtr + (offCur - pLookup->u.MMIO2.off), HCPhys, PAGE_SIZE, 0);
+                    if (RT_FAILURE(rc))
+                        break;
+                }
+                break;
+            }
+
             case MMLOOKUPHYPERTYPE_DYNAMIC:
                 /* do nothing here since these are either fences or managed by someone else using PGM. */
@@ -383,4 +399,87 @@
     return rc;
 }
+
+
+/**
+ * Maps a portion of an MMIO2 region into the hypervisor region.
+ *
+ * Callers of this API must never deregister the MMIO2 region before the
+ * VM is powered off. If this becomes a requirement MMR3HyperUnmapMMIO2
+ * API will be needed to perform cleanups.
+ *
+ * @return VBox status code.
+ *
+ * @param   pVM         Pointer to the shared VM structure.
+ * @param   pDevIns     The device owning the MMIO2 memory.
+ * @param   iRegion     The region.
+ * @param   off         The offset into the region. Will be rounded down to closest page boundrary.
+ * @param   cb          The number of bytes to map. Will be rounded up to the closest page boundrary.
+ * @param   pszDesc     Mapping description.
+ * @param   pGCPtr      Where to store the GC address.
+ */
+MMR3DECL(int) MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
+                                const char *pszDesc, PRTGCPTR pGCPtr)
+{
+    LogFlow(("MMR3HyperMapMMIO2: pDevIns=%p iRegion=%#x off=%VGp cb=%VGp pszDesc=%p:{%s} pGCPtr=%p\n",
+             pDevIns, iRegion, off, cb, pszDesc, pszDesc, pGCPtr));
+    int rc;
+
+    /*
+     * Validate input.
+     */
+    AssertReturn(pszDesc && *pszDesc, VERR_INVALID_PARAMETER);
+    AssertReturn(off + cb > off, VERR_INVALID_PARAMETER);
+    uint32_t const offPage = off & PAGE_OFFSET_MASK;
+    off &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
+    cb += offPage;
+    cb = RT_ALIGN_Z(cb, PAGE_SIZE);
+    const RTGCPHYS offEnd = off + cb;
+    AssertReturn(offEnd > off, VERR_INVALID_PARAMETER);
+    for (RTGCPHYS offCur = off; offCur < offEnd; offCur += PAGE_SIZE)
+    {
+        RTHCPHYS HCPhys;
+        rc = PGMR3PhysMMIO2GetHCPhys(pVM, pDevIns, iRegion, offCur, &HCPhys);
+        AssertMsgRCReturn(rc, ("rc=%Rrc - iRegion=%d off=%RGp\n", rc, iRegion, off), rc);
+    }
+
+    /*
+     * Add the memory to the hypervisor area.
+     */
+    RTGCPTR         GCPtr;
+    PMMLOOKUPHYPER  pLookup;
+    rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
+    if (VBOX_SUCCESS(rc))
+    {
+        pLookup->enmType = MMLOOKUPHYPERTYPE_MMIO2;
+        pLookup->u.MMIO2.pDevIns = pDevIns;
+        pLookup->u.MMIO2.iRegion = iRegion;
+        pLookup->u.MMIO2.off = off;
+
+        /*
+         * Update the page table.
+         */
+        if (pVM->mm.s.fPGMInitialized)
+        {
+            for (RTGCPHYS offCur = off; offCur < offEnd; offCur += PAGE_SIZE)
+            {
+                RTHCPHYS HCPhys;
+                rc = PGMR3PhysMMIO2GetHCPhys(pVM, pDevIns, iRegion, offCur, &HCPhys);
+                AssertRCReturn(rc, VERR_INTERNAL_ERROR);
+                rc = PGMMap(pVM, GCPtr + (offCur - off), HCPhys, PAGE_SIZE, 0);
+                if (VBOX_FAILURE(rc))
+                {
+                    AssertMsgFailed(("rc=%Vrc offCur=%RGp %s\n", rc, offCur, pszDesc));
+                    break;
+                }
+            }
+        }
+
+        if (VBOX_SUCCESS(rc) && pGCPtr)
+            *pGCPtr = GCPtr | offPage;
+    }
+    return rc;
+}
+
+
 
 
@@ -855,6 +954,7 @@
 
             case MMLOOKUPHYPERTYPE_GCPHYS:
+            case MMLOOKUPHYPERTYPE_MMIO2:
             case MMLOOKUPHYPERTYPE_DYNAMIC:
-                /* can convert these kind of records. */
+                /* can (or don't want to) convert these kind of records. */
                 break;
 
@@ -978,4 +1078,13 @@
                 break;
 
+            case MMLOOKUPHYPERTYPE_MMIO2:
+                pHlp->pfnPrintf(pHlp, "%VGv-%VGv %*s MMIO2   %VGp%*s %s\n",
+                                pLookup->off + pVM->mm.s.pvHyperAreaGC,
+                                pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
+                                sizeof(RTHCPTR) * 2, "",
+                                pLookup->u.MMIO2.off, RT_ABS(sizeof(RTHCPHYS) - sizeof(RTGCPHYS)) * 2, "",
+                                pLookup->pszDesc);
+                break;
+
             case MMLOOKUPHYPERTYPE_DYNAMIC:
                 pHlp->pfnPrintf(pHlp, "%VGv-%VGv %*s DYNAMIC %*s %s\n",
Index: trunk/src/VBox/VMM/MMInternal.h
===================================================================
--- trunk/src/VBox/VMM/MMInternal.h	(revision 7634)
+++ trunk/src/VBox/VMM/MMInternal.h	(revision 7635)
@@ -563,4 +563,6 @@
     /** Mapping of contiguous GC physical memory. */
     MMLOOKUPHYPERTYPE_GCPHYS,
+    /** Mapping of MMIO2 memory. */
+    MMLOOKUPHYPERTYPE_MMIO2,
     /** Dynamic mapping area (MMR3HyperReserve).
      * A conversion will require to check what's in the page table for the pages. */
@@ -610,4 +612,14 @@
             RTGCPHYS                GCPhys;
         } GCPhys;
+        /** MMIO2 memory. */
+        struct
+        {
+            /** The device instance owning the MMIO2 region. */
+            PPDMDEVINS              pDevIns;
+            /** The region number. */
+            uint32_t                iRegion;
+            /** The offset into the MMIO2 region. */
+            RTGCPHYS                off;
+        } MMIO2;
     } u;
     /** Description. */
Index: trunk/src/VBox/VMM/MMPhys.cpp
===================================================================
--- trunk/src/VBox/VMM/MMPhys.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/MMPhys.cpp	(revision 7635)
@@ -181,80 +181,4 @@
         /* Cleanup is done in VM destruction to which failure of this function will lead. */
         /* Not true in case of MM_PHYS_TYPE_DYNALLOC_CHUNK */
-    }
-
-    return rc;
-}
-
-
-/**
- * Relocate previously registered externally allocated RAM for the virtual machine.
- *
- * Use this only for MMIO ranges or the guest will become very confused.
- * The memory registered with the VM thru this interface must not be freed
- * before the virtual machine has been destroyed. Bad things may happen... :-)
- *
- * @return VBox status code.
- * @param   pVM         VM handle.
- * @param   GCPhysOld   The physical address the ram was registered at.
- * @param   GCPhysNew   The physical address the ram shall be registered at.
- * @param   cb          Size of the memory. Must be page aligend.
- */
-MMR3DECL(int) MMR3PhysRelocate(PVM pVM, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, unsigned cb)
-{
-    Log(("MMR3PhysRelocate: GCPhysOld=%VGp GCPhysNew=%VGp cb=%#x\n", GCPhysOld, GCPhysNew, cb));
-
-    /*
-     * Validate input.
-     */
-    AssertMsg(pVM, ("Invalid VM pointer\n"));
-    AssertReturn(RT_ALIGN_T(GCPhysOld, PAGE_SIZE, RTGCPHYS) == GCPhysOld, VERR_INVALID_PARAMETER);
-    AssertReturn(RT_ALIGN_T(GCPhysNew, PAGE_SIZE, RTGCPHYS) == GCPhysNew, VERR_INVALID_PARAMETER);
-    AssertReturn(RT_ALIGN(cb, PAGE_SIZE) == cb, VERR_INVALID_PARAMETER);
-    RTGCPHYS GCPhysLast;
-    GCPhysLast = GCPhysOld + (cb - 1);
-    AssertReturn(GCPhysLast > GCPhysOld, VERR_INVALID_PARAMETER);
-    GCPhysLast = GCPhysNew + (cb - 1);
-    AssertReturn(GCPhysLast > GCPhysNew, VERR_INVALID_PARAMETER);
-
-    /*
-     * Find the old memory region.
-     */
-    PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem;
-    while (pCur)
-    {
-        if (    pCur->eType == MM_LOCKED_TYPE_PHYS
-            &&  GCPhysOld == pCur->u.phys.GCPhys
-            &&  cb == pCur->cb)
-            break;
-
-        /* next */
-        pCur = pCur->pNext;
-    }
-    if (!pCur)
-    {
-        AssertMsgFailed(("Unknown old region! %VGp LB%#x\n", GCPhysOld, cb));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /*
-     * Region is already locked, just need to change GC address.
-     */
-/** @todo r=bird: check for conflicts? */
-    pCur->u.phys.GCPhys = GCPhysNew;
-
-    /*
-     * Relocate the registered RAM range with PGM.
-     */
-    int rc = PGMR3PhysRelocate(pVM, GCPhysOld, GCPhysNew, cb);
-    if (VBOX_SUCCESS(rc))
-    {
-        /* Somewhat hackish way to relocate the region with REM. There
-         * is unfortunately no official way to unregister anything with
-         * REM, as there is no way to unregister memory with QEMU.
-         * This implementation seems to work, but is not very pretty. */
-        /// @todo one day provide a proper MMIO relocation operation
-        REMR3NotifyPhysReserve(pVM, GCPhysOld, cb);
-        REMR3NotifyPhysRamRegister(pVM, GCPhysNew, cb,
-                                   pCur->aPhysPages[0].Phys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2));
     }
 
Index: trunk/src/VBox/VMM/PDM.cpp
===================================================================
--- trunk/src/VBox/VMM/PDM.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/PDM.cpp	(revision 7635)
@@ -107,4 +107,5 @@
 #include <VBox/pdm.h>
 #include <VBox/mm.h>
+#include <VBox/pgm.h>
 #include <VBox/ssm.h>
 #include <VBox/vm.h>
@@ -428,4 +429,5 @@
         //pdmR3ThreadDestroyDevice(pVM, pDevIns);
         //PDMR3QueueDestroyDevice(pVM, pDevIns);
+        PGMR3PhysMMIO2Deregister(pVM, pDevIns, UINT32_MAX);
     }
 
Index: trunk/src/VBox/VMM/PDMDevice.cpp
===================================================================
--- trunk/src/VBox/VMM/PDMDevice.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/PDMDevice.cpp	(revision 7635)
@@ -69,4 +69,5 @@
 *   Internal Functions                                                         *
 *******************************************************************************/
+__BEGIN_DECLS
 static DECLCALLBACK(int) pdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pDevReg);
 static DECLCALLBACK(void *) pdmR3DevReg_MMHeapAlloc(PPDMDEVREGCB pCallbacks, size_t cb);
@@ -162,4 +163,9 @@
                                                uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx);
 static DECLCALLBACK(int) pdmR3DevHlp_ROMProtectShadow(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTUINT cbRange);
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Register(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, void **ppv, const char *pszDesc);
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Deregister(PPDMDEVINS pDevIns, uint32_t iRegion);
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Map(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys);
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys);
+static DECLCALLBACK(int) pdmR3DevHlp_MMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTGCPTR pGCPtr);
 
 static DECLCALLBACK(PVM) pdmR3DevHlp_Untrusted_GetVM(PPDMDEVINS pDevIns);
@@ -196,4 +202,9 @@
                                                            uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx);
 static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_ROMProtectShadow(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTUINT cbRange);
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMIO2Register(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, void **ppv, const char *pszDesc);
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMIO2Deregister(PPDMDEVINS pDevIns, uint32_t iRegion);
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMIO2Map(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys);
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys);
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTGCPTR pGCPtr);
 /** @} */
 
@@ -247,4 +258,5 @@
 static DECLCALLBACK(void) pdmR3PciHlp_IsaSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel);
 static DECLCALLBACK(void) pdmR3PciHlp_IoApicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel);
+static DECLCALLBACK(bool) pdmR3PciHlp_IsMMIO2Base(PPDMDEVINS pDevIns, PPDMDEVINS pOwner, RTGCPHYS GCPhys);
 #ifdef VBOX_WITH_PDM_LOCK
 static DECLCALLBACK(int) pdmR3PciHlp_Lock(PPDMDEVINS pDevIns, int rc);
@@ -270,4 +282,6 @@
  */
 #define PDM_PHYS_READWRITE_FROM_ANY_THREAD
+
+__END_DECLS
 
 /*******************************************************************************
@@ -359,4 +373,9 @@
     pdmR3DevHlp_GetCpuId,
     pdmR3DevHlp_ROMProtectShadow,
+    pdmR3DevHlp_MMIO2Register,
+    pdmR3DevHlp_MMIO2Deregister,
+    pdmR3DevHlp_MMIO2Map,
+    pdmR3DevHlp_MMIO2Unmap,
+    pdmR3DevHlp_MMHyperMapMMIO2,
     PDM_DEVHLP_VERSION /* the end */
 };
@@ -448,4 +467,9 @@
     pdmR3DevHlp_Untrusted_QueryCPUId,
     pdmR3DevHlp_Untrusted_ROMProtectShadow,
+    pdmR3DevHlp_Untrusted_MMIO2Register,
+    pdmR3DevHlp_Untrusted_MMIO2Deregister,
+    pdmR3DevHlp_Untrusted_MMIO2Map,
+    pdmR3DevHlp_Untrusted_MMIO2Unmap,
+    pdmR3DevHlp_Untrusted_MMHyperMapMMIO2,
     PDM_DEVHLP_VERSION /* the end */
 };
@@ -514,10 +538,11 @@
     pdmR3PciHlp_IsaSetIrq,
     pdmR3PciHlp_IoApicSetIrq,
+    pdmR3PciHlp_IsMMIO2Base,
+    pdmR3PciHlp_GetGCHelpers,
+    pdmR3PciHlp_GetR0Helpers,
 #ifdef VBOX_WITH_PDM_LOCK
     pdmR3PciHlp_Lock,
     pdmR3PciHlp_Unlock,
 #endif
-    pdmR3PciHlp_GetGCHelpers,
-    pdmR3PciHlp_GetR0Helpers,
     PDM_PCIHLPR3_VERSION, /* the end */
 };
@@ -1884,4 +1909,5 @@
     LogFlow(("pdmR3DevHlp_ISASetIrq: caller='%s'/%d: returns void\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
 }
+
 
 /** @copydoc PDMDEVHLP::pfnISASetIrqNoWait */
@@ -3598,4 +3624,94 @@
 
 
+/**
+ * @copydoc PDMDEVHLP::pfnMMIO2Register
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Register(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, void **ppv, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VM_ASSERT_EMT(pDevIns->Internal.s.pVMHC);
+    LogFlow(("pdmR3DevHlp_MMIO2Register: caller='%s'/%d: iRegion=#x cb=%#RGp ppv=%p pszDescp=%p:{%s}\n",
+             pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, iRegion, cb, ppv, pszDesc, pszDesc));
+
+    int rc = PGMR3PhysMMIO2Register(pDevIns->Internal.s.pVMHC, pDevIns, iRegion, cb, ppv, pszDesc);
+
+    LogFlow(("pdmR3DevHlp_MMIO2Register: caller='%s'/%d: returns %Rrc\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMIO2Deregister
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Deregister(PPDMDEVINS pDevIns, uint32_t iRegion)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VM_ASSERT_EMT(pDevIns->Internal.s.pVMHC);
+    LogFlow(("pdmR3DevHlp_MMIO2Deregister: caller='%s'/%d: iRegion=#x\n",
+             pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, iRegion));
+
+    AssertReturn(iRegion == UINT32_MAX, VERR_INVALID_PARAMETER);
+
+    int rc = PGMR3PhysMMIO2Deregister(pDevIns->Internal.s.pVMHC, pDevIns, iRegion);
+
+    LogFlow(("pdmR3DevHlp_MMIO2Deregister: caller='%s'/%d: returns %Rrc\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMIO2Map
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Map(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VM_ASSERT_EMT(pDevIns->Internal.s.pVMHC);
+    LogFlow(("pdmR3DevHlp_MMIO2Map: caller='%s'/%d: iRegion=#x GCPhys=%#RGp\n",
+             pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, iRegion, GCPhys));
+
+    int rc = PGMR3PhysMMIO2Map(pDevIns->Internal.s.pVMHC, pDevIns, iRegion, GCPhys);
+
+    LogFlow(("pdmR3DevHlp_MMIO2Map: caller='%s'/%d: returns %Rrc\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMIO2Unmap
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VM_ASSERT_EMT(pDevIns->Internal.s.pVMHC);
+    LogFlow(("pdmR3DevHlp_MMIO2Unmap: caller='%s'/%d: iRegion=#x GCPhys=%#RGp\n",
+             pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, iRegion, GCPhys));
+
+    int rc = PGMR3PhysMMIO2Unmap(pDevIns->Internal.s.pVMHC, pDevIns, iRegion, GCPhys);
+
+    LogFlow(("pdmR3DevHlp_MMIO2Unmap: caller='%s'/%d: returns %Rrc\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLP::pfnMMHyperMapMMIO2
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
+                                                     const char *pszDesc, PRTGCPTR pGCPtr)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VM_ASSERT_EMT(pDevIns->Internal.s.pVMHC);
+    LogFlow(("pdmR3DevHlp_MMHyperMapMMIO2: caller='%s'/%d: iRegion=#x off=%RGp cb=%RGp pszDesc=%p:{%s} pGCPtr=%p\n",
+             pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, iRegion, off, cb, pszDesc, pszDesc, pGCPtr));
+
+    int rc = MMR3HyperMapMMIO2(pDevIns->Internal.s.pVMHC, pDevIns, iRegion, off, cb, pszDesc, pGCPtr);
+
+    LogFlow(("pdmR3DevHlp_MMHyperMapMMIO2: caller='%s'/%d: returns %Rrc\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+
+
 
 /** @copydoc PDMDEVHLP::pfnGetVM */
@@ -3906,4 +4022,51 @@
     return VERR_ACCESS_DENIED;
 }
+
+
+/** @copydoc PDMDEVHLP::pfnMMIO2Register */
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMIO2Register(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, void **ppv, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertReleaseMsgFailed(("Untrusted device called trusted helper! '%s'/%d\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
+    return VERR_ACCESS_DENIED;
+}
+
+
+/** @copydoc PDMDEVHLP::pfnMMIO2Deregister */
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMIO2Deregister(PPDMDEVINS pDevIns, uint32_t iRegion)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertReleaseMsgFailed(("Untrusted device called trusted helper! '%s'/%d\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
+    return VERR_ACCESS_DENIED;
+}
+
+
+/** @copydoc PDMDEVHLP::pfnMMIO2Map */
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMIO2Map(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertReleaseMsgFailed(("Untrusted device called trusted helper! '%s'/%d\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
+    return VERR_ACCESS_DENIED;
+}
+
+
+/** @copydoc PDMDEVHLP::pfnMMIO2Unmap */
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMIO2Unmap(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertReleaseMsgFailed(("Untrusted device called trusted helper! '%s'/%d\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
+    return VERR_ACCESS_DENIED;
+}
+
+
+/** @copydoc PDMDEVHLP::pfnMMHyperMapMMIO2 */
+static DECLCALLBACK(int) pdmR3DevHlp_Untrusted_MMHyperMapMMIO2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTGCPTR pGCPtr)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertReleaseMsgFailed(("Untrusted device called trusted helper! '%s'/%d\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
+    return VERR_ACCESS_DENIED;
+}
+
+
 
 
@@ -4153,4 +4316,15 @@
     Log4(("pdmR3PciHlp_IsaSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
     PDMIoApicSetIrq(pDevIns->Internal.s.pVMHC, iIrq, iLevel);
+}
+
+
+/** @copydoc PDMPCIHLPR3::pfnIsMMIO2Base */
+static DECLCALLBACK(bool) pdmR3PciHlp_IsMMIO2Base(PPDMDEVINS pDevIns, PPDMDEVINS pOwner, RTGCPHYS GCPhys)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VM_ASSERT_EMT(pDevIns->Internal.s.pVMHC);
+    bool fRc = PGMR3PhysMMIO2IsBase(pDevIns->Internal.s.pVMHC, pOwner, GCPhys);
+    Log4(("pdmR3PciHlp_IsMMIO2Base: pOwner=%p GCPhys=%RGp -> %RTbool\n", pOwner, GCPhys, fRc));
+    return fRc;
 }
 
Index: trunk/src/VBox/VMM/PGMInternal.h
===================================================================
--- trunk/src/VBox/VMM/PGMInternal.h	(revision 7634)
+++ trunk/src/VBox/VMM/PGMInternal.h	(revision 7635)
@@ -573,5 +573,6 @@
         (pPage)->fSomethingElse = 0; \
         (pPage)->idPageX        = (_idPage); \
-        (pPage)->u3Type         = (_uType); \
+        /*(pPage)->u3Type         = (_uType); - later */ \
+        PGM_PAGE_SET_TYPE(pPage, _uType); \
         (pPage)->u29B           = 0; \
     } while (0)
@@ -599,5 +600,6 @@
 #define PGM_PAGE_STATE_ZERO             0
 /** A allocated page.
- * This is a per-VM page allocated from the page pool.
+ * This is a per-VM page allocated from the page pool (or wherever
+ * we get MMIO2 pages from if the type is MMIO2).
  */
 #define PGM_PAGE_STATE_ALLOCATED        1
@@ -713,6 +715,19 @@
  * @param   _enmType    The new page type (PGMPAGETYPE).
  */
+#ifdef VBOX_WITH_NEW_PHYS_CODE
 #define PGM_PAGE_SET_TYPE(pPage, _enmType) \
                                         do { (pPage)->u3Type = (_enmType); } while (0)
+#else
+#define PGM_PAGE_SET_TYPE(pPage, _enmType) \
+    do { \
+        (pPage)->u3Type = (_enmType); \
+        if ((_enmType) == PGMPAGETYPE_ROM) \
+            (pPage)->HCPhys |= MM_RAM_FLAGS_ROM; \
+        else if ((_enmType) == PGMPAGETYPE_ROM_SHADOW) \
+            (pPage)->HCPhys |= MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2; \
+        else if ((_enmType) == PGMPAGETYPE_MMIO2) \
+            (pPage)->HCPhys |= MM_RAM_FLAGS_MMIO2; \
+    } while (0)
+#endif
 
 
@@ -985,5 +1000,5 @@
     /** Pointer to the next range - R0. */
     R0PTRTYPE(struct PGMROMRANGE *) pNextR0;
-    /** Pointer to the next range - R0. */
+    /** Pointer to the next range - GC. */
     GCPTRTYPE(struct PGMROMRANGE *) pNextGC;
 #if GC_ARCH_BITS == 32
@@ -1010,4 +1025,43 @@
 /** Pointer to a ROM range. */
 typedef PGMROMRANGE *PPGMROMRANGE;
+
+
+/**
+ * A registered MMIO2 (= Device RAM) range.
+ *
+ * There are a few reason why we need to keep track of these
+ * registrations. One of them is the deregistration & cleanup
+ * stuff, while another is that the PGMRAMRANGE associated with
+ * such a region may have to be removed from the ram range list.
+ *
+ * Overlapping with a RAM range has to be 100% or none at all. The
+ * pages in the existing RAM range must not be ROM nor MMIO. A guru
+ * meditation will be raised if a partial overlap or an overlap of
+ * ROM pages is encountered. On an overlap we will free all the
+ * existing RAM pages and put in the ram range pages instead.
+ */
+typedef struct PGMMMIO2RANGE
+{
+    /** The owner of the range. (a device) */
+    PPDMDEVINSR3                        pDevInsR3;
+    /** Pointer to the ring-3 mapping of the allocation. */
+    RTR3PTR                             pvR3;
+    /** Pointer to the next range - R3. */
+    R3PTRTYPE(struct PGMMMIO2RANGE *)   pNextR3;
+    /** Whether it's mapped or not. */
+    bool                                fMapped;
+    /** Whether it's overlapping or not. */
+    bool                                fOverlapping;
+    /** The PCI region number.
+     * @remarks This ASSUMES that nobody will ever really need to have multiple
+     *          PCI devices with matching MMIO region numbers on a single device. */
+    uint8_t                             iRegion;
+    /**< Alignment padding for putting the ram range on a PGMPAGE alignment boundrary. */
+    uint8_t                             abAlignemnt[HC_ARCH_BITS == 32 ? 1 : 5];
+    /** The associated RAM range. */
+    PGMRAMRANGE                         RamRange;
+} PGMMMIO2RANGE;
+/** Pointer to a MMIO2 range. */
+typedef PGMMMIO2RANGE *PPGMMMIO2RANGE;
 
 
@@ -2048,4 +2102,8 @@
     RTGCPTR                         GCPtrPadding2;
 
+    /** Pointer to the list of MMIO2 ranges - for R3.
+     * Registration order. */
+    R3PTRTYPE(PPGMMMIO2RANGE)       pMmio2RangesR3;
+
     /** PGM offset based trees - HC Ptr. */
     R3R0PTRTYPE(PPGMTREES)          pTreesHC;
@@ -2529,4 +2587,5 @@
 
 
+void            pgmPhysFreePage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys);
 int             pgmPhysPageLoadIntoTlb(PPGM pPGM, RTGCPHYS GCPhys);
 int             pgmPhysPageMakeWritable(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys);
Index: trunk/src/VBox/VMM/PGMPhys.cpp
===================================================================
--- trunk/src/VBox/VMM/PGMPhys.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/PGMPhys.cpp	(revision 7635)
@@ -110,5 +110,5 @@
 
 /**
- * Links a new RAM range into the list.
+ * Unlink an existing RAM range from the list.
  *
  * @param   pVM         Pointer to the shared VM structure.
@@ -116,5 +116,5 @@
  * @param   pPrev       Pointer to the previous list entry. If NULL, insert as head.
  */
-static void pgmR3PhysUnlinkRamRange(PVM pVM, PPGMRAMRANGE pRam, PPGMRAMRANGE pPrev)
+static void pgmR3PhysUnlinkRamRange2(PVM pVM, PPGMRAMRANGE pRam, PPGMRAMRANGE pPrev)
 {
     Assert(pPrev ? pPrev->pNextR3 == pRam : pVM->pgm.s.pRamRangesR3 == pRam);
@@ -131,4 +131,5 @@
     else
     {
+        Assert(pVM->pgm.s.pRamRangesR3 == pRam);
         pVM->pgm.s.pRamRangesR3 = pNext;
         pVM->pgm.s.pRamRangesR0 = pNext ? MMHyperCCToR0(pVM, pNext) : NIL_RTR0PTR;
@@ -137,4 +138,26 @@
 
     pgmUnlock(pVM);
+}
+
+
+/**
+ * Unlink an existing RAM range from the list.
+ *
+ * @param   pVM         Pointer to the shared VM structure.
+ * @param   pRam        Pointer to the new list entry.
+ */
+static void pgmR3PhysUnlinkRamRange(PVM pVM, PPGMRAMRANGE pRam)
+{
+    /* find prev. */
+    PPGMRAMRANGE pPrev = NULL;
+    PPGMRAMRANGE pCur = pVM->pgm.s.pRamRangesR3;
+    while (pCur != pRam)
+    {
+        pPrev = pCur;
+        pCur = pCur->pNextR3;
+    }
+    AssertFatal(pCur);
+
+    pgmR3PhysUnlinkRamRange2(pVM, pRam, pPrev);
 }
 
@@ -202,5 +225,5 @@
     PPGMRAMRANGE pNew;
     rc = MMR3HyperAllocOnceNoRel(pVM, cbRamRange, 0, MM_TAG_PGM_PHYS, (void **)&pNew);
-    AssertLogRelMsgRCReturn(rc, ("cbRamRange=%zd\n", cbRamRange), rc);
+    AssertLogRelMsgRCReturn(rc, ("cbRamRange=%zu\n", cbRamRange), rc);
 
     /*
@@ -275,4 +298,24 @@
 
 /**
+ * Locate a MMIO2 range.
+ *
+ * @returns Pointer to the MMIO2 range.
+ * @param   pVM             Pointer to the shared VM structure.
+ * @param   pDevIns         The device instance owning the region.
+ * @param   iRegion         The region.
+ */
+DECLINLINE(PPGMMMIO2RANGE) pgmR3PhysMMIO2Find(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion)
+{
+    /*
+     * Search the list.
+     */
+    for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
+        if (pCur->pDevInsR3 == pDevIns)
+            return pCur;
+    return NULL;
+}
+
+
+/**
  * Allocate and register a MMIO2 region.
  *
@@ -287,33 +330,441 @@
  * is replaced, this is of course incorrectly but it's too much
  * effort.
- */
-PDMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb, void **ppv, const char *pszDesc)
-{
-    return -1;
-}
-
-
-/**
- * Reallocates a MMIO2 region.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS on success, *ppv pointing to the R3 mapping of the memory.
+ * @retval  VERR_ALREADY_EXISTS if the region already exists.
+ *
+ * @param   pVM             Pointer to the shared VM structure.
+ * @param   pDevIns         The device instance owning the region.
+ * @param   iRegion         The region number. If the MMIO2 memory is a PCI I/O region
+ *                          this number has to be the number of that region. Otherwise
+ *                          it can be any number safe UINT8_MAX.
+ * @param   cb              The size of the region. Must be page aligned.
+ * @param   ppv             Where to store the pointer to the ring-3 mapping of the memory.
+ * @param   pszDesc         The description.
+ */
+PDMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, void **ppv, const char *pszDesc)
+{
+    /*
+     * Validate input.
+     */
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(ppv, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
+    AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
+    AssertReturn(pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion) == NULL, VERR_ALREADY_EXISTS);
+    AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+    AssertReturn(cb, VERR_INVALID_PARAMETER);
+
+    const uint32_t cPages = cb >> PAGE_SHIFT;
+    AssertLogRelReturn((RTGCPHYS)cPages << PAGE_SHIFT == cb, VERR_INVALID_PARAMETER);
+    AssertLogRelReturn(cPages <= INT32_MAX / 2, VERR_NO_MEMORY);
+
+    /*
+     * Try reserve and allocate the backing memory first as this is what is
+     * most likely to fail.
+     */
+    int rc = MMR3AdjustFixedReservation(pVM, cPages, pszDesc);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    void *pvPages;
+    PSUPPAGE paPages = (PSUPPAGE)RTMemTmpAlloc(cPages * sizeof(SUPPAGE));
+    if (RT_SUCCESS(rc))
+        rc = SUPPageAllocLockedEx(cPages, &pvPages, paPages);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Create the MMIO2 range record for it.
+         */
+        const size_t cbRange = RT_OFFSETOF(PGMMMIO2RANGE, RamRange.aPages[cPages]);
+        PPGMMMIO2RANGE pNew;
+        rc = MMR3HyperAllocOnceNoRel(pVM, cbRange, 0, MM_TAG_PGM_PHYS, (void **)&pNew);
+        AssertLogRelMsgRC(rc, ("cbRamRange=%zu\n", cbRange));
+        if (RT_SUCCESS(rc))
+        {
+            pNew->pDevInsR3 = pDevIns;
+            pNew->pvR3 = pvPages;
+            //pNew->pNext = NULL;
+            //pNew->fMapped = false;
+            //pNew->fOverlapping = false;
+            pNew->iRegion = iRegion;
+            pNew->RamRange.GCPhys = NIL_RTGCPHYS;
+            pNew->RamRange.GCPhysLast = NIL_RTGCPHYS;
+            pNew->RamRange.pszDesc = pszDesc;
+            pNew->RamRange.cb = cb;
+            //pNew->RamRange.fFlags = 0;
+
+            pNew->RamRange.pvHC = pvPages;      ///@todo remove this
+            pNew->RamRange.pavHCChunkHC = NULL; ///@todo remove this
+            pNew->RamRange.pavHCChunkGC = 0;    ///@todo remove this
+
+            uint32_t iPage = cPages;
+            while (iPage-- > 0)
+            {
+                PGM_PAGE_INIT(&pNew->RamRange.aPages[iPage],
+                              paPages[iPage].Phys & X86_PTE_PAE_PG_MASK, NIL_GMM_PAGEID,
+                              PGMPAGETYPE_MMIO2, PGM_PAGE_STATE_ALLOCATED);
+            }
+
+            /*
+             * Link it into the list.
+             * Since there is no particular order, just push it.
+             */
+            pNew->pNextR3 = pVM->pgm.s.pMmio2RangesR3;
+            pVM->pgm.s.pMmio2RangesR3 = pNew;
+
+            *ppv = pvPages;
+            RTMemTmpFree(paPages);
+            return VINF_SUCCESS;
+        }
+
+        SUPPageFreeLocked(pvPages, cPages);
+    }
+    RTMemTmpFree(paPages);
+    MMR3AdjustFixedReservation(pVM, -cPages, pszDesc);
+    return rc;
+}
+
+
+/**
+ * Deregisters and frees a MMIO2 region.
+ *
+ * Any physical (and virtual) access handlers registered for the region must
+ * be deregistered before calling this function.
+ *
+ * @returns VBox status code.
+ * @param   pVM             Pointer to the shared VM structure.
+ * @param   pDevIns         The device instance owning the region.
+ * @param   iRegion         The region. If it's UINT32_MAX it'll be a wildcard match.
+ */
+PDMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion)
+{
+    /*
+     * Validate input.
+     */
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iRegion <= UINT8_MAX || iRegion == UINT32_MAX, VERR_INVALID_PARAMETER);
+
+    int rc = VINF_SUCCESS;
+    unsigned cFound = 0;
+    PPGMMMIO2RANGE pPrev = NULL;
+    PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3;
+    while (pCur)
+    {
+        if (    pCur->pDevInsR3 == pDevIns
+            &&  (   iRegion == UINT32_MAX
+                 || pCur->iRegion == iRegion))
+        {
+            cFound++;
+
+            /*
+             * Unmap it if it's mapped.
+             */
+            if (pCur->fMapped)
+            {
+                int rc2 = PGMR3PhysMMIO2Unmap(pVM, pCur->pDevInsR3, pCur->iRegion, pCur->RamRange.GCPhys);
+                AssertRC(rc2);
+                if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+                    rc = rc2;
+            }
+
+            /*
+             * Unlink it
+             */
+            PPGMMMIO2RANGE pNext = pCur->pNextR3;
+            if (pPrev)
+                pPrev->pNextR3 = pNext;
+            else
+                pVM->pgm.s.pMmio2RangesR3 = pNext;
+            pCur->pNextR3 = NULL;
+
+            /*
+             * Free the memory.
+             */
+            int rc2 = SUPPageFreeLocked(pCur->pvR3, pCur->RamRange.cb >> PAGE_SHIFT);
+            AssertRC(rc2);
+            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+                rc = rc2;
+
+            rc2 = MMR3AdjustFixedReservation(pVM, -(pCur->RamRange.cb >> PAGE_SHIFT), pCur->RamRange.pszDesc);
+            AssertRC(rc2);
+            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+                rc = rc2;
+
+            /* we're leaking hyper memory here if done at runtime. */
+            Assert(   VMR3GetState(pVM) == VMSTATE_OFF
+                   || VMR3GetState(pVM) == VMSTATE_DESTROYING
+                   || VMR3GetState(pVM) == VMSTATE_TERMINATED);
+            /*rc = MMHyperFree(pVM, pCur);
+            AssertRCReturn(rc, rc); - not safe, see the alloc call. */
+
+            /* next */
+            pCur = pNext;
+        }
+        else
+        {
+            pPrev = pCur;
+            pCur = pCur->pNextR3;
+        }
+    }
+
+    return !cFound && iRegion != UINT32_MAX ? VERR_NOT_FOUND : rc;
+}
+
+
+/**
+ * Maps a MMIO2 region.
  *
  * This is done when a guest / the bios / state loading changes the
  * PCI config. The replacing of base memory has the same restrictions
  * as during registration, of course.
- */
-PDMR3DECL(int) PGMR3PhysMMIO2Relocate(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew)
-{
-    return -1;
-}
-
-
-/**
- * Deregisters and frees a MMIO2 region.
- *
- * Any physical (and virtual) access handlers registered for the region must
- * be deregistered before calling this function.
- */
-PDMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, RTGCPHYS GCPhys, void *pv)
-{
-    return -1;
+ *
+ * @returns VBox status code.
+ *
+ * @param   pVM             Pointer to the shared VM structure.
+ * @param   pDevIns         The
+ */
+PDMR3DECL(int) PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    /*
+     * Validate input
+     */
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
+    AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
+    AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
+    AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+
+    PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
+    AssertReturn(pCur, VERR_NOT_FOUND);
+    AssertReturn(!pCur->fMapped, VERR_WRONG_ORDER);
+    Assert(pCur->RamRange.GCPhys == NIL_RTGCPHYS);
+    Assert(pCur->RamRange.GCPhysLast == NIL_RTGCPHYS);
+
+    const RTGCPHYS GCPhysLast = GCPhys + pCur->RamRange.cb - 1;
+    AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
+
+    /*
+     * Find our location in the ram range list, checking for
+     * restriction we don't bother implementing yet (partially overlapping).
+     */
+    bool fRamExists = false;
+    PPGMRAMRANGE pRamPrev = NULL;
+    PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
+    while (pRam && GCPhysLast >= pRam->GCPhys)
+    {
+        if (    GCPhys     <= pRam->GCPhysLast
+            &&  GCPhysLast >= pRam->GCPhys)
+        {
+            /* completely within? */
+            AssertLogRelMsgReturn(   GCPhys     >= pRam->GCPhys
+                                  && GCPhysLast <= pRam->GCPhysLast,
+                                  ("%RGp-%RGp (MMIO2/%s) falls partly outside %RGp-%RGp (%s)\n",
+                                   GCPhys, GCPhysLast, pCur->RamRange.pszDesc,
+                                   pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
+                                  VERR_PGM_RAM_CONFLICT);
+            fRamExists = true;
+            break;
+        }
+
+        /* next */
+        pRamPrev = pRam;
+        pRam = pRam->pNextR3;
+    }
+    if (fRamExists)
+    {
+        PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
+        uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
+        while (cPagesLeft-- > 0)
+        {
+            AssertLogRelMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
+                                  ("%RGp isn't a RAM page (%d) - mapping %RGp-%RGp (MMIO2/%s).\n",
+                                   GCPhys, PGM_PAGE_GET_TYPE(pPage), GCPhys, GCPhysLast, pCur->RamRange.pszDesc),
+                                  VERR_PGM_RAM_CONFLICT);
+            pPage++;
+        }
+    }
+    Log(("PGMR3PhysMMIO2Map: %RGp-%RGp fRamExists=%RTbool %s\n",
+         GCPhys, GCPhysLast, fRamExists, pCur->RamRange.pszDesc));
+
+    /*
+     * Make the changes.
+     */
+    pgmLock(pVM);
+
+    pCur->RamRange.GCPhys = GCPhys;
+    pCur->RamRange.GCPhysLast = GCPhysLast;
+    pCur->fMapped = true;
+    pCur->fOverlapping = fRamExists;
+
+    if (fRamExists)
+    {
+        /* replace the pages, freeing all present RAM pages. */
+        PPGMPAGE pPageSrc = &pCur->RamRange.aPages[0];
+        PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
+        uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
+        while (cPagesLeft-- > 0)
+        {
+            pgmPhysFreePage(pVM, pPageDst, GCPhys);
+
+            RTHCPHYS const HCPhys = PGM_PAGE_GET_HCPHYS(pPageSrc);
+            PGM_PAGE_SET_HCPHYS(pPageDst, HCPhys);
+            PGM_PAGE_SET_TYPE(pPageDst, PGMPAGETYPE_MMIO2);
+            PGM_PAGE_SET_STATE(pPageDst, PGM_PAGE_STATE_ALLOCATED);
+
+            GCPhys += PAGE_SIZE;
+            pPageSrc++;
+            pPageDst++;
+        }
+    }
+    else
+    {
+        /* link in the ram range */
+        pgmR3PhysLinkRamRange(pVM, &pCur->RamRange, pRamPrev);
+        REMR3NotifyPhysRamRegister(pVM, GCPhys, pCur->RamRange.cb, 0);
+    }
+
+    pgmUnlock(pVM);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Unmaps a MMIO2 region.
+ *
+ * This is done when a guest / the bios / state loading changes the
+ * PCI config. The replacing of base memory has the same restrictions
+ * as during registration, of course.
+ */
+PDMR3DECL(int) PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    /*
+     * Validate input
+     */
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
+    AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
+    AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
+    AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+
+    PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
+    AssertReturn(pCur, VERR_NOT_FOUND);
+    AssertReturn(pCur->fMapped, VERR_WRONG_ORDER);
+    AssertReturn(pCur->RamRange.GCPhys == GCPhys, VERR_INVALID_PARAMETER);
+    Assert(pCur->RamRange.GCPhysLast != NIL_RTGCPHYS);
+
+    Log(("PGMR3PhysMMIO2Unmap: %RGp-%RGp %s\n",
+         pCur->RamRange.GCPhys, pCur->RamRange.GCPhysLast, pCur->RamRange.pszDesc));
+
+    /*
+     * Unmap it.
+     */
+    pgmLock(pVM);
+
+    if (pCur->fOverlapping)
+    {
+        /* Restore the RAM pages we've replaced. */
+        PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
+        while (pRam->GCPhys > pCur->RamRange.GCPhysLast)
+            pRam = pRam->pNextR3;
+
+        RTHCPHYS const HCPhysZeroPg = pVM->pgm.s.HCPhysZeroPg;
+        Assert(HCPhysZeroPg != 0 && HCPhysZeroPg != NIL_RTHCPHYS);
+        PPGMPAGE pPageDst = &pRam->aPages[(pCur->RamRange.GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
+        uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
+        while (cPagesLeft-- > 0)
+        {
+            PGM_PAGE_SET_HCPHYS(pPageDst, pVM->pgm.s.HCPhysZeroPg);
+            PGM_PAGE_SET_TYPE(pPageDst, PGMPAGETYPE_RAM);
+            PGM_PAGE_SET_STATE(pPageDst, PGM_PAGE_STATE_ZERO);
+
+            pPageDst++;
+        }
+    }
+    else
+    {
+        REMR3NotifyPhysReserve(pVM, pCur->RamRange.GCPhys, pCur->RamRange.cb);
+        pgmR3PhysUnlinkRamRange(pVM, &pCur->RamRange);
+    }
+
+    pCur->RamRange.GCPhys = NIL_RTGCPHYS;
+    pCur->RamRange.GCPhysLast = NIL_RTGCPHYS;
+    pCur->fOverlapping = false;
+    pCur->fMapped = false;
+
+    pgmUnlock(pVM);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Checks if the given address is an MMIO2 base address or not.
+ *
+ * @returns true/false accordingly.
+ * @param   pVM             Pointer to the shared VM structure.
+ * @param   pDevIns         The owner of the memory, optional.
+ * @param   GCPhys          The address to check.
+ */
+PDMR3DECL(bool) PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
+{
+    /*
+     * Validate input
+     */
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
+    AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
+    AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+
+    /*
+     * Search the list.
+     */
+    for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
+        if (pCur->RamRange.GCPhys == GCPhys)
+        {
+            Assert(pCur->fMapped);
+            return true;
+        }
+    return false;
+}
+
+
+/**
+ * Gets the HC physical address of a page in the MMIO2 region.
+ *
+ * This is API is intended for MMHyper and shouldn't be called
+ * by anyone else...
+ *
+ * @returns VBox status code.
+ * @param   pVM             Pointer to the shared VM structure.
+ * @param   pDevIns         The owner of the memory, optional.
+ * @param   iRegion         The region.
+ * @param   off             The page expressed an offset into the MMIO2 region.
+ * @param   pHCPhys         Where to store the result.
+ */
+PDMR3DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys)
+{
+    /*
+     * Validate input
+     */
+    VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
+    AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
+    AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
+
+    PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
+    AssertReturn(pCur, VERR_NOT_FOUND);
+    AssertReturn(off < pCur->RamRange.cb, VERR_INVALID_PARAMETER);
+
+    PCPGMPAGE pPage = &pCur->RamRange.aPages[off >> PAGE_SHIFT];
+    *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage);
+    return VINF_SUCCESS;
 }
 
@@ -431,4 +882,5 @@
                                   VERR_PGM_RAM_CONFLICT);
             Assert(PGM_PAGE_IS_ZERO(pPage));
+            pPage++;
         }
     }
@@ -616,5 +1068,5 @@
             }
 
-            pgmR3PhysUnlinkRamRange(pVM, pRamNew, pRamPrev);
+            pgmR3PhysUnlinkRamRange2(pVM, pRamNew, pRamPrev);
             if (pRamNew)
                 MMHyperFree(pVM, pRamNew);
@@ -1278,120 +1730,4 @@
 
 #endif /* !VBOX_WITH_NEW_PHYS_CODE */
-
-/**
- * Interface MMIO handler relocation calls.
- *
- * It relocates an existing physical memory range with PGM.
- *
- * @returns VBox status.
- * @param   pVM             The VM handle.
- * @param   GCPhysOld       Previous GC physical address of the RAM range. (page aligned)
- * @param   GCPhysNew       New GC physical address of the RAM range. (page aligned)
- * @param   cb              Size of the RAM range. (page aligned)
- */
-PGMR3DECL(int) PGMR3PhysRelocate(PVM pVM, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, size_t cb)
-{
-    /*
-     * Validate input.
-     * (Not so important because callers are only MMR3PhysRelocate(),
-     *  but anyway...)
-     */
-    Log(("PGMR3PhysRelocate Old %VGp New %VGp (%#x bytes)\n", GCPhysOld, GCPhysNew, cb));
-
-    Assert(RT_ALIGN_Z(cb, PAGE_SIZE) == cb && cb);
-    Assert(RT_ALIGN_T(GCPhysOld, PAGE_SIZE, RTGCPHYS) == GCPhysOld);
-    Assert(RT_ALIGN_T(GCPhysNew, PAGE_SIZE, RTGCPHYS) == GCPhysNew);
-    RTGCPHYS GCPhysLast;
-    GCPhysLast = GCPhysOld + (cb - 1);
-    if (GCPhysLast < GCPhysOld)
-    {
-        AssertMsgFailed(("The old range wraps! GCPhys=%VGp cb=%#x\n", GCPhysOld, cb));
-        return VERR_INVALID_PARAMETER;
-    }
-    GCPhysLast = GCPhysNew + (cb - 1);
-    if (GCPhysLast < GCPhysNew)
-    {
-        AssertMsgFailed(("The new range wraps! GCPhys=%VGp cb=%#x\n", GCPhysNew, cb));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /*
-     * Find and remove old range location.
-     */
-    pgmLock(pVM);
-    PPGMRAMRANGE    pPrev = NULL;
-    PPGMRAMRANGE    pCur = pVM->pgm.s.pRamRangesR3;
-    while (pCur)
-    {
-        if (pCur->GCPhys == GCPhysOld && pCur->cb == cb)
-            break;
-
-        /* next */
-        pPrev = pCur;
-        pCur = pCur->pNextR3;
-    }
-    if (pPrev)
-    {
-        pPrev->pNextR3 = pCur->pNextR3;
-        pPrev->pNextR0 = pCur->pNextR0;
-        pPrev->pNextGC = pCur->pNextGC;
-    }
-    else
-    {
-        pVM->pgm.s.pRamRangesR3 = pCur->pNextR3;
-        pVM->pgm.s.pRamRangesR0 = pCur->pNextR0;
-        pVM->pgm.s.pRamRangesGC = pCur->pNextGC;
-    }
-
-    /*
-     * Update the range.
-     */
-    pCur->GCPhys    = GCPhysNew;
-    pCur->GCPhysLast= GCPhysLast;
-    PPGMRAMRANGE    pNew = pCur;
-
-    /*
-     * Find range location and check for conflicts.
-     */
-    pPrev = NULL;
-    pCur = pVM->pgm.s.pRamRangesR3;
-    while (pCur)
-    {
-        if (GCPhysNew <= pCur->GCPhysLast && GCPhysLast >= pCur->GCPhys)
-        {
-            AssertMsgFailed(("Conflict! This cannot happen!\n"));
-            pgmUnlock(pVM);
-            return VERR_PGM_RAM_CONFLICT;
-        }
-        if (GCPhysLast < pCur->GCPhys)
-            break;
-
-        /* next */
-        pPrev = pCur;
-        pCur = pCur->pNextR3;
-    }
-
-    /*
-     * Reinsert the RAM range.
-     */
-    pNew->pNextR3 = pCur;
-    pNew->pNextR0 = pCur ? MMHyperCCToR0(pVM, pCur) : 0;
-    pNew->pNextGC = pCur ? MMHyperCCToGC(pVM, pCur) : 0;
-    if (pPrev)
-    {
-        pPrev->pNextR3 = pNew;
-        pPrev->pNextR0 = MMHyperCCToR0(pVM, pNew);
-        pPrev->pNextGC = MMHyperCCToGC(pVM, pNew);
-    }
-    else
-    {
-        pVM->pgm.s.pRamRangesR3 = pNew;
-        pVM->pgm.s.pRamRangesR0 = MMHyperCCToR0(pVM, pNew);
-        pVM->pgm.s.pRamRangesGC = MMHyperCCToGC(pVM, pNew);
-    }
-
-    pgmUnlock(pVM);
-    return VINF_SUCCESS;
-}
 
 
Index: trunk/src/VBox/VMM/VMMAll/MMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/MMAll.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/VMMAll/MMAll.cpp	(revision 7635)
@@ -69,4 +69,5 @@
 
             case MMLOOKUPHYPERTYPE_GCPHYS:  /* (for now we'll not allow these kind of conversions) */
+            case MMLOOKUPHYPERTYPE_MMIO2:
             case MMLOOKUPHYPERTYPE_DYNAMIC:
                 break;
@@ -535,4 +536,5 @@
 
             case MMLOOKUPHYPERTYPE_GCPHYS:  /* (for now we'll not allow these kind of conversions) */
+            case MMLOOKUPHYPERTYPE_MMIO2:
             case MMLOOKUPHYPERTYPE_DYNAMIC:
                 break;
Index: trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 7635)
@@ -240,4 +240,22 @@
     }
     pgmUnlock(pVM);
+}
+
+
+/**
+ * Frees the specified RAM page.
+ *
+ * This is used by ballooning and remapping MMIO2.
+ *
+ * @param   pVM         Pointer to the shared VM structure.
+ * @param   pPage       Pointer to the page structure.
+ * @param   GCPhys      The guest physical address of the page, if applicable.
+ */
+void pgmPhysFreePage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
+{
+    AssertFatal(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM);
+
+    /** @todo implement this... */
+    AssertFatalFailed();
 }
 
Index: trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp
===================================================================
--- trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp	(revision 7635)
@@ -563,4 +563,11 @@
     GEN_CHECK_OFF(PGMROMRANGE, aPages);
     GEN_CHECK_OFF(PGMROMRANGE, aPages[1]);
+    GEN_CHECK_SIZE(PGMMMIO2RANGE);
+    GEN_CHECK_OFF(PGMMMIO2RANGE, pDevInsR3);
+    GEN_CHECK_OFF(PGMMMIO2RANGE, pNextR3);
+    GEN_CHECK_OFF(PGMMMIO2RANGE, fMapped);
+    GEN_CHECK_OFF(PGMMMIO2RANGE, fOverlapping);
+    GEN_CHECK_OFF(PGMMMIO2RANGE, iRegion);
+    GEN_CHECK_OFF(PGMMMIO2RANGE, RamRange);
     GEN_CHECK_SIZE(PGMTREES);
     GEN_CHECK_OFF(PGMTREES, PhysHandlers);
Index: trunk/src/VBox/VMM/testcase/tstVMStructSize.cpp
===================================================================
--- trunk/src/VBox/VMM/testcase/tstVMStructSize.cpp	(revision 7634)
+++ trunk/src/VBox/VMM/testcase/tstVMStructSize.cpp	(revision 7635)
@@ -210,4 +210,5 @@
     CHECK_SIZE(PGMPAGE, 16);
     CHECK_MEMBER_ALIGNMENT(PGMRAMRANGE, aPages, 16);
+    CHECK_MEMBER_ALIGNMENT(PGMMMIO2RANGE, RamRange, 16);
 
     /* misc */
Index: trunk/src/recompiler/VBoxREMWrapper.cpp
===================================================================
--- trunk/src/recompiler/VBoxREMWrapper.cpp	(revision 7634)
+++ trunk/src/recompiler/VBoxREMWrapper.cpp	(revision 7635)
@@ -2041,5 +2041,5 @@
 }
 
-REMDECL(bool) REMR3IsPageAccessHandled(PVM pVM, RTGCPHYS GCPhys)
+REMR3DECL(bool) REMR3IsPageAccessHandled(PVM pVM, RTGCPHYS GCPhys)
 {
 #ifdef USE_REM_STUBS
Index: trunk/src/recompiler/VBoxRecompiler.c
===================================================================
--- trunk/src/recompiler/VBoxRecompiler.c	(revision 7634)
+++ trunk/src/recompiler/VBoxRecompiler.c	(revision 7635)
@@ -2611,9 +2611,11 @@
 
 /**
- * Notification about a successful MMR3PhysRegister() call.
+ * Notification about a successful memory deregistration or reservation.
  *
  * @param   pVM         VM Handle.
  * @param   GCPhys      Start physical address.
  * @param   cb          The size of the range.
+ * @todo    Rename to REMR3NotifyPhysRamDeregister (for MMIO2) as we won't
+ *          reserve any memory soon.
  */
 REMR3DECL(void) REMR3NotifyPhysReserve(PVM pVM, RTGCPHYS GCPhys, RTUINT cb)
@@ -2700,4 +2702,5 @@
     pVM->rem.s.fIgnoreAll = true;
 
+/** @todo this isn't right, MMIO can (in theory) be restored as RAM. */
     if (enmType == PGMPHYSHANDLERTYPE_MMIO)
         cpu_register_physical_memory(GCPhys, cb, IO_MEM_UNASSIGNED);
@@ -2711,7 +2714,6 @@
         else
         {
-            /* This is not perfect, but it'll do for PD monitoring... */
-            Assert(cb == PAGE_SIZE);
             Assert(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys);
+            Assert(RT_ALIGN_T(cb, PAGE_SIZE, RTGCPHYS) == cb);
             cpu_register_physical_memory(GCPhys, cb, GCPhys);
         }
@@ -2785,5 +2787,5 @@
  * @remark  This function will only work correctly in VBOX_STRICT builds!
  */
-REMDECL(bool) REMR3IsPageAccessHandled(PVM pVM, RTGCPHYS GCPhys)
+REMR3DECL(bool) REMR3IsPageAccessHandled(PVM pVM, RTGCPHYS GCPhys)
 {
 #ifdef VBOX_STRICT
