[edk2-devel] [PATCH 4/4] MdeModulePkg/DxeIpl: Create 5-level page table for long mode

Laszlo Ersek lersek at redhat.com
Tue Jul 23 19:20:05 UTC 2019


On 07/23/19 17:29, Ni, Ray wrote:
> 
> 
>> -----Original Message-----
>> From: devel at edk2.groups.io <devel at edk2.groups.io> On Behalf Of Laszlo Ersek
>> Sent: Tuesday, July 23, 2019 5:46 PM
>> To: devel at edk2.groups.io; Ni, Ray <ray.ni at intel.com>
>> Cc: Dong, Eric <eric.dong at intel.com>
>> Subject: Re: [edk2-devel] [PATCH 4/4] MdeModulePkg/DxeIpl: Create 5-level page table for long mode
>>
>> On 07/22/19 10:15, Ni, Ray wrote:
>>> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2008
>>>
>>> DxeIpl is responsible to create page table for DXE phase running
>>> either in long mode or in 32bit mode with certain protection
>>> mechanism enabled (refer to ToBuildPageTable()).
>>>
>>> The patch updates DxeIpl to create 5-level page table for DXE phase
>>> running in long mode when PcdUse5LevelPageTable is TRUE and CPU
>>> supports 5-level page table.
>>>
>>> Signed-off-by: Ray Ni <ray.ni at intel.com>
>>> Cc: Eric Dong <eric.dong at intel.com>
>>> Cc: Laszlo Ersek <lersek at redhat.com>
>>> ---
>>>  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |   1 +
>>>  .../Core/DxeIplPeim/X64/VirtualMemory.c       | 227 ++++++++++++------
>>>  2 files changed, 151 insertions(+), 77 deletions(-)
>>>
>>> diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>>> index abc3217b01..98bc17fc9d 100644
>>> --- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>>> +++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
>>> @@ -110,6 +110,7 @@ [Pcd.IA32,Pcd.X64]
>>>    gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask    ## CONSUMES
>>>    gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask               ## CONSUMES
>>>    gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                       ## CONSUMES
>>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable                  ## SOMETIMES_CONSUMES
>>>
>>>  [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
>>>    gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
>>> diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>>> index edc38e4525..a5bcdcc734 100644
>>> --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>>> +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
>>> @@ -15,7 +15,7 @@
>>>      2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel
>>>      3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
>>>
>>> -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
>>> +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
>>>  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
>>>
>>>  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> @@ -626,14 +626,19 @@ CreateIdentityMappingPageTables (
>>>    )
>>>  {
>>>    UINT32                                        RegEax;
>>> +  UINT32                                        RegEbx;
>>> +  UINT32                                        RegEcx;
>>>    UINT32                                        RegEdx;
>>>    UINT8                                         PhysicalAddressBits;
>>>    EFI_PHYSICAL_ADDRESS                          PageAddress;
>>> +  UINTN                                         IndexOfPml5Entries;
>>>    UINTN                                         IndexOfPml4Entries;
>>>    UINTN                                         IndexOfPdpEntries;
>>>    UINTN                                         IndexOfPageDirectoryEntries;
>>> +  UINT32                                        NumberOfPml5EntriesNeeded;
>>>    UINT32                                        NumberOfPml4EntriesNeeded;
>>>    UINT32                                        NumberOfPdpEntriesNeeded;
>>> +  PAGE_MAP_AND_DIRECTORY_POINTER                *PageMapLevel5Entry;
>>>    PAGE_MAP_AND_DIRECTORY_POINTER                *PageMapLevel4Entry;
>>>    PAGE_MAP_AND_DIRECTORY_POINTER                *PageMap;
>>>    PAGE_MAP_AND_DIRECTORY_POINTER                *PageDirectoryPointerEntry;
>>> @@ -641,9 +646,11 @@ CreateIdentityMappingPageTables (
>>>    UINTN                                         TotalPagesNum;
>>>    UINTN                                         BigPageAddress;
>>>    VOID                                          *Hob;
>>> +  BOOLEAN                                       Page5LevelSupport;
>>>    BOOLEAN                                       Page1GSupport;
>>>    PAGE_TABLE_1G_ENTRY                           *PageDirectory1GEntry;
>>>    UINT64                                        AddressEncMask;
>>> +  IA32_CR4                                      Cr4;
>>>
>>>    //
>>>    // Make sure AddressEncMask is contained to smallest supported address field
>>> @@ -677,33 +684,66 @@ CreateIdentityMappingPageTables (
>>>      }
>>>    }
>>>
>>> +  Page5LevelSupport = FALSE;
>>> +  if (PcdGetBool (PcdUse5LevelPageTable)) {
>>> +    AsmCpuidEx (0x7, 0, &RegEax, &RegEbx, &RegEcx, &RegEdx);
>>> +    DEBUG ((DEBUG_INFO, "Cpuid(7/0): %08x/%08x/%08x/%08x\n", RegEax, RegEbx, RegEcx, RegEdx));
>>> +    if ((RegEcx & BIT16) != 0) {
>>
>> (1) Would it be possible to use macro names here, for Index and SubIndex
>> in AsmCpuidEx(), and a "better" macro name than BIT16, in the RegEcx check?
> 
> There are macros which are defined in UefiCpuPkg for the CPUID leaf functions
> and structures for the CPUID output data.
> But since there is rule that MdeModulePkg cannot depend on UefiCpuPkg so
> the code cannot use those macros/structures.
> 
> I am thinking of a new rule that UefiCpuPkg and MdeModulePkg can depend on each other.
> I haven't talked with Mike on this. Not sure if he is ok on this.
> For this case, yes I can temporary define 2 macros: one for 0x7, the other for BIT16.

I'm aware of this restriction. I think it's a good one; personally I
wouldn't like MdeModulePkg to depend on UefiCpuPkg. For example, while
MdeModulePkg is very necessary for AARCH64 platforms, UefiCpuPkg doesn't
appear necessary for AARCH64 platforms.

If both MdeModulePkg and UefiCpuPkg depend on such macros, then the
macros should arguably be defined in
"MdeModulePkg/Include/IndustryStandard", or even
"MdePkg/Include/IndustryStandard". The registers and bit-fields come
from published industry specifications. (Published by Intel :) )

>>> +      Page5LevelSupport = TRUE;
>>> +    }
>>> +  }
>>> +
>>> +  DEBUG ((DEBUG_INFO, "AddressBits/5LevelPaging/1GPage = %d/%d/%d\n", PhysicalAddressBits, Page5LevelSupport,
>> Page1GSupport));
>>> +
>>
>> (2) Can we format this log message as:
>>
>>   AddressBits=%d 5LevelPaging=%d 1GPage=%d
> 
> ok.
> 
>>
>> ?
>>
>>>    //
>>> -  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
>>> +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses
>>> +  //  when 5-Level Paging is disabled,
>>> +  //  due to either unsupported by HW, or disabled by PCD.
>>>    //
>>>    ASSERT (PhysicalAddressBits <= 52);
>>> -  if (PhysicalAddressBits > 48) {
>>> +  if (!Page5LevelSupport && PhysicalAddressBits > 48) {
>>>      PhysicalAddressBits = 48;
>>>    }
>>>
>>>    //
>>>    // Calculate the table entries needed.
>>>    //
>>> -  if (PhysicalAddressBits <= 39 ) {
>>> -    NumberOfPml4EntriesNeeded = 1;
>>> -    NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
>>> -  } else {
>>> -    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
>>> -    NumberOfPdpEntriesNeeded = 512;
>>> +  NumberOfPml5EntriesNeeded = 1;
>>> +  if (PhysicalAddressBits > 48) {
>>> +    NumberOfPml5EntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 48);
>>> +    PhysicalAddressBits = 48;
>>>    }
>>>
>>> +  NumberOfPml4EntriesNeeded = 1;
>>> +  if (PhysicalAddressBits > 39) {
>>> +    NumberOfPml4EntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 39);
>>> +    PhysicalAddressBits = 39;
>>> +  }
>>> +
>>> +  NumberOfPdpEntriesNeeded = 1;
>>> +  ASSERT (PhysicalAddressBits > 30);
>>> +  NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 30);
>>> +
>>>    //
>>>    // Pre-allocate big pages to avoid later allocations.
>>>    //
>>>    if (!Page1GSupport) {
>>> -    TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
>>> +    TotalPagesNum = ((NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1) * NumberOfPml5EntriesNeeded
>> + 1;
>>>    } else {
>>> -    TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
>>> +    TotalPagesNum = (NumberOfPml4EntriesNeeded + 1) * NumberOfPml5EntriesNeeded + 1;
>>> +  }
>>> +
>>> +  //
>>> +  // Substract the one page occupied by PML5 entries if 5-Level Paging is disabled.
>>> +  //
>>> +  if (!Page5LevelSupport) {
>>> +    TotalPagesNum--;
>>>    }
>>> +
>>> +  DEBUG ((DEBUG_INFO, "Pml5/Pml4/Pdp/TotalPage = %d/%d/%d/%d\n",
>>> +    NumberOfPml5EntriesNeeded, NumberOfPml4EntriesNeeded,
>>> +    NumberOfPdpEntriesNeeded, TotalPagesNum));
>>> +
>>
>> (3) Same comment about log message formatting as in (2).
>>
>> (4) Please log UINT32 values with %u, not %d.
>>
>> (5) Please log UINTN values with %Lu (and cast them to UINT64 first).
> 
> 
> ok to above 3, 4, 5.
> 
>>
>> (6) More generally, can we please replace this patch with three patches,
>> in the series?
>>
>> - the first patch should extract the TotalPagesNum calculation to a
>> separate *library* function (it should be a public function in a BASE or
>> PEIM library)
>>
>> - the second patch should extend the TotalPagesNum calculation in the
>> library function to 5-level paging
>>
>> - the third patch should be the remaining code from the present patch.
>>
>> Here's why: in OvmfPkg/PlatformPei, the GetPeiMemoryCap() function
>> duplicates this calculation. In OVMF, PEI-phase memory allocations can
>> be dominated by the page tables built for 64-bit DXE, and so
>> OvmfPkg/PlatformPei must know, for sizing the permanent PEI RAM, how
>> much RAM the DXE IPL PEIM will need for those page tables.
>>
>> I would *really* dislike copying this update (for 5-level paging) from
>> CreateIdentityMappingPageTables() to GetPeiMemoryCap(). Instead, the
>> calculation should be extracted to a library function, and then OVMF
>> (and all other platforms affected similarly) could call the new function.
>>
>> If this is not feasible or very much out of scope, then I guess we'll
>> just keep the PCD as FALSE in OVMF, for the time being.
>>
> 
> BZ https://bugzilla.tianocore.org/show_bug.cgi?id=847 may be what
> you need.

Oh, indeed. I'm subscribed to this BZ, but the last update was in Jan
2018 :)

> Extracting a library API to return how many pages are needed for page tables
> needs to consider several cases:
> 1. 4K or 2M or 1G page size is used.
> 2. range of physical memory
> 3. page table level
> 
> But right now, this is not in the high priority in my to-do list.
> I can help to change GetPeiMemoryCap() for short-term needs.
> Are you ok with this?

No, I'm not.

Obviously, I'm not trying to force you to abstract out the library in
question, just for OVMF's sake. What I'm saying is that I strongly
prefer delaying 5-level paging support in OVMF until this library
becomes available, over duplicating yet more code (and complex code, at
that) from other Packages to OvmfPkg. From that perspective, I
appreciate the new PCD very much, because it should make this postponing
easy.

In other words, there is no short-term need.

Thank you!
Laszlo

-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#44267): https://edk2.groups.io/g/devel/message/44267
Mute This Topic: https://groups.io/mt/32556535/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list