Index: trunk/src/VBox/Main/src-client/ConsoleImplConfigArmV8.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/ConsoleImplConfigArmV8.cpp	(revision 106955)
+++ trunk/src/VBox/Main/src-client/ConsoleImplConfigArmV8.cpp	(revision 106957)
@@ -187,10 +187,6 @@
 
     BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(pVMM, chipsetType, IommuType_None);
-    ResourceAssignmentManager *pResMgr = ResourceAssignmentManager::createInstance(pVMM, chipsetType, IommuType_None,
-                                                                                   RT_MAX(_1G + cbRam, _4G),                  /*GCPhysMmio*/
-                                                                                   _1G,                                       /*GCPhysRam*/
-                                                                                   VBOXPLATFORMARMV8_PHYS_ADDR + _1M,         /*GCPhysMmio32Start*/
-                                                                                   _1G - (VBOXPLATFORMARMV8_PHYS_ADDR + _1M), /*cbMmio32*/
-                                                                                   32                                         /*cInterrupts*/);
+    ResourceAssignmentManager *pResMgr = ResourceAssignmentManager::createInstance(pVMM, chipsetType, IommuType_None, 32 /*cInterrupts*/,
+                                                                                   _4G); /* Start looking for free MMIO regions at 4GiB downwards. */
     SystemTableBuilder *pSysTblsBldAcpi = NULL;
 
@@ -211,5 +207,16 @@
     Assert(pRoot);
 
-    RTGCPHYS GCPhysRam = NIL_RTGCPHYS;
+    /*
+     * The VBox platform descriptor, FDT and ACPI tables will reside at the end of the 4GiB
+     * address space and we reserve 2MiB for those.
+     */
+    RTGCPHYS cbPlatformDesc     = _2M;
+    RTGCPHYS GCPhysPlatformDesc = VBOXPLATFORMARMV8_PHYS_ADDR - (cbPlatformDesc - _64K);
+
+    RTGCPHYS GCPhysRamBase = 128 * _1M;
+    RTGCPHYS cbRamBase     = RT_MIN(cbRam, _4G - _512M - 128 * _1M);
+
+    RTGCPHYS GCPhysFw = 0;
+    RTGCPHYS cbFw     = _64M;
 
     // catching throws from InsertConfigString and friends.
@@ -281,5 +288,5 @@
         vrc = RTFdtNodePropertyAddU32(     hFdt, "phandle", idPHandleAbpPClk);              VRC();
         vrc = RTFdtNodePropertyAddString(  hFdt, "clock-output-names", "clk24mhz");         VRC();
-        vrc = RTFdtNodePropertyAddU32(     hFdt, "clock-frequency",    24 * 1000 * 1000);   VRC();
+        vrc = RTFdtNodePropertyAddU32(     hFdt, "clock-frequency",    ASMReadCntFrqEl0()); VRC();
         vrc = RTFdtNodePropertyAddU32(     hFdt, "#clock-cells",       0);                  VRC();
         vrc = RTFdtNodePropertyAddString(  hFdt, "compatible",         "fixed-clock");      VRC();
@@ -304,13 +311,38 @@
         InsertConfigNode(pMM, "MemRegions", &pMem);
 
-        hrc = pResMgr->assignRamRegion("Conventional", cbRam, &GCPhysRam);                  H();
+        /*
+         * Windows requires the TPM to be available at 0xfed40000 so reserve this region first, even
+         * if no TPM is configured.
+         */
+        RTGCPHYS GCPhysTpm = 0xfed40000;
+        RTGCPHYS cbTpm     = 0x5000 + 0x1000; /* TPM + PPI region. */
+        hrc = pResMgr->assignFixedMmioRegion("tpm", GCPhysTpm, cbTpm);                              H();
+
+        /*
+         * The firmware ROM will start at the beginning of the address space and span 64MiB
+         * After that comes the flash and spans another 64MiB (even if the real size is smaller).
+         */
+        hrc = pResMgr->assignFixedRomRegion("firmware", GCPhysFw, cbFw);                            H();
+
+        RTGCPHYS GCPhysFlash = _64M;
+        RTGCPHYS cbFlash     = _64M;
+        hrc = pResMgr->assignFixedMmioRegion("flash", GCPhysFlash, cbFlash);                        H();
+
+        hrc = pResMgr->assignFixedRomRegion("platform-tables", GCPhysPlatformDesc, cbPlatformDesc); H();
+
+        /*
+         * The base RAM will start at 128MiB (end of flash region) and goes up to 4GiB - 512MiB
+         * (for the MMIO hole).
+         * If more RAM is configured the high region will start at 4GiB.
+         */
+        hrc = pResMgr->assignFixedRamRegion("RAM Base", GCPhysRamBase, cbRamBase);                  H();
 
         PCFGMNODE pMemRegion = NULL;
-        InsertConfigNode(pMem, "Conventional", &pMemRegion);
-        InsertConfigInteger(pMemRegion, "GCPhysStart", GCPhysRam);
-        InsertConfigInteger(pMemRegion, "Size", cbRam);
-
-        vrc = RTFdtNodeAddF(hFdt, "memory@%RGp", GCPhysRam);                                VRC();
-        vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysRam, cbRam);               VRC();
+        InsertConfigNode(pMem, "Base", &pMemRegion);
+        InsertConfigInteger(pMemRegion, "GCPhysStart", GCPhysRamBase);
+        InsertConfigInteger(pMemRegion, "Size", cbRamBase);
+
+        vrc = RTFdtNodeAddF(hFdt, "memory@%RGp", GCPhysRamBase);                            VRC();
+        vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysRamBase, cbRamBase);       VRC();
         vrc = RTFdtNodePropertyAddString(  hFdt, "device_type",      "memory");             VRC();
         vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
@@ -318,6 +350,29 @@
         if (pSysTblsBldAcpi)
         {
-            vrc = pSysTblsBldAcpi->addMemory(GCPhysRam, cbRam);
+            vrc = pSysTblsBldAcpi->addMemory(GCPhysRamBase, cbRamBase);
             VRC();
+        }
+
+        if (cbRamBase < cbRam)
+        {
+            RTGCPHYS GCPhysRamHigh = _4G;
+            RTGCPHYS cbRamHigh     = cbRam - cbRamBase;
+
+            hrc = pResMgr->assignFixedRamRegion("RAM High", GCPhysRamHigh, cbRamHigh);        H();
+
+            InsertConfigNode(pMem, "High", &pMemRegion);
+            InsertConfigInteger(pMemRegion, "GCPhysStart", GCPhysRamHigh);
+            InsertConfigInteger(pMemRegion, "Size", cbRamHigh);
+
+            vrc = RTFdtNodeAddF(hFdt, "memory@%RGp", GCPhysRamHigh);                        VRC();
+            vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysRamHigh, cbRamHigh);   VRC();
+            vrc = RTFdtNodePropertyAddString(  hFdt, "device_type",      "memory");         VRC();
+            vrc = RTFdtNodeFinalize(hFdt);                                                  VRC();
+
+            if (pSysTblsBldAcpi)
+            {
+                vrc = pSysTblsBldAcpi->addMemory(GCPhysRamHigh, cbRamHigh);
+                VRC();
+            }
         }
 
@@ -440,5 +495,5 @@
         InsertConfigNode(pResources,    "ArmV8Desc",             &pRes);
         InsertConfigInteger(pRes,       "RegisterAsRom",         1);
-        InsertConfigInteger(pRes,       "GCPhysLoadAddress",     VBOXPLATFORMARMV8_PHYS_ADDR);
+        InsertConfigInteger(pRes,       "GCPhysLoadAddress",     GCPhysPlatformDesc);
         InsertConfigString(pRes,        "ResourceId",            "VBoxArmV8Desc");
 
@@ -447,16 +502,22 @@
          */
         RTGCPHYS GCPhysIntcDist;
+        RTGCPHYS GCPhysIntcIts;
+        RTGCPHYS cbMmioIntcDist;
+        RTGCPHYS cbMmioIntcIts;
         RTGCPHYS GCPhysIntcReDist;
-        RTGCPHYS cbMmioIntcDist;
         RTGCPHYS cbMmioIntcReDist;
 
-        /* Each vCPU needs on re-distributor, this would allow for up to 256 vCPUs in the future. */
-        hrc = pResMgr->assignMmioRegion("gic", 256 * _64K, &GCPhysIntcReDist, &cbMmioIntcReDist);       H();
-        hrc = pResMgr->assignMmioRegion("gic", _64K, &GCPhysIntcDist, &cbMmioIntcDist);                 H();
-
-#ifndef RT_OS_LINUX
+        /* Allow for up to 256 vCPUs in the future without changing the address space layout. */
+        hrc = pResMgr->assignMmioRegion("gic", _64K + 256 * _128K, &GCPhysIntcDist, &cbMmioIntcDist);     H();
+        GCPhysIntcReDist = GCPhysIntcDist + _64K;
+        cbMmioIntcReDist = 256 * _128K;
+        cbMmioIntcDist = _64K;
+
+        hrc = pResMgr->assignMmioRegion("gic-its", 2 * _64K, &GCPhysIntcIts, &cbMmioIntcIts);             H();
+
+#ifdef RT_OS_DARWIN
         InsertConfigNode(pDevices, "gic",                   &pDev);
 #else
-        /* On Linux we default to the KVM in-kernel GIC for now. */
+        /* On Linux we default to the KVM in-kernel GIC and on Windows we are forced to the Hyper-V GIC for now. */
         InsertConfigNode(pDevices, "gic-nem",               &pDev);
 #endif
@@ -466,9 +527,10 @@
         InsertConfigInteger(pCfg,  "DistributorMmioBase",   GCPhysIntcDist);
         InsertConfigInteger(pCfg,  "RedistributorMmioBase", GCPhysIntcReDist);
+        InsertConfigInteger(pCfg,  "ItsMmioBase",           GCPhysIntcIts);
 
         vrc = RTFdtNodeAddF(hFdt, "intc@%RGp", GCPhysIntcDist);                                         VRC();
         vrc = RTFdtNodePropertyAddU32(     hFdt, "phandle",          idPHandleIntCtrl);                 VRC();
         vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 4,
-                                           GCPhysIntcDist, cbMmioIntcDist,      /* Distributor */
+                                           GCPhysIntcDist, cbMmioIntcDist,       /* Distributor */
                                            GCPhysIntcReDist, cbMmioIntcReDist); /* Re-Distributor */    VRC();
         vrc = RTFdtNodePropertyAddU32(     hFdt, "#redistributor-regions", 1);                          VRC();
@@ -500,5 +562,5 @@
 
         /*
-         * Configure the perofrmance monitoring unit.
+         * Configure the performance monitoring unit.
          */
         /** @todo Make this configurable and enable as default for Windows VMs because they assume a working PMU
@@ -542,5 +604,5 @@
         InsertConfigNode(pDev,     "0",            &pInst);
         InsertConfigNode(pInst,    "Config",        &pCfg);
-        InsertConfigInteger(pCfg,  "BaseAddress",  64 * _1M);
+        InsertConfigInteger(pCfg,  "BaseAddress",  GCPhysFlash);
         InsertConfigInteger(pCfg,  "Size",        768 * _1K);
         InsertConfigString(pCfg,   "FlashFile",   "nvram");
@@ -552,6 +614,6 @@
         vrc = RTFdtNodePropertyAddU32(     hFdt, "bank-width", 4);                          VRC();
         vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 4,
-                                           0,          0x04000000,  /* First region (EFI). */
-                                           0x04000000, 0x04000000); /* Second region (NVRAM). */ VRC();
+                                           GCPhysFw,    cbFw,     /* First region (EFI). */
+                                           GCPhysFlash, cbFlash); /* Second region (NVRAM). */ VRC();
         vrc = RTFdtNodePropertyAddString(  hFdt, "compatible", "cfi-flash");                VRC();
         vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
@@ -638,7 +700,7 @@
         vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
 
-        /* Configure gpio keys. */
+        /* Configure gpio keys (The Windows GPIO PL061 driver doesn't like 64-bit MMIO addresses...). */
         hrc = pResMgr->assignSingleInterrupt("arm-pl061-gpio", &iIrq);                      H();
-        hrc = pResMgr->assignMmioRegion("arm-pl061-gpio", _4K, &GCPhysMmioStart, &cbMmio);  H();
+        hrc = pResMgr->assignMmio32Region("arm-pl061-gpio", _4K, &GCPhysMmioStart, &cbMmio);  H();
         InsertConfigNode(pDevices, "arm-pl061-gpio",&pDev);
         InsertConfigNode(pDev,     "0",            &pInst);
@@ -660,5 +722,5 @@
         if (pSysTblsBldAcpi)
         {
-            vrc = pSysTblsBldAcpi->addMmioDevice("arm-pl061-gpio", 0, GCPhysMmioStart, _4K, iIrq);
+            vrc = pSysTblsBldAcpi->addMmioDevice("arm-pl061-gpio", 0, GCPhysMmioStart, cbMmio, iIrq);
             VRC();
         }
@@ -687,78 +749,4 @@
         vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
 
-        hrc = pResMgr->assignInterrupts("pci-generic-ecam", 4 /*cInterrupts*/, &iIrq);      H();
-        uint32_t aPinIrqs[] = { iIrq, iIrq + 1, iIrq + 2, iIrq + 3 };
-        RTGCPHYS GCPhysPciMmioEcam, GCPhysPciMmio, GCPhysPciMmio32;
-        RTGCPHYS cbPciMmioEcam, cbPciMmio, cbPciMmio32;
-        hrc = pResMgr->assignMmioRegionAligned("pci-pio",    _64K, _64K,                              &GCPhysMmioStart,   &cbMmio);         H();
-        hrc = pResMgr->assignMmioRegion(       "pci-ecam",   16 * _1M,                                &GCPhysPciMmioEcam, &cbPciMmioEcam);  H();
-        hrc = pResMgr->assignMmioRegion(       "pci-mmio",   _2G,                                     &GCPhysPciMmio,     &cbPciMmio);      H();
-        hrc = pResMgr->assignMmio32Region(     "pci-mmio32", _1G - VBOXPLATFORMARMV8_PHYS_ADDR - _1M, &GCPhysPciMmio32,   &cbPciMmio32);    H();
-
-        InsertConfigNode(pDevices, "pci-generic-ecam",  &pDev);
-        InsertConfigNode(pDev,     "0",            &pInst);
-        InsertConfigNode(pInst,    "Config",        &pCfg);
-        InsertConfigInteger(pCfg,  "MmioEcamBase",   GCPhysPciMmioEcam);
-        InsertConfigInteger(pCfg,  "MmioEcamLength", cbPciMmioEcam);
-        InsertConfigInteger(pCfg,  "MmioPioBase",    GCPhysMmioStart);
-        InsertConfigInteger(pCfg,  "MmioPioSize",    cbMmio);
-        InsertConfigInteger(pCfg,  "IntPinA",        aPinIrqs[0]);
-        InsertConfigInteger(pCfg,  "IntPinB",        aPinIrqs[1]);
-        InsertConfigInteger(pCfg,  "IntPinC",        aPinIrqs[2]);
-        InsertConfigInteger(pCfg,  "IntPinD",        aPinIrqs[3]);
-        vrc = RTFdtNodeAddF(hFdt, "pcie@%RGp", GCPhysPciMmio);                              VRC();
-        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "interrupt-map-mask", 4, 0xf800, 0, 0, 7); VRC();
-
-        uint32_t aIrqCells[32 * 4 * 10]; RT_ZERO(aIrqCells); /* Maximum of 32 devices on the root bus, each supporting 4 interrupts (INTA# ... INTD#). */
-        uint32_t *pau32IrqCell = &aIrqCells[0];
-        uint32_t iIrqPinSwizzle = 0;
-
-        for (uint32_t i = 0; i < 32; i++)
-        {
-            for (uint32_t iIrqPin = 0; iIrqPin < 4; iIrqPin++)
-            {
-                pau32IrqCell[0] = i << 11; /* The dev part, composed as dev.fn. */
-                pau32IrqCell[1] = 0;
-                pau32IrqCell[2] = 0;
-                pau32IrqCell[3] = iIrqPin + 1;
-                pau32IrqCell[4] = idPHandleIntCtrl;
-                pau32IrqCell[5] = 0;
-                pau32IrqCell[6] = 0;
-                pau32IrqCell[7] = 0;
-                pau32IrqCell[8] = aPinIrqs[(iIrqPinSwizzle + iIrqPin) % RT_ELEMENTS(aPinIrqs)];
-                pau32IrqCell[9] = 0x04;
-                pau32IrqCell += 10;
-            }
-
-            iIrqPinSwizzle++;
-        }
-
-        vrc = RTFdtNodePropertyAddCellsU32AsArray(hFdt, "interrupt-map", RT_ELEMENTS(aIrqCells), &aIrqCells[0]);
-        vrc = RTFdtNodePropertyAddU32(     hFdt, "#interrupt-cells", 1);                        VRC();
-        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "ranges", 21,
-                                           0x1000000, 0, 0,
-                                           GCPhysMmioStart >> 32, GCPhysMmioStart, cbMmio >> 32, cbMmio,
-                                           0x2000000, GCPhysPciMmio32 >> 32, GCPhysPciMmio32, GCPhysPciMmio32 >> 32, GCPhysPciMmio32,
-                                           cbPciMmio32 >> 32, cbPciMmio32,
-                                           0x3000000, GCPhysPciMmio >> 32, GCPhysPciMmio, GCPhysPciMmio >> 32, GCPhysPciMmio,
-                                           cbPciMmio >> 32, cbPciMmio);                         VRC();
-        vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysPciMmioEcam, cbPciMmioEcam);   VRC();
-        /** @todo msi-map */
-        vrc = RTFdtNodePropertyAddEmpty(   hFdt, "dma-coherent");                               VRC();
-        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "bus-range", 2, 0, 0xf);                       VRC();
-        vrc = RTFdtNodePropertyAddU32(     hFdt, "linux,pci-domain", 0);                        VRC();
-        vrc = RTFdtNodePropertyAddU32(     hFdt, "#size-cells", 2);                             VRC();
-        vrc = RTFdtNodePropertyAddU32(     hFdt, "#address-cells", 3);                          VRC();
-        vrc = RTFdtNodePropertyAddString(  hFdt, "device_type", "pci");                         VRC();
-        vrc = RTFdtNodePropertyAddString(  hFdt, "compatible", "pci-host-ecam-generic");        VRC();
-        vrc = RTFdtNodeFinalize(hFdt);                                                          VRC();
-
-        if (pSysTblsBldAcpi)
-        {
-            vrc = pSysTblsBldAcpi->configurePcieRootBus("pci-generic-ecam", aPinIrqs, GCPhysMmioStart, GCPhysPciMmioEcam,
-                                                        cbPciMmioEcam, GCPhysMmioStart, cbMmio, GCPhysPciMmio32, cbPciMmio32);
-            VRC();
-        }
-
 #if defined(VBOX_WITH_TPM)
         /*
@@ -773,5 +761,4 @@
         {
             hrc = pResMgr->assignSingleInterrupt("tpm", &iIrq);                               H();
-            hrc = pResMgr->assignMmioRegion("tpm", 5 * _1K, &GCPhysMmioStart, &cbMmio);       H();
 
             InsertConfigNode(pDevices, "tpm", &pDev);
@@ -779,7 +766,7 @@
             InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
             InsertConfigNode(pInst,    "Config", &pCfg);
-            InsertConfigInteger(pCfg,  "MmioBase", GCPhysMmioStart);
+            InsertConfigInteger(pCfg,  "MmioBase", GCPhysTpm);
             InsertConfigInteger(pCfg,  "Irq",      iIrq);
-            //InsertConfigInteger(pCfg,  "Crb",      1); /* boolean */
+            InsertConfigInteger(pCfg,  "Crb",      1); /* boolean */
 
             InsertConfigNode(pInst,    "LUN#0", &pLunL0);
@@ -811,7 +798,7 @@
             }
 
-            vrc = RTFdtNodeAddF(hFdt, "tpm@%RGp", GCPhysMmioStart);                           VRC();
+            vrc = RTFdtNodeAddF(hFdt, "tpm@%RGp", GCPhysTpm);                                   VRC();
             vrc = RTFdtNodePropertyAddCellsU32(hFdt, "interrupts", 3, 0x00, iIrq, 0x04);        VRC();
-            vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysMmioStart, cbMmio);        VRC();
+            vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysTpm, cbTpm);               VRC();
             vrc = RTFdtNodePropertyAddStringList(hFdt, "compatible", 1, "tcg,tpm-tis-mmio");    VRC();
             vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
@@ -819,9 +806,8 @@
             if (pSysTblsBldAcpi)
             {
-                vrc = pSysTblsBldAcpi->configureTpm2(false /*fCrb*/, GCPhysMmioStart, cbMmio, iIrq);
+                vrc = pSysTblsBldAcpi->configureTpm2(true /*fCrb*/, GCPhysTpm, cbTpm, iIrq);
                 VRC();
             }
 
-#if 0
             /* Add the device for the physical presence interface. */
             InsertConfigNode(   pDevices, "tpm-ppi",  &pDev);
@@ -829,8 +815,82 @@
             InsertConfigInteger(pInst,    "Trusted",  1); /* boolean */
             InsertConfigNode(   pInst,    "Config",   &pCfg);
-            InsertConfigInteger(pCfg,     "MmioBase", TPM_PPI_MMIO_BASE_DEFAULT);
+            InsertConfigInteger(pCfg,     "MmioBase", GCPhysTpm + 0x5000);
+        }
 #endif
-        }
-#endif
+
+        hrc = pResMgr->assignInterrupts("pci-generic-ecam", 4 /*cInterrupts*/, &iIrq);      H();
+        uint32_t aPinIrqs[] = { iIrq, iIrq + 1, iIrq + 2, iIrq + 3 };
+        RTGCPHYS GCPhysPciMmioEcam, GCPhysPciMmio, GCPhysPciMmio32;
+        RTGCPHYS cbPciMmioEcam, cbPciMmio, cbPciMmio32;
+
+        hrc = pResMgr->assignMmioRegionAligned("pci-pio",    _64K, _64K, &GCPhysMmioStart,   &cbMmio, false /*fOnly32Bit*/); H();
+        hrc = pResMgr->assignMmioRegion(       "pci-ecam",   16 * _1M,   &GCPhysPciMmioEcam, &cbPciMmioEcam);              H();
+        hrc = pResMgr->assignMmioRegion(       "pci-mmio",   _2G,        &GCPhysPciMmio,     &cbPciMmio);                  H();
+        hrc = pResMgr->assignMmio32Region(     "pci-mmio32", _256M,      &GCPhysPciMmio32,   &cbPciMmio32);                H();
+
+        InsertConfigNode(pDevices, "pci-generic-ecam",  &pDev);
+        InsertConfigNode(pDev,     "0",            &pInst);
+        InsertConfigNode(pInst,    "Config",        &pCfg);
+        InsertConfigInteger(pCfg,  "MmioEcamBase",   GCPhysPciMmioEcam);
+        InsertConfigInteger(pCfg,  "MmioEcamLength", cbPciMmioEcam);
+        InsertConfigInteger(pCfg,  "MmioPioBase",    GCPhysMmioStart);
+        InsertConfigInteger(pCfg,  "MmioPioSize",    cbMmio);
+        InsertConfigInteger(pCfg,  "IntPinA",        aPinIrqs[0]);
+        InsertConfigInteger(pCfg,  "IntPinB",        aPinIrqs[1]);
+        InsertConfigInteger(pCfg,  "IntPinC",        aPinIrqs[2]);
+        InsertConfigInteger(pCfg,  "IntPinD",        aPinIrqs[3]);
+        vrc = RTFdtNodeAddF(hFdt, "pcie@%RGp", GCPhysPciMmio);                              VRC();
+        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "interrupt-map-mask", 4, 0xf800, 0, 0, 7); VRC();
+
+        uint32_t aIrqCells[32 * 4 * 10]; RT_ZERO(aIrqCells); /* Maximum of 32 devices on the root bus, each supporting 4 interrupts (INTA# ... INTD#). */
+        uint32_t *pau32IrqCell = &aIrqCells[0];
+        uint32_t iIrqPinSwizzle = 0;
+
+        for (uint32_t i = 0; i < 32; i++)
+        {
+            for (uint32_t iIrqPin = 0; iIrqPin < 4; iIrqPin++)
+            {
+                pau32IrqCell[0] = i << 11; /* The dev part, composed as dev.fn. */
+                pau32IrqCell[1] = 0;
+                pau32IrqCell[2] = 0;
+                pau32IrqCell[3] = iIrqPin + 1;
+                pau32IrqCell[4] = idPHandleIntCtrl;
+                pau32IrqCell[5] = 0;
+                pau32IrqCell[6] = 0;
+                pau32IrqCell[7] = 0;
+                pau32IrqCell[8] = aPinIrqs[(iIrqPinSwizzle + iIrqPin) % RT_ELEMENTS(aPinIrqs)];
+                pau32IrqCell[9] = 0x04;
+                pau32IrqCell += 10;
+            }
+
+            iIrqPinSwizzle++;
+        }
+
+        vrc = RTFdtNodePropertyAddCellsU32AsArray(hFdt, "interrupt-map", RT_ELEMENTS(aIrqCells), &aIrqCells[0]);
+        vrc = RTFdtNodePropertyAddU32(     hFdt, "#interrupt-cells", 1);                        VRC();
+        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "ranges", 21,
+                                           0x1000000, 0, 0,
+                                           GCPhysMmioStart >> 32, GCPhysMmioStart, cbMmio >> 32, cbMmio,
+                                           0x2000000, GCPhysPciMmio32 >> 32, GCPhysPciMmio32, GCPhysPciMmio32 >> 32, GCPhysPciMmio32,
+                                           cbPciMmio32 >> 32, cbPciMmio32,
+                                           0x3000000, GCPhysPciMmio >> 32, GCPhysPciMmio, GCPhysPciMmio >> 32, GCPhysPciMmio,
+                                           cbPciMmio >> 32, cbPciMmio);                         VRC();
+        vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysPciMmioEcam, cbPciMmioEcam);   VRC();
+        /** @todo msi-map */
+        vrc = RTFdtNodePropertyAddEmpty(   hFdt, "dma-coherent");                               VRC();
+        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "bus-range", 2, 0, 0xf);                       VRC();
+        vrc = RTFdtNodePropertyAddU32(     hFdt, "linux,pci-domain", 0);                        VRC();
+        vrc = RTFdtNodePropertyAddU32(     hFdt, "#size-cells", 2);                             VRC();
+        vrc = RTFdtNodePropertyAddU32(     hFdt, "#address-cells", 3);                          VRC();
+        vrc = RTFdtNodePropertyAddString(  hFdt, "device_type", "pci");                         VRC();
+        vrc = RTFdtNodePropertyAddString(  hFdt, "compatible", "pci-host-ecam-generic");        VRC();
+        vrc = RTFdtNodeFinalize(hFdt);                                                          VRC();
+
+        if (pSysTblsBldAcpi)
+        {
+            vrc = pSysTblsBldAcpi->configurePcieRootBus("pci-generic-ecam", aPinIrqs, GCPhysMmioStart, GCPhysPciMmioEcam,
+                                                        cbPciMmioEcam, GCPhysMmioStart, cbMmio, GCPhysPciMmio32, cbPciMmio32);
+            VRC();
+        }
 
         /*
@@ -931,19 +991,14 @@
     VBOXPLATFORMARMV8 ArmV8Platform; RT_ZERO(ArmV8Platform);
 
-    /* Make room for the descriptor at the beginning. */
-    vrc = RTVfsIoStrmZeroFill(hVfsIosDesc, sizeof(ArmV8Platform));
-    AssertRCReturnStmt(vrc, RTFdtDestroy(hFdt), vrc);
-
     vrc = RTFdtDumpToVfsIoStrm(hFdt, RTFDTTYPE_DTB, 0 /*fFlags*/, hVfsIosDesc, NULL /*pErrInfo*/);
     uint64_t cbFdt = 0;
     if (RT_SUCCESS(vrc))
-    {
         vrc = RTVfsFileQuerySize(hVfsFileDesc, &cbFdt);
-        cbFdt -= sizeof(ArmV8Platform);
-    }
     AssertRCReturnStmt(vrc, RTFdtDestroy(hFdt), vrc);
 
     vrc = RTVfsIoStrmZeroFill(hVfsIosDesc, (RTFOFF)(RT_ALIGN_64(cbFdt, _64K) - cbFdt));
     AssertRCReturn(vrc, vrc);
+
+    cbFdt = RT_ALIGN_64(cbFdt, _64K);
 
     RTGCPHYS GCPhysMmioStart;
@@ -962,8 +1017,9 @@
     if (pSysTblsBldAcpi)
     {
-        vrc = pSysTblsBldAcpi->finishTables(VBOXPLATFORMARMV8_PHYS_ADDR + sizeof(ArmV8Platform) + RT_ALIGN_64(cbFdt, _64K),
+        vrc = pSysTblsBldAcpi->finishTables(GCPhysPlatformDesc + cbFdt,
                                             hVfsIosDesc, &GCPhysXsdp, &cbAcpiXsdp, &cbAcpi);
         AssertRCReturn(vrc, vrc);
-        Assert(GCPhysXsdp > VBOXPLATFORMARMV8_PHYS_ADDR);
+        Assert(   GCPhysXsdp > GCPhysPlatformDesc
+               && GCPhysXsdp < VBOXPLATFORMARMV8_PHYS_ADDR);
 
         /* Dump the ACPI table for debugging purposes if requested. */
@@ -982,5 +1038,15 @@
         vrc = RTVfsIoStrmZeroFill(hVfsIosDesc, (RTFOFF)(RT_ALIGN_64(cbAcpi, _64K) - cbAcpi));
         AssertRCReturn(vrc, vrc);
+
+        cbAcpi = RT_ALIGN_64(cbAcpi, _64K);
     }
+
+    /* Fill the room until the end where the platform descriptor lives. */
+    vrc = RTVfsIoStrmZeroFill(hVfsIosDesc, cbPlatformDesc - sizeof(ArmV8Platform) - cbFdt - cbAcpi);
+    AssertRCReturnStmt(vrc, RTFdtDestroy(hFdt), vrc);
+
+    RTGCPHYS GCPhysMmio    = 0;
+    RTGCPHYS cbMmioAbove4G = 0;
+    pResMgr->queryMmioRegion(&GCPhysMmio, &cbMmioAbove4G);
 
     ArmV8Platform.u32Magic            = VBOXPLATFORMARMV8_MAGIC;
@@ -988,24 +1054,24 @@
     ArmV8Platform.cbDesc              = sizeof(ArmV8Platform);
     ArmV8Platform.fFlags              = 0;
-    ArmV8Platform.u64PhysAddrRamBase  = GCPhysRam;
-    ArmV8Platform.cbRamBase           = cbRam;
-    ArmV8Platform.i64OffFdt           = sizeof(ArmV8Platform);
-    ArmV8Platform.cbFdt               = RT_ALIGN_64(cbFdt, _64K);
+    ArmV8Platform.u64PhysAddrRamBase  = GCPhysRamBase;
+    ArmV8Platform.cbRamBase           = cbRamBase;
+    ArmV8Platform.i64OffFdt           = (int64_t)GCPhysPlatformDesc - VBOXPLATFORMARMV8_PHYS_ADDR;
+    ArmV8Platform.cbFdt               = cbFdt;
     if (cbAcpi)
     {
-        ArmV8Platform.i64OffAcpi      = sizeof(ArmV8Platform) + RT_ALIGN_64(cbFdt, _64K);
-        ArmV8Platform.cbAcpi          = RT_ALIGN_64(cbAcpi, _64K);
-        ArmV8Platform.i64OffAcpiXsdp  = GCPhysXsdp - VBOXPLATFORMARMV8_PHYS_ADDR;
+        ArmV8Platform.i64OffAcpi      = (int64_t)(GCPhysPlatformDesc + cbFdt) - VBOXPLATFORMARMV8_PHYS_ADDR;
+        ArmV8Platform.cbAcpi          = cbAcpi;
+        ArmV8Platform.i64OffAcpiXsdp  = (int64_t)GCPhysXsdp - VBOXPLATFORMARMV8_PHYS_ADDR;
         ArmV8Platform.cbAcpiXsdp      = cbAcpiXsdp;
     }
-    ArmV8Platform.i64OffUefiRom       = -128 * _1M;
+    ArmV8Platform.i64OffUefiRom       = (int64_t)GCPhysFw - VBOXPLATFORMARMV8_PHYS_ADDR;
     ArmV8Platform.cbUefiRom           = _64M;
-    ArmV8Platform.i64OffMmio          = GCPhysMmioStart - _128M;
-    ArmV8Platform.cbMmio              = cbMmio;
-    ArmV8Platform.i64OffMmio32        = GCPhysMmio32Start - _128M;
-    ArmV8Platform.cbMmio32            = cbMmio32;
+    ArmV8Platform.i64OffMmio          = GCPhysMmio ? (int64_t)GCPhysMmio - VBOXPLATFORMARMV8_PHYS_ADDR : 0;
+    ArmV8Platform.cbMmio              = cbMmioAbove4G;
+    ArmV8Platform.i64OffMmio32        = (int64_t)(_4G - _512M) - VBOXPLATFORMARMV8_PHYS_ADDR;
+    ArmV8Platform.cbMmio32            = _512M - _2M; /* Just assign the whole MMIO hole (except for the platform descriptor region). */
 
     /* Add the VBox platform descriptor to the resource store. */
-    vrc = RTVfsIoStrmWriteAt(hVfsIosDesc, 0, &ArmV8Platform, sizeof(ArmV8Platform), true /*fBlocking*/, NULL /*pcbWritten*/);
+    vrc = RTVfsIoStrmWrite(hVfsIosDesc, &ArmV8Platform, sizeof(ArmV8Platform), true /*fBlocking*/, NULL /*pcbWritten*/);
     RTVfsIoStrmRelease(hVfsIosDesc);
     vrc = mptrResourceStore->i_addItem("resources", "VBoxArmV8Desc", hVfsFileDesc);
@@ -1024,4 +1090,6 @@
     }
 
+    pResMgr->dumpMemoryRegionsToReleaseLog();
+
     delete pResMgr; /* Delete the address/interrupt assignment manager. */
 
Index: trunk/src/VBox/Main/src-client/ResourceAssignmentManager.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/ResourceAssignmentManager.cpp	(revision 106955)
+++ trunk/src/VBox/Main/src-client/ResourceAssignmentManager.cpp	(revision 106957)
@@ -35,14 +35,9 @@
 #include "ResourceAssignmentManager.h"
 
+#include <VBox/com/array.h>
+
 #include <iprt/asm.h>
+#include <iprt/mem.h>
 #include <iprt/string.h>
-
-#include <VBox/vmm/cfgm.h>
-#include <VBox/vmm/vmmr3vtable.h>
-#include <VBox/com/array.h>
-
-#include <map>
-#include <vector>
-#include <algorithm>
 
 
@@ -50,4 +45,43 @@
 *   Structures and Typedefs                                                                                                      *
 *********************************************************************************************************************************/
+/**
+ * Address space range type.
+ */
+typedef enum RESOURCEREGIONTYPE
+{
+    /** Free region. */
+    kResourceRegionType_Free = 0,
+    /** RAM. */
+    kResourceRegionType_Ram,
+    /** ROM. */
+    kResourceRegionType_Rom,
+    /** MMIO. */
+    kResourceRegionType_Mmio,
+    /** 32bit hack. */
+    kResourceRegionType_32Bit_Hack = 0x7fffffff
+} RESOURCEREGIONTYPE;
+
+
+/**
+ * Address space range descriptor.
+ */
+typedef struct RESOURCEREGION
+{
+    /** Region name. */
+    char                szName[32];
+    /** Physical start address of the region. */
+    RTGCPHYS            GCPhysStart;
+    /** Physical end address of the region. */
+    RTGCPHYS            GCPhysEnd;
+    /** Region type. */
+    RESOURCEREGIONTYPE  enmType;
+    /** Padding. */
+    uint32_t            u32Pad;
+} RESOURCEREGION;
+AssertCompileSize(RESOURCEREGION, 56);
+/** Pointer to a resource region. */
+typedef RESOURCEREGION *PRESOURCEREGION;
+/** Pointer to a const resource region. */
+typedef const RESOURCEREGION *PCRESOURCEREGION;
 
 
@@ -63,59 +97,45 @@
 struct ResourceAssignmentManager::State
 {
-    struct MemoryRange
-    {
-        char          szDevName[32];
-        RTGCPHYS      mGCPhysStart;
-        RTGCPHYS      mGCPhysEnd;
-
-        MemoryRange(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd)
-        {
-            RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
-            this->mGCPhysStart = GCPhysStart;
-            this->mGCPhysEnd   = GCPhysEnd;
-        }
-
-        bool operator==(const MemoryRange &a) const
-        {
-            return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) == 0;
-        }
-    };
-
-    typedef std::vector<MemoryRange> AddrRangeList;
-
     ChipsetType_T    mChipsetType;
     IommuType_T      mIommuType;
-    PCVMMR3VTABLE    mpVMM;
-    AddrRangeList    mAddrRanges;
-
-    RTGCPHYS         mGCPhysMmioStartOrig;
-    RTGCPHYS         mGCPhysMmioStart;
-    RTGCPHYS         mGCPhysMmio32StartOrig;
-    RTGCPHYS         mGCPhysMmio32Start;
-    RTGCPHYS         mcbMmio32;
-    RTGCPHYS         mGCPhysRamStart;
+
+    /** Pointer to the array of regions (sorted by address, not overlapping, adjacent). */
+    PRESOURCEREGION  m_paRegions;
+    /** Number of used regions. */
+    uint32_t         m_cRegions;
+    /** Number of regions the allocated array can hold. */
+    uint32_t         m_cRegionsMax;
+
     uint32_t         mcInterrupts;
     uint32_t         miInterrupt;
 
     State()
-        : mChipsetType(ChipsetType_Null), mpVMM(NULL)
+        : mChipsetType(ChipsetType_Null)
+        , mIommuType(IommuType_None)
+        , m_paRegions(NULL)
+        , m_cRegions(0)
+        , m_cRegionsMax(0)
+        , mcInterrupts(0)
+        , miInterrupt(0)
     {}
     ~State()
     {}
 
-    HRESULT init(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType,
-                 RTGCPHYS GCPhysMmioTop, RTGCPHYS GCPhysRamStart,
-                 RTGCPHYS GCPhysMmio32Start, RTGCPHYS cbMmio32, uint32_t cInterrupts);
-
-    HRESULT addAddrRange(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd);
+    HRESULT init(ChipsetType_T chipsetType, IommuType_T iommuType, uint32_t cInterrupts);
+
+    HRESULT ensureAdditionalRegions(uint32_t cRegions);
+    void setRegion(PRESOURCEREGION pRegion, const char *pszName, RESOURCEREGIONTYPE enmType,
+                   RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd);
+    HRESULT addAddrRange(const char *pszName, RESOURCEREGIONTYPE enmType, RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd);
+    HRESULT findNextFreeAddrRange(RTGCPHYS cbRegion, RTGCPHYS cbAlignment, RTGCPHYS GCPhysMax, RTGCPHYS GCPhysHint,
+                                  PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion);
+
+    void dumpToReleaseLog(void);
 };
 
 
-HRESULT ResourceAssignmentManager::State::init(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType,
-                                               RTGCPHYS GCPhysMmioStart, RTGCPHYS GCPhysRamStart,
-                                               RTGCPHYS GCPhysMmio32Start, RTGCPHYS cbMmio32, uint32_t cInterrupts)
-{
-    mpVMM = pVMM;
-
+HRESULT ResourceAssignmentManager::State::init(ChipsetType_T chipsetType, IommuType_T iommuType,
+                                               uint32_t cInterrupts)
+{
     Assert(chipsetType == ChipsetType_ARMv8Virtual);
     Assert(iommuType == IommuType_None); /* For now no IOMMU support on ARMv8. */
@@ -123,111 +143,283 @@
     mChipsetType           = chipsetType;
     mIommuType             = iommuType;
-    mGCPhysMmioStart       = GCPhysMmioStart;
-    mGCPhysMmioStartOrig   = GCPhysMmioStart;
-    mGCPhysRamStart        = GCPhysRamStart;
-    mGCPhysMmio32Start     = GCPhysMmio32Start;
-    mGCPhysMmio32StartOrig = GCPhysMmio32Start;
-    mcbMmio32              = cbMmio32;
     mcInterrupts           = cInterrupts;
     miInterrupt            = 0;
-    return S_OK;
-}
-
-HRESULT ResourceAssignmentManager::State::addAddrRange(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
-{
-    MemoryRange memRange(pszName, GCPhysStart, GCPhysStart + cbRegion - 1);
-    mAddrRanges.push_back(memRange);
-    return S_OK;
-}
+
+    m_paRegions = (PRESOURCEREGION)RTMemRealloc(m_paRegions, 32 * sizeof(*m_paRegions));
+    if (!m_paRegions)
+        return E_OUTOFMEMORY;
+
+    m_paRegions[m_cRegions].enmType     = kResourceRegionType_Free;
+    m_paRegions[m_cRegions].GCPhysStart = 0;
+    m_paRegions[m_cRegions].GCPhysEnd   = UINT64_MAX;
+    strcpy(&m_paRegions[m_cRegions].szName[0], "Free");
+    m_cRegions++;
+
+    return S_OK;
+}
+
+
+HRESULT ResourceAssignmentManager::State::ensureAdditionalRegions(uint32_t cRegions)
+{
+    if (m_cRegions + cRegions == m_cRegionsMax)
+    {
+        uint32_t const cRegionsNew = m_cRegionsMax + 32;
+        PRESOURCEREGION paDescsNew = (PRESOURCEREGION)RTMemRealloc(m_paRegions, cRegionsNew * sizeof(*paDescsNew));
+        if (!paDescsNew)
+            return E_OUTOFMEMORY;
+
+        m_paRegions   = paDescsNew;
+        m_cRegionsMax = cRegionsNew;
+    }
+
+    return S_OK;
+}
+
+
+void ResourceAssignmentManager::State::setRegion(PRESOURCEREGION pRegion, const char *pszName, RESOURCEREGIONTYPE enmType,
+                                                 RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd)
+{
+    strncpy(&pRegion->szName[0], pszName, sizeof(pRegion->szName));
+    pRegion->szName[sizeof(pRegion->szName) - 1] = '\0';
+    pRegion->enmType     = enmType;
+    pRegion->GCPhysStart = GCPhysStart;
+    pRegion->GCPhysEnd   = GCPhysEnd;
+}
+
+
+HRESULT ResourceAssignmentManager::State::addAddrRange(const char *pszName, RESOURCEREGIONTYPE enmType,
+                                                       RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
+{
+    RTGCPHYS GCPhysEnd = GCPhysStart + cbRegion - 1;
+
+    /* Find the right spot in the array where to insert the range, it must not overlap with an existing used range. */
+    uint32_t iRegion = 0;
+    while (   iRegion < m_cRegions
+           && GCPhysStart > m_paRegions[iRegion].GCPhysEnd)
+        iRegion++;
+
+    Assert(   iRegion == m_cRegions - 1
+           || m_paRegions[iRegion].enmType != m_paRegions[iRegion + 1].enmType);
+
+    /* Check that there is sufficient free space. */
+    if (   (m_paRegions[iRegion].enmType != kResourceRegionType_Free)
+        || GCPhysEnd > m_paRegions[iRegion].GCPhysEnd)
+        return E_INVALIDARG;
+
+    Assert(m_paRegions[iRegion].enmType == kResourceRegionType_Free);
+
+    /* Requested region fits exactly into the free region. */
+    if (   GCPhysStart == m_paRegions[iRegion].GCPhysStart
+        && GCPhysEnd   == m_paRegions[iRegion].GCPhysEnd)
+    {
+        setRegion(&m_paRegions[iRegion], pszName, enmType, GCPhysStart, GCPhysEnd);
+        return S_OK;
+    }
+
+    HRESULT hrc = ensureAdditionalRegions(2 /*cRegions*/); /* Need two additional region descriptors max. */
+    if (FAILED(hrc))
+        return hrc;
+
+    /* Need to split the region into two or three depending on where the requested region lies. */
+    if (GCPhysStart == m_paRegions[iRegion].GCPhysStart)
+    {
+        /* At the start, move the free regions and everything at the end. */
+        memmove(&m_paRegions[iRegion + 1], &m_paRegions[iRegion], (m_cRegions - iRegion) * sizeof(*m_paRegions));
+        setRegion(&m_paRegions[iRegion], pszName, enmType, GCPhysStart, GCPhysEnd);
+
+        /* Adjust the free region. */
+        m_paRegions[iRegion + 1].GCPhysStart = GCPhysStart + cbRegion;
+        m_cRegions++;
+    }
+    else if (GCPhysStart + cbRegion - 1 == m_paRegions[iRegion].GCPhysEnd)
+    {
+        /* At the end of the region, move the remaining regions and adjust ranges. */
+        if (iRegion < m_cRegions)
+            memmove(&m_paRegions[iRegion + 2], &m_paRegions[iRegion + 1], (m_cRegions - iRegion) * sizeof(*m_paRegions));
+        setRegion(&m_paRegions[iRegion + 1], pszName, enmType, GCPhysStart, GCPhysEnd);
+        m_paRegions[iRegion].GCPhysEnd = GCPhysStart - 1;
+        m_cRegions++;
+    }
+    else
+    {
+        /* Somewhere in the middle, split into three regions. */
+        if (iRegion < m_cRegions)
+            memmove(&m_paRegions[iRegion + 3], &m_paRegions[iRegion + 1], (m_cRegions - iRegion) * sizeof(*m_paRegions));
+        setRegion(&m_paRegions[iRegion + 1], pszName, enmType, GCPhysStart, GCPhysEnd);
+        setRegion(&m_paRegions[iRegion + 2], "Free", kResourceRegionType_Free, GCPhysStart + cbRegion, m_paRegions[iRegion].GCPhysEnd);
+        m_paRegions[iRegion].GCPhysEnd = GCPhysStart - 1;
+        m_cRegions += 2;
+    }
+
+    return S_OK;
+}
+
+
+HRESULT ResourceAssignmentManager::State::findNextFreeAddrRange(RTGCPHYS cbRegion, RTGCPHYS cbAlignment, RTGCPHYS GCPhysMax,
+                                                                RTGCPHYS GCPhysHint, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
+{
+    AssertReturn(GCPhysMax >= cbRegion, E_FAIL);
+    GCPhysMax -= cbRegion;
+
+    uint32_t iRegion = 0;
+    if (GCPhysHint)
+    {
+        /* Look for free address range downwards from the hint first. */
+        iRegion = m_cRegions - 1;
+        while (iRegion)
+        {
+            PCRESOURCEREGION pRegion = &m_paRegions[iRegion];
+
+            /* Region must be free and satisfy the alignment++ requirements. */
+            RTGCPHYS GCPhysStartAligned = RT_ALIGN_T(pRegion->GCPhysEnd - cbRegion + 1, cbAlignment, RTGCPHYS);
+            if (   pRegion->enmType == kResourceRegionType_Free
+                && GCPhysHint >= pRegion->GCPhysEnd
+                && GCPhysMax >= pRegion->GCPhysEnd
+                && GCPhysStartAligned >= pRegion->GCPhysStart
+                && pRegion->GCPhysEnd - GCPhysStartAligned + 1 >= cbRegion)
+            {
+                *pGCPhysStart = GCPhysStartAligned;
+                *pcbRegion    = cbRegion;
+                return S_OK;
+            }
+
+            iRegion--;
+        }
+    }
+
+    /* Find a free region which satisfies or requirements. */
+    while (   iRegion < m_cRegions
+           && GCPhysMax >= m_paRegions[iRegion].GCPhysStart)
+    {
+        PCRESOURCEREGION pRegion = &m_paRegions[iRegion];
+
+        /* Region must be free and satisfy the alignment++ requirements. */
+        RTGCPHYS GCPhysStartAligned = RT_ALIGN_T(pRegion->GCPhysStart, cbAlignment, RTGCPHYS);
+        if (   pRegion->enmType == kResourceRegionType_Free
+            && GCPhysStartAligned >= pRegion->GCPhysStart
+            && pRegion->GCPhysEnd - GCPhysStartAligned + 1 >= cbRegion)
+        {
+            *pGCPhysStart = pRegion->GCPhysStart;
+            *pcbRegion    = cbRegion;
+            return S_OK;
+        }
+
+        iRegion++;
+    }
+
+    return E_OUTOFMEMORY;
+}
+
+
+static const char *resourceManagerRegionType2Str(RESOURCEREGIONTYPE enmType)
+{
+    switch (enmType)
+    {
+        case kResourceRegionType_Free: return "FREE";
+        case kResourceRegionType_Ram:  return "RAM ";
+        case kResourceRegionType_Rom:  return "ROM ";
+        case kResourceRegionType_Mmio: return "MMIO";
+        default: AssertFailed(); return "UNKNOWN";
+    }
+}
+
+
+void ResourceAssignmentManager::State::dumpToReleaseLog(void)
+{
+    LogRel(("Memory Regions:\n"));
+    for (uint32_t iRegion = 0; iRegion < m_cRegions; iRegion++)
+    {
+        LogRel(("    %RGp - %RGp (%zu) %s %s\n",
+                m_paRegions[iRegion].GCPhysStart,
+                m_paRegions[iRegion].GCPhysEnd,
+                m_paRegions[iRegion].GCPhysEnd - m_paRegions[iRegion].GCPhysStart + 1,
+                m_paRegions[iRegion].szName));
+    }
+}
+
 
 ResourceAssignmentManager::ResourceAssignmentManager()
-    : pState(NULL)
-{
-    pState = new State();
-    Assert(pState);
-}
+    : m_pState(NULL)
+{
+    m_pState = new State();
+    Assert(m_pState);
+}
+
 
 ResourceAssignmentManager::~ResourceAssignmentManager()
 {
-    if (pState)
-    {
-        delete pState;
-        pState = NULL;
-    }
-}
+    if (m_pState)
+    {
+        delete m_pState;
+        m_pState = NULL;
+    }
+}
+
 
 ResourceAssignmentManager *ResourceAssignmentManager::createInstance(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType,
-                                                                     RTGCPHYS GCPhysMmioTop, RTGCPHYS GCPhysRamStart,
-                                                                     RTGCPHYS GCPhysMmio32Start, RTGCPHYS cbMmio32,
-                                                                     uint32_t cInterrupts)
-{
+                                                                     uint32_t cInterrupts, RTGCPHYS GCPhysMmioHint)
+{
+    RT_NOREF(pVMM);
+
     ResourceAssignmentManager *pInstance = new ResourceAssignmentManager();
-    pInstance->pState->init(pVMM, chipsetType, iommuType, GCPhysMmioTop, GCPhysRamStart, GCPhysMmio32Start, cbMmio32, cInterrupts);
+
+    pInstance->m_GCPhysMmioHint = GCPhysMmioHint;
+    pInstance->m_pState->init(chipsetType, iommuType, cInterrupts);
     Assert(pInstance);
     return pInstance;
 }
 
+
+HRESULT ResourceAssignmentManager::assignFixedRomRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
+{
+    return m_pState->addAddrRange(pszName, kResourceRegionType_Rom, GCPhysStart, cbRegion);
+}
+
+
+HRESULT ResourceAssignmentManager::assignFixedRamRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
+{
+    return m_pState->addAddrRange(pszName, kResourceRegionType_Ram, GCPhysStart, cbRegion);
+}
+
+
+HRESULT ResourceAssignmentManager::assignFixedMmioRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
+{
+    return m_pState->addAddrRange(pszName, kResourceRegionType_Mmio, GCPhysStart, cbRegion);
+}
+
+
+HRESULT ResourceAssignmentManager::assignMmioRegionAligned(const char *pszName, RTGCPHYS cbRegion, RTGCPHYS cbAlignment, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion,
+                                                           bool fOnly32Bit)
+{
+    RTGCPHYS GCPhysRegionStart;
+    RTGCPHYS cbRegionFinal;
+    HRESULT hrc = m_pState->findNextFreeAddrRange(cbRegion, cbAlignment, fOnly32Bit ? _4G : RTGCPHYS_MAX,
+                                                  m_GCPhysMmioHint, &GCPhysRegionStart, &cbRegionFinal);
+    if (SUCCEEDED(hrc))
+    {
+        *pGCPhysStart = GCPhysRegionStart;
+        *pcbRegion    = cbRegionFinal;
+        return assignFixedMmioRegion(pszName, GCPhysRegionStart, cbRegion);
+    }
+
+    return hrc;
+}
+
+
 HRESULT ResourceAssignmentManager::assignMmioRegion(const char *pszName, RTGCPHYS cbRegion, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
 {
-    RTGCPHYS cbRegionAligned = RT_ALIGN_T(cbRegion, _4K, RTGCPHYS);
-    RTGCPHYS GCPhysMmioStart = pState->mGCPhysMmioStart;
-
-    *pGCPhysStart = GCPhysMmioStart;
-    *pcbRegion    = cbRegionAligned;
-    pState->mGCPhysMmioStart += cbRegionAligned;
-    pState->addAddrRange(pszName, GCPhysMmioStart, cbRegionAligned);
-    return S_OK;
-}
+    return assignMmioRegionAligned(pszName, cbRegion, _4K, pGCPhysStart, pcbRegion, false /*fOnly32Bit*/);
+}
+
 
 HRESULT ResourceAssignmentManager::assignMmio32Region(const char *pszName, RTGCPHYS cbRegion, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
 {
-    RTGCPHYS cbRegionAligned = RT_ALIGN_T(cbRegion, _4K, RTGCPHYS);
-    RTGCPHYS GCPhysMmioStart = pState->mGCPhysMmio32Start;
-
-    if (GCPhysMmioStart > pState->mGCPhysRamStart)
-    {
-        AssertLogRelMsgFailed(("ResourceAssignmentManager: MMIO32 range for %s would overlap RAM region\n", pszName));
-        return E_INVALIDARG;
-    }
-
-    *pGCPhysStart = GCPhysMmioStart;
-    *pcbRegion    = cbRegionAligned;
-    pState->mGCPhysMmio32Start += cbRegionAligned;
-    pState->addAddrRange(pszName, GCPhysMmioStart, cbRegionAligned);
-    return S_OK;
-}
-
-HRESULT ResourceAssignmentManager::assignMmioRegionAligned(const char *pszName, RTGCPHYS cbRegion, RTGCPHYS cbAlignment, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
-{
-    RTGCPHYS cbRegionAligned = RT_ALIGN_T(cbRegion, cbAlignment, RTGCPHYS);
-    RTGCPHYS GCPhysMmioStart = pState->mGCPhysMmioStart;
-
-    GCPhysMmioStart = RT_ALIGN_T(GCPhysMmioStart, cbAlignment, RTGCPHYS);
-
-    *pGCPhysStart = GCPhysMmioStart;
-    *pcbRegion    = cbRegionAligned;
-    pState->mGCPhysMmioStart = GCPhysMmioStart + cbRegionAligned;
-    pState->addAddrRange(pszName, GCPhysMmioStart, cbRegionAligned);
-    return S_OK;
-}
-
-HRESULT ResourceAssignmentManager::assignFixedAddress(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
-{
-    RT_NOREF(pszName, GCPhysStart, cbRegion);
-    AssertReleaseFailed();
-    return S_OK;
-}
-
-HRESULT ResourceAssignmentManager::assignRamRegion(const char *pszName, RTGCPHYS cbRam, PRTGCPHYS pGCPhysStart)
-{
-    *pGCPhysStart = pState->mGCPhysRamStart;
-    pState->mGCPhysRamStart += cbRam;
-    pState->addAddrRange(pszName, *pGCPhysStart, cbRam);
-    return S_OK;
-}
+    return assignMmioRegionAligned(pszName, cbRegion, _4K, pGCPhysStart, pcbRegion, true /*fOnly32Bit*/);
+}
+
 
 HRESULT ResourceAssignmentManager::assignInterrupts(const char *pszName, uint32_t cInterrupts, uint32_t *piInterruptFirst)
 {
-    if (pState->miInterrupt + cInterrupts > pState->mcInterrupts)
+    if (m_pState->miInterrupt + cInterrupts > m_pState->mcInterrupts)
     {
         AssertLogRelMsgFailed(("ResourceAssignmentManager: Interrupt count for %s exceeds number of available interrupts\n", pszName));
@@ -235,8 +427,56 @@
     }
 
-    *piInterruptFirst = pState->miInterrupt;
-    pState->miInterrupt += cInterrupts;
-    return S_OK;
-}
+    *piInterruptFirst = m_pState->miInterrupt;
+    m_pState->miInterrupt += cInterrupts;
+    return S_OK;
+}
+
+HRESULT ResourceAssignmentManager::queryMmioRegion(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
+{
+    /*
+     * This ASSUMES that there are adjacent MMIO regions above 4GiB which can be combined into one single region
+     * (adjacent and no ROM/RAM regions inbetween).
+     */
+    *pGCPhysMmioStart = 0;
+    *pcbMmio          = 0;
+
+    /* Look for the start. */
+    for (uint32_t i = 0; i < m_pState->m_cRegions; i++)
+    {
+        PCRESOURCEREGION pRegion = &m_pState->m_paRegions[i];
+
+        if (   pRegion->GCPhysStart >= _4G
+            && pRegion->enmType == kResourceRegionType_Mmio)
+        {
+            RTGCPHYS cbMmio = pRegion->GCPhysEnd - pRegion->GCPhysStart + 1;
+
+            *pGCPhysMmioStart = pRegion->GCPhysStart;
+
+            /* Add up any remaining MMIO regions adjacent to this one. */
+            for (uint32_t j = i; j < m_pState->m_cRegions; j++)
+            {
+                pRegion = &m_pState->m_paRegions[i];
+                if (   pRegion->enmType == kResourceRegionType_Mmio
+                    && pRegion->GCPhysStart == *pGCPhysMmioStart + cbMmio)
+                    cbMmio += pRegion->GCPhysEnd - pRegion->GCPhysStart + 1;
+                else
+                    break;
+            }
+
+            *pcbMmio = cbMmio;
+            return S_OK;
+        }
+    }
+
+    return S_OK;
+}
+
+
+HRESULT ResourceAssignmentManager::queryMmio32Region(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
+{
+    RT_NOREF(pGCPhysMmioStart, pcbMmio);
+    return S_OK;
+}
+
 
 HRESULT ResourceAssignmentManager::assignSingleInterrupt(const char *pszName, uint32_t *piInterrupt)
@@ -245,15 +485,7 @@
 }
 
-HRESULT ResourceAssignmentManager::queryMmioRegion(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
-{
-    *pGCPhysMmioStart = pState->mGCPhysMmioStartOrig;
-    *pcbMmio          = pState->mGCPhysMmioStart - pState->mGCPhysMmioStartOrig;
-    return S_OK;
-}
-
-HRESULT ResourceAssignmentManager::queryMmio32Region(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
-{
-    *pGCPhysMmioStart = pState->mGCPhysMmio32StartOrig;
-    *pcbMmio          = pState->mcbMmio32;
-    return S_OK;
-}
+
+void ResourceAssignmentManager::dumpMemoryRegionsToReleaseLog(void)
+{
+    m_pState->dumpToReleaseLog();
+}
