Index: /trunk/include/VBox/pgm.h
===================================================================
--- /trunk/include/VBox/pgm.h	(revision 6853)
+++ /trunk/include/VBox/pgm.h	(revision 6854)
@@ -289,5 +289,5 @@
     PGMROMPROT_READ_RAM_WRITE_IGNORE,
     /** Read from the shadow ROM page, ignore writes.
-     * Map the shadow page read-write, no access handler. */
+     * Map the shadow page read-write, disabled write access handler. */
     PGMROMPROT_READ_RAM_WRITE_RAM,
     /** The end of valid values. */
@@ -296,4 +296,14 @@
     PGMROMPROT_32BIT_HACK = 0x7fffffff
 } PGMROMPROT;
+
+/**
+ * Is the ROM mapped (true) or is the shadow RAM mapped (false).
+ *
+ * @returns boolean.
+ * @param   enmProt     The PGMROMPROT value, must be valid.
+ */
+#define PGMROMPROT_IS_ROM(enmProt) \
+    (    (enmProt) == PGMROMPROT_READ_ROM_WRITE_IGNORE \
+      || (enmProt) == PGMROMPROT_READ_ROM_WRITE_RAM )
 
 
Index: /trunk/src/VBox/VMM/PGM.cpp
===================================================================
--- /trunk/src/VBox/VMM/PGM.cpp	(revision 6853)
+++ /trunk/src/VBox/VMM/PGM.cpp	(revision 6854)
@@ -1711,4 +1711,11 @@
         }
     }
+
+#ifdef VBOX_WITH_NEW_PHYS_CODE
+    /*
+     * Zero shadow ROM pages.
+     */
+    rc = pgmR3PhysRomReset(pVM);
+#endif
 
     /*
Index: /trunk/src/VBox/VMM/PGMHandler.cpp
===================================================================
--- /trunk/src/VBox/VMM/PGMHandler.cpp	(revision 6853)
+++ /trunk/src/VBox/VMM/PGMHandler.cpp	(revision 6854)
@@ -70,8 +70,8 @@
  * @param   pfnHandlerR3    The R3 handler.
  * @param   pvUserR3        User argument to the R3 handler.
- * @param   pszModR0        The R0 handler module. NULL means default R0 module.
+ * @param   pszModR0        The R0 handler module. NULL means the default R0 module.
  * @param   pszHandlerR0    The R0 handler symbol name.
  * @param   pvUserR0        User argument to the R0 handler.
- * @param   pszModGC        The GC handler module. NULL means default GC module.
+ * @param   pszModGC        The GC handler module. NULL means the default GC module.
  * @param   pszHandlerGC    The GC handler symbol name.
  * @param   pvUserGC        User argument to the GC handler.
Index: /trunk/src/VBox/VMM/PGMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/PGMInternal.h	(revision 6853)
+++ /trunk/src/VBox/VMM/PGMInternal.h	(revision 6854)
@@ -481,6 +481,6 @@
     /** MMIO2 page. (RWX) */
     PGMPAGETYPE_MMIO2,
-    /** Shadowed ROM in PGMROMPROT_READ_RAM_WRITE_RAM mode. (RWX) */
-    PGMPAGETYPE_ROM_RAM,
+    /** Shadowed ROM. (RWX) */
+    PGMPAGETYPE_ROM_SHADOW,
     /** ROM page. (R-X) */
     PGMPAGETYPE_ROM,
@@ -495,6 +495,6 @@
  * @{ */
 #define PGMPAGETYPE_IS_READABLE(type)   ( (type) <= PGMPAGETYPE_ROM )
-#define PGMPAGETYPE_IS_WRITEABLE(type)  ( (type) <= PGMPAGETYPE_ROM_RAM )
-#define PGMPAGETYPE_IS_RWX(type)        ( (type) <= PGMPAGETYPE_ROM_RAM )
+#define PGMPAGETYPE_IS_WRITEABLE(type)  ( (type) <= PGMPAGETYPE_ROM_SHADOW )
+#define PGMPAGETYPE_IS_RWX(type)        ( (type) <= PGMPAGETYPE_ROM_SHADOW )
 #define PGMPAGETYPE_IS_ROX(type)        ( (type) == PGMPAGETYPE_ROM )
 #define PGMPAGETYPE_IS_NP(type)         ( (type) == PGMPAGETYPE_MMIO )
@@ -634,8 +634,8 @@
  * @param   pPage       Pointer to the physical guest page tracking structure.
  */
-#define PGM_PAGE_GET_PAGE_IN_CHUNK(pPage)   ( (pPage)->idPage & (RT_BIT_32(GMM_CHUNKID_SHIFT) - 1) )
+#define PGM_PAGE_GET_PAGE_IN_CHUNK(pPage)   ( (pPage)->idPage & GMM_PAGEID_IDX_MASK )
 /* later:
 #if GMM_CHUNKID_SHIFT <= 12
-# define PGM_PAGE_GET_PAGE_IN_CHUNK(pPage)  ( (uint32_t)((pPage)->HCPhys & (RT_BIT_32(GMM_CHUNKID_SHIFT) - 1)) )
+# define PGM_PAGE_GET_PAGE_IN_CHUNK(pPage)  ( (uint32_t)((pPage)->HCPhys & GMM_PAGEID_IDX_MASK) )
 #else
 # define PGM_PAGE_GET_PAGE_IN_CHUNK(pPage)  (   (uint32_t)((pPage)->HCPhys & 0xfff) \
@@ -751,21 +751,23 @@
  * Per page tracking structure for ROM image.
  *
- * This is in addition to PGMPAGE, which will be set up with one
- * of the two pages described here.
+ * A ROM image may have a shadow page, in which case we may have
+ * two pages backing it. This structure contains the PGMPAGE for
+ * both while PGMRAMRANGE have a copy of the active one. It is
+ * important that these aren't out of sync in any regard other
+ * than page pool tracking data.
  */
 typedef struct PGMROMPAGE
 {
-    /** The virgin page (read-only). */
-    RTHCPHYS    HCPhysVirgin;
-    /** The shadow page (read-write). */
-    RTHCPHYS    HCPhysShadow;
-    /** The page id of the virgin page. NIL_GMM_PAGEID if it's the zero page. */
-    uint32_t    idPageVirgin;
-    /** The page id of the shadow page. NIL_GMM_PAGEID if it's the zero page. */
-    uint32_t    idPageShadow;
-    /** The current protection status. */
+    /** The page structure for the virgin ROM page. */
+    PGMPAGE     Virgin;
+    /** The page structure for the shadow RAM page. */
+    PGMPAGE     Shadow;
+    /** The current protection setting. */
     PGMROMPROT  enmProt;
-    uint32_t    u32Padding;             /**< Structure size padding.*/
+    /** Pad the structure size to a multiple of 8. */
+    uint32_t    u32Padding;
 } PGMROMPAGE;
+/** Pointer to a ROM page tracking structure. */
+typedef PGMROMPAGE *PPGMROMPAGE;
 
 
@@ -2330,6 +2332,9 @@
 
 int             pgmPhysPageLoadIntoTlb(PPGM pPGM, RTGCPHYS GCPhys);
+int             pgmPhysPageMakeWritable(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys);
+int             pgmPhysPageMap(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMPAGEMAP ppMap, void **ppv);
 #ifdef IN_RING3
 int             pgmR3PhysChunkMap(PVM pVM, uint32_t idChunk, PPPGMCHUNKR3MAP ppChunk);
+int             pgmR3PhysRomReset(PVM pVM);
 #ifndef VBOX_WITH_NEW_PHYS_CODE
 int             pgmr3PhysGrowRange(PVM pVM, RTGCPHYS GCPhys);
Index: /trunk/src/VBox/VMM/PGMPhys.cpp
===================================================================
--- /trunk/src/VBox/VMM/PGMPhys.cpp	(revision 6853)
+++ /trunk/src/VBox/VMM/PGMPhys.cpp	(revision 6854)
@@ -42,4 +42,11 @@
 
 
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+/*static - shut up warning */
+DECLCALLBACK(int) pgmR3PhysRomWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
+
+
 
 /*
@@ -407,5 +414,5 @@
      */
     PPGMROMRANGE pRomNew;
-    rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMROMRANGE, aPages[cPages]), sizeof(PGMROMPAGE), MM_TAG_PGM_PHYS, (void **)pRomNew);
+    rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMROMRANGE, aPages[cPages]), 0, MM_TAG_PGM_PHYS, (void **)pRomNew);
     if (RT_SUCCESS(rc))
     {
@@ -415,7 +422,10 @@
         if (RT_SUCCESS(rc))
         {
+            pgmLock(pVM);
+
             /*
              * Initialize and insert the RAM range (if required).
              */
+            PPGMROMPAGE pRomPage = &pRomNew->aPages[0];
             if (!fRamExists)
             {
@@ -428,5 +438,5 @@
 
                 PPGMPAGE pPage = &pRamNew->aPages[0];
-                for (uint32_t iPage = 0; iPage < cPages; iPage++)
+                for (uint32_t iPage = 0; iPage < cPages; iPage++, pPage++, pRomPage++)
                 {
                     pPage->fWrittenTo = 0;
@@ -437,4 +447,6 @@
                     PGM_PAGE_SET_STATE(pPage,  PGM_PAGE_STATE_ALLOCATED);
                     PGM_PAGE_SET_PAGEID(pPage, pReq->aPages[iPage].idPage);
+
+                    pRomPage->Virgin = *pPage;
                 }
 
@@ -444,5 +456,5 @@
             {
                 PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
-                for (uint32_t iPage = 0; iPage < cPages; iPage++)
+                for (uint32_t iPage = 0; iPage < cPages; iPage++, pPage++, pRomPage++)
                 {
                     PGM_PAGE_SET_TYPE(pPage,   PGMPAGETYPE_ROM);
@@ -450,8 +462,12 @@
                     PGM_PAGE_SET_STATE(pPage,  PGM_PAGE_STATE_ALLOCATED);
                     PGM_PAGE_SET_PAGEID(pPage, pReq->aPages[iPage].idPage);
+
+                    pRomPage->Virgin = *pPage;
                 }
 
                 pRamNew = pRam;
             }
+            pgmUnlock(pVM);
+
 
             /*
@@ -459,18 +475,25 @@
              */
             rc = PGMR3HandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE, GCPhys, GCPhysLast,
-                                              NULL, NULL, /** @todo we actually need a ring-3 write handler here for shadowed ROMs, so hack REM! */
-                                              NULL, "pgmGuestROMWriteHandler", 0,
-                                              NULL, "pgmGuestROMWriteHandler", 0, pszDesc);
+#if 0 /** @todo we actually need a ring-3 write handler here for shadowed ROMs, so hack REM! */
+                                              pgmR3PhysRomWriteHandler, pRomNew,
+#else
+                                              NULL, NULL,
+#endif
+                                              NULL, "pgmGuestROMWriteHandler", MMHyperCCToR0(pVM, pRomNew),
+                                              NULL, "pgmGuestROMWriteHandler", MMHyperCCToGC(pVM, pRomNew), pszDesc);
             if (RT_SUCCESS(rc))
             {
+                pgmLock(pVM);
+
                 /*
                  * Copy the image over to the virgin pages.
                  * This must be done after linking in the RAM range.
                  */
-                for (uint32_t iPage = 0; iPage < cPages; iPage++)
+                PPGMPAGE pRamPage = &pRamNew->aPages[(GCPhys - pRamNew->GCPhys) >> PAGE_SHIFT];
+                for (uint32_t iPage = 0; iPage < cPages; iPage++, pRamPage++)
                 {
-                    void *pvDst;
-                    PGMPAGEMAPLOCK Lock;
-                    int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhys + (iPage << PAGE_SHIFT), &pvDst, &Lock);
+                    void *pvDstPage;
+                    PPGMPAGEMAP pMapIgnored;
+                    rc = pgmPhysPageMap(pVM, pRamPage, GCPhys + (iPage << PAGE_SHIFT), &pMapIgnored, &pvDstPage);
                     if (RT_FAILURE(rc))
                     {
@@ -478,6 +501,5 @@
                         break;
                     }
-                    memcpy(pvDst, (const uint8_t *)pvBinary + (iPage << PAGE_SHIFT), PAGE_SIZE);
-                    PGMPhysReleasePageMappingLock(pVM, &Lock);
+                    memcpy(pvDstPage, (const uint8_t *)pvBinary + (iPage << PAGE_SHIFT), PAGE_SIZE);
                 }
                 if (RT_SUCCESS(rc))
@@ -485,4 +507,5 @@
                     /*
                      * Initialize the ROM range.
+                     * Note that the Virgin member of the pages has already been initialized above.
                      */
                     pRomNew->GCPhys = GCPhys;
@@ -495,8 +518,14 @@
                     for (unsigned iPage = 0; iPage < cPages; iPage++)
                     {
-                        pRomNew->aPages[iPage].HCPhysVirgin = pReq->aPages[iPage].HCPhysGCPhys;
-                        pRomNew->aPages[iPage].HCPhysShadow = NIL_RTHCPHYS;
-                        pRomNew->aPages[iPage].idPageVirgin = pReq->aPages[iPage].idPage;
-                        pRomNew->aPages[iPage].idPageShadow = NIL_GMM_PAGEID;
+                        PPGMROMPAGE pPage = &pRomNew->aPages[iPage];
+
+                        pPage->Shadow.HCPhys = 0;
+                        pPage->Shadow.fWrittenTo = 0;
+                        pPage->Shadow.fSomethingElse = 0;
+                        pPage->Shadow.u29B = 0;
+                        PGM_PAGE_SET_TYPE(  &pPage->Shadow, PGMPAGETYPE_ROM_SHADOW);
+                        PGM_PAGE_SET_STATE( &pPage->Shadow, PGM_PAGE_STATE_ZERO);
+                        PGM_PAGE_SET_PAGEID(&pPage->Shadow, pReq->aPages[iPage].idPage);
+
                         pRomNew->aPages[iPage].enmProt = PGMROMPROT_READ_ROM_WRITE_IGNORE;
                     }
@@ -525,4 +554,5 @@
 
                     GMMR3AllocatePagesCleanup(pReq);
+                    pgmUnlock(pVM);
                     return VINF_SUCCESS;
                 }
@@ -530,6 +560,8 @@
                 /* bail out */
 
+                pgmUnlock(pVM);
                 int rc2 = PGMHandlerPhysicalDeregister(pVM, GCPhys);
                 AssertRC(rc2);
+                pgmLock(pVM);
             }
 
@@ -544,5 +576,284 @@
     GMMR3FreeAllocatedPages(pVM, pReq);
     GMMR3AllocatePagesCleanup(pReq);
+    pgmUnlock(pVM);
     return rc;
+}
+
+
+/**
+ * \#PF Handler callback for ROM write accesses.
+ *
+ * @returns VINF_SUCCESS if the handler have carried out the operation.
+ * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
+ * @param   pVM             VM Handle.
+ * @param   GCPhys          The physical address the guest is writing to.
+ * @param   pvPhys          The HC mapping of that address.
+ * @param   pvBuf           What the guest is reading/writing.
+ * @param   cbBuf           How much it's reading/writing.
+ * @param   enmAccessType   The access type.
+ * @param   pvUser          User argument.
+ */
+/*static - shut up warning */
+ DECLCALLBACK(int) pgmR3PhysRomWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
+{
+    PPGMROMRANGE    pRom = (PPGMROMRANGE)pvUser;
+    const uint32_t  iPage = GCPhys - pRom->GCPhys;
+    Assert(iPage < (pRom->cb >> PAGE_SHIFT));
+    PPGMROMPAGE     pRomPage = &pRom->aPages[iPage];
+    switch (pRomPage->enmProt)
+    {
+        /*
+         * Ignore.
+         */
+        case PGMROMPROT_READ_ROM_WRITE_IGNORE:
+        case PGMROMPROT_READ_RAM_WRITE_IGNORE:
+            return VINF_SUCCESS;
+
+        /*
+         * Write to the ram page.
+         */
+        case PGMROMPROT_READ_ROM_WRITE_RAM:
+        case PGMROMPROT_READ_RAM_WRITE_RAM: /* yes this will get here too, it's *way* simpler that way. */
+        {
+            /* This should be impossible now, pvPhys doesn't work cross page anylonger. */
+            Assert(((GCPhys - pRom->GCPhys + cbBuf - 1) >> PAGE_SHIFT) == iPage);
+
+            /*
+             * Take the lock, do lazy allocation, map the page and copy the data.
+             *
+             * Note that we have to bypass the mapping TLB since it works on
+             * guest physical addresses and entering the shadow page would
+             * kind of screw things up...
+             */
+            int rc = pgmLock(pVM);
+            AssertRC(rc);
+
+            if (RT_UNLIKELY(PGM_PAGE_GET_STATE(&pRomPage->Shadow) != PGM_PAGE_STATE_ALLOCATED))
+            {
+                rc = pgmPhysPageMakeWritable(pVM, &pRomPage->Shadow, GCPhys);
+                if (RT_FAILURE(rc))
+                {
+                    pgmUnlock(pVM);
+                    return rc;
+                }
+            }
+
+            void *pvDstPage;
+            PPGMPAGEMAP pMapIgnored;
+            rc = pgmPhysPageMap(pVM, &pRomPage->Shadow, GCPhys & X86_PTE_PG_MASK, &pMapIgnored, &pvDstPage);
+            if (RT_SUCCESS(rc))
+                memcpy((uint8_t *)pvDstPage + (GCPhys & PAGE_OFFSET_MASK), pvBuf, cbBuf);
+
+            pgmUnlock(pVM);
+            return rc;
+        }
+
+        default:
+            AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhys=%RGp\n",
+                                   pRom->aPages[iPage].enmProt, iPage, GCPhys),
+                                  VERR_INTERNAL_ERROR);
+    }
+}
+
+
+
+/**
+ * Called by PGMR3Reset to reset the shadow, switch to the virgin,
+ * and verify that the virgin part is untouched.
+ *
+ * This is done after the normal memory has been cleared.
+ *
+ * @param   pVM         The VM handle.
+ */
+int pgmR3PhysRomReset(PVM pVM)
+{
+    for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)
+    {
+        const uint32_t cPages = pRom->cb >> PAGE_SHIFT;
+
+        if (pRom->fFlags & PGMPHYS_ROM_FLAG_SHADOWED)
+        {
+            /*
+             * Reset the physical handler.
+             */
+            int rc = PGMR3PhysRomProtect(pVM, pRom->GCPhys, pRom->cb, PGMROMPROT_READ_ROM_WRITE_IGNORE);
+            AssertRCReturn(rc, rc);
+
+            /*
+             * What we do with the shadow pages depends on the memory
+             * preallocation option. If not enabled, we'll just throw
+             * out all the dirty pages and replace them by the zero page.
+             */
+            if (1)///@todo !pVM->pgm.f.fRamPreAlloc)
+            {
+                /* Count dirty shadow pages. */
+                uint32_t cDirty = 0;
+                uint32_t iPage = cPages;
+                while (iPage-- > 0)
+                    if (PGM_PAGE_GET_STATE(&pRom->aPages[iPage].Shadow) != PGM_PAGE_STATE_ZERO)
+                        cDirty++;
+                if (cDirty)
+                {
+                    /* Free the dirty pages. */
+                    PGMMFREEPAGESREQ pReq;
+                    rc = GMMR3FreePagesPrepare(pVM, &pReq, cDirty, GMMACCOUNT_BASE);
+                    AssertRCReturn(rc, rc);
+
+                    uint32_t iReqPage = 0;
+                    for (iPage = 0; iPage < cPages; iPage++)
+                        if (PGM_PAGE_GET_STATE(&pRom->aPages[iPage].Shadow) != PGM_PAGE_STATE_ZERO)
+                        {
+                            pReq->aPages[iReqPage].idPage = PGM_PAGE_GET_PAGEID(&pRom->aPages[iPage].Shadow);
+                            iReqPage++;
+                        }
+
+                    rc = GMMR3FreePagesPerform(pVM, pReq);
+                    GMMR3FreePagesCleanup(pReq);
+                    AssertRCReturn(rc, rc);
+
+                    /* setup the zero page. */
+                    for (iPage = 0; iPage < cPages; iPage++)
+                        if (PGM_PAGE_GET_STATE(&pRom->aPages[iPage].Shadow) != PGM_PAGE_STATE_ZERO)
+                        {
+                            PGM_PAGE_SET_STATE( &pRom->aPages[iPage].Shadow, PGM_PAGE_STATE_ZERO);
+                            PGM_PAGE_SET_HCPHYS(&pRom->aPages[iPage].Shadow, pVM->pgm.s.HCPhysZeroPg);
+                            PGM_PAGE_SET_PAGEID(&pRom->aPages[iPage].Shadow, NIL_GMM_PAGEID);
+                            pRom->aPages[iPage].Shadow.fWrittenTo = false;
+                            iReqPage++;
+                        }
+                }
+            }
+            else
+            {
+                /* clear all the pages. */
+                pgmLock(pVM);
+                for (uint32_t iPage = 0; iPage < cPages; iPage++)
+                {
+                    const RTGCPHYS GCPhys = pRom->GCPhys + (iPage << PAGE_SHIFT);
+                    rc = pgmPhysPageMakeWritable(pVM, &pRom->aPages[iPage].Shadow, GCPhys);
+                    if (RT_FAILURE(rc))
+                        break;
+
+                    void *pvDstPage;
+                    PPGMPAGEMAP pMapIgnored;
+                    rc = pgmPhysPageMap(pVM, &pRom->aPages[iPage].Shadow, GCPhys, &pMapIgnored, &pvDstPage);
+                    if (RT_FAILURE(rc))
+                        break;
+                    memset(pvDstPage, 0, PAGE_SIZE);
+                }
+                pgmUnlock(pVM);
+                AssertRCReturn(rc, rc);
+            }
+        }
+
+#ifdef VBOX_STRICT
+        /*
+         * Verify that the virgin page is unchanged if possible.
+         */
+        if (pRom->pvOriginal)
+        {
+            uint8_t const *pbSrcPage = (uint8_t const *)pRom->pvOriginal;
+            for (uint32_t iPage = 0; iPage < cPages; iPage++, pbSrcPage += PAGE_SIZE)
+            {
+                const RTGCPHYS GCPhys = pRom->GCPhys + (iPage << PAGE_SHIFT);
+                PPGMPAGEMAP pMapIgnored;
+                void *pvDstPage;
+                int rc = pgmPhysPageMap(pVM, &pRom->aPages[iPage].Virgin, GCPhys, &pMapIgnored, &pvDstPage);
+                if (RT_FAILURE(rc))
+                    break;
+                if (memcmp(pvDstPage, pbSrcPage, PAGE_SIZE))
+                    LogRel(("pgmR3PhysRomReset: %RGp rom page changed (%s) - loaded saved state?\n",
+                            GCPhys, pRom->pszDesc));
+            }
+        }
+#endif
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Change the shadowing of a range of ROM pages.
+ *
+ * This is intended for implementing chipset specific memory registers
+ * and will not be very strict about the input. It will silently ignore
+ * any pages that are not the part of a shadowed ROM.
+ *
+ * @returns VBox status code.
+ * @param   pVM         Pointer to the shared VM structure.
+ * @param   GCPhys      Where to start. Page aligned.
+ * @param   cb          How much to change. Page aligned.
+ * @param   enmProt     The new ROM protection.
+ */
+PGMR3DECL(int) PGMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMROMPROT enmProt)
+{
+    /*
+     * Check input
+     */
+    if (!cb)
+        return VINF_SUCCESS;
+    AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+    AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+    RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
+    AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
+    AssertReturn(enmProt >= PGMROMPROT_INVALID && enmProt <= PGMROMPROT_END, VERR_INVALID_PARAMETER);
+
+    /*
+     * Process the request.
+     */
+    bool fFlushedPool = false;
+    for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)
+        if (    GCPhys     <= pRom->GCPhysLast
+            &&  GCPhysLast >= pRom->GCPhys)
+        {
+            /*
+             * Iterate the relevant pages and the ncessary make changes.
+             */
+            bool fChanges = false;
+            uint32_t const cPages = pRom->GCPhysLast > GCPhysLast
+                                  ? pRom->cb >> PAGE_SHIFT
+                                  : (GCPhysLast - pRom->GCPhys) >> PAGE_SHIFT;
+            for (uint32_t iPage = (GCPhys - pRom->GCPhys) >> PAGE_SHIFT;
+                 iPage < cPages;
+                 iPage++)
+            {
+                PPGMROMPAGE pRomPage = &pRom->aPages[iPage];
+                if (PGMROMPROT_IS_ROM(pRomPage->enmProt) != PGMROMPROT_IS_ROM(enmProt))
+                {
+                    fChanges = true;
+
+                    /* flush the page pool first so we don't leave any usage references dangling. */
+                    if (!fFlushedPool)
+                    {
+                        pgmPoolFlushAll(pVM);
+                        fFlushedPool = true;
+                    }
+
+                    PPGMPAGE pOld = PGMROMPROT_IS_ROM(pRomPage->enmProt) ? &pRomPage->Virgin : &pRomPage->Shadow;
+                    PPGMPAGE pNew = PGMROMPROT_IS_ROM(pRomPage->enmProt) ? &pRomPage->Shadow : &pRomPage->Virgin;
+                    PPGMPAGE pRamPage = pgmPhysGetPage(&pVM->pgm.s, pRom->GCPhys + (iPage << PAGE_SHIFT));
+
+                    *pOld = *pRamPage;
+                    *pRamPage = *pNew;
+                    /** @todo sync the volatile flags (handlers) when these have been moved out of HCPhys. */
+                }
+            }
+
+            /*
+             * Reset the access handler if we made changes, no need
+             * to optimize this.
+             */
+            if (fChanges)
+            {
+                int rc = PGMHandlerPhysicalReset(pVM, pRom->GCPhys);
+                AssertRCReturn(rc, rc);
+            }
+
+            /* Advance - cb isn't updated. */
+            GCPhys = pRom->GCPhys + (cPages << PAGE_SHIFT);
+        }
+
+    return VINF_SUCCESS;
 }
 
Index: /trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp	(revision 6853)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp	(revision 6854)
@@ -993,43 +993,5 @@
 }
 
-
 #ifndef IN_RING3
-
-# ifdef IN_RING0
-/** @todo try combine this with iom and em. */
-
-/**
- * Read callback for disassembly function; supports reading bytes that cross a page boundary
- *
- * @returns VBox status code.
- * @param   pSrc        GC source pointer
- * @param   pDest       HC destination pointer
- * @param   size        Number of bytes to read
- * @param   pvUserdata  Callback specific user data (pCpu)
- *
- */
-DECLCALLBACK(int) pgmReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata)
-{
-    DISCPUSTATE  *pCpu     = (DISCPUSTATE *)pvUserdata;
-    PVM           pVM      = (PVM)pCpu->apvUserData[0];
-
-    int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
-    AssertRC(rc);
-    return rc;
-}
-
-inline int pgmDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
-{
-    return DISCoreOneEx(InstrGC, pCpu->mode, pgmReadBytes, pVM, pCpu, pOpsize);
-}
-
-# else /* !IN_RING0 (i.e. in IN_GC) */
-inline int pgmDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
-{
-    return DISCoreOne(pCpu, InstrGC, pOpsize);
-}
-
-#endif /* !IN_RING0 (i.e. in IN_GC) */
-
 
 /**
@@ -1043,41 +1005,63 @@
  * @param   pvFault     The fault address (cr2).
  * @param   GCPhysFault The GC physical address corresponding to pvFault.
- * @param   pvUser      User argument.
+ * @param   pvUser      User argument. Pointer to the ROM range structure.
  */
 PGMDECL(int) pgmGuestROMWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, RTGCPHYS GCPhysFault, void *pvUser)
 {
-    DISCPUSTATE Cpu;
-    Cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
-    if (Cpu.mode == CPUMODE_32BIT)
-    {
-        RTGCPTR GCPtrCode;
-        int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &GCPtrCode);
-        if (VBOX_SUCCESS(rc))
-        {
+    int rc;
+#ifdef VBOX_WITH_NEW_PHYS_CODE
+    PPGMROMRANGE pRom = (PPGMROMRANGE)pvUser;
+    uint32_t iPage = GCPhysFault - pRom->GCPhys;
+    Assert(iPage < (pRom->cb >> PAGE_SHIFT));
+    switch (pRom->aPages[iPage].enmProt)
+    {
+        case PGMROMPROT_READ_ROM_WRITE_IGNORE:
+        case PGMROMPROT_READ_RAM_WRITE_IGNORE:
+        {
+#endif
+            /*
+             * If it's a simple instruction which doesn't change the cpu state
+             * we will simply skip it. Otherwise we'll have to defer it to REM.
+             */
             uint32_t cbOp;
-            rc = pgmDisCoreOne(pVM, &Cpu, (RTGCUINTPTR)GCPtrCode, &cbOp);
-            if (VBOX_SUCCESS(rc))
+            DISCPUSTATE Cpu;
+            rc = EMInterpretDisasOne(pVM, pRegFrame, &Cpu, &cbOp);
+            if (     RT_SUCCESS(rc)
+                &&   Cpu.mode == CPUMODE_32BIT
+                &&  !(Cpu.prefix & (PREFIX_REPNE | PREFIX_REP | PREFIX_SEG)))
             {
-                /* ASSUMES simple instructions.
-                 * For instance 'pop [ROM_ADDRESS]' or 'and [ROM_ADDRESS], eax' better
-                 * not occure or we'll screw up the cpu state.
-                 */
-                /** @todo We're assuming too much here I think. */
-                if (!(Cpu.prefix & (PREFIX_REPNE | PREFIX_REP | PREFIX_SEG)))
+                switch (Cpu.opcode)
                 {
-                    /*
-                     * Move on to the next instruction.
-                     */
-                    pRegFrame->eip += cbOp;
-                    STAM_COUNTER_INC(&pVM->pgm.s.StatGCGuestROMWriteHandled);
-                    return VINF_SUCCESS;
+                    /** @todo Find other instructions we can safely skip, possibly
+                     * adding this kind of detection to DIS or EM. */
+                    case OP_MOV:
+                        pRegFrame->eip += cbOp;
+                        STAM_COUNTER_INC(&pVM->pgm.s.StatGCGuestROMWriteHandled);
+                        return VINF_SUCCESS;
                 }
-                LogFlow(("pgmGuestROMWriteHandler: wrong prefix!!\n"));
             }
-        }
-    }
+            else if (RT_UNLIKELY(rc == VERR_INTERNAL_ERROR))
+                return rc;
+#ifdef VBOX_WITH_NEW_PHYS_CODE
+            break;
+        }
+
+        case PGMROMPROT_READ_RAM_WRITE_RAM:
+            rc = PGMHandlerPhysicalPageTempOff(pVM, pRom->GCPhys, GCPhysFault & X86_PTE_PG_MASK);
+            AssertRC(rc);
+        case PGMROMPROT_READ_ROM_WRITE_RAM:
+            /* Handle it in ring-3 because it's *way* easier there. */
+            break;
+
+        default:
+            AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhysFault=%RGp\n",
+                                   pRom->aPages[iPage].enmProt, iPage, GCPhysFault),
+                                  VERR_INTERNAL_ERROR);
+    }
+#endif
 
     STAM_COUNTER_INC(&pVM->pgm.s.StatGCGuestROMWriteUnhandled);
     return VINF_EM_RAW_EMULATE_INSTR;
 }
-#endif /* !IN_RING3 */
+
+#endif /* IN_RING3 */
Index: /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 6853)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 6854)
@@ -313,4 +313,5 @@
         STAM_COUNTER_INC(&pVM->pgm.s.StatPageReplaceShared);
         pVM->pgm.s.cSharedPages--;
+/** @todo err.. what about copying the page content? */
     }
     else
@@ -319,4 +320,5 @@
         STAM_COUNTER_INC(&pVM->pgm.s.StatPageReplaceZero);
         pVM->pgm.s.cZeroPages--;
+/** @todo verify that the handy page is zero! */
     }
 
@@ -565,5 +567,8 @@
         PPGMPAGE pPage = pTlbe->pPage;
         if (RT_UNLIKELY(pPage->u2State != PGM_PAGE_STATE_ALLOCATED))
+        {
             rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
+            /** @todo stuff is missing here! */
+        }
         if (RT_SUCCESS(rc))
         {
Index: /trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp
===================================================================
--- /trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp	(revision 6853)
+++ /trunk/src/VBox/VMM/testcase/tstVMStructGC.cpp	(revision 6854)
@@ -547,8 +547,6 @@
     GEN_CHECK_OFF(PGMRAMRANGE, aPages[1]);
     GEN_CHECK_SIZE(PGMROMPAGE);
-    GEN_CHECK_OFF(PGMROMPAGE, HCPhysVirgin);
-    GEN_CHECK_OFF(PGMROMPAGE, HCPhysShadow);
-    GEN_CHECK_OFF(PGMROMPAGE, idPageVirgin);
-    GEN_CHECK_OFF(PGMROMPAGE, idPageShadow);
+    GEN_CHECK_OFF(PGMROMPAGE, Virgin);
+    GEN_CHECK_OFF(PGMROMPAGE, Shadow);
     GEN_CHECK_OFF(PGMROMPAGE, enmProt);
     GEN_CHECK_SIZE(PGMROMRANGE);
Index: /trunk/src/VBox/VMM/testcase/tstVMStructSize.cpp
===================================================================
--- /trunk/src/VBox/VMM/testcase/tstVMStructSize.cpp	(revision 6853)
+++ /trunk/src/VBox/VMM/testcase/tstVMStructSize.cpp	(revision 6854)
@@ -212,6 +212,4 @@
     CHECK_SIZE(PGMPAGE, 16);
     CHECK_MEMBER_ALIGNMENT(PGMRAMRANGE, aPages, 16);
-    CHECK_SIZE(PGMROMPAGE, 32);
-    CHECK_MEMBER_ALIGNMENT(PGMROMRANGE, aPages, 32);
 
     /* misc */
