VirtualBox

Changeset 106957 in vbox for trunk/src/VBox/Main/src-client


Ignore:
Timestamp:
Nov 12, 2024 12:09:04 PM (2 months ago)
Author:
vboxsync
Message:

Main/ResourceAssignmentManager: Rewrite to accomodate for the fact that Windows guests have several requirements on where devices are located (TPM needs to be at fixed 0xfed40000, PL061 GPIO driver doesn't support 64bit MMIO, the GIC re-disitributor emulated by Hyper-V requires 128KiB of MMIO space rather than the 64KiB we currently reserve). This will break saved state compatibility (whether we want to restore this functionality is up for discussion), bugref:10732

Location:
trunk/src/VBox/Main/src-client
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-client/ConsoleImplConfigArmV8.cpp

    r106476 r106957  
    187187
    188188    BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(pVMM, chipsetType, IommuType_None);
    189     ResourceAssignmentManager *pResMgr = ResourceAssignmentManager::createInstance(pVMM, chipsetType, IommuType_None,
    190                                                                                    RT_MAX(_1G + cbRam, _4G),                  /*GCPhysMmio*/
    191                                                                                    _1G,                                       /*GCPhysRam*/
    192                                                                                    VBOXPLATFORMARMV8_PHYS_ADDR + _1M,         /*GCPhysMmio32Start*/
    193                                                                                    _1G - (VBOXPLATFORMARMV8_PHYS_ADDR + _1M), /*cbMmio32*/
    194                                                                                    32                                         /*cInterrupts*/);
     189    ResourceAssignmentManager *pResMgr = ResourceAssignmentManager::createInstance(pVMM, chipsetType, IommuType_None, 32 /*cInterrupts*/,
     190                                                                                   _4G); /* Start looking for free MMIO regions at 4GiB downwards. */
    195191    SystemTableBuilder *pSysTblsBldAcpi = NULL;
    196192
     
    211207    Assert(pRoot);
    212208
    213     RTGCPHYS GCPhysRam = NIL_RTGCPHYS;
     209    /*
     210     * The VBox platform descriptor, FDT and ACPI tables will reside at the end of the 4GiB
     211     * address space and we reserve 2MiB for those.
     212     */
     213    RTGCPHYS cbPlatformDesc     = _2M;
     214    RTGCPHYS GCPhysPlatformDesc = VBOXPLATFORMARMV8_PHYS_ADDR - (cbPlatformDesc - _64K);
     215
     216    RTGCPHYS GCPhysRamBase = 128 * _1M;
     217    RTGCPHYS cbRamBase     = RT_MIN(cbRam, _4G - _512M - 128 * _1M);
     218
     219    RTGCPHYS GCPhysFw = 0;
     220    RTGCPHYS cbFw     = _64M;
    214221
    215222    // catching throws from InsertConfigString and friends.
     
    281288        vrc = RTFdtNodePropertyAddU32(     hFdt, "phandle", idPHandleAbpPClk);              VRC();
    282289        vrc = RTFdtNodePropertyAddString(  hFdt, "clock-output-names", "clk24mhz");         VRC();
    283         vrc = RTFdtNodePropertyAddU32(     hFdt, "clock-frequency",    24 * 1000 * 1000);  VRC();
     290        vrc = RTFdtNodePropertyAddU32(     hFdt, "clock-frequency",    ASMReadCntFrqEl0()); VRC();
    284291        vrc = RTFdtNodePropertyAddU32(     hFdt, "#clock-cells",       0);                  VRC();
    285292        vrc = RTFdtNodePropertyAddString(  hFdt, "compatible",         "fixed-clock");      VRC();
     
    304311        InsertConfigNode(pMM, "MemRegions", &pMem);
    305312
    306         hrc = pResMgr->assignRamRegion("Conventional", cbRam, &GCPhysRam);                  H();
     313        /*
     314         * Windows requires the TPM to be available at 0xfed40000 so reserve this region first, even
     315         * if no TPM is configured.
     316         */
     317        RTGCPHYS GCPhysTpm = 0xfed40000;
     318        RTGCPHYS cbTpm     = 0x5000 + 0x1000; /* TPM + PPI region. */
     319        hrc = pResMgr->assignFixedMmioRegion("tpm", GCPhysTpm, cbTpm);                              H();
     320
     321        /*
     322         * The firmware ROM will start at the beginning of the address space and span 64MiB
     323         * After that comes the flash and spans another 64MiB (even if the real size is smaller).
     324         */
     325        hrc = pResMgr->assignFixedRomRegion("firmware", GCPhysFw, cbFw);                            H();
     326
     327        RTGCPHYS GCPhysFlash = _64M;
     328        RTGCPHYS cbFlash     = _64M;
     329        hrc = pResMgr->assignFixedMmioRegion("flash", GCPhysFlash, cbFlash);                        H();
     330
     331        hrc = pResMgr->assignFixedRomRegion("platform-tables", GCPhysPlatformDesc, cbPlatformDesc); H();
     332
     333        /*
     334         * The base RAM will start at 128MiB (end of flash region) and goes up to 4GiB - 512MiB
     335         * (for the MMIO hole).
     336         * If more RAM is configured the high region will start at 4GiB.
     337         */
     338        hrc = pResMgr->assignFixedRamRegion("RAM Base", GCPhysRamBase, cbRamBase);                  H();
    307339
    308340        PCFGMNODE pMemRegion = NULL;
    309         InsertConfigNode(pMem, "Conventional", &pMemRegion);
    310         InsertConfigInteger(pMemRegion, "GCPhysStart", GCPhysRam);
    311         InsertConfigInteger(pMemRegion, "Size", cbRam);
    312 
    313         vrc = RTFdtNodeAddF(hFdt, "memory@%RGp", GCPhysRam);                                VRC();
    314         vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysRam, cbRam);               VRC();
     341        InsertConfigNode(pMem, "Base", &pMemRegion);
     342        InsertConfigInteger(pMemRegion, "GCPhysStart", GCPhysRamBase);
     343        InsertConfigInteger(pMemRegion, "Size", cbRamBase);
     344
     345        vrc = RTFdtNodeAddF(hFdt, "memory@%RGp", GCPhysRamBase);                            VRC();
     346        vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysRamBase, cbRamBase);       VRC();
    315347        vrc = RTFdtNodePropertyAddString(  hFdt, "device_type",      "memory");             VRC();
    316348        vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
     
    318350        if (pSysTblsBldAcpi)
    319351        {
    320             vrc = pSysTblsBldAcpi->addMemory(GCPhysRam, cbRam);
     352            vrc = pSysTblsBldAcpi->addMemory(GCPhysRamBase, cbRamBase);
    321353            VRC();
     354        }
     355
     356        if (cbRamBase < cbRam)
     357        {
     358            RTGCPHYS GCPhysRamHigh = _4G;
     359            RTGCPHYS cbRamHigh     = cbRam - cbRamBase;
     360
     361            hrc = pResMgr->assignFixedRamRegion("RAM High", GCPhysRamHigh, cbRamHigh);        H();
     362
     363            InsertConfigNode(pMem, "High", &pMemRegion);
     364            InsertConfigInteger(pMemRegion, "GCPhysStart", GCPhysRamHigh);
     365            InsertConfigInteger(pMemRegion, "Size", cbRamHigh);
     366
     367            vrc = RTFdtNodeAddF(hFdt, "memory@%RGp", GCPhysRamHigh);                        VRC();
     368            vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysRamHigh, cbRamHigh);   VRC();
     369            vrc = RTFdtNodePropertyAddString(  hFdt, "device_type",      "memory");         VRC();
     370            vrc = RTFdtNodeFinalize(hFdt);                                                  VRC();
     371
     372            if (pSysTblsBldAcpi)
     373            {
     374                vrc = pSysTblsBldAcpi->addMemory(GCPhysRamHigh, cbRamHigh);
     375                VRC();
     376            }
    322377        }
    323378
     
    440495        InsertConfigNode(pResources,    "ArmV8Desc",             &pRes);
    441496        InsertConfigInteger(pRes,       "RegisterAsRom",         1);
    442         InsertConfigInteger(pRes,       "GCPhysLoadAddress",     VBOXPLATFORMARMV8_PHYS_ADDR);
     497        InsertConfigInteger(pRes,       "GCPhysLoadAddress",     GCPhysPlatformDesc);
    443498        InsertConfigString(pRes,        "ResourceId",            "VBoxArmV8Desc");
    444499
     
    447502         */
    448503        RTGCPHYS GCPhysIntcDist;
     504        RTGCPHYS GCPhysIntcIts;
     505        RTGCPHYS cbMmioIntcDist;
     506        RTGCPHYS cbMmioIntcIts;
    449507        RTGCPHYS GCPhysIntcReDist;
    450         RTGCPHYS cbMmioIntcDist;
    451508        RTGCPHYS cbMmioIntcReDist;
    452509
    453         /* Each vCPU needs on re-distributor, this would allow for up to 256 vCPUs in the future. */
    454         hrc = pResMgr->assignMmioRegion("gic", 256 * _64K, &GCPhysIntcReDist, &cbMmioIntcReDist);       H();
    455         hrc = pResMgr->assignMmioRegion("gic", _64K, &GCPhysIntcDist, &cbMmioIntcDist);                 H();
    456 
    457 #ifndef RT_OS_LINUX
     510        /* Allow for up to 256 vCPUs in the future without changing the address space layout. */
     511        hrc = pResMgr->assignMmioRegion("gic", _64K + 256 * _128K, &GCPhysIntcDist, &cbMmioIntcDist);     H();
     512        GCPhysIntcReDist = GCPhysIntcDist + _64K;
     513        cbMmioIntcReDist = 256 * _128K;
     514        cbMmioIntcDist = _64K;
     515
     516        hrc = pResMgr->assignMmioRegion("gic-its", 2 * _64K, &GCPhysIntcIts, &cbMmioIntcIts);             H();
     517
     518#ifdef RT_OS_DARWIN
    458519        InsertConfigNode(pDevices, "gic",                   &pDev);
    459520#else
    460         /* On Linux we default to the KVM in-kernel GIC for now. */
     521        /* On Linux we default to the KVM in-kernel GIC and on Windows we are forced to the Hyper-V GIC for now. */
    461522        InsertConfigNode(pDevices, "gic-nem",               &pDev);
    462523#endif
     
    466527        InsertConfigInteger(pCfg,  "DistributorMmioBase",   GCPhysIntcDist);
    467528        InsertConfigInteger(pCfg,  "RedistributorMmioBase", GCPhysIntcReDist);
     529        InsertConfigInteger(pCfg,  "ItsMmioBase",           GCPhysIntcIts);
    468530
    469531        vrc = RTFdtNodeAddF(hFdt, "intc@%RGp", GCPhysIntcDist);                                         VRC();
    470532        vrc = RTFdtNodePropertyAddU32(     hFdt, "phandle",          idPHandleIntCtrl);                 VRC();
    471533        vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 4,
    472                                            GCPhysIntcDist, cbMmioIntcDist,      /* Distributor */
     534                                           GCPhysIntcDist, cbMmioIntcDist,       /* Distributor */
    473535                                           GCPhysIntcReDist, cbMmioIntcReDist); /* Re-Distributor */    VRC();
    474536        vrc = RTFdtNodePropertyAddU32(     hFdt, "#redistributor-regions", 1);                          VRC();
     
    500562
    501563        /*
    502          * Configure the perofrmance monitoring unit.
     564         * Configure the performance monitoring unit.
    503565         */
    504566        /** @todo Make this configurable and enable as default for Windows VMs because they assume a working PMU
     
    542604        InsertConfigNode(pDev,     "0",            &pInst);
    543605        InsertConfigNode(pInst,    "Config",        &pCfg);
    544         InsertConfigInteger(pCfg,  "BaseAddress",  64 * _1M);
     606        InsertConfigInteger(pCfg,  "BaseAddress",  GCPhysFlash);
    545607        InsertConfigInteger(pCfg,  "Size",        768 * _1K);
    546608        InsertConfigString(pCfg,   "FlashFile",   "nvram");
     
    552614        vrc = RTFdtNodePropertyAddU32(     hFdt, "bank-width", 4);                          VRC();
    553615        vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 4,
    554                                            0,          0x04000000,  /* First region (EFI). */
    555                                            0x04000000, 0x04000000); /* Second region (NVRAM). */ VRC();
     616                                           GCPhysFw,    cbFw,     /* First region (EFI). */
     617                                           GCPhysFlash, cbFlash); /* Second region (NVRAM). */ VRC();
    556618        vrc = RTFdtNodePropertyAddString(  hFdt, "compatible", "cfi-flash");                VRC();
    557619        vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
     
    638700        vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
    639701
    640         /* Configure gpio keys. */
     702        /* Configure gpio keys (The Windows GPIO PL061 driver doesn't like 64-bit MMIO addresses...). */
    641703        hrc = pResMgr->assignSingleInterrupt("arm-pl061-gpio", &iIrq);                      H();
    642         hrc = pResMgr->assignMmioRegion("arm-pl061-gpio", _4K, &GCPhysMmioStart, &cbMmio);  H();
     704        hrc = pResMgr->assignMmio32Region("arm-pl061-gpio", _4K, &GCPhysMmioStart, &cbMmio);  H();
    643705        InsertConfigNode(pDevices, "arm-pl061-gpio",&pDev);
    644706        InsertConfigNode(pDev,     "0",            &pInst);
     
    660722        if (pSysTblsBldAcpi)
    661723        {
    662             vrc = pSysTblsBldAcpi->addMmioDevice("arm-pl061-gpio", 0, GCPhysMmioStart, _4K, iIrq);
     724            vrc = pSysTblsBldAcpi->addMmioDevice("arm-pl061-gpio", 0, GCPhysMmioStart, cbMmio, iIrq);
    663725            VRC();
    664726        }
     
    687749        vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
    688750
    689         hrc = pResMgr->assignInterrupts("pci-generic-ecam", 4 /*cInterrupts*/, &iIrq);      H();
    690         uint32_t aPinIrqs[] = { iIrq, iIrq + 1, iIrq + 2, iIrq + 3 };
    691         RTGCPHYS GCPhysPciMmioEcam, GCPhysPciMmio, GCPhysPciMmio32;
    692         RTGCPHYS cbPciMmioEcam, cbPciMmio, cbPciMmio32;
    693         hrc = pResMgr->assignMmioRegionAligned("pci-pio",    _64K, _64K,                              &GCPhysMmioStart,   &cbMmio);         H();
    694         hrc = pResMgr->assignMmioRegion(       "pci-ecam",   16 * _1M,                                &GCPhysPciMmioEcam, &cbPciMmioEcam);  H();
    695         hrc = pResMgr->assignMmioRegion(       "pci-mmio",   _2G,                                     &GCPhysPciMmio,     &cbPciMmio);      H();
    696         hrc = pResMgr->assignMmio32Region(     "pci-mmio32", _1G - VBOXPLATFORMARMV8_PHYS_ADDR - _1M, &GCPhysPciMmio32,   &cbPciMmio32);    H();
    697 
    698         InsertConfigNode(pDevices, "pci-generic-ecam",  &pDev);
    699         InsertConfigNode(pDev,     "0",            &pInst);
    700         InsertConfigNode(pInst,    "Config",        &pCfg);
    701         InsertConfigInteger(pCfg,  "MmioEcamBase",   GCPhysPciMmioEcam);
    702         InsertConfigInteger(pCfg,  "MmioEcamLength", cbPciMmioEcam);
    703         InsertConfigInteger(pCfg,  "MmioPioBase",    GCPhysMmioStart);
    704         InsertConfigInteger(pCfg,  "MmioPioSize",    cbMmio);
    705         InsertConfigInteger(pCfg,  "IntPinA",        aPinIrqs[0]);
    706         InsertConfigInteger(pCfg,  "IntPinB",        aPinIrqs[1]);
    707         InsertConfigInteger(pCfg,  "IntPinC",        aPinIrqs[2]);
    708         InsertConfigInteger(pCfg,  "IntPinD",        aPinIrqs[3]);
    709         vrc = RTFdtNodeAddF(hFdt, "pcie@%RGp", GCPhysPciMmio);                              VRC();
    710         vrc = RTFdtNodePropertyAddCellsU32(hFdt, "interrupt-map-mask", 4, 0xf800, 0, 0, 7); VRC();
    711 
    712         uint32_t aIrqCells[32 * 4 * 10]; RT_ZERO(aIrqCells); /* Maximum of 32 devices on the root bus, each supporting 4 interrupts (INTA# ... INTD#). */
    713         uint32_t *pau32IrqCell = &aIrqCells[0];
    714         uint32_t iIrqPinSwizzle = 0;
    715 
    716         for (uint32_t i = 0; i < 32; i++)
    717         {
    718             for (uint32_t iIrqPin = 0; iIrqPin < 4; iIrqPin++)
    719             {
    720                 pau32IrqCell[0] = i << 11; /* The dev part, composed as dev.fn. */
    721                 pau32IrqCell[1] = 0;
    722                 pau32IrqCell[2] = 0;
    723                 pau32IrqCell[3] = iIrqPin + 1;
    724                 pau32IrqCell[4] = idPHandleIntCtrl;
    725                 pau32IrqCell[5] = 0;
    726                 pau32IrqCell[6] = 0;
    727                 pau32IrqCell[7] = 0;
    728                 pau32IrqCell[8] = aPinIrqs[(iIrqPinSwizzle + iIrqPin) % RT_ELEMENTS(aPinIrqs)];
    729                 pau32IrqCell[9] = 0x04;
    730                 pau32IrqCell += 10;
    731             }
    732 
    733             iIrqPinSwizzle++;
    734         }
    735 
    736         vrc = RTFdtNodePropertyAddCellsU32AsArray(hFdt, "interrupt-map", RT_ELEMENTS(aIrqCells), &aIrqCells[0]);
    737         vrc = RTFdtNodePropertyAddU32(     hFdt, "#interrupt-cells", 1);                        VRC();
    738         vrc = RTFdtNodePropertyAddCellsU32(hFdt, "ranges", 21,
    739                                            0x1000000, 0, 0,
    740                                            GCPhysMmioStart >> 32, GCPhysMmioStart, cbMmio >> 32, cbMmio,
    741                                            0x2000000, GCPhysPciMmio32 >> 32, GCPhysPciMmio32, GCPhysPciMmio32 >> 32, GCPhysPciMmio32,
    742                                            cbPciMmio32 >> 32, cbPciMmio32,
    743                                            0x3000000, GCPhysPciMmio >> 32, GCPhysPciMmio, GCPhysPciMmio >> 32, GCPhysPciMmio,
    744                                            cbPciMmio >> 32, cbPciMmio);                         VRC();
    745         vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysPciMmioEcam, cbPciMmioEcam);   VRC();
    746         /** @todo msi-map */
    747         vrc = RTFdtNodePropertyAddEmpty(   hFdt, "dma-coherent");                               VRC();
    748         vrc = RTFdtNodePropertyAddCellsU32(hFdt, "bus-range", 2, 0, 0xf);                       VRC();
    749         vrc = RTFdtNodePropertyAddU32(     hFdt, "linux,pci-domain", 0);                        VRC();
    750         vrc = RTFdtNodePropertyAddU32(     hFdt, "#size-cells", 2);                             VRC();
    751         vrc = RTFdtNodePropertyAddU32(     hFdt, "#address-cells", 3);                          VRC();
    752         vrc = RTFdtNodePropertyAddString(  hFdt, "device_type", "pci");                         VRC();
    753         vrc = RTFdtNodePropertyAddString(  hFdt, "compatible", "pci-host-ecam-generic");        VRC();
    754         vrc = RTFdtNodeFinalize(hFdt);                                                          VRC();
    755 
    756         if (pSysTblsBldAcpi)
    757         {
    758             vrc = pSysTblsBldAcpi->configurePcieRootBus("pci-generic-ecam", aPinIrqs, GCPhysMmioStart, GCPhysPciMmioEcam,
    759                                                         cbPciMmioEcam, GCPhysMmioStart, cbMmio, GCPhysPciMmio32, cbPciMmio32);
    760             VRC();
    761         }
    762 
    763751#if defined(VBOX_WITH_TPM)
    764752        /*
     
    773761        {
    774762            hrc = pResMgr->assignSingleInterrupt("tpm", &iIrq);                               H();
    775             hrc = pResMgr->assignMmioRegion("tpm", 5 * _1K, &GCPhysMmioStart, &cbMmio);       H();
    776763
    777764            InsertConfigNode(pDevices, "tpm", &pDev);
     
    779766            InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
    780767            InsertConfigNode(pInst,    "Config", &pCfg);
    781             InsertConfigInteger(pCfg,  "MmioBase", GCPhysMmioStart);
     768            InsertConfigInteger(pCfg,  "MmioBase", GCPhysTpm);
    782769            InsertConfigInteger(pCfg,  "Irq",      iIrq);
    783             //InsertConfigInteger(pCfg,  "Crb",      1); /* boolean */
     770            InsertConfigInteger(pCfg,  "Crb",      1); /* boolean */
    784771
    785772            InsertConfigNode(pInst,    "LUN#0", &pLunL0);
     
    811798            }
    812799
    813             vrc = RTFdtNodeAddF(hFdt, "tpm@%RGp", GCPhysMmioStart);                           VRC();
     800            vrc = RTFdtNodeAddF(hFdt, "tpm@%RGp", GCPhysTpm);                                   VRC();
    814801            vrc = RTFdtNodePropertyAddCellsU32(hFdt, "interrupts", 3, 0x00, iIrq, 0x04);        VRC();
    815             vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysMmioStart, cbMmio);        VRC();
     802            vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysTpm, cbTpm);               VRC();
    816803            vrc = RTFdtNodePropertyAddStringList(hFdt, "compatible", 1, "tcg,tpm-tis-mmio");    VRC();
    817804            vrc = RTFdtNodeFinalize(hFdt);                                                      VRC();
     
    819806            if (pSysTblsBldAcpi)
    820807            {
    821                 vrc = pSysTblsBldAcpi->configureTpm2(false /*fCrb*/, GCPhysMmioStart, cbMmio, iIrq);
     808                vrc = pSysTblsBldAcpi->configureTpm2(true /*fCrb*/, GCPhysTpm, cbTpm, iIrq);
    822809                VRC();
    823810            }
    824811
    825 #if 0
    826812            /* Add the device for the physical presence interface. */
    827813            InsertConfigNode(   pDevices, "tpm-ppi",  &pDev);
     
    829815            InsertConfigInteger(pInst,    "Trusted",  1); /* boolean */
    830816            InsertConfigNode(   pInst,    "Config",   &pCfg);
    831             InsertConfigInteger(pCfg,     "MmioBase", TPM_PPI_MMIO_BASE_DEFAULT);
     817            InsertConfigInteger(pCfg,     "MmioBase", GCPhysTpm + 0x5000);
     818        }
    832819#endif
    833         }
    834 #endif
     820
     821        hrc = pResMgr->assignInterrupts("pci-generic-ecam", 4 /*cInterrupts*/, &iIrq);      H();
     822        uint32_t aPinIrqs[] = { iIrq, iIrq + 1, iIrq + 2, iIrq + 3 };
     823        RTGCPHYS GCPhysPciMmioEcam, GCPhysPciMmio, GCPhysPciMmio32;
     824        RTGCPHYS cbPciMmioEcam, cbPciMmio, cbPciMmio32;
     825
     826        hrc = pResMgr->assignMmioRegionAligned("pci-pio",    _64K, _64K, &GCPhysMmioStart,   &cbMmio, false /*fOnly32Bit*/); H();
     827        hrc = pResMgr->assignMmioRegion(       "pci-ecam",   16 * _1M,   &GCPhysPciMmioEcam, &cbPciMmioEcam);              H();
     828        hrc = pResMgr->assignMmioRegion(       "pci-mmio",   _2G,        &GCPhysPciMmio,     &cbPciMmio);                  H();
     829        hrc = pResMgr->assignMmio32Region(     "pci-mmio32", _256M,      &GCPhysPciMmio32,   &cbPciMmio32);                H();
     830
     831        InsertConfigNode(pDevices, "pci-generic-ecam",  &pDev);
     832        InsertConfigNode(pDev,     "0",            &pInst);
     833        InsertConfigNode(pInst,    "Config",        &pCfg);
     834        InsertConfigInteger(pCfg,  "MmioEcamBase",   GCPhysPciMmioEcam);
     835        InsertConfigInteger(pCfg,  "MmioEcamLength", cbPciMmioEcam);
     836        InsertConfigInteger(pCfg,  "MmioPioBase",    GCPhysMmioStart);
     837        InsertConfigInteger(pCfg,  "MmioPioSize",    cbMmio);
     838        InsertConfigInteger(pCfg,  "IntPinA",        aPinIrqs[0]);
     839        InsertConfigInteger(pCfg,  "IntPinB",        aPinIrqs[1]);
     840        InsertConfigInteger(pCfg,  "IntPinC",        aPinIrqs[2]);
     841        InsertConfigInteger(pCfg,  "IntPinD",        aPinIrqs[3]);
     842        vrc = RTFdtNodeAddF(hFdt, "pcie@%RGp", GCPhysPciMmio);                              VRC();
     843        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "interrupt-map-mask", 4, 0xf800, 0, 0, 7); VRC();
     844
     845        uint32_t aIrqCells[32 * 4 * 10]; RT_ZERO(aIrqCells); /* Maximum of 32 devices on the root bus, each supporting 4 interrupts (INTA# ... INTD#). */
     846        uint32_t *pau32IrqCell = &aIrqCells[0];
     847        uint32_t iIrqPinSwizzle = 0;
     848
     849        for (uint32_t i = 0; i < 32; i++)
     850        {
     851            for (uint32_t iIrqPin = 0; iIrqPin < 4; iIrqPin++)
     852            {
     853                pau32IrqCell[0] = i << 11; /* The dev part, composed as dev.fn. */
     854                pau32IrqCell[1] = 0;
     855                pau32IrqCell[2] = 0;
     856                pau32IrqCell[3] = iIrqPin + 1;
     857                pau32IrqCell[4] = idPHandleIntCtrl;
     858                pau32IrqCell[5] = 0;
     859                pau32IrqCell[6] = 0;
     860                pau32IrqCell[7] = 0;
     861                pau32IrqCell[8] = aPinIrqs[(iIrqPinSwizzle + iIrqPin) % RT_ELEMENTS(aPinIrqs)];
     862                pau32IrqCell[9] = 0x04;
     863                pau32IrqCell += 10;
     864            }
     865
     866            iIrqPinSwizzle++;
     867        }
     868
     869        vrc = RTFdtNodePropertyAddCellsU32AsArray(hFdt, "interrupt-map", RT_ELEMENTS(aIrqCells), &aIrqCells[0]);
     870        vrc = RTFdtNodePropertyAddU32(     hFdt, "#interrupt-cells", 1);                        VRC();
     871        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "ranges", 21,
     872                                           0x1000000, 0, 0,
     873                                           GCPhysMmioStart >> 32, GCPhysMmioStart, cbMmio >> 32, cbMmio,
     874                                           0x2000000, GCPhysPciMmio32 >> 32, GCPhysPciMmio32, GCPhysPciMmio32 >> 32, GCPhysPciMmio32,
     875                                           cbPciMmio32 >> 32, cbPciMmio32,
     876                                           0x3000000, GCPhysPciMmio >> 32, GCPhysPciMmio, GCPhysPciMmio >> 32, GCPhysPciMmio,
     877                                           cbPciMmio >> 32, cbPciMmio);                         VRC();
     878        vrc = RTFdtNodePropertyAddCellsU64(hFdt, "reg", 2, GCPhysPciMmioEcam, cbPciMmioEcam);   VRC();
     879        /** @todo msi-map */
     880        vrc = RTFdtNodePropertyAddEmpty(   hFdt, "dma-coherent");                               VRC();
     881        vrc = RTFdtNodePropertyAddCellsU32(hFdt, "bus-range", 2, 0, 0xf);                       VRC();
     882        vrc = RTFdtNodePropertyAddU32(     hFdt, "linux,pci-domain", 0);                        VRC();
     883        vrc = RTFdtNodePropertyAddU32(     hFdt, "#size-cells", 2);                             VRC();
     884        vrc = RTFdtNodePropertyAddU32(     hFdt, "#address-cells", 3);                          VRC();
     885        vrc = RTFdtNodePropertyAddString(  hFdt, "device_type", "pci");                         VRC();
     886        vrc = RTFdtNodePropertyAddString(  hFdt, "compatible", "pci-host-ecam-generic");        VRC();
     887        vrc = RTFdtNodeFinalize(hFdt);                                                          VRC();
     888
     889        if (pSysTblsBldAcpi)
     890        {
     891            vrc = pSysTblsBldAcpi->configurePcieRootBus("pci-generic-ecam", aPinIrqs, GCPhysMmioStart, GCPhysPciMmioEcam,
     892                                                        cbPciMmioEcam, GCPhysMmioStart, cbMmio, GCPhysPciMmio32, cbPciMmio32);
     893            VRC();
     894        }
    835895
    836896        /*
     
    931991    VBOXPLATFORMARMV8 ArmV8Platform; RT_ZERO(ArmV8Platform);
    932992
    933     /* Make room for the descriptor at the beginning. */
    934     vrc = RTVfsIoStrmZeroFill(hVfsIosDesc, sizeof(ArmV8Platform));
    935     AssertRCReturnStmt(vrc, RTFdtDestroy(hFdt), vrc);
    936 
    937993    vrc = RTFdtDumpToVfsIoStrm(hFdt, RTFDTTYPE_DTB, 0 /*fFlags*/, hVfsIosDesc, NULL /*pErrInfo*/);
    938994    uint64_t cbFdt = 0;
    939995    if (RT_SUCCESS(vrc))
    940     {
    941996        vrc = RTVfsFileQuerySize(hVfsFileDesc, &cbFdt);
    942         cbFdt -= sizeof(ArmV8Platform);
    943     }
    944997    AssertRCReturnStmt(vrc, RTFdtDestroy(hFdt), vrc);
    945998
    946999    vrc = RTVfsIoStrmZeroFill(hVfsIosDesc, (RTFOFF)(RT_ALIGN_64(cbFdt, _64K) - cbFdt));
    9471000    AssertRCReturn(vrc, vrc);
     1001
     1002    cbFdt = RT_ALIGN_64(cbFdt, _64K);
    9481003
    9491004    RTGCPHYS GCPhysMmioStart;
     
    9621017    if (pSysTblsBldAcpi)
    9631018    {
    964         vrc = pSysTblsBldAcpi->finishTables(VBOXPLATFORMARMV8_PHYS_ADDR + sizeof(ArmV8Platform) + RT_ALIGN_64(cbFdt, _64K),
     1019        vrc = pSysTblsBldAcpi->finishTables(GCPhysPlatformDesc + cbFdt,
    9651020                                            hVfsIosDesc, &GCPhysXsdp, &cbAcpiXsdp, &cbAcpi);
    9661021        AssertRCReturn(vrc, vrc);
    967         Assert(GCPhysXsdp > VBOXPLATFORMARMV8_PHYS_ADDR);
     1022        Assert(   GCPhysXsdp > GCPhysPlatformDesc
     1023               && GCPhysXsdp < VBOXPLATFORMARMV8_PHYS_ADDR);
    9681024
    9691025        /* Dump the ACPI table for debugging purposes if requested. */
     
    9821038        vrc = RTVfsIoStrmZeroFill(hVfsIosDesc, (RTFOFF)(RT_ALIGN_64(cbAcpi, _64K) - cbAcpi));
    9831039        AssertRCReturn(vrc, vrc);
     1040
     1041        cbAcpi = RT_ALIGN_64(cbAcpi, _64K);
    9841042    }
     1043
     1044    /* Fill the room until the end where the platform descriptor lives. */
     1045    vrc = RTVfsIoStrmZeroFill(hVfsIosDesc, cbPlatformDesc - sizeof(ArmV8Platform) - cbFdt - cbAcpi);
     1046    AssertRCReturnStmt(vrc, RTFdtDestroy(hFdt), vrc);
     1047
     1048    RTGCPHYS GCPhysMmio    = 0;
     1049    RTGCPHYS cbMmioAbove4G = 0;
     1050    pResMgr->queryMmioRegion(&GCPhysMmio, &cbMmioAbove4G);
    9851051
    9861052    ArmV8Platform.u32Magic            = VBOXPLATFORMARMV8_MAGIC;
     
    9881054    ArmV8Platform.cbDesc              = sizeof(ArmV8Platform);
    9891055    ArmV8Platform.fFlags              = 0;
    990     ArmV8Platform.u64PhysAddrRamBase  = GCPhysRam;
    991     ArmV8Platform.cbRamBase           = cbRam;
    992     ArmV8Platform.i64OffFdt           = sizeof(ArmV8Platform);
    993     ArmV8Platform.cbFdt               = RT_ALIGN_64(cbFdt, _64K);
     1056    ArmV8Platform.u64PhysAddrRamBase  = GCPhysRamBase;
     1057    ArmV8Platform.cbRamBase           = cbRamBase;
     1058    ArmV8Platform.i64OffFdt           = (int64_t)GCPhysPlatformDesc - VBOXPLATFORMARMV8_PHYS_ADDR;
     1059    ArmV8Platform.cbFdt               = cbFdt;
    9941060    if (cbAcpi)
    9951061    {
    996         ArmV8Platform.i64OffAcpi      = sizeof(ArmV8Platform) + RT_ALIGN_64(cbFdt, _64K);
    997         ArmV8Platform.cbAcpi          = RT_ALIGN_64(cbAcpi, _64K);
    998         ArmV8Platform.i64OffAcpiXsdp  = GCPhysXsdp - VBOXPLATFORMARMV8_PHYS_ADDR;
     1062        ArmV8Platform.i64OffAcpi      = (int64_t)(GCPhysPlatformDesc + cbFdt) - VBOXPLATFORMARMV8_PHYS_ADDR;
     1063        ArmV8Platform.cbAcpi          = cbAcpi;
     1064        ArmV8Platform.i64OffAcpiXsdp  = (int64_t)GCPhysXsdp - VBOXPLATFORMARMV8_PHYS_ADDR;
    9991065        ArmV8Platform.cbAcpiXsdp      = cbAcpiXsdp;
    10001066    }
    1001     ArmV8Platform.i64OffUefiRom       = -128 * _1M;
     1067    ArmV8Platform.i64OffUefiRom       = (int64_t)GCPhysFw - VBOXPLATFORMARMV8_PHYS_ADDR;
    10021068    ArmV8Platform.cbUefiRom           = _64M;
    1003     ArmV8Platform.i64OffMmio          = GCPhysMmioStart - _128M;
    1004     ArmV8Platform.cbMmio              = cbMmio;
    1005     ArmV8Platform.i64OffMmio32        = GCPhysMmio32Start - _128M;
    1006     ArmV8Platform.cbMmio32            = cbMmio32;
     1069    ArmV8Platform.i64OffMmio          = GCPhysMmio ? (int64_t)GCPhysMmio - VBOXPLATFORMARMV8_PHYS_ADDR : 0;
     1070    ArmV8Platform.cbMmio              = cbMmioAbove4G;
     1071    ArmV8Platform.i64OffMmio32        = (int64_t)(_4G - _512M) - VBOXPLATFORMARMV8_PHYS_ADDR;
     1072    ArmV8Platform.cbMmio32            = _512M - _2M; /* Just assign the whole MMIO hole (except for the platform descriptor region). */
    10071073
    10081074    /* Add the VBox platform descriptor to the resource store. */
    1009     vrc = RTVfsIoStrmWriteAt(hVfsIosDesc, 0, &ArmV8Platform, sizeof(ArmV8Platform), true /*fBlocking*/, NULL /*pcbWritten*/);
     1075    vrc = RTVfsIoStrmWrite(hVfsIosDesc, &ArmV8Platform, sizeof(ArmV8Platform), true /*fBlocking*/, NULL /*pcbWritten*/);
    10101076    RTVfsIoStrmRelease(hVfsIosDesc);
    10111077    vrc = mptrResourceStore->i_addItem("resources", "VBoxArmV8Desc", hVfsFileDesc);
     
    10241090    }
    10251091
     1092    pResMgr->dumpMemoryRegionsToReleaseLog();
     1093
    10261094    delete pResMgr; /* Delete the address/interrupt assignment manager. */
    10271095
  • trunk/src/VBox/Main/src-client/ResourceAssignmentManager.cpp

    r106061 r106957  
    3535#include "ResourceAssignmentManager.h"
    3636
     37#include <VBox/com/array.h>
     38
    3739#include <iprt/asm.h>
     40#include <iprt/mem.h>
    3841#include <iprt/string.h>
    39 
    40 #include <VBox/vmm/cfgm.h>
    41 #include <VBox/vmm/vmmr3vtable.h>
    42 #include <VBox/com/array.h>
    43 
    44 #include <map>
    45 #include <vector>
    46 #include <algorithm>
    4742
    4843
     
    5045*   Structures and Typedefs                                                                                                      *
    5146*********************************************************************************************************************************/
     47/**
     48 * Address space range type.
     49 */
     50typedef enum RESOURCEREGIONTYPE
     51{
     52    /** Free region. */
     53    kResourceRegionType_Free = 0,
     54    /** RAM. */
     55    kResourceRegionType_Ram,
     56    /** ROM. */
     57    kResourceRegionType_Rom,
     58    /** MMIO. */
     59    kResourceRegionType_Mmio,
     60    /** 32bit hack. */
     61    kResourceRegionType_32Bit_Hack = 0x7fffffff
     62} RESOURCEREGIONTYPE;
     63
     64
     65/**
     66 * Address space range descriptor.
     67 */
     68typedef struct RESOURCEREGION
     69{
     70    /** Region name. */
     71    char                szName[32];
     72    /** Physical start address of the region. */
     73    RTGCPHYS            GCPhysStart;
     74    /** Physical end address of the region. */
     75    RTGCPHYS            GCPhysEnd;
     76    /** Region type. */
     77    RESOURCEREGIONTYPE  enmType;
     78    /** Padding. */
     79    uint32_t            u32Pad;
     80} RESOURCEREGION;
     81AssertCompileSize(RESOURCEREGION, 56);
     82/** Pointer to a resource region. */
     83typedef RESOURCEREGION *PRESOURCEREGION;
     84/** Pointer to a const resource region. */
     85typedef const RESOURCEREGION *PCRESOURCEREGION;
    5286
    5387
     
    6397struct ResourceAssignmentManager::State
    6498{
    65     struct MemoryRange
    66     {
    67         char          szDevName[32];
    68         RTGCPHYS      mGCPhysStart;
    69         RTGCPHYS      mGCPhysEnd;
    70 
    71         MemoryRange(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd)
    72         {
    73             RTStrCopy(this->szDevName, sizeof(szDevName), pszName);
    74             this->mGCPhysStart = GCPhysStart;
    75             this->mGCPhysEnd   = GCPhysEnd;
    76         }
    77 
    78         bool operator==(const MemoryRange &a) const
    79         {
    80             return RTStrNCmp(szDevName, a.szDevName, sizeof(szDevName)) == 0;
    81         }
    82     };
    83 
    84     typedef std::vector<MemoryRange> AddrRangeList;
    85 
    8699    ChipsetType_T    mChipsetType;
    87100    IommuType_T      mIommuType;
    88     PCVMMR3VTABLE    mpVMM;
    89     AddrRangeList    mAddrRanges;
    90 
    91     RTGCPHYS         mGCPhysMmioStartOrig;
    92     RTGCPHYS         mGCPhysMmioStart;
    93     RTGCPHYS         mGCPhysMmio32StartOrig;
    94     RTGCPHYS         mGCPhysMmio32Start;
    95     RTGCPHYS         mcbMmio32;
    96     RTGCPHYS         mGCPhysRamStart;
     101
     102    /** Pointer to the array of regions (sorted by address, not overlapping, adjacent). */
     103    PRESOURCEREGION  m_paRegions;
     104    /** Number of used regions. */
     105    uint32_t         m_cRegions;
     106    /** Number of regions the allocated array can hold. */
     107    uint32_t         m_cRegionsMax;
     108
    97109    uint32_t         mcInterrupts;
    98110    uint32_t         miInterrupt;
    99111
    100112    State()
    101         : mChipsetType(ChipsetType_Null), mpVMM(NULL)
     113        : mChipsetType(ChipsetType_Null)
     114        , mIommuType(IommuType_None)
     115        , m_paRegions(NULL)
     116        , m_cRegions(0)
     117        , m_cRegionsMax(0)
     118        , mcInterrupts(0)
     119        , miInterrupt(0)
    102120    {}
    103121    ~State()
    104122    {}
    105123
    106     HRESULT init(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType,
    107                  RTGCPHYS GCPhysMmioTop, RTGCPHYS GCPhysRamStart,
    108                  RTGCPHYS GCPhysMmio32Start, RTGCPHYS cbMmio32, uint32_t cInterrupts);
    109 
    110     HRESULT addAddrRange(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd);
     124    HRESULT init(ChipsetType_T chipsetType, IommuType_T iommuType, uint32_t cInterrupts);
     125
     126    HRESULT ensureAdditionalRegions(uint32_t cRegions);
     127    void setRegion(PRESOURCEREGION pRegion, const char *pszName, RESOURCEREGIONTYPE enmType,
     128                   RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd);
     129    HRESULT addAddrRange(const char *pszName, RESOURCEREGIONTYPE enmType, RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd);
     130    HRESULT findNextFreeAddrRange(RTGCPHYS cbRegion, RTGCPHYS cbAlignment, RTGCPHYS GCPhysMax, RTGCPHYS GCPhysHint,
     131                                  PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion);
     132
     133    void dumpToReleaseLog(void);
    111134};
    112135
    113136
    114 HRESULT ResourceAssignmentManager::State::init(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType,
    115                                                RTGCPHYS GCPhysMmioStart, RTGCPHYS GCPhysRamStart,
    116                                                RTGCPHYS GCPhysMmio32Start, RTGCPHYS cbMmio32, uint32_t cInterrupts)
    117 {
    118     mpVMM = pVMM;
    119 
     137HRESULT ResourceAssignmentManager::State::init(ChipsetType_T chipsetType, IommuType_T iommuType,
     138                                               uint32_t cInterrupts)
     139{
    120140    Assert(chipsetType == ChipsetType_ARMv8Virtual);
    121141    Assert(iommuType == IommuType_None); /* For now no IOMMU support on ARMv8. */
     
    123143    mChipsetType           = chipsetType;
    124144    mIommuType             = iommuType;
    125     mGCPhysMmioStart       = GCPhysMmioStart;
    126     mGCPhysMmioStartOrig   = GCPhysMmioStart;
    127     mGCPhysRamStart        = GCPhysRamStart;
    128     mGCPhysMmio32Start     = GCPhysMmio32Start;
    129     mGCPhysMmio32StartOrig = GCPhysMmio32Start;
    130     mcbMmio32              = cbMmio32;
    131145    mcInterrupts           = cInterrupts;
    132146    miInterrupt            = 0;
    133     return S_OK;
    134 }
    135 
    136 HRESULT ResourceAssignmentManager::State::addAddrRange(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
    137 {
    138     MemoryRange memRange(pszName, GCPhysStart, GCPhysStart + cbRegion - 1);
    139     mAddrRanges.push_back(memRange);
    140     return S_OK;
    141 }
     147
     148    m_paRegions = (PRESOURCEREGION)RTMemRealloc(m_paRegions, 32 * sizeof(*m_paRegions));
     149    if (!m_paRegions)
     150        return E_OUTOFMEMORY;
     151
     152    m_paRegions[m_cRegions].enmType     = kResourceRegionType_Free;
     153    m_paRegions[m_cRegions].GCPhysStart = 0;
     154    m_paRegions[m_cRegions].GCPhysEnd   = UINT64_MAX;
     155    strcpy(&m_paRegions[m_cRegions].szName[0], "Free");
     156    m_cRegions++;
     157
     158    return S_OK;
     159}
     160
     161
     162HRESULT ResourceAssignmentManager::State::ensureAdditionalRegions(uint32_t cRegions)
     163{
     164    if (m_cRegions + cRegions == m_cRegionsMax)
     165    {
     166        uint32_t const cRegionsNew = m_cRegionsMax + 32;
     167        PRESOURCEREGION paDescsNew = (PRESOURCEREGION)RTMemRealloc(m_paRegions, cRegionsNew * sizeof(*paDescsNew));
     168        if (!paDescsNew)
     169            return E_OUTOFMEMORY;
     170
     171        m_paRegions   = paDescsNew;
     172        m_cRegionsMax = cRegionsNew;
     173    }
     174
     175    return S_OK;
     176}
     177
     178
     179void ResourceAssignmentManager::State::setRegion(PRESOURCEREGION pRegion, const char *pszName, RESOURCEREGIONTYPE enmType,
     180                                                 RTGCPHYS GCPhysStart, RTGCPHYS GCPhysEnd)
     181{
     182    strncpy(&pRegion->szName[0], pszName, sizeof(pRegion->szName));
     183    pRegion->szName[sizeof(pRegion->szName) - 1] = '\0';
     184    pRegion->enmType     = enmType;
     185    pRegion->GCPhysStart = GCPhysStart;
     186    pRegion->GCPhysEnd   = GCPhysEnd;
     187}
     188
     189
     190HRESULT ResourceAssignmentManager::State::addAddrRange(const char *pszName, RESOURCEREGIONTYPE enmType,
     191                                                       RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
     192{
     193    RTGCPHYS GCPhysEnd = GCPhysStart + cbRegion - 1;
     194
     195    /* Find the right spot in the array where to insert the range, it must not overlap with an existing used range. */
     196    uint32_t iRegion = 0;
     197    while (   iRegion < m_cRegions
     198           && GCPhysStart > m_paRegions[iRegion].GCPhysEnd)
     199        iRegion++;
     200
     201    Assert(   iRegion == m_cRegions - 1
     202           || m_paRegions[iRegion].enmType != m_paRegions[iRegion + 1].enmType);
     203
     204    /* Check that there is sufficient free space. */
     205    if (   (m_paRegions[iRegion].enmType != kResourceRegionType_Free)
     206        || GCPhysEnd > m_paRegions[iRegion].GCPhysEnd)
     207        return E_INVALIDARG;
     208
     209    Assert(m_paRegions[iRegion].enmType == kResourceRegionType_Free);
     210
     211    /* Requested region fits exactly into the free region. */
     212    if (   GCPhysStart == m_paRegions[iRegion].GCPhysStart
     213        && GCPhysEnd   == m_paRegions[iRegion].GCPhysEnd)
     214    {
     215        setRegion(&m_paRegions[iRegion], pszName, enmType, GCPhysStart, GCPhysEnd);
     216        return S_OK;
     217    }
     218
     219    HRESULT hrc = ensureAdditionalRegions(2 /*cRegions*/); /* Need two additional region descriptors max. */
     220    if (FAILED(hrc))
     221        return hrc;
     222
     223    /* Need to split the region into two or three depending on where the requested region lies. */
     224    if (GCPhysStart == m_paRegions[iRegion].GCPhysStart)
     225    {
     226        /* At the start, move the free regions and everything at the end. */
     227        memmove(&m_paRegions[iRegion + 1], &m_paRegions[iRegion], (m_cRegions - iRegion) * sizeof(*m_paRegions));
     228        setRegion(&m_paRegions[iRegion], pszName, enmType, GCPhysStart, GCPhysEnd);
     229
     230        /* Adjust the free region. */
     231        m_paRegions[iRegion + 1].GCPhysStart = GCPhysStart + cbRegion;
     232        m_cRegions++;
     233    }
     234    else if (GCPhysStart + cbRegion - 1 == m_paRegions[iRegion].GCPhysEnd)
     235    {
     236        /* At the end of the region, move the remaining regions and adjust ranges. */
     237        if (iRegion < m_cRegions)
     238            memmove(&m_paRegions[iRegion + 2], &m_paRegions[iRegion + 1], (m_cRegions - iRegion) * sizeof(*m_paRegions));
     239        setRegion(&m_paRegions[iRegion + 1], pszName, enmType, GCPhysStart, GCPhysEnd);
     240        m_paRegions[iRegion].GCPhysEnd = GCPhysStart - 1;
     241        m_cRegions++;
     242    }
     243    else
     244    {
     245        /* Somewhere in the middle, split into three regions. */
     246        if (iRegion < m_cRegions)
     247            memmove(&m_paRegions[iRegion + 3], &m_paRegions[iRegion + 1], (m_cRegions - iRegion) * sizeof(*m_paRegions));
     248        setRegion(&m_paRegions[iRegion + 1], pszName, enmType, GCPhysStart, GCPhysEnd);
     249        setRegion(&m_paRegions[iRegion + 2], "Free", kResourceRegionType_Free, GCPhysStart + cbRegion, m_paRegions[iRegion].GCPhysEnd);
     250        m_paRegions[iRegion].GCPhysEnd = GCPhysStart - 1;
     251        m_cRegions += 2;
     252    }
     253
     254    return S_OK;
     255}
     256
     257
     258HRESULT ResourceAssignmentManager::State::findNextFreeAddrRange(RTGCPHYS cbRegion, RTGCPHYS cbAlignment, RTGCPHYS GCPhysMax,
     259                                                                RTGCPHYS GCPhysHint, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
     260{
     261    AssertReturn(GCPhysMax >= cbRegion, E_FAIL);
     262    GCPhysMax -= cbRegion;
     263
     264    uint32_t iRegion = 0;
     265    if (GCPhysHint)
     266    {
     267        /* Look for free address range downwards from the hint first. */
     268        iRegion = m_cRegions - 1;
     269        while (iRegion)
     270        {
     271            PCRESOURCEREGION pRegion = &m_paRegions[iRegion];
     272
     273            /* Region must be free and satisfy the alignment++ requirements. */
     274            RTGCPHYS GCPhysStartAligned = RT_ALIGN_T(pRegion->GCPhysEnd - cbRegion + 1, cbAlignment, RTGCPHYS);
     275            if (   pRegion->enmType == kResourceRegionType_Free
     276                && GCPhysHint >= pRegion->GCPhysEnd
     277                && GCPhysMax >= pRegion->GCPhysEnd
     278                && GCPhysStartAligned >= pRegion->GCPhysStart
     279                && pRegion->GCPhysEnd - GCPhysStartAligned + 1 >= cbRegion)
     280            {
     281                *pGCPhysStart = GCPhysStartAligned;
     282                *pcbRegion    = cbRegion;
     283                return S_OK;
     284            }
     285
     286            iRegion--;
     287        }
     288    }
     289
     290    /* Find a free region which satisfies or requirements. */
     291    while (   iRegion < m_cRegions
     292           && GCPhysMax >= m_paRegions[iRegion].GCPhysStart)
     293    {
     294        PCRESOURCEREGION pRegion = &m_paRegions[iRegion];
     295
     296        /* Region must be free and satisfy the alignment++ requirements. */
     297        RTGCPHYS GCPhysStartAligned = RT_ALIGN_T(pRegion->GCPhysStart, cbAlignment, RTGCPHYS);
     298        if (   pRegion->enmType == kResourceRegionType_Free
     299            && GCPhysStartAligned >= pRegion->GCPhysStart
     300            && pRegion->GCPhysEnd - GCPhysStartAligned + 1 >= cbRegion)
     301        {
     302            *pGCPhysStart = pRegion->GCPhysStart;
     303            *pcbRegion    = cbRegion;
     304            return S_OK;
     305        }
     306
     307        iRegion++;
     308    }
     309
     310    return E_OUTOFMEMORY;
     311}
     312
     313
     314static const char *resourceManagerRegionType2Str(RESOURCEREGIONTYPE enmType)
     315{
     316    switch (enmType)
     317    {
     318        case kResourceRegionType_Free: return "FREE";
     319        case kResourceRegionType_Ram:  return "RAM ";
     320        case kResourceRegionType_Rom:  return "ROM ";
     321        case kResourceRegionType_Mmio: return "MMIO";
     322        default: AssertFailed(); return "UNKNOWN";
     323    }
     324}
     325
     326
     327void ResourceAssignmentManager::State::dumpToReleaseLog(void)
     328{
     329    LogRel(("Memory Regions:\n"));
     330    for (uint32_t iRegion = 0; iRegion < m_cRegions; iRegion++)
     331    {
     332        LogRel(("    %RGp - %RGp (%zu) %s %s\n",
     333                m_paRegions[iRegion].GCPhysStart,
     334                m_paRegions[iRegion].GCPhysEnd,
     335                m_paRegions[iRegion].GCPhysEnd - m_paRegions[iRegion].GCPhysStart + 1,
     336                m_paRegions[iRegion].szName));
     337    }
     338}
     339
    142340
    143341ResourceAssignmentManager::ResourceAssignmentManager()
    144     : pState(NULL)
    145 {
    146     pState = new State();
    147     Assert(pState);
    148 }
     342    : m_pState(NULL)
     343{
     344    m_pState = new State();
     345    Assert(m_pState);
     346}
     347
    149348
    150349ResourceAssignmentManager::~ResourceAssignmentManager()
    151350{
    152     if (pState)
    153     {
    154         delete pState;
    155         pState = NULL;
    156     }
    157 }
     351    if (m_pState)
     352    {
     353        delete m_pState;
     354        m_pState = NULL;
     355    }
     356}
     357
    158358
    159359ResourceAssignmentManager *ResourceAssignmentManager::createInstance(PCVMMR3VTABLE pVMM, ChipsetType_T chipsetType, IommuType_T iommuType,
    160                                                                      RTGCPHYS GCPhysMmioTop, RTGCPHYS GCPhysRamStart,
    161                                                                      RTGCPHYS GCPhysMmio32Start, RTGCPHYS cbMmio32,
    162                                                                      uint32_t cInterrupts)
    163 {
     360                                                                     uint32_t cInterrupts, RTGCPHYS GCPhysMmioHint)
     361{
     362    RT_NOREF(pVMM);
     363
    164364    ResourceAssignmentManager *pInstance = new ResourceAssignmentManager();
    165     pInstance->pState->init(pVMM, chipsetType, iommuType, GCPhysMmioTop, GCPhysRamStart, GCPhysMmio32Start, cbMmio32, cInterrupts);
     365
     366    pInstance->m_GCPhysMmioHint = GCPhysMmioHint;
     367    pInstance->m_pState->init(chipsetType, iommuType, cInterrupts);
    166368    Assert(pInstance);
    167369    return pInstance;
    168370}
    169371
     372
     373HRESULT ResourceAssignmentManager::assignFixedRomRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
     374{
     375    return m_pState->addAddrRange(pszName, kResourceRegionType_Rom, GCPhysStart, cbRegion);
     376}
     377
     378
     379HRESULT ResourceAssignmentManager::assignFixedRamRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
     380{
     381    return m_pState->addAddrRange(pszName, kResourceRegionType_Ram, GCPhysStart, cbRegion);
     382}
     383
     384
     385HRESULT ResourceAssignmentManager::assignFixedMmioRegion(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
     386{
     387    return m_pState->addAddrRange(pszName, kResourceRegionType_Mmio, GCPhysStart, cbRegion);
     388}
     389
     390
     391HRESULT ResourceAssignmentManager::assignMmioRegionAligned(const char *pszName, RTGCPHYS cbRegion, RTGCPHYS cbAlignment, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion,
     392                                                           bool fOnly32Bit)
     393{
     394    RTGCPHYS GCPhysRegionStart;
     395    RTGCPHYS cbRegionFinal;
     396    HRESULT hrc = m_pState->findNextFreeAddrRange(cbRegion, cbAlignment, fOnly32Bit ? _4G : RTGCPHYS_MAX,
     397                                                  m_GCPhysMmioHint, &GCPhysRegionStart, &cbRegionFinal);
     398    if (SUCCEEDED(hrc))
     399    {
     400        *pGCPhysStart = GCPhysRegionStart;
     401        *pcbRegion    = cbRegionFinal;
     402        return assignFixedMmioRegion(pszName, GCPhysRegionStart, cbRegion);
     403    }
     404
     405    return hrc;
     406}
     407
     408
    170409HRESULT ResourceAssignmentManager::assignMmioRegion(const char *pszName, RTGCPHYS cbRegion, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
    171410{
    172     RTGCPHYS cbRegionAligned = RT_ALIGN_T(cbRegion, _4K, RTGCPHYS);
    173     RTGCPHYS GCPhysMmioStart = pState->mGCPhysMmioStart;
    174 
    175     *pGCPhysStart = GCPhysMmioStart;
    176     *pcbRegion    = cbRegionAligned;
    177     pState->mGCPhysMmioStart += cbRegionAligned;
    178     pState->addAddrRange(pszName, GCPhysMmioStart, cbRegionAligned);
    179     return S_OK;
    180 }
     411    return assignMmioRegionAligned(pszName, cbRegion, _4K, pGCPhysStart, pcbRegion, false /*fOnly32Bit*/);
     412}
     413
    181414
    182415HRESULT ResourceAssignmentManager::assignMmio32Region(const char *pszName, RTGCPHYS cbRegion, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
    183416{
    184     RTGCPHYS cbRegionAligned = RT_ALIGN_T(cbRegion, _4K, RTGCPHYS);
    185     RTGCPHYS GCPhysMmioStart = pState->mGCPhysMmio32Start;
    186 
    187     if (GCPhysMmioStart > pState->mGCPhysRamStart)
    188     {
    189         AssertLogRelMsgFailed(("ResourceAssignmentManager: MMIO32 range for %s would overlap RAM region\n", pszName));
    190         return E_INVALIDARG;
    191     }
    192 
    193     *pGCPhysStart = GCPhysMmioStart;
    194     *pcbRegion    = cbRegionAligned;
    195     pState->mGCPhysMmio32Start += cbRegionAligned;
    196     pState->addAddrRange(pszName, GCPhysMmioStart, cbRegionAligned);
    197     return S_OK;
    198 }
    199 
    200 HRESULT ResourceAssignmentManager::assignMmioRegionAligned(const char *pszName, RTGCPHYS cbRegion, RTGCPHYS cbAlignment, PRTGCPHYS pGCPhysStart, PRTGCPHYS pcbRegion)
    201 {
    202     RTGCPHYS cbRegionAligned = RT_ALIGN_T(cbRegion, cbAlignment, RTGCPHYS);
    203     RTGCPHYS GCPhysMmioStart = pState->mGCPhysMmioStart;
    204 
    205     GCPhysMmioStart = RT_ALIGN_T(GCPhysMmioStart, cbAlignment, RTGCPHYS);
    206 
    207     *pGCPhysStart = GCPhysMmioStart;
    208     *pcbRegion    = cbRegionAligned;
    209     pState->mGCPhysMmioStart = GCPhysMmioStart + cbRegionAligned;
    210     pState->addAddrRange(pszName, GCPhysMmioStart, cbRegionAligned);
    211     return S_OK;
    212 }
    213 
    214 HRESULT ResourceAssignmentManager::assignFixedAddress(const char *pszName, RTGCPHYS GCPhysStart, RTGCPHYS cbRegion)
    215 {
    216     RT_NOREF(pszName, GCPhysStart, cbRegion);
    217     AssertReleaseFailed();
    218     return S_OK;
    219 }
    220 
    221 HRESULT ResourceAssignmentManager::assignRamRegion(const char *pszName, RTGCPHYS cbRam, PRTGCPHYS pGCPhysStart)
    222 {
    223     *pGCPhysStart = pState->mGCPhysRamStart;
    224     pState->mGCPhysRamStart += cbRam;
    225     pState->addAddrRange(pszName, *pGCPhysStart, cbRam);
    226     return S_OK;
    227 }
     417    return assignMmioRegionAligned(pszName, cbRegion, _4K, pGCPhysStart, pcbRegion, true /*fOnly32Bit*/);
     418}
     419
    228420
    229421HRESULT ResourceAssignmentManager::assignInterrupts(const char *pszName, uint32_t cInterrupts, uint32_t *piInterruptFirst)
    230422{
    231     if (pState->miInterrupt + cInterrupts > pState->mcInterrupts)
     423    if (m_pState->miInterrupt + cInterrupts > m_pState->mcInterrupts)
    232424    {
    233425        AssertLogRelMsgFailed(("ResourceAssignmentManager: Interrupt count for %s exceeds number of available interrupts\n", pszName));
     
    235427    }
    236428
    237     *piInterruptFirst = pState->miInterrupt;
    238     pState->miInterrupt += cInterrupts;
    239     return S_OK;
    240 }
     429    *piInterruptFirst = m_pState->miInterrupt;
     430    m_pState->miInterrupt += cInterrupts;
     431    return S_OK;
     432}
     433
     434HRESULT ResourceAssignmentManager::queryMmioRegion(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
     435{
     436    /*
     437     * This ASSUMES that there are adjacent MMIO regions above 4GiB which can be combined into one single region
     438     * (adjacent and no ROM/RAM regions inbetween).
     439     */
     440    *pGCPhysMmioStart = 0;
     441    *pcbMmio          = 0;
     442
     443    /* Look for the start. */
     444    for (uint32_t i = 0; i < m_pState->m_cRegions; i++)
     445    {
     446        PCRESOURCEREGION pRegion = &m_pState->m_paRegions[i];
     447
     448        if (   pRegion->GCPhysStart >= _4G
     449            && pRegion->enmType == kResourceRegionType_Mmio)
     450        {
     451            RTGCPHYS cbMmio = pRegion->GCPhysEnd - pRegion->GCPhysStart + 1;
     452
     453            *pGCPhysMmioStart = pRegion->GCPhysStart;
     454
     455            /* Add up any remaining MMIO regions adjacent to this one. */
     456            for (uint32_t j = i; j < m_pState->m_cRegions; j++)
     457            {
     458                pRegion = &m_pState->m_paRegions[i];
     459                if (   pRegion->enmType == kResourceRegionType_Mmio
     460                    && pRegion->GCPhysStart == *pGCPhysMmioStart + cbMmio)
     461                    cbMmio += pRegion->GCPhysEnd - pRegion->GCPhysStart + 1;
     462                else
     463                    break;
     464            }
     465
     466            *pcbMmio = cbMmio;
     467            return S_OK;
     468        }
     469    }
     470
     471    return S_OK;
     472}
     473
     474
     475HRESULT ResourceAssignmentManager::queryMmio32Region(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
     476{
     477    RT_NOREF(pGCPhysMmioStart, pcbMmio);
     478    return S_OK;
     479}
     480
    241481
    242482HRESULT ResourceAssignmentManager::assignSingleInterrupt(const char *pszName, uint32_t *piInterrupt)
     
    245485}
    246486
    247 HRESULT ResourceAssignmentManager::queryMmioRegion(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
    248 {
    249     *pGCPhysMmioStart = pState->mGCPhysMmioStartOrig;
    250     *pcbMmio          = pState->mGCPhysMmioStart - pState->mGCPhysMmioStartOrig;
    251     return S_OK;
    252 }
    253 
    254 HRESULT ResourceAssignmentManager::queryMmio32Region(PRTGCPHYS pGCPhysMmioStart, PRTGCPHYS pcbMmio)
    255 {
    256     *pGCPhysMmioStart = pState->mGCPhysMmio32StartOrig;
    257     *pcbMmio          = pState->mcbMmio32;
    258     return S_OK;
    259 }
     487
     488void ResourceAssignmentManager::dumpMemoryRegionsToReleaseLog(void)
     489{
     490    m_pState->dumpToReleaseLog();
     491}
Note: See TracChangeset for help on using the changeset viewer.

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