public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Laszlo Ersek" <lersek@redhat.com>
To: devel@edk2.groups.io, kraxel@redhat.com
Cc: Oliver Steffen <osteffen@redhat.com>,
	Jiewen Yao <jiewen.yao@intel.com>,
	Ard Biesheuvel <ardb+tianocore@kernel.org>
Subject: Re: [edk2-devel] [PATCH 2/3] OvmfPkg/PlatformPei: rewrite page table calculation
Date: Wed, 31 Jan 2024 16:13:24 +0100	[thread overview]
Message-ID: <cbe72962-0562-e776-b80e-e4a3762df558@redhat.com> (raw)
In-Reply-To: <20240131120000.358090-3-kraxel@redhat.com>

On 1/31/24 12:59, Gerd Hoffmann wrote:
> Consider 5-level paging.  Simplify calculation to make it easier to
> understand.  The new calculation is not 100% exact, but we only need
> a rough estimate to reserve enough memory.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  OvmfPkg/PlatformPei/MemDetect.c | 42 ++++++++++++++++++---------------
>  1 file changed, 23 insertions(+), 19 deletions(-)

The cover letter should have explained that this series depends on the
5-level paging series -- or else, this one should be appended to that
series.

With no on-list connection between them, it's a mess for me to keep
track of which one to merge first.

> 
> diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
> index 338798b54171..e22743b4bfaa 100644
> --- a/OvmfPkg/PlatformPei/MemDetect.c
> +++ b/OvmfPkg/PlatformPei/MemDetect.c
> @@ -184,8 +184,10 @@ GetPeiMemoryCap (
>    BOOLEAN  Page1GSupport;
>    UINT32   RegEax;
>    UINT32   RegEdx;
> -  UINT32   Pml4Entries;
> -  UINT32   PdpEntries;
> +  UINT32   Level5Pages;
> +  UINT32   Level4Pages;
> +  UINT32   Level3Pages;
> +  UINT32   Level2Pages;
>    UINTN    TotalPages;
>    UINTN    ApStacks;
>    UINTN    MemoryCap;
> @@ -203,8 +205,7 @@ GetPeiMemoryCap (
>    //
>    // 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".
> +  // of those.
>    //
>    Page1GSupport = FALSE;
>    if (PcdGetBool (PcdUse1GPageTable)) {
> @@ -217,23 +218,26 @@ GetPeiMemoryCap (
>      }
>    }
>  
> -  if (PlatformInfoHob->PhysMemAddressWidth <= 39) {
> -    Pml4Entries = 1;
> -    PdpEntries  = 1 << (PlatformInfoHob->PhysMemAddressWidth - 30);
> -    ASSERT (PdpEntries <= 0x200);
> -  } else {
> -    if (PlatformInfoHob->PhysMemAddressWidth > 48) {
> -      Pml4Entries = 0x200;
> -    } else {
> -      Pml4Entries = 1 << (PlatformInfoHob->PhysMemAddressWidth - 39);
> -    }
> -
> -    ASSERT (Pml4Entries <= 0x200);
> -    PdpEntries = 512;
> +  //
> +  // This calculation doesn't return the *exact* number of page table
> +  // pages needed.  But we only need a rough estimate to reserve
> +  // enough memory, being off by a few pages isn't much of problem.
> +  // So keep the calculation simple and easy to understand.
> +  //
> +  // Page size is 4k, which needs 12 address bits.
> +  // Page tables on all levels have 512 entries, mapping to 9 address bits.
> +  // We use large pages (2M or 1G), so level 1 never exists.
> +  // Start with level 2, where a page covers 12 + 9 + 9 = 30 address bits.
> +  //

The calculation seems correct. On level 2, using 2MB page size for the
physical address space, one entry covers 2MB of phys address space, and
we have 512 entries in one 4KB page table page. This means one page
table page covers 512 * 2MB = 1024MB = 1GB = 2^30 B.

(1) The wording is difficult to follow though, for me anyway. How about
this:

-------
- A 4KB page accommodates the least significant 12 bits of the virtual
address.
- A page table entry at any level consumes 8 bytes, so a 4KB page table
page (at any level) contains 512 entries, and accommodates 9 bits of the
virtual address.
- we minimally cover the phys address space with 2MB pages, so level 1
never exists.
- If 1G paging is available, then level 2 doesn't exist either.
- Start with level 2, where a page table page accommodates 9 + 9 + 12 =
30 bits of the virtual address (and covers 1GB of physical address space).
-------

If you think this isn't any easier to follow, then feel free to stick
with your description.

> +  Level2Pages = (1 << (PlatformInfoHob->PhysMemAddressWidth - 30)) + 1;

General calculation:

  2^PhysMemAddressWidth / 2^21 / 2^9 ==
  2^(PhysMemAddressWidth - 21 - 9) ==
  1 << (PhysMemAddressWidth - 30)

OK. The left-shift of the signed int (INT32) constant "1" is also safe,
given that (I think?) PhysMemAddressWidth cannot be larger than 57. So
the shift count is at most 27, and 1 << 27 is safe.

(2) Why do we need to add 1?

I don't think there's a need for rounding up. The original dividend,
2^PhysMemAddressWidth, is an integral power of two, and
PhysMemAddressWidth is minimally 36 (IIRC). (If PhysMemAddressWidth were
less than 30, then the left shift would be undefined, to begin with.)

> +  Level3Pages = (Level2Pages >> 9) + 1;
> +  Level4Pages = (Level3Pages >> 9) + 1;
> +  Level5Pages = (Level4Pages >> 9) + 1;
> +  if (Page1GSupport) {
> +    Level2Pages = 0;
>    }

(3) I'm sorry, these +1 additions *really* annoy me, not to mention the
fact that we *include* those increments in the further shifting. Can we do:

  UINT64  End;
  UINT64  Level2Pages, Level3Pages, Level4Pages, Level5Pages;

  End         = 1LLU << PlatformInfoHob->PhysMemAddressWidth;
  Level2Pages = Page1GSupport ? 0LLU : End >> 30;
  Level3Pages = MAX (End >> 39, 1LLU);
  Level4Pages = MAX (End >> 48, 1LLU);
  Level5Pages = 1;

This doesn't seem any more complicated, and it's exact, I believe.

>  
> -  TotalPages = Page1GSupport ? Pml4Entries + 1 :
> -               (PdpEntries + 1) * Pml4Entries + 1;
> +  TotalPages = Level5Pages + Level4Pages + Level3Pages + Level2Pages;
>    ASSERT (TotalPages <= 0x40201);

(4) The ASSERT() is no longer correct, for two reasons: (a) it does not
consider 5-level paging, (b) the calculation from the patch is not exact
anyway.

But, I think the method I'm proposing should be exact (discounting that
with 5-level paging unavailable, Level5Pages should be set to zero).

Assuming PhysMemAddressWidth is 57, and 1GB pages are not supported, we get:

  Level2Pages = BIT27;
  Level3Pages = BIT18;
  Level4Pages = BIT9;
  Level5Pages = BIT0;

therefore

  ASSERT (TotalPages <= 0x8040201);

in other words, we only need to add BIT27 to the existing constant
0x40201, in the ASSERT().

>  
>    ApStacks  = PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber * PcdGet32 (PcdCpuApStackSize);

Thanks
Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#114905): https://edk2.groups.io/g/devel/message/114905
Mute This Topic: https://groups.io/mt/104073300/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  reply	other threads:[~2024-01-31 15:13 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-31 11:59 [edk2-devel] [PATCH 0/3] OvmfPkg/PlatformPei: scaleability fixes for GetPeiMemoryCap() Gerd Hoffmann
2024-01-31 11:59 ` [edk2-devel] [PATCH 1/3] OvmfPkg/PlatformPei: consider AP stacks for pei memory cap Gerd Hoffmann
2024-01-31 14:08   ` Laszlo Ersek
2024-01-31 14:55     ` Gerd Hoffmann
2024-01-31 19:29       ` Laszlo Ersek
2024-01-31 11:59 ` [edk2-devel] [PATCH 2/3] OvmfPkg/PlatformPei: rewrite page table calculation Gerd Hoffmann
2024-01-31 15:13   ` Laszlo Ersek [this message]
2024-01-31 15:21     ` Laszlo Ersek
2024-01-31 16:28     ` Gerd Hoffmann
2024-02-01 21:04       ` Laszlo Ersek
2024-01-31 12:00 ` [edk2-devel] [PATCH 3/3] OvmfPkg/PlatformPei: log pei memory cap details Gerd Hoffmann
2024-01-31 15:38   ` Laszlo Ersek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cbe72962-0562-e776-b80e-e4a3762df558@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox