Thanks for working to increase the supported guest-physical RAM size.

Reviewed-by: Brian J. Johnson <bjohn...@sgi.com>

On 06/23/2015 02:53 PM, Laszlo Ersek wrote:
> We'll soon increase the maximum guest-physical RAM size supported by OVMF.
> For more RAM, the DXE IPL is going to build more page tables, and for that
> it's going to need a bigger chunk from the permanent PEI RAM.
>
> Otherwise CreateIdentityMappingPageTables() would fail with:
>
>> DXE IPL Entry
>> Loading PEIM at 0x000BFF61000 EntryPoint=0x000BFF61260 DxeCore.efi
>> Loading DXE CORE at 0x000BFF61000 EntryPoint=0x000BFF61260
>> AllocatePages failed: No 0x40201 Pages is available.
>> There is only left 0x3F1F pages memory resource to be allocated.
>> ASSERT .../MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c(123):
>> BigPageAddress != 0
>
> (The above example belongs to the artificially high, maximal address width
> of 52, clamped by the DXE core to 48. The address width of 48 bits
> corresponds to 256 TB or RAM, and requires a bit more than 1GB for paging
> structures.)
>
> Cc: Maoming <maoming.maom...@huawei.com>
> Cc: Huangpeng (Peter) <peter.huangp...@huawei.com>
> Cc: Wei Liu <wei.l...@citrix.com>
> Cc: Brian J. Johnson <bjohn...@sgi.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Laszlo Ersek <ler...@redhat.com>
> ---
>
> Notes:
>      v2:
>      - imitating CreateIdentityMappingPageTables() [Jordan, Brian]
>
>   OvmfPkg/PlatformPei/PlatformPei.inf |   2 +
>   OvmfPkg/PlatformPei/Platform.h      |   7 ++
>   OvmfPkg/PlatformPei/MemDetect.c     | 119 +++++++++++++++++++-
>   OvmfPkg/PlatformPei/Platform.c      |   1 +
>   4 files changed, 126 insertions(+), 3 deletions(-)
>
> diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf 
> b/OvmfPkg/PlatformPei/PlatformPei.inf
> index 721495b..cb7d7dd 100644
> --- a/OvmfPkg/PlatformPei/PlatformPei.inf
> +++ b/OvmfPkg/PlatformPei/PlatformPei.inf
> @@ -83,6 +83,8 @@ [Pcd]
>     gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved
>     gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration
>     gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable
>     gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
>
>   [Ppis]
> diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
> index 31640e9..8b6a976 100644
> --- a/OvmfPkg/PlatformPei/Platform.h
> +++ b/OvmfPkg/PlatformPei/Platform.h
> @@ -59,6 +59,11 @@ AddUntestedMemoryRangeHob (
>     EFI_PHYSICAL_ADDRESS        MemoryLimit
>     );
>
> +VOID
> +AddressWidthInitialization (
> +  VOID
> +  );
> +
>   EFI_STATUS
>   PublishPeiMemory (
>     VOID
> @@ -100,4 +105,6 @@ extern EFI_BOOT_MODE mBootMode;
>
>   extern BOOLEAN mS3Supported;
>
> +extern UINT8 mPhysMemAddressWidth;
> +
>   #endif // _PLATFORM_PEI_H_INCLUDED_
> diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
> index bd7bb02..ceff1e2 100644
> --- a/OvmfPkg/PlatformPei/MemDetect.c
> +++ b/OvmfPkg/PlatformPei/MemDetect.c
> @@ -36,6 +36,8 @@ Module Name:
>   #include "Platform.h"
>   #include "Cmos.h"
>
> +UINT8 mPhysMemAddressWidth;
> +
>   UINT32
>   GetSystemMemorySizeBelow4gb (
>     VOID
> @@ -84,6 +86,112 @@ GetSystemMemorySizeAbove4gb (
>     return LShiftU64 (Size, 16);
>   }
>
> +
> +/**
> +  Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
> +**/
> +VOID
> +AddressWidthInitialization (
> +  VOID
> +  )
> +{
> +  UINT64 FirstNonAddress;
> +
> +  //
> +  // As guest-physical memory size grows, the permanent PEI RAM requirements
> +  // are dominated by the identity-mapping page tables built by the DXE IPL.
> +  // The DXL IPL keys off of the physical address bits advertized in the CPU
> +  // HOB. To conserve memory, we calculate the minimum address width here.
> +  //
> +  FirstNonAddress      = BASE_4GB + GetSystemMemorySizeAbove4gb ();
> +  mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
> +
> +  //
> +  // If FirstNonAddress is not an integral power of two, then we need an
> +  // additional bit.
> +  //
> +  if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
> +    ++mPhysMemAddressWidth;
> +  }
> +
> +  //
> +  // The minimum address width is 36 (covers up to and excluding 64 GB, which
> +  // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
> +  // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. 
> We
> +  // can simply assert that here, since 48 bits are good enough for 256 TB.
> +  //
> +  if (mPhysMemAddressWidth <= 36) {
> +    mPhysMemAddressWidth = 36;
> +  }
> +  ASSERT (mPhysMemAddressWidth <= 48);
> +}
> +
> +
> +/**
> +  Calculate the cap for the permanent PEI memory.
> +**/
> +STATIC
> +UINT32
> +GetPeiMemoryCap (
> +  VOID
> +  )
> +{
> +  BOOLEAN Page1GSupport;
> +  UINT32  RegEax;
> +  UINT32  RegEdx;
> +  UINT32  Pml4Entries;
> +  UINT32  PdpEntries;
> +  UINTN   TotalPages;
> +
> +  //
> +  // If DXE is 32-bit, then just return the traditional 64 MB cap.
> +  //
> +#ifdef MDE_CPU_IA32
> +  if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
> +    return SIZE_64MB;
> +  }
> +#endif
> +
> +  //
> +  // Dependent on physical address width, PEI memory allocations can be
> +  // dominated by the page tables built for 64-bit DXE. So we key the cap off
> +  // of those. The code below is based on CreateIdentityMappingPageTables() 
> in
> +  // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
> +  //
> +  Page1GSupport = FALSE;
> +  if (PcdGetBool (PcdUse1GPageTable)) {
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax >= 0x80000001) {
> +      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> +      if ((RegEdx & BIT26) != 0) {
> +        Page1GSupport = TRUE;
> +      }
> +    }
> +  }
> +
> +  if (mPhysMemAddressWidth <= 39) {
> +    Pml4Entries = 1;
> +    PdpEntries = 1 << (mPhysMemAddressWidth - 30);
> +    ASSERT (PdpEntries <= 0x200);
> +  } else {
> +    Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
> +    ASSERT (Pml4Entries <= 0x200);
> +    PdpEntries = 512;
> +  }
> +
> +  TotalPages = Page1GSupport ? Pml4Entries + 1 :
> +                               (PdpEntries + 1) * Pml4Entries + 1;
> +  ASSERT (TotalPages <= 0x40201);
> +
> +  //
> +  // Add 64 MB for miscellaneous allocations. Note that for
> +  // mPhysMemAddressWidth values close to 36, the cap will actually be
> +  // dominated by this increment.
> +  //
> +  return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);
> +}
> +
> +
>   /**
>     Publish PEI core memory
>
> @@ -99,6 +207,7 @@ PublishPeiMemory (
>     EFI_PHYSICAL_ADDRESS        MemoryBase;
>     UINT64                      MemorySize;
>     UINT64                      LowerMemorySize;
> +  UINT32                      PeiMemoryCap;
>
>     if (mBootMode == BOOT_ON_S3_RESUME) {
>       MemoryBase = PcdGet32 (PcdS3AcpiReservedMemoryBase);
> @@ -106,14 +215,18 @@ PublishPeiMemory (
>     } else {
>       LowerMemorySize = GetSystemMemorySizeBelow4gb ();
>
> +    PeiMemoryCap = GetPeiMemoryCap ();
> +    DEBUG ((EFI_D_INFO, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
> +      __FUNCTION__, mPhysMemAddressWidth, PeiMemoryCap >> 10));
> +
>       //
>       // Determine the range of memory to use during PEI
>       //
>       MemoryBase = PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 
> (PcdOvmfDxeMemFvSize);
>       MemorySize = LowerMemorySize - MemoryBase;
> -    if (MemorySize > SIZE_64MB) {
> -      MemoryBase = LowerMemorySize - SIZE_64MB;
> -      MemorySize = SIZE_64MB;
> +    if (MemorySize > PeiMemoryCap) {
> +      MemoryBase = LowerMemorySize - PeiMemoryCap;
> +      MemorySize = PeiMemoryCap;
>       }
>     }
>
> diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
> index 2105787..6557a33 100644
> --- a/OvmfPkg/PlatformPei/Platform.c
> +++ b/OvmfPkg/PlatformPei/Platform.c
> @@ -442,6 +442,7 @@ InitializePlatform (
>     }
>
>     BootModeInitialization ();
> +  AddressWidthInitialization ();
>
>     PublishPeiMemory ();
>
>


-- 

                                                Brian J. Johnson

--------------------------------------------------------------------

   My statements are my own, are not authorized by SGI, and do not
   necessarily represent SGI’s positions.

------------------------------------------------------------------------------
Monitor 25 network devices or servers for free with OpManager!
OpManager is web-based network management software that monitors 
network devices and physical & virtual servers, alerts via email & sms 
for fault. Monitor 25 devices for free with no restriction. Download now
http://ad.doubleclick.net/ddm/clk/292181274;119417398;o
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to