public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Ni, Ray" <ray.ni@intel.com>
To: "Yao, Jiewen" <jiewen.yao@intel.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Dong, Eric" <eric.dong@intel.com>
Subject: Re: [edk2-devel] [PATCH 3/3] UefiCpuPkg/PiSmmCpu: Enable 5 level paging when CPU supports
Date: Fri, 28 Jun 2019 07:27:48 +0000	[thread overview]
Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C1F4B96@SHSMSX104.ccr.corp.intel.com> (raw)
In-Reply-To: <74D8A39837DF1E4DA445A8C0B3885C503F6D34E6@shsmsx102.ccr.corp.intel.com>

Jiewen,
I tested the above 2^48 memory address access in SMM environment to ensure no GP fault.

The code is internally used for a while and this patch is to upstream the code to edk2 repo.

Thanks,
Ray

> -----Original Message-----
> From: Yao, Jiewen <jiewen.yao@intel.com>
> Sent: Friday, June 28, 2019 3:18 PM
> To: devel@edk2.groups.io; Ni, Ray <ray.ni@intel.com>
> Cc: Dong, Eric <eric.dong@intel.com>
> Subject: RE: [edk2-devel] [PATCH 3/3] UefiCpuPkg/PiSmmCpu: Enable 5 level
> paging when CPU supports
> 
> Hi
> Would you please share the info on what test has been done for this 5 level
> paging?
> 
> Such as stack paging enable/disable, SMM profile, etc.
> 
> Thank you
> Yao Jiewen
> 
> > -----Original Message-----
> > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> Ni,
> > Ray
> > Sent: Friday, June 28, 2019 2:47 PM
> > To: devel@edk2.groups.io
> > Cc: Dong, Eric <eric.dong@intel.com>
> > Subject: [edk2-devel] [PATCH 3/3] UefiCpuPkg/PiSmmCpu: Enable 5 level
> > paging when CPU supports
> >
> > REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1946
> >
> > The patch changes SMM environment to use 5 level paging when CPU
> > supports it.
> >
> > Signed-off-by: Ray Ni <ray.ni@intel.com>
> > Cc: Eric Dong <eric.dong@intel.com>
> > ---
> >  .../PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c   |  20 +-
> >  UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c        | 272 ++++++----
> >  UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c       | 483
> > ++++++++++++------
> >  UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.nasm   |  12 +
> >  .../PiSmmCpuDxeSmm/X64/SmmProfileArch.c       |  72 ++-
> >  5 files changed, 559 insertions(+), 300 deletions(-)
> >
> > diff --git
> a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> > b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> > index 069be3aaa5..55090e9c3e 100644
> > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
> > @@ -125,18 +125,36 @@ GetPageTableEntry (
> >    UINTN                 Index2;
> >    UINTN                 Index3;
> >    UINTN                 Index4;
> > +  UINTN                 Index5;
> >    UINT64                *L1PageTable;
> >    UINT64                *L2PageTable;
> >    UINT64                *L3PageTable;
> >    UINT64                *L4PageTable;
> > +  UINT64                *L5PageTable;
> > +  IA32_CR4              Cr4;
> > +  BOOLEAN               Enable5LevelPaging;
> >
> > +  Index5 = ((UINTN)RShiftU64 (Address, 48)) &
> PAGING_PAE_INDEX_MASK;
> >    Index4 = ((UINTN)RShiftU64 (Address, 39)) &
> PAGING_PAE_INDEX_MASK;
> >    Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;
> >    Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;
> >    Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;
> >
> > +  Cr4.UintN = AsmReadCr4 ();
> > +  Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
> > +
> >    if (sizeof(UINTN) == sizeof(UINT64)) {
> > -    L4PageTable = (UINT64 *)GetPageTableBase ();
> > +    if (Enable5LevelPaging) {
> > +      L5PageTable = (UINT64 *)GetPageTableBase ();
> > +      if (L5PageTable[Index5] == 0) {
> > +        *PageAttribute = PageNone;
> > +        return NULL;
> > +      }
> > +
> > +      L4PageTable = (UINT64 *)(UINTN)(L5PageTable[Index5] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +    } else {
> > +      L4PageTable = (UINT64 *)GetPageTableBase ();
> > +    }
> >      if (L4PageTable[Index4] == 0) {
> >        *PageAttribute = PageNone;
> >        return NULL;
> > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
> > b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
> > index e2b6a2d9b2..c5131526f0 100644
> > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
> > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
> > @@ -534,43 +534,78 @@ InitPaging (
> >    VOID
> >    )
> >  {
> > +  UINT64                            Pml5Entry;
> > +  UINT64                            Pml4Entry;
> > +  UINT64                            *Pml5;
> >    UINT64                            *Pml4;
> >    UINT64                            *Pdpt;
> >    UINT64                            *Pd;
> >    UINT64                            *Pt;
> >    UINTN                             Address;
> > +  UINTN                             Pml5Index;
> >    UINTN                             Pml4Index;
> >    UINTN                             PdptIndex;
> >    UINTN                             PdIndex;
> >    UINTN                             PtIndex;
> >    UINTN                             NumberOfPdptEntries;
> >    UINTN                             NumberOfPml4Entries;
> > +  UINTN                             NumberOfPml5Entries;
> >    UINTN                             SizeOfMemorySpace;
> >    BOOLEAN                           Nx;
> > +  IA32_CR4                          Cr4;
> > +  BOOLEAN                           Enable5LevelPaging;
> > +
> > +  Cr4.UintN = AsmReadCr4 ();
> > +  Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
> >
> >    if (sizeof (UINTN) == sizeof (UINT64)) {
> > -    Pml4 = (UINT64*)(UINTN)mSmmProfileCr3;
> > +    if (!Enable5LevelPaging) {
> > +      Pml5Entry = (UINTN) mSmmProfileCr3 | IA32_PG_P;
> > +      Pml5 = &Pml5Entry;
> > +    } else {
> > +      Pml5 = (UINT64*) (UINTN) mSmmProfileCr3;
> > +    }
> >      SizeOfMemorySpace = HighBitSet64 (gPhyMask) + 1;
> >      //
> >      // Calculate the table entries of PML4E and PDPTE.
> >      //
> > -    if (SizeOfMemorySpace <= 39 ) {
> > -      NumberOfPml4Entries = 1;
> > -      NumberOfPdptEntries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace
> > - 30));
> > -    } else {
> > -      NumberOfPml4Entries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace
> > - 39));
> > -      NumberOfPdptEntries = 512;
> > +    NumberOfPml5Entries = 1;
> > +    if (SizeOfMemorySpace > 48) {
> > +      NumberOfPml5Entries = (UINTN) LShiftU64 (1, SizeOfMemorySpace
> > - 48);
> > +      SizeOfMemorySpace = 48;
> >      }
> > -  } else {
> > +
> >      NumberOfPml4Entries = 1;
> > +    if (SizeOfMemorySpace > 39) {
> > +      NumberOfPml4Entries = (UINTN) LShiftU64 (1, SizeOfMemorySpace
> > - 39);
> > +      SizeOfMemorySpace = 39;
> > +    }
> > +
> > +    NumberOfPdptEntries = 1;
> > +    ASSERT (SizeOfMemorySpace > 30);
> > +    NumberOfPdptEntries = (UINTN) LShiftU64 (1, SizeOfMemorySpace -
> > 30);
> > +  } else {
> > +    Pml4Entry = (UINTN) mSmmProfileCr3 | IA32_PG_P;
> > +    Pml4 = &Pml4Entry;
> > +    Pml5Entry = (UINTN) Pml4 | IA32_PG_P;
> > +    Pml5 = &Pml5Entry;
> > +    NumberOfPml5Entries  = 1;
> > +    NumberOfPml4Entries  = 1;
> >      NumberOfPdptEntries  = 4;
> >    }
> >
> >    //
> >    // Go through page table and change 2MB-page into 4KB-page.
> >    //
> > -  for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) {
> > -    if (sizeof (UINTN) == sizeof (UINT64)) {
> > +  for (Pml5Index = 0; Pml5Index < NumberOfPml5Entries; Pml5Index++) {
> > +    if ((Pml5[Pml5Index] & IA32_PG_P) == 0) {
> > +      //
> > +      // If PML5 entry does not exist, skip it
> > +      //
> > +      continue;
> > +    }
> > +    Pml4 = (UINT64 *) (UINTN) (Pml5[Pml5Index] &
> > PHYSICAL_ADDRESS_MASK);
> > +    for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) {
> >        if ((Pml4[Pml4Index] & IA32_PG_P) == 0) {
> >          //
> >          // If PML4 entry does not exist, skip it
> > @@ -578,63 +613,76 @@ InitPaging (
> >          continue;
> >        }
> >        Pdpt = (UINT64 *)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask
> > & PHYSICAL_ADDRESS_MASK);
> > -    } else {
> > -      Pdpt = (UINT64*)(UINTN)mSmmProfileCr3;
> > -    }
> > -    for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++,
> > Pdpt++) {
> > -      if ((*Pdpt & IA32_PG_P) == 0) {
> > -        //
> > -        // If PDPT entry does not exist, skip it
> > -        //
> > -        continue;
> > -      }
> > -      if ((*Pdpt & IA32_PG_PS) != 0) {
> > -        //
> > -        // This is 1G entry, skip it
> > -        //
> > -        continue;
> > -      }
> > -      Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask &
> > PHYSICAL_ADDRESS_MASK);
> > -      if (Pd == 0) {
> > -        continue;
> > -      }
> > -      for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++, Pd++)
> > {
> > -        if ((*Pd & IA32_PG_P) == 0) {
> > +      for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++,
> > Pdpt++) {
> > +        if ((*Pdpt & IA32_PG_P) == 0) {
> > +          //
> > +          // If PDPT entry does not exist, skip it
> > +          //
> > +          continue;
> > +        }
> > +        if ((*Pdpt & IA32_PG_PS) != 0) {
> >            //
> > -          // If PD entry does not exist, skip it
> > +          // This is 1G entry, skip it
> >            //
> >            continue;
> >          }
> > -        Address = (((PdptIndex << 9) + PdIndex) << 21);
> > +        Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask &
> > PHYSICAL_ADDRESS_MASK);
> > +        if (Pd == 0) {
> > +          continue;
> > +        }
> > +        for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++,
> > Pd++) {
> > +          if ((*Pd & IA32_PG_P) == 0) {
> > +            //
> > +            // If PD entry does not exist, skip it
> > +            //
> > +            continue;
> > +          }
> > +          Address = (UINTN) LShiftU64 (
> > +                              LShiftU64 (
> > +                                LShiftU64 ((Pml5Index << 9) +
> > Pml4Index, 9) + PdptIndex,
> > +                                9
> > +                                ) + PdIndex,
> > +                                21
> > +                              );
> >
> > -        //
> > -        // If it is 2M page, check IsAddressSplit()
> > -        //
> > -        if (((*Pd & IA32_PG_PS) != 0) && IsAddressSplit (Address)) {
> >            //
> > -          // Based on current page table, create 4KB page table for split
> > area.
> > +          // If it is 2M page, check IsAddressSplit()
> >            //
> > -          ASSERT (Address == (*Pd & PHYSICAL_ADDRESS_MASK));
> > +          if (((*Pd & IA32_PG_PS) != 0) && IsAddressSplit (Address)) {
> > +            //
> > +            // Based on current page table, create 4KB page table for
> > split area.
> > +            //
> > +            ASSERT (Address == (*Pd & PHYSICAL_ADDRESS_MASK));
> > +
> > +            Pt = AllocatePageTableMemory (1);
> > +            ASSERT (Pt != NULL);
> >
> > -          Pt = AllocatePageTableMemory (1);
> > -          ASSERT (Pt != NULL);
> > +            *Pd = (UINTN) Pt | IA32_PG_RW | IA32_PG_P;
> >
> > -          // Split it
> > -          for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++) {
> > -            Pt[PtIndex] = Address + ((PtIndex << 12) | mAddressEncMask
> > | PAGE_ATTRIBUTE_BITS);
> > -          } // end for PT
> > -          *Pd = (UINT64)(UINTN)Pt | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS;
> > -        } // end if IsAddressSplit
> > -      } // end for PD
> > -    } // end for PDPT
> > -  } // end for PML4
> > +            // Split it
> > +            for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++,
> > Pt++) {
> > +              *Pt = Address + ((PtIndex << 12) | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS);
> > +            } // end for PT
> > +            *Pd = (UINT64)(UINTN)Pt | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS;
> > +          } // end if IsAddressSplit
> > +        } // end for PD
> > +      } // end for PDPT
> > +    } // end for PML4
> > +  } // end for PML5
> >
> >    //
> >    // Go through page table and set several page table entries to absent or
> > execute-disable.
> >    //
> >    DEBUG ((EFI_D_INFO, "Patch page table start ...\n"));
> > -  for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) {
> > -    if (sizeof (UINTN) == sizeof (UINT64)) {
> > +  for (Pml5Index = 0; Pml5Index < NumberOfPml5Entries; Pml5Index++) {
> > +    if ((Pml5[Pml5Index] & IA32_PG_P) == 0) {
> > +      //
> > +      // If PML5 entry does not exist, skip it
> > +      //
> > +      continue;
> > +    }
> > +    Pml4 = (UINT64 *) (UINTN) (Pml5[Pml5Index] &
> > PHYSICAL_ADDRESS_MASK);
> > +    for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) {
> >        if ((Pml4[Pml4Index] & IA32_PG_P) == 0) {
> >          //
> >          // If PML4 entry does not exist, skip it
> > @@ -642,69 +690,73 @@ InitPaging (
> >          continue;
> >        }
> >        Pdpt = (UINT64 *)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask
> > & PHYSICAL_ADDRESS_MASK);
> > -    } else {
> > -      Pdpt = (UINT64*)(UINTN)mSmmProfileCr3;
> > -    }
> > -    for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++,
> > Pdpt++) {
> > -      if ((*Pdpt & IA32_PG_P) == 0) {
> > -        //
> > -        // If PDPT entry does not exist, skip it
> > -        //
> > -        continue;
> > -      }
> > -      if ((*Pdpt & IA32_PG_PS) != 0) {
> > -        //
> > -        // This is 1G entry, set NX bit and skip it
> > -        //
> > -        if (mXdSupported) {
> > -          *Pdpt = *Pdpt | IA32_PG_NX;
> > +      for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++,
> > Pdpt++) {
> > +        if ((*Pdpt & IA32_PG_P) == 0) {
> > +          //
> > +          // If PDPT entry does not exist, skip it
> > +          //
> > +          continue;
> >          }
> > -        continue;
> > -      }
> > -      Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask &
> > PHYSICAL_ADDRESS_MASK);
> > -      if (Pd == 0) {
> > -        continue;
> > -      }
> > -      for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++, Pd++)
> > {
> > -        if ((*Pd & IA32_PG_P) == 0) {
> > +        if ((*Pdpt & IA32_PG_PS) != 0) {
> >            //
> > -          // If PD entry does not exist, skip it
> > +          // This is 1G entry, set NX bit and skip it
> >            //
> > +          if (mXdSupported) {
> > +            *Pdpt = *Pdpt | IA32_PG_NX;
> > +          }
> >            continue;
> >          }
> > -        Address = (((PdptIndex << 9) + PdIndex) << 21);
> > -
> > -        if ((*Pd & IA32_PG_PS) != 0) {
> > -          // 2MB page
> > -
> > -          if (!IsAddressValid (Address, &Nx)) {
> > +        Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask &
> > PHYSICAL_ADDRESS_MASK);
> > +        if (Pd == 0) {
> > +          continue;
> > +        }
> > +        for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++,
> > Pd++) {
> > +          if ((*Pd & IA32_PG_P) == 0) {
> >              //
> > -            // Patch to remove Present flag and RW flag
> > +            // If PD entry does not exist, skip it
> >              //
> > -            *Pd = *Pd & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
> > -          }
> > -          if (Nx && mXdSupported) {
> > -            *Pd = *Pd | IA32_PG_NX;
> > -          }
> > -        } else {
> > -          // 4KB page
> > -          Pt = (UINT64 *)(UINTN)(*Pd & ~mAddressEncMask &
> > PHYSICAL_ADDRESS_MASK);
> > -          if (Pt == 0) {
> >              continue;
> >            }
> > -          for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++,
> > Pt++) {
> > +          Address = (UINTN) LShiftU64 (
> > +                              LShiftU64 (
> > +                                LShiftU64 ((Pml5Index << 9) +
> > Pml4Index, 9) + PdptIndex,
> > +                                9
> > +                                ) + PdIndex,
> > +                                21
> > +                              );
> > +
> > +          if ((*Pd & IA32_PG_PS) != 0) {
> > +            // 2MB page
> > +
> >              if (!IsAddressValid (Address, &Nx)) {
> > -              *Pt = *Pt & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
> > +              //
> > +              // Patch to remove Present flag and RW flag
> > +              //
> > +              *Pd = *Pd & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
> >              }
> >              if (Nx && mXdSupported) {
> > -              *Pt = *Pt | IA32_PG_NX;
> > +              *Pd = *Pd | IA32_PG_NX;
> > +            }
> > +          } else {
> > +            // 4KB page
> > +            Pt = (UINT64 *)(UINTN)(*Pd & ~mAddressEncMask &
> > PHYSICAL_ADDRESS_MASK);
> > +            if (Pt == 0) {
> > +              continue;
> >              }
> > -            Address += SIZE_4KB;
> > -          } // end for PT
> > -        } // end if PS
> > -      } // end for PD
> > -    } // end for PDPT
> > -  } // end for PML4
> > +            for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++,
> > Pt++) {
> > +              if (!IsAddressValid (Address, &Nx)) {
> > +                *Pt = *Pt & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
> > +              }
> > +              if (Nx && mXdSupported) {
> > +                *Pt = *Pt | IA32_PG_NX;
> > +              }
> > +              Address += SIZE_4KB;
> > +            } // end for PT
> > +          } // end if PS
> > +        } // end for PD
> > +      } // end for PDPT
> > +    } // end for PML4
> > +  } // end for PML5
> >
> >    //
> >    // Flush TLB
> > @@ -1156,6 +1208,20 @@ RestorePageTableBelow4G (
> >  {
> >    UINTN         PTIndex;
> >    UINTN         PFIndex;
> > +  IA32_CR4      Cr4;
> > +  BOOLEAN       Enable5LevelPaging;
> > +
> > +  Cr4.UintN = AsmReadCr4 ();
> > +  Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
> > +
> > +  //
> > +  // PML5
> > +  //
> > +  if (Enable5LevelPaging) {
> > +    PTIndex = (UINTN)BitFieldRead64 (PFAddress, 48, 56);
> > +    ASSERT (PageTable[PTIndex] != 0);
> > +    PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > PHYSICAL_ADDRESS_MASK);
> > +  }
> >
> >    //
> >    // PML4
> > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
> > b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
> > index 3d5d663d99..c088010327 100644
> > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
> > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
> > @@ -16,6 +16,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> >  LIST_ENTRY                          mPagePool =
> > INITIALIZE_LIST_HEAD_VARIABLE (mPagePool);
> >  BOOLEAN                             m1GPageTableSupport =
> > FALSE;
> >  BOOLEAN                             mCpuSmmStaticPageTable;
> > +BOOLEAN                             m5LevelPagingSupport;
> >
> >  /**
> >    Disable CET.
> > @@ -60,6 +61,31 @@ Is1GPageSupport (
> >    return FALSE;
> >  }
> >
> > +/**
> > +  Check if 5-level paging is supported by processor or not.
> > +
> > +  @retval TRUE   5-level paging is supported.
> > +  @retval FALSE  5-level paging is not supported.
> > +
> > +**/
> > +BOOLEAN
> > +Is5LevelPagingSupport (
> > +  VOID
> > +  )
> > +{
> > +  CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_ECX EcxFlags;
> > +
> > +  AsmCpuidEx (
> > +    CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS,
> > +    CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO,
> > +    NULL,
> > +    NULL,
> > +    &EcxFlags.Uint32,
> > +    NULL
> > +    );
> > +  return (BOOLEAN) (EcxFlags.Bits.FiveLevelPage != 0);
> > +}
> > +
> >  /**
> >    Set sub-entries number in entry.
> >
> > @@ -130,14 +156,6 @@ CalculateMaximumSupportAddress (
> >        PhysicalAddressBits = 36;
> >      }
> >    }
> > -
> > -  //
> > -  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> > addresses.
> > -  //
> > -  ASSERT (PhysicalAddressBits <= 52);
> > -  if (PhysicalAddressBits > 48) {
> > -    PhysicalAddressBits = 48;
> > -  }
> >    return PhysicalAddressBits;
> >  }
> >
> > @@ -152,89 +170,137 @@ SetStaticPageTable (
> >    )
> >  {
> >    UINT64                                        PageAddress;
> > +  UINTN
> > NumberOfPml5EntriesNeeded;
> >    UINTN
> > NumberOfPml4EntriesNeeded;
> >    UINTN
> > NumberOfPdpEntriesNeeded;
> > +  UINTN
> > IndexOfPml5Entries;
> >    UINTN
> > IndexOfPml4Entries;
> >    UINTN
> > IndexOfPdpEntries;
> >    UINTN
> > IndexOfPageDirectoryEntries;
> > +  UINT64
> > *PageMapLevel5Entry;
> >    UINT64
> > *PageMapLevel4Entry;
> >    UINT64                                        *PageMap;
> >    UINT64
> > *PageDirectoryPointerEntry;
> >    UINT64
> > *PageDirectory1GEntry;
> >    UINT64
> > *PageDirectoryEntry;
> >
> > -  if (mPhysicalAddressBits <= 39 ) {
> > -    NumberOfPml4EntriesNeeded = 1;
> > -    NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1,
> > (mPhysicalAddressBits - 30));
> > -  } else {
> > -    NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1,
> > (mPhysicalAddressBits - 39));
> > -    NumberOfPdpEntriesNeeded = 512;
> > +  //
> > +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> > addresses
> > +  //  when 5-Level Paging is disabled.
> > +  //
> > +  ASSERT (mPhysicalAddressBits <= 52);
> > +  if (!m5LevelPagingSupport && mPhysicalAddressBits > 48) {
> > +    mPhysicalAddressBits = 48;
> > +  }
> > +
> > +  NumberOfPml5EntriesNeeded = 1;
> > +  if (mPhysicalAddressBits > 48) {
> > +    NumberOfPml5EntriesNeeded = (UINTN) LShiftU64 (1,
> > mPhysicalAddressBits - 48);
> > +    mPhysicalAddressBits = 48;
> > +  }
> > +
> > +  NumberOfPml4EntriesNeeded = 1;
> > +  if (mPhysicalAddressBits > 39) {
> > +    NumberOfPml4EntriesNeeded = (UINTN) LShiftU64 (1,
> > mPhysicalAddressBits - 39);
> > +    mPhysicalAddressBits = 39;
> >    }
> >
> > +  NumberOfPdpEntriesNeeded = 1;
> > +  ASSERT (mPhysicalAddressBits > 30);
> > +  NumberOfPdpEntriesNeeded = (UINTN) LShiftU64 (1,
> > mPhysicalAddressBits - 30);
> > +
> >    //
> >    // By architecture only one PageMapLevel4 exists - so lets allocate
> > storage for it.
> >    //
> >    PageMap         = (VOID *) PageTable;
> >
> >    PageMapLevel4Entry = PageMap;
> > -  PageAddress        = 0;
> > -  for (IndexOfPml4Entries = 0; IndexOfPml4Entries <
> > NumberOfPml4EntriesNeeded; IndexOfPml4Entries++,
> > PageMapLevel4Entry++) {
> > +  PageMapLevel5Entry = NULL;
> > +  if (m5LevelPagingSupport) {
> >      //
> > -    // Each PML4 entry points to a page of Page Directory Pointer entries.
> > +    // By architecture only one PageMapLevel5 exists - so lets allocate
> > storage for it.
> >      //
> > -    PageDirectoryPointerEntry = (UINT64 *) ((*PageMapLevel4Entry) &
> > ~mAddressEncMask & gPhyMask);
> > -    if (PageDirectoryPointerEntry == NULL) {
> > -      PageDirectoryPointerEntry = AllocatePageTableMemory (1);
> > -      ASSERT(PageDirectoryPointerEntry != NULL);
> > -      ZeroMem (PageDirectoryPointerEntry, EFI_PAGES_TO_SIZE(1));
> > +    PageMapLevel5Entry = PageMap;
> > +  }
> > +  PageAddress        = 0;
> >
> > -      *PageMapLevel4Entry = (UINT64)(UINTN)PageDirectoryPointerEntry
> > | mAddressEncMask | PAGE_ATTRIBUTE_BITS;
> > +  for ( IndexOfPml5Entries = 0
> > +      ; IndexOfPml5Entries < NumberOfPml5EntriesNeeded
> > +      ; IndexOfPml5Entries++, PageMapLevel5Entry++) {
> > +    //
> > +    // Each PML5 entry points to a page of PML4 entires.
> > +    // So lets allocate space for them and fill them in in the
> > IndexOfPml4Entries loop.
> > +    // When 5-Level Paging is disabled, below allocation happens only
> > once.
> > +    //
> > +    if (m5LevelPagingSupport) {
> > +      PageMapLevel4Entry = (UINT64 *) ((*PageMapLevel5Entry) &
> > ~mAddressEncMask & gPhyMask);
> > +      if (PageMapLevel4Entry == NULL) {
> > +        PageMapLevel4Entry = AllocatePageTableMemory (1);
> > +        ASSERT(PageMapLevel4Entry != NULL);
> > +        ZeroMem (PageMapLevel4Entry, EFI_PAGES_TO_SIZE(1));
> > +
> > +        *PageMapLevel5Entry = (UINT64)(UINTN)PageMapLevel4Entry |
> > mAddressEncMask | PAGE_ATTRIBUTE_BITS;
> > +      }
> >      }
> >
> > -    if (m1GPageTableSupport) {
> > -      PageDirectory1GEntry = PageDirectoryPointerEntry;
> > -      for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries
> > < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++,
> > PageAddress += SIZE_1GB) {
> > -        if (IndexOfPml4Entries == 0 && IndexOfPageDirectoryEntries < 4) {
> > -          //
> > -          // Skip the < 4G entries
> > -          //
> > -          continue;
> > -        }
> > -        //
> > -        // Fill in the Page Directory entries
> > -        //
> > -        *PageDirectory1GEntry = PageAddress | mAddressEncMask |
> > IA32_PG_PS | PAGE_ATTRIBUTE_BITS;
> > +    for (IndexOfPml4Entries = 0; IndexOfPml4Entries <
> > (NumberOfPml5EntriesNeeded == 1 ? NumberOfPml4EntriesNeeded : 512);
> > IndexOfPml4Entries++, PageMapLevel4Entry++) {
> > +      //
> > +      // Each PML4 entry points to a page of Page Directory Pointer
> > entries.
> > +      //
> > +      PageDirectoryPointerEntry = (UINT64 *) ((*PageMapLevel4Entry) &
> > ~mAddressEncMask & gPhyMask);
> > +      if (PageDirectoryPointerEntry == NULL) {
> > +        PageDirectoryPointerEntry = AllocatePageTableMemory (1);
> > +        ASSERT(PageDirectoryPointerEntry != NULL);
> > +        ZeroMem (PageDirectoryPointerEntry, EFI_PAGES_TO_SIZE(1));
> > +
> > +        *PageMapLevel4Entry =
> > (UINT64)(UINTN)PageDirectoryPointerEntry | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS;
> >        }
> > -    } else {
> > -      PageAddress = BASE_4GB;
> > -      for (IndexOfPdpEntries = 0; IndexOfPdpEntries <
> > NumberOfPdpEntriesNeeded; IndexOfPdpEntries++,
> > PageDirectoryPointerEntry++) {
> > -        if (IndexOfPml4Entries == 0 && IndexOfPdpEntries < 4) {
> > -          //
> > -          // Skip the < 4G entries
> > -          //
> > -          continue;
> > -        }
> > -        //
> > -        // Each Directory Pointer entries points to a page of Page
> > Directory entires.
> > -        // So allocate space for them and fill them in in the
> > IndexOfPageDirectoryEntries loop.
> > -        //
> > -        PageDirectoryEntry = (UINT64 *) ((*PageDirectoryPointerEntry) &
> > ~mAddressEncMask & gPhyMask);
> > -        if (PageDirectoryEntry == NULL) {
> > -          PageDirectoryEntry = AllocatePageTableMemory (1);
> > -          ASSERT(PageDirectoryEntry != NULL);
> > -          ZeroMem (PageDirectoryEntry, EFI_PAGES_TO_SIZE(1));
> >
> > +      if (m1GPageTableSupport) {
> > +        PageDirectory1GEntry = PageDirectoryPointerEntry;
> > +        for (IndexOfPageDirectoryEntries = 0;
> > IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++,
> > PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
> > +          if (IndexOfPml4Entries == 0 && IndexOfPageDirectoryEntries <
> > 4) {
> > +            //
> > +            // Skip the < 4G entries
> > +            //
> > +            continue;
> > +          }
> >            //
> > -          // Fill in a Page Directory Pointer Entries
> > +          // Fill in the Page Directory entries
> >            //
> > -          *PageDirectoryPointerEntry =
> > (UINT64)(UINTN)PageDirectoryEntry | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS;
> > +          *PageDirectory1GEntry = PageAddress | mAddressEncMask |
> > IA32_PG_PS | PAGE_ATTRIBUTE_BITS;
> >          }
> > -
> > -        for (IndexOfPageDirectoryEntries = 0;
> > IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++,
> > PageDirectoryEntry++, PageAddress += SIZE_2MB) {
> > +      } else {
> > +        PageAddress = BASE_4GB;
> > +        for (IndexOfPdpEntries = 0; IndexOfPdpEntries <
> > (NumberOfPml4EntriesNeeded == 1 ? NumberOfPdpEntriesNeeded : 512);
> > IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
> > +          if (IndexOfPml4Entries == 0 && IndexOfPdpEntries < 4) {
> > +            //
> > +            // Skip the < 4G entries
> > +            //
> > +            continue;
> > +          }
> >            //
> > -          // Fill in the Page Directory entries
> > +          // Each Directory Pointer entries points to a page of Page
> > Directory entires.
> > +          // So allocate space for them and fill them in in the
> > IndexOfPageDirectoryEntries loop.
> >            //
> > -          *PageDirectoryEntry = PageAddress | mAddressEncMask |
> > IA32_PG_PS | PAGE_ATTRIBUTE_BITS;
> > +          PageDirectoryEntry = (UINT64 *) ((*PageDirectoryPointerEntry)
> > & ~mAddressEncMask & gPhyMask);
> > +          if (PageDirectoryEntry == NULL) {
> > +            PageDirectoryEntry = AllocatePageTableMemory (1);
> > +            ASSERT(PageDirectoryEntry != NULL);
> > +            ZeroMem (PageDirectoryEntry, EFI_PAGES_TO_SIZE(1));
> > +
> > +            //
> > +            // Fill in a Page Directory Pointer Entries
> > +            //
> > +            *PageDirectoryPointerEntry =
> > (UINT64)(UINTN)PageDirectoryEntry | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS;
> > +          }
> > +
> > +          for (IndexOfPageDirectoryEntries = 0;
> > IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++,
> > PageDirectoryEntry++, PageAddress += SIZE_2MB) {
> > +            //
> > +            // Fill in the Page Directory entries
> > +            //
> > +            *PageDirectoryEntry = PageAddress | mAddressEncMask |
> > IA32_PG_PS | PAGE_ATTRIBUTE_BITS;
> > +          }
> >          }
> >        }
> >      }
> > @@ -259,6 +325,8 @@ SmmInitPageTable (
> >    UINTN
> > PageFaultHandlerHookAddress;
> >    IA32_IDT_GATE_DESCRIPTOR          *IdtEntry;
> >    EFI_STATUS                        Status;
> > +  UINT64                            *Pml4Entry;
> > +  UINT64                            *Pml5Entry;
> >
> >    //
> >    // Initialize spin lock
> > @@ -266,12 +334,13 @@ SmmInitPageTable (
> >    InitializeSpinLock (mPFLock);
> >
> >    mCpuSmmStaticPageTable = PcdGetBool (PcdCpuSmmStaticPageTable);
> > -  m1GPageTableSupport = Is1GPageSupport ();
> > -  DEBUG ((DEBUG_INFO, "1GPageTableSupport - 0x%x\n",
> > m1GPageTableSupport));
> > -  DEBUG ((DEBUG_INFO, "PcdCpuSmmStaticPageTable - 0x%x\n",
> > mCpuSmmStaticPageTable));
> > -
> > -  mPhysicalAddressBits = CalculateMaximumSupportAddress ();
> > -  DEBUG ((DEBUG_INFO, "PhysicalAddressBits - 0x%x\n",
> > mPhysicalAddressBits));
> > +  m1GPageTableSupport    = Is1GPageSupport ();
> > +  m5LevelPagingSupport   = Is5LevelPagingSupport ();
> > +  mPhysicalAddressBits   = CalculateMaximumSupportAddress ();
> > +  DEBUG ((DEBUG_INFO, "5LevelPaging Support     - %d\n",
> > m5LevelPagingSupport));
> > +  DEBUG ((DEBUG_INFO, "1GPageTable Support      - %d\n",
> > m1GPageTableSupport));
> > +  DEBUG ((DEBUG_INFO, "PcdCpuSmmStaticPageTable - %d\n",
> > mCpuSmmStaticPageTable));
> > +  DEBUG ((DEBUG_INFO, "PhysicalAddressBits      - %d\n",
> > mPhysicalAddressBits));
> >    //
> >    // Generate PAE page table for the first 4GB memory space
> >    //
> > @@ -288,15 +357,30 @@ SmmInitPageTable (
> >    //
> >    // Fill Page-Table-Level4 (PML4) entry
> >    //
> > -  PTEntry = (UINT64*)AllocatePageTableMemory (1);
> > -  ASSERT (PTEntry != NULL);
> > -  *PTEntry = Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS;
> > -  ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));
> > +  Pml4Entry = (UINT64*)AllocatePageTableMemory (1);
> > +  ASSERT (Pml4Entry != NULL);
> > +  *Pml4Entry = Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS;
> > +  ZeroMem (Pml4Entry + 1, EFI_PAGE_SIZE - sizeof (*Pml4Entry));
> >
> >    //
> >    // Set sub-entries number
> >    //
> > -  SetSubEntriesNum (PTEntry, 3);
> > +  SetSubEntriesNum (Pml4Entry, 3);
> > +  PTEntry = Pml4Entry;
> > +
> > +  if (m5LevelPagingSupport) {
> > +    //
> > +    // Fill PML5 entry
> > +    //
> > +    Pml5Entry = (UINT64*)AllocatePageTableMemory (1);
> > +    *Pml5Entry = (UINTN) Pml4Entry | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS;
> > +    ZeroMem (Pml5Entry + 1, EFI_PAGE_SIZE - sizeof (*Pml5Entry));
> > +    //
> > +    // Set sub-entries number
> > +    //
> > +    SetSubEntriesNum (Pml5Entry, 1);
> > +    PTEntry = Pml5Entry;
> > +  }
> >
> >    if (mCpuSmmStaticPageTable) {
> >      SetStaticPageTable ((UINTN)PTEntry);
> > @@ -344,7 +428,7 @@ SmmInitPageTable (
> >    }
> >
> >    //
> > -  // Return the address of PML4 (to set CR3)
> > +  // Return the address of PML4/PML5 (to set CR3)
> >    //
> >    return (UINT32)(UINTN)PTEntry;
> >  }
> > @@ -436,12 +520,16 @@ ReclaimPages (
> >    VOID
> >    )
> >  {
> > +  UINT64                       Pml5Entry;
> > +  UINT64                       *Pml5;
> >    UINT64                       *Pml4;
> >    UINT64                       *Pdpt;
> >    UINT64                       *Pdt;
> > +  UINTN                        Pml5Index;
> >    UINTN                        Pml4Index;
> >    UINTN                        PdptIndex;
> >    UINTN                        PdtIndex;
> > +  UINTN                        MinPml5;
> >    UINTN                        MinPml4;
> >    UINTN                        MinPdpt;
> >    UINTN                        MinPdt;
> > @@ -451,120 +539,147 @@ ReclaimPages (
> >    BOOLEAN                      PML4EIgnore;
> >    BOOLEAN                      PDPTEIgnore;
> >    UINT64                       *ReleasePageAddress;
> > +  IA32_CR4                     Cr4;
> > +  BOOLEAN                      Enable5LevelPaging;
> >
> >    Pml4 = NULL;
> >    Pdpt = NULL;
> >    Pdt  = NULL;
> >    MinAcc  = (UINT64)-1;
> >    MinPml4 = (UINTN)-1;
> > +  MinPml5 = (UINTN)-1;
> >    MinPdpt = (UINTN)-1;
> >    MinPdt  = (UINTN)-1;
> >    Acc     = 0;
> >    ReleasePageAddress = 0;
> >
> > +  Cr4.UintN = AsmReadCr4 ();
> > +  Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
> > +  Pml5 = (UINT64*)(UINTN)(AsmReadCr3 () & gPhyMask);
> > +
> > +  if (!Enable5LevelPaging) {
> > +    //
> > +    // Create one fake PML5 entry for 4-Level Paging
> > +    // so that the page table parsing logic only handles 5-Level page
> > structure.
> > +    //
> > +    Pml5Entry = (UINTN) Pml5 | IA32_PG_P;
> > +    Pml5 = &Pml5Entry;
> > +  }
> > +
> >    //
> >    // First, find the leaf entry has the smallest access record value
> >    //
> > -  Pml4 = (UINT64*)(UINTN)(AsmReadCr3 () & gPhyMask);
> > -  for (Pml4Index = 0; Pml4Index < EFI_PAGE_SIZE / sizeof (*Pml4);
> > Pml4Index++) {
> > -    if ((Pml4[Pml4Index] & IA32_PG_P) == 0 || (Pml4[Pml4Index] &
> > IA32_PG_PMNT) != 0) {
> > +  for (Pml5Index = 0; Pml5Index < Enable5LevelPaging ? (EFI_PAGE_SIZE /
> > sizeof (*Pml4)) : 1; Pml5Index++) {
> > +    if ((Pml5[Pml5Index] & IA32_PG_P) == 0 || (Pml5[Pml5Index] &
> > IA32_PG_PMNT) != 0) {
> >        //
> > -      // If the PML4 entry is not present or is masked, skip it
> > +      // If the PML5 entry is not present or is masked, skip it
> >        //
> >        continue;
> >      }
> > -    Pdpt = (UINT64*)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask &
> > gPhyMask);
> > -    PML4EIgnore = FALSE;
> > -    for (PdptIndex = 0; PdptIndex < EFI_PAGE_SIZE / sizeof (*Pdpt);
> > PdptIndex++) {
> > -      if ((Pdpt[PdptIndex] & IA32_PG_P) == 0 || (Pdpt[PdptIndex] &
> > IA32_PG_PMNT) != 0) {
> > +    Pml4 = (UINT64*)(UINTN)(Pml5[Pml5Index] & gPhyMask);
> > +    for (Pml4Index = 0; Pml4Index < EFI_PAGE_SIZE / sizeof (*Pml4);
> > Pml4Index++) {
> > +      if ((Pml4[Pml4Index] & IA32_PG_P) == 0 || (Pml4[Pml4Index] &
> > IA32_PG_PMNT) != 0) {
> >          //
> > -        // If the PDPT entry is not present or is masked, skip it
> > +        // If the PML4 entry is not present or is masked, skip it
> >          //
> > -        if ((Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) {
> > -          //
> > -          // If the PDPT entry is masked, we will ignore checking the
> > PML4 entry
> > -          //
> > -          PML4EIgnore = TRUE;
> > -        }
> >          continue;
> >        }
> > -      if ((Pdpt[PdptIndex] & IA32_PG_PS) == 0) {
> > -        //
> > -        // It's not 1-GByte pages entry, it should be a PDPT entry,
> > -        // we will not check PML4 entry more
> > -        //
> > -        PML4EIgnore = TRUE;
> > -        Pdt =  (UINT64*)(UINTN)(Pdpt[PdptIndex] & ~mAddressEncMask
> > & gPhyMask);
> > -        PDPTEIgnore = FALSE;
> > -        for (PdtIndex = 0; PdtIndex < EFI_PAGE_SIZE / sizeof(*Pdt);
> > PdtIndex++) {
> > -          if ((Pdt[PdtIndex] & IA32_PG_P) == 0 || (Pdt[PdtIndex] &
> > IA32_PG_PMNT) != 0) {
> > +      Pdpt = (UINT64*)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask &
> > gPhyMask);
> > +      PML4EIgnore = FALSE;
> > +      for (PdptIndex = 0; PdptIndex < EFI_PAGE_SIZE / sizeof (*Pdpt);
> > PdptIndex++) {
> > +        if ((Pdpt[PdptIndex] & IA32_PG_P) == 0 || (Pdpt[PdptIndex] &
> > IA32_PG_PMNT) != 0) {
> > +          //
> > +          // If the PDPT entry is not present or is masked, skip it
> > +          //
> > +          if ((Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) {
> >              //
> > -            // If the PD entry is not present or is masked, skip it
> > +            // If the PDPT entry is masked, we will ignore checking the
> > PML4 entry
> >              //
> > -            if ((Pdt[PdtIndex] & IA32_PG_PMNT) != 0) {
> > +            PML4EIgnore = TRUE;
> > +          }
> > +          continue;
> > +        }
> > +        if ((Pdpt[PdptIndex] & IA32_PG_PS) == 0) {
> > +          //
> > +          // It's not 1-GByte pages entry, it should be a PDPT entry,
> > +          // we will not check PML4 entry more
> > +          //
> > +          PML4EIgnore = TRUE;
> > +          Pdt = (UINT64*)(UINTN)(Pdpt[PdptIndex] &
> > ~mAddressEncMask & gPhyMask);
> > +          PDPTEIgnore = FALSE;
> > +          for (PdtIndex = 0; PdtIndex < EFI_PAGE_SIZE / sizeof(*Pdt);
> > PdtIndex++) {
> > +            if ((Pdt[PdtIndex] & IA32_PG_P) == 0 || (Pdt[PdtIndex] &
> > IA32_PG_PMNT) != 0) {
> > +              //
> > +              // If the PD entry is not present or is masked, skip it
> > +              //
> > +              if ((Pdt[PdtIndex] & IA32_PG_PMNT) != 0) {
> > +                //
> > +                // If the PD entry is masked, we will not PDPT entry
> > more
> > +                //
> > +                PDPTEIgnore = TRUE;
> > +              }
> > +              continue;
> > +            }
> > +            if ((Pdt[PdtIndex] & IA32_PG_PS) == 0) {
> >                //
> > -              // If the PD entry is masked, we will not PDPT entry more
> > +              // It's not 2 MByte page table entry, it should be PD entry
> > +              // we will find the entry has the smallest access record
> > value
> >                //
> >                PDPTEIgnore = TRUE;
> > +              Acc = GetAndUpdateAccNum (Pdt + PdtIndex);
> > +              if (Acc < MinAcc) {
> > +                //
> > +                // If the PD entry has the smallest access record value,
> > +                // save the Page address to be released
> > +                //
> > +                MinAcc  = Acc;
> > +                MinPml5 = Pml5Index;
> > +                MinPml4 = Pml4Index;
> > +                MinPdpt = PdptIndex;
> > +                MinPdt  = PdtIndex;
> > +                ReleasePageAddress = Pdt + PdtIndex;
> > +              }
> >              }
> > -            continue;
> >            }
> > -          if ((Pdt[PdtIndex] & IA32_PG_PS) == 0) {
> > +          if (!PDPTEIgnore) {
> >              //
> > -            // It's not 2 MByte page table entry, it should be PD entry
> > -            // we will find the entry has the smallest access record value
> > +            // If this PDPT entry has no PDT entries pointer to 4 KByte
> > pages,
> > +            // it should only has the entries point to 2 MByte Pages
> >              //
> > -            PDPTEIgnore = TRUE;
> > -            Acc = GetAndUpdateAccNum (Pdt + PdtIndex);
> > +            Acc = GetAndUpdateAccNum (Pdpt + PdptIndex);
> >              if (Acc < MinAcc) {
> >                //
> > -              // If the PD entry has the smallest access record value,
> > +              // If the PDPT entry has the smallest access record value,
> >                // save the Page address to be released
> >                //
> >                MinAcc  = Acc;
> > +              MinPml5 = Pml5Index;
> >                MinPml4 = Pml4Index;
> >                MinPdpt = PdptIndex;
> > -              MinPdt  = PdtIndex;
> > -              ReleasePageAddress = Pdt + PdtIndex;
> > +              MinPdt  = (UINTN)-1;
> > +              ReleasePageAddress = Pdpt + PdptIndex;
> >              }
> >            }
> >          }
> > -        if (!PDPTEIgnore) {
> > -          //
> > -          // If this PDPT entry has no PDT entries pointer to 4 KByte
> > pages,
> > -          // it should only has the entries point to 2 MByte Pages
> > -          //
> > -          Acc = GetAndUpdateAccNum (Pdpt + PdptIndex);
> > -          if (Acc < MinAcc) {
> > -            //
> > -            // If the PDPT entry has the smallest access record value,
> > -            // save the Page address to be released
> > -            //
> > -            MinAcc  = Acc;
> > -            MinPml4 = Pml4Index;
> > -            MinPdpt = PdptIndex;
> > -            MinPdt  = (UINTN)-1;
> > -            ReleasePageAddress = Pdpt + PdptIndex;
> > -          }
> > -        }
> >        }
> > -    }
> > -    if (!PML4EIgnore) {
> > -      //
> > -      // If PML4 entry has no the PDPT entry pointer to 2 MByte pages,
> > -      // it should only has the entries point to 1 GByte Pages
> > -      //
> > -      Acc = GetAndUpdateAccNum (Pml4 + Pml4Index);
> > -      if (Acc < MinAcc) {
> > +      if (!PML4EIgnore) {
> >          //
> > -        // If the PML4 entry has the smallest access record value,
> > -        // save the Page address to be released
> > +        // If PML4 entry has no the PDPT entry pointer to 2 MByte pages,
> > +        // it should only has the entries point to 1 GByte Pages
> >          //
> > -        MinAcc  = Acc;
> > -        MinPml4 = Pml4Index;
> > -        MinPdpt = (UINTN)-1;
> > -        MinPdt  = (UINTN)-1;
> > -        ReleasePageAddress = Pml4 + Pml4Index;
> > +        Acc = GetAndUpdateAccNum (Pml4 + Pml4Index);
> > +        if (Acc < MinAcc) {
> > +          //
> > +          // If the PML4 entry has the smallest access record value,
> > +          // save the Page address to be released
> > +          //
> > +          MinAcc  = Acc;
> > +          MinPml5 = Pml5Index;
> > +          MinPml4 = Pml4Index;
> > +          MinPdpt = (UINTN)-1;
> > +          MinPdt  = (UINTN)-1;
> > +          ReleasePageAddress = Pml4 + Pml4Index;
> > +        }
> >        }
> >      }
> >    }
> > @@ -588,6 +703,7 @@ ReclaimPages (
> >        //
> >        // If 4 KByte Page Table is released, check the PDPT entry
> >        //
> > +      Pml4 = (UINT64 *) (UINTN) (Pml5[MinPml5] & gPhyMask);
> >        Pdpt = (UINT64*)(UINTN)(Pml4[MinPml4] & ~mAddressEncMask &
> > gPhyMask);
> >        SubEntriesNum = GetSubEntriesNum(Pdpt + MinPdpt);
> >        if (SubEntriesNum == 0) {
> > @@ -679,7 +795,7 @@ SmiDefaultPFHandler (
> >    )
> >  {
> >    UINT64                            *PageTable;
> > -  UINT64                            *Pml4;
> > +  UINT64                            *PageTableTop;
> >    UINT64                            PFAddress;
> >    UINTN                             StartBit;
> >    UINTN                             EndBit;
> > @@ -690,6 +806,8 @@ SmiDefaultPFHandler (
> >    UINTN                             PageAttribute;
> >    EFI_STATUS                        Status;
> >    UINT64                            *UpperEntry;
> > +  BOOLEAN                           Enable5LevelPaging;
> > +  IA32_CR4                          Cr4;
> >
> >    //
> >    // Set default SMM page attribute
> > @@ -699,9 +817,12 @@ SmiDefaultPFHandler (
> >    PageAttribute = 0;
> >
> >    EndBit = 0;
> > -  Pml4 = (UINT64*)(AsmReadCr3 () & gPhyMask);
> > +  PageTableTop = (UINT64*)(AsmReadCr3 () & gPhyMask);
> >    PFAddress = AsmReadCr2 ();
> >
> > +  Cr4.UintN = AsmReadCr4 ();
> > +  Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 != 0);
> > +
> >    Status = GetPlatformPageTableAttribute (PFAddress, &PageSize,
> > &NumOfPages, &PageAttribute);
> >    //
> >    // If platform not support page table attribute, set default SMM page
> > attribute
> > @@ -755,9 +876,9 @@ SmiDefaultPFHandler (
> >    }
> >
> >    for (Index = 0; Index < NumOfPages; Index++) {
> > -    PageTable  = Pml4;
> > +    PageTable  = PageTableTop;
> >      UpperEntry = NULL;
> > -    for (StartBit = 39; StartBit > EndBit; StartBit -= 9) {
> > +    for (StartBit = Enable5LevelPaging ? 48 : 39; StartBit > EndBit; StartBit
> > -= 9) {
> >        PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8);
> >        if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> >          //
> > @@ -941,13 +1062,20 @@ SetPageTableAttributes (
> >    UINTN                 Index2;
> >    UINTN                 Index3;
> >    UINTN                 Index4;
> > +  UINTN                 Index5;
> >    UINT64                *L1PageTable;
> >    UINT64                *L2PageTable;
> >    UINT64                *L3PageTable;
> >    UINT64                *L4PageTable;
> > +  UINT64                *L5PageTable;
> >    BOOLEAN               IsSplitted;
> >    BOOLEAN               PageTableSplitted;
> >    BOOLEAN               CetEnabled;
> > +  IA32_CR4              Cr4;
> > +  BOOLEAN               Enable5LevelPaging;
> > +
> > +  Cr4.UintN = AsmReadCr4 ();
> > +  Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
> >
> >    //
> >    // Don't do this if
> > @@ -991,44 +1119,59 @@ SetPageTableAttributes (
> >    do {
> >      DEBUG ((DEBUG_INFO, "Start...\n"));
> >      PageTableSplitted = FALSE;
> > -
> > -    L4PageTable = (UINT64 *)GetPageTableBase ();
> > -    SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L4PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> > -    PageTableSplitted = (PageTableSplitted || IsSplitted);
> > -
> > -    for (Index4 = 0; Index4 < SIZE_4KB/sizeof(UINT64); Index4++) {
> > -      L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > -      if (L3PageTable == NULL) {
> > -        continue;
> > -      }
> > -
> > -      SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> > +    L5PageTable = NULL;
> > +    if (Enable5LevelPaging) {
> > +      L5PageTable = (UINT64 *)GetPageTableBase ();
> > +      SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L5PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> >        PageTableSplitted = (PageTableSplitted || IsSplitted);
> > +    }
> >
> > -      for (Index3 = 0; Index3 < SIZE_4KB/sizeof(UINT64); Index3++) {
> > -        if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
> > -          // 1G
> > +    for (Index5 = 0; Index5 < (Enable5LevelPaging ?
> > SIZE_4KB/sizeof(UINT64) : 1); Index5++) {
> > +      if (Enable5LevelPaging) {
> > +        L4PageTable = (UINT64 *)(UINTN)(L5PageTable[Index5] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +        if (L4PageTable == NULL) {
> >            continue;
> >          }
> > -        L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > -        if (L2PageTable == NULL) {
> > +      } else {
> > +        L4PageTable = (UINT64 *)GetPageTableBase ();
> > +      }
> > +      SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L4PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> > +      PageTableSplitted = (PageTableSplitted || IsSplitted);
> > +
> > +      for (Index4 = 0; Index4 < SIZE_4KB/sizeof(UINT64); Index4++) {
> > +        L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +        if (L3PageTable == NULL) {
> >            continue;
> >          }
> >
> > -        SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> > +        SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> >          PageTableSplitted = (PageTableSplitted || IsSplitted);
> >
> > -        for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {
> > -          if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
> > -            // 2M
> > +        for (Index3 = 0; Index3 < SIZE_4KB/sizeof(UINT64); Index3++) {
> > +          if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
> > +            // 1G
> >              continue;
> >            }
> > -          L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > -          if (L1PageTable == NULL) {
> > +          L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +          if (L2PageTable == NULL) {
> >              continue;
> >            }
> > -          SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> > +
> > +          SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> >            PageTableSplitted = (PageTableSplitted || IsSplitted);
> > +
> > +          for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {
> > +            if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
> > +              // 2M
> > +              continue;
> > +            }
> > +            L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +            if (L1PageTable == NULL) {
> > +              continue;
> > +            }
> > +            SmmSetMemoryAttributesEx
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB,
> > EFI_MEMORY_RO, &IsSplitted);
> > +            PageTableSplitted = (PageTableSplitted || IsSplitted);
> > +          }
> >          }
> >        }
> >      }
> > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.nasm
> > b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.nasm
> > index 741e4b7da2..b5e0405b3b 100644
> > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.nasm
> > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.nasm
> > @@ -69,6 +69,7 @@ extern ASM_PFX(mXdSupported)
> >  global ASM_PFX(gPatchXdSupported)
> >  global ASM_PFX(gPatchSmiStack)
> >  global ASM_PFX(gPatchSmiCr3)
> > +global ASM_PFX(m5LevelPagingSupport)
> >  global ASM_PFX(gcSmiHandlerTemplate)
> >  global ASM_PFX(gcSmiHandlerSize)
> >
> > @@ -124,6 +125,17 @@ ProtFlatMode:
> >  ASM_PFX(gPatchSmiCr3):
> >      mov     cr3, rax
> >      mov     eax, 0x668                   ; as cr4.PGE is not set
> > here, refresh cr3
> > +
> > +    DB      0xb1                        ; mov cl,
> > m5LevelPagingSupport
> > +ASM_PFX(m5LevelPagingSupport): DB 0
> > +    cmp     cl, 0
> > +    je      SkipEnable5LevelPaging
> > +    ;
> > +    ; Enable 5-Level Paging bit
> > +    ;
> > +    bts     eax, 12                     ; Set LA57 bit (bit #12)
> > +SkipEnable5LevelPaging:
> > +
> >      mov     cr4, rax                    ; in PreModifyMtrrs() to
> > flush TLB.
> >  ; Load TSS
> >      sub     esp, 8                      ; reserve room in stack
> > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c
> > b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c
> > index e7c78d36fc..63bae5a913 100644
> > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c
> > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmProfileArch.c
> > @@ -1,7 +1,7 @@
> >  /** @file
> >  X64 processor specific functions to enable SMM profile.
> >
> > -Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
> > +Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
> >  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> >
> >  SPDX-License-Identifier: BSD-2-Clause-Patent
> > @@ -147,9 +147,14 @@ RestorePageTableAbove4G (
> >    BOOLEAN       Existed;
> >    UINTN         Index;
> >    UINTN         PFIndex;
> > +  IA32_CR4      Cr4;
> > +  BOOLEAN       Enable5LevelPaging;
> >
> >    ASSERT ((PageTable != NULL) && (IsValidPFAddress != NULL));
> >
> > +  Cr4.UintN = AsmReadCr4 ();
> > +  Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
> > +
> >    //
> >    // If page fault address is 4GB above.
> >    //
> > @@ -161,38 +166,48 @@ RestorePageTableAbove4G (
> >    //
> >    Existed = FALSE;
> >    PageTable = (UINT64*)(AsmReadCr3 () & PHYSICAL_ADDRESS_MASK);
> > -  PTIndex = BitFieldRead64 (PFAddress, 39, 47);
> > -  if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
> > -    // PML4E
> > -    PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
> > -    PTIndex = BitFieldRead64 (PFAddress, 30, 38);
> > +  PTIndex = 0;
> > +  if (Enable5LevelPaging) {
> > +    PTIndex = BitFieldRead64 (PFAddress, 48, 56);
> > +  }
> > +  if ((!Enable5LevelPaging) || ((PageTable[PTIndex] & IA32_PG_P) != 0)) {
> > +    // PML5E
> > +    if (Enable5LevelPaging) {
> > +      PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
> > +    }
> > +    PTIndex = BitFieldRead64 (PFAddress, 39, 47);
> >      if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
> > -      // PDPTE
> > +      // PML4E
> >        PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
> > -      PTIndex = BitFieldRead64 (PFAddress, 21, 29);
> > -      // PD
> > -      if ((PageTable[PTIndex] & IA32_PG_PS) != 0) {
> > -        //
> > -        // 2MB page
> > -        //
> > -        Address = (UINT64)(PageTable[PTIndex] & ~mAddressEncMask &
> > PHYSICAL_ADDRESS_MASK);
> > -        if ((Address & ~((1ull << 21) - 1)) == ((PFAddress &
> > PHYSICAL_ADDRESS_MASK & ~((1ull << 21) - 1)))) {
> > -          Existed = TRUE;
> > -        }
> > -      } else {
> > -        //
> > -        // 4KB page
> > -        //
> > -        PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > ~mAddressEncMask& PHYSICAL_ADDRESS_MASK);
> > -        if (PageTable != 0) {
> > +      PTIndex = BitFieldRead64 (PFAddress, 30, 38);
> > +      if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
> > +        // PDPTE
> > +        PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
> > +        PTIndex = BitFieldRead64 (PFAddress, 21, 29);
> > +        // PD
> > +        if ((PageTable[PTIndex] & IA32_PG_PS) != 0) {
> >            //
> > -          // When there is a valid entry to map to 4KB page, need not
> > create a new entry to map 2MB.
> > +          // 2MB page
> >            //
> > -          PTIndex = BitFieldRead64 (PFAddress, 12, 20);
> >            Address = (UINT64)(PageTable[PTIndex] & ~mAddressEncMask
> > & PHYSICAL_ADDRESS_MASK);
> > -          if ((Address & ~((1ull << 12) - 1)) == (PFAddress &
> > PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1))) {
> > +          if ((Address & ~((1ull << 21) - 1)) == ((PFAddress &
> > PHYSICAL_ADDRESS_MASK & ~((1ull << 21) - 1)))) {
> >              Existed = TRUE;
> >            }
> > +        } else {
> > +          //
> > +          // 4KB page
> > +          //
> > +          PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > ~mAddressEncMask& PHYSICAL_ADDRESS_MASK);
> > +          if (PageTable != 0) {
> > +            //
> > +            // When there is a valid entry to map to 4KB page, need not
> > create a new entry to map 2MB.
> > +            //
> > +            PTIndex = BitFieldRead64 (PFAddress, 12, 20);
> > +            Address = (UINT64)(PageTable[PTIndex] &
> > ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
> > +            if ((Address & ~((1ull << 12) - 1)) == (PFAddress &
> > PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1))) {
> > +              Existed = TRUE;
> > +            }
> > +          }
> >          }
> >        }
> >      }
> > @@ -221,6 +236,11 @@ RestorePageTableAbove4G (
> >      //
> >      PageTable = (UINT64*)(AsmReadCr3 () & PHYSICAL_ADDRESS_MASK);
> >      PFAddress = AsmReadCr2 ();
> > +    // PML5E
> > +    if (Enable5LevelPaging) {
> > +      PTIndex = BitFieldRead64 (PFAddress, 48, 56);
> > +      PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
> > +    }
> >      // PML4E
> >      PTIndex = BitFieldRead64 (PFAddress, 39, 47);
> >      PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] &
> > ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
> > --
> > 2.21.0.windows.1
> >
> >
> > 


  reply	other threads:[~2019-06-28  7:27 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-28  6:46 [PATCH 0/3] Enable 5 level paging when CPU supports Ni, Ray
2019-06-28  6:46 ` [PATCH 1/3] UefiCpuPkg/PiSmmCpu: Change variable names and comments to follow SDM Ni, Ray
2019-06-28  6:46 ` [PATCH 2/3] MdePkg/BaseLib.h: Update IA32_CR4 structure for 5-level paging Ni, Ray
2019-06-28  6:47 ` [PATCH 3/3] UefiCpuPkg/PiSmmCpu: Enable 5 level paging when CPU supports Ni, Ray
2019-06-28  7:18   ` [edk2-devel] " Yao, Jiewen
2019-06-28  7:27     ` Ni, Ray [this message]
2019-06-28 15:32       ` Laszlo Ersek
2019-06-28 15:36   ` Laszlo Ersek
2019-07-01 12:44   ` Laszlo Ersek
2019-07-02 14:44     ` Ni, Ray
2019-07-02 15:18       ` Laszlo Ersek
2019-07-02 15:20         ` Laszlo Ersek
2019-07-03 10:08           ` 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=734D49CCEBEEF84792F5B80ED585239D5C1F4B96@SHSMSX104.ccr.corp.intel.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