diff --git a/UefiTestingPkg/Include/Library/FlatPageTableLib.h b/UefiTestingPkg/Include/Library/FlatPageTableLib.h
new file mode 100644
index 0000000000..a244a2c23e
--- /dev/null
+++ b/UefiTestingPkg/Include/Library/FlatPageTableLib.h
@@ -0,0 +1,166 @@
+/** @file
+  Library to parse page/translation table entries.
+
+  Copyright (c) Microsoft Corporation.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PAGE_TABLE_ATTRIBUTE_LIB_H_
+#define PAGE_TABLE_ATTRIBUTE_LIB_H_
+
+typedef struct {
+  UINT64    LinearAddress;
+  UINT64    Length;
+  UINT64    PageEntry;
+} PAGE_MAP_ENTRY;
+
+typedef struct {
+  UINT32            ArchSignature;
+  PAGE_MAP_ENTRY    *Entries;
+  UINTN             EntryCount;
+  UINTN             EntryPagesAllocated;
+} PAGE_MAP;
+
+// The signature of the PAGE_MAP struct is used to determine the architecture of the page/translation table
+// entries.
+#define AARCH64_PAGE_MAP_SIGNATURE  SIGNATURE_32 ('A','A','6','4')
+#define X64_PAGE_MAP_SIGNATURE      SIGNATURE_32 ('X','6','4',' ')
+
+// This union can be used to interpret each PAGE_MAP_ENTRY on an AARCH64 system.
+typedef union {
+  struct {
+    UINT64    Valid                      : 1;  // BIT0
+    UINT64    BlockOrTable               : 1;  // BIT1
+    UINT64    AttributeIndex             : 3;  // BIT2-4
+    UINT64    NonSecure                  : 1;  // BIT5
+    UINT64    AccessPermissions          : 2;  // BIT6-7
+    UINT64    Shareability               : 2;  // BIT8-9
+    UINT64    AccessFlag                 : 1;  // BIT10
+    UINT64    NonGlobal                  : 1;  // BIT11
+    UINT64    Oa                         : 4;  // BIT12-15
+    UINT64    Nt                         : 1;  // BIT16
+    UINT64    OutputAddress              : 33; // BIT17-49
+    UINT64    Guarded                    : 1;  // BIT50
+    UINT64    Dirty                      : 1;  // BIT51
+    UINT64    Contiguous                 : 1;  // BIT52
+    UINT64    Pxn                        : 1;  // BIT53
+    UINT64    Xn                         : 1;  // BIT54
+    UINT64    Ignored                    : 4;  // BIT55-58
+    UINT64    PageBasedHardwareAttribute : 4;  // BIT59-62
+    UINT64    Reserved                   : 1;  // BIT63
+  } Bits;
+  UINT64    Uint64;
+} AARCH64_PAGE_MAP_ENTRY;
+
+// This union can be used to interpret each PAGE_MAP_ENTRY on an X64 system.
+typedef union {
+  struct {
+    UINT64    Present              : 1;  // BIT0
+    UINT64    ReadWrite            : 1;  // BIT1
+    UINT64    UserSupervisor       : 1;  // BIT2
+    UINT64    WriteThrough         : 1;  // BIT3
+    UINT64    CacheDisabled        : 1;  // BIT4
+    UINT64    Accessed             : 1;  // BIT5
+    UINT64    Dirty                : 1;  // BIT6
+    UINT64    Pat                  : 1;  // BIT7
+    UINT64    Global               : 1;  // BIT8
+    UINT64    Reserved1            : 3;  // BIT9-11
+    UINT64    PageTableBaseAddress : 40; // BIT12-51
+    UINT64    Reserved2            : 7;  // BIT52-58
+    UINT64    ProtectionKey        : 4;  // BIT59-62
+    UINT64    Nx                   : 1;  // BIT63
+  } Bits;
+  UINT64    Uint64;
+} X64_PAGE_MAP_ENTRY;
+
+// When the page/translation table is parsed to create an array of PAGE_MAP_ENTRY, the following bitmasks
+// are used to determine the attributes of one page/translation table entry are the same as another
+// page/translation table entry. If contiguous leaf/block entries have the same attributes, then they
+// will be represented in a single PAGE_MAP_ENTRY.
+#define AARCH64_ATTRIBUTES_MASK  ((0xFFFULL << 52) | (0x3FFULL << 2))
+#define X64_ATTRIBUTES_MASK      ((0xFFFULL << 52) | 0xFFFULL)
+
+/**
+  Populate the input page/translation table map.
+
+  @param[in, out]      Map         Pointer to the PAGE_MAP struct to be populated.
+
+  @retval RETURN_SUCCESS           The translation table is parsed successfully.
+  @retval RETURN_INVALID_PARAMETER MapCount is NULL, or Map is NULL but *MapCount is nonzero.
+  @retval RETURN_BUFFER_TOO_SMALL  *MapCount is too small.
+                                   MapCount is updated to indicate the expected number of entries.
+                                   Caller may still get RETURN_BUFFER_TOO_SMALL with the new MapCount.
+**/
+EFI_STATUS
+EFIAPI
+CreateFlatPageTable (
+  IN OUT PAGE_MAP  *Map
+  );
+
+/**
+  Checks the input flat page/translation table for the input region and converts the associated
+  table entries to EFI access attributes.
+
+  @param[in]  Map                 Pointer to the PAGE_MAP struct to be parsed
+  @param[in]  Address             Start address of the region
+  @param[in]  Length              Length of the region
+  @param[out] Attributes          EFI Attributes of the region (EFI_MEMORY_XP, EFI_MEMORY_RO, EFI_MEMORY_RP)
+
+  @retval EFI_SUCCESS             The output Attributes is valid
+  @retval EFI_INVALID_PARAMETER   The flat translation table has not been built or
+                                  Attributes was NULL or Length was 0
+  @retval EFI_NOT_FOUND           The input region could not be found.
+**/
+EFI_STATUS
+EFIAPI
+GetRegionAccessAttributes (
+  IN PAGE_MAP  *Map,
+  IN UINT64    Address,
+  IN UINT64    Length,
+  OUT UINT64   *Attributes
+  );
+
+/**
+  Parses the input page to determine if it is writable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is writable.
+  @retval FALSE   The page is not writable.
+**/
+BOOLEAN
+EFIAPI
+IsPageWritable (
+  IN UINT64  Page
+  );
+
+/**
+  Parses the input page to determine if it is executable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is executable.
+  @retval FALSE   The page is not executable.
+**/
+BOOLEAN
+EFIAPI
+IsPageExecutable (
+  IN UINT64  Page
+  );
+
+/**
+  Parses the input page to determine if it is readable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is readable.
+  @retval FALSE   The page is not readable.
+**/
+BOOLEAN
+EFIAPI
+IsPageReadable (
+  IN UINT64  Page
+  );
+
+#endif
diff --git a/UefiTestingPkg/Library/FlatPageTableLib/AArch64/FlatPageTableAArch64.c b/UefiTestingPkg/Library/FlatPageTableLib/AArch64/FlatPageTableAArch64.c
new file mode 100644
index 0000000000..0350e2d4b2
--- /dev/null
+++ b/UefiTestingPkg/Library/FlatPageTableLib/AArch64/FlatPageTableAArch64.c
@@ -0,0 +1,371 @@
+/** @file
+  AArch64 specific page table attribute library functions.
+
+  Copyright (c) Microsoft Corporation.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/ArmLib.h>
+#include <Chipset/AArch64Mmu.h>
+#include <Library/DebugLib.h>
+#include <Library/FlatPageTableLib.h>
+
+#define TCR_EL1_HPD_FIELD             BIT41   // Assumes translation table is located at TTBR0 (UEFI spec dictated)
+#define TCR_EL2_HPD_FIELD             BIT24
+#define ID_AA64MMFR1_EL1_HPD_MASK     0xF000
+#define TT_HERITABLE_ATTRIBUTES_MASK  (TT_TABLE_AP_MASK | TT_TABLE_PXN | TT_TABLE_UXN)
+
+#define IS_VALID(page)                 ((page & 0x1) != 0)
+#define IS_TABLE(page, level)          ((level == 3) ? FALSE : (((page) & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY))
+#define IS_BLOCK(page, level)          ((level == 3) ? (((page) & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY_LEVEL3) : ((page & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY))
+#define ROOT_TABLE_LEN(T0SZ)           (TT_ENTRY_COUNT >> ((T0SZ) - 16) % 9)
+#define ARM_TT_BASE_ADDRESS(page)      (page & TT_ADDRESS_MASK_BLOCK_ENTRY)
+#define ARM_TT_BLOCK_ATTRIBUTES(page)  (page & AARCH64_ATTRIBUTES_MASK)
+
+typedef union {
+  struct {
+    UINT64    Valid           : 1;  // BIT0
+    UINT64    BlockOrTable    : 1;  // BIT1
+    UINT64    LowerAttributes : 10; // BIT2-11
+    UINT64    Address         : 36; // BIT12-47
+    UINT64    Reserved        : 3;  // BIT48-50
+    UINT64    Ignored         : 8;  // BIT51-58
+    UINT64    PxnTable        : 1;  // BIT59
+    UINT64    XnTable         : 1;  // BIT60
+    UINT64    ApTable         : 2;  // BIT61-62
+    UINT64    NsTable         : 1;  // BIT63
+  } Bits;
+  UINT64    Uint64;
+} TRANSLATION_TABLE_ENTRY_HERITABLE;
+
+typedef union {
+  struct {
+    UINT64    Valid           : 1;  // BIT0
+    UINT64    BlockOrTable    : 1;  // BIT1
+    UINT64    LowerAttributes : 10; // BIT2-11
+    UINT64    LevelZeroIndex  : 9;  // BIT12-20
+    UINT64    LevelOneIndex   : 9;  // BIT21-29
+    UINT64    LevelTwoIndex   : 9;  // BIT30-38
+    UINT64    LevelThreeIndex : 9;  // BIT39-47
+    UINT64    Reserved        : 3;  // BIT48-50
+    UINT64    Ignored         : 8;  // BIT51-58
+    UINT64    PxnTable        : 1;  // BIT59
+    UINT64    XnTable         : 1;  // BIT60
+    UINT64    ApTable         : 2;  // BIT61-62
+    UINT64    NsTable         : 1;  // BIT63
+  } Bits;
+  UINT64    Uint64;
+} TRANSLATION_TABLE_ENTRY_TABLE;
+
+typedef AARCH64_PAGE_MAP_ENTRY TRANSLATION_TABLE_ENTRY_BLOCK;
+
+typedef union {
+  TRANSLATION_TABLE_ENTRY_BLOCK        Tteb;
+  TRANSLATION_TABLE_ENTRY_TABLE        Ttet;
+  TRANSLATION_TABLE_ENTRY_HERITABLE    Tteh;
+  UINT64                               Uint64;
+} TRANSLATION_TABLE_ENTRY_UNION;
+
+STATIC BOOLEAN  mHierarchicalControlEnabled = FALSE;
+
+/**
+  Reads the ID_AA64MMFR1_EL1 special register.
+
+  @retval The UINT64 value of the ID_AA64MMFR1_EL1 special register.
+**/
+STATIC
+UINT64
+Asm_Read_ID_AA64MMFR1_EL1 (
+  VOID
+  )
+{
+  UINT64  value = 0;
+  __asm volatile ("mrs %0, ID_AA64MMFR1_EL1" : "=r" (value) ::);
+
+  return value;
+}
+
+/**
+  Checks the ID_AA64MMFR1_EL1 and TCR special registers to see if hierarchical control is enabled.
+
+  Function was derived from Armv8 A Architecture Manual version H.a
+  Section 13.2.65: "ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1"
+  Section D13.2.131: TCR_EL1, Translation Control Register (EL1)
+  Section D13.2.132: TCR_EL2, Translation Control Register (EL2)
+
+  @retval TRUE  Hierarchical control is enabled.
+  @retval FALSE Hierarchical control is disabled.
+**/
+STATIC
+BOOLEAN
+IsHierarchicalControlEnabled (
+  VOID
+  )
+{
+  return ((Asm_Read_ID_AA64MMFR1_EL1 () & ID_AA64MMFR1_EL1_HPD_MASK) != 0) &&
+         ((ArmReadCurrentEL () == AARCH64_EL2) ? (ArmGetTCR () & TCR_EL2_HPD_FIELD) == 0 :
+          (ArmGetTCR () & TCR_EL1_HPD_FIELD) == 0);
+}
+
+/**
+  Recursively parse the translation table and populate the entries in the input Map.
+
+  @param[in]      PageTableBaseAddress        The base address of the 512 page table entries in the specified level
+  @param[in]      Level                       Page level (0, 1, 2, 3)
+  @param[in]      RegionStart                 The base linear address of the region covered by the page table entries
+  @param[in]      ParentHeritableAttributes    The heritable attributes of parent table entries.
+  @param[in, out] Map                         Pointer to an array that describes multiple linear address ranges.
+  @param[in, out] MapCount                    Pointer to a UINTN that hold the actual number of entries in the Map.
+  @param[in]      MapCapacity                 The maximum number of entries the Map can hold.
+  @param[in]      LastEntry                   Pointer to last map entry.
+  @param[in]      OneEntry                    Pointer to a library internal storage that holds one map entry which is
+                                              used when Map array is at capacity.
+**/
+STATIC
+VOID
+TranslationTableParseRecursive (
+  IN     UINT64                             PageTableBaseAddress,
+  IN     UINTN                              Level,
+  IN     UINT64                             RegionStart,
+  IN     TRANSLATION_TABLE_ENTRY_HERITABLE  ParentHeritableAttributes,
+  IN OUT PAGE_MAP_ENTRY                     *Map,
+  IN OUT UINTN                              *MapCount,
+  IN     UINTN                              MapCapacity,
+  IN     PAGE_MAP_ENTRY                     **LastEntry,
+  IN     PAGE_MAP_ENTRY                     *OneEntry
+  )
+{
+  TRANSLATION_TABLE_ENTRY_UNION  *PagingEntry;
+  UINTN                          Index;
+  TRANSLATION_TABLE_ENTRY_UNION  ScratchEntry;
+  UINT64                         RegionLength;
+  UINTN                          EntryCount;
+
+  if ((OneEntry == NULL) || (MapCount == NULL)) {
+    return;
+  }
+
+  PagingEntry  = (TRANSLATION_TABLE_ENTRY_UNION *)(UINTN)PageTableBaseAddress;
+  RegionLength = TT_BLOCK_ENTRY_SIZE_AT_LEVEL (Level);
+  if (Level == 0) {
+    EntryCount = ROOT_TABLE_LEN (ArmGetTCR () & TCR_T0SZ_MASK);
+  } else {
+    EntryCount = TT_ENTRY_COUNT;
+  }
+
+  for (Index = 0; Index < EntryCount; Index++, RegionStart += RegionLength) {
+    // Skip unmapped entries
+    if (!IS_VALID (PagingEntry[Index].Uint64)) {
+      continue;
+    }
+
+    if (IS_BLOCK (PagingEntry[Index].Uint64, Level)) {
+      // FUTURE WORK: Should we check the feature register to see if blocks are allowed at level 1?
+      ASSERT (Level == 1 || Level == 2 || Level == 3);
+
+      ScratchEntry.Uint64 = PagingEntry[Index].Tteb.Uint64;
+
+      // If the entry is a block, then then some access attributes are inherited from the parent
+      // when FEAT_HPDS is active
+      if (mHierarchicalControlEnabled) {
+        // Check if the parent table entry has XnTable bits to pass down to the block entry.
+        //
+        // This logic was derived from the Armv8 A Architecture Manual version H.a
+        // Section D5.4.5: Data access permission controls
+        // Subsection: Hierarchical control of instruction fetching
+        //
+        // If in EL2, only the XN bit is valid
+        if ((ArmReadCurrentEL () == AARCH64_EL2) && (ParentHeritableAttributes.Bits.XnTable != 0)) {
+          ScratchEntry.Tteb.Bits.Xn = 1;
+        }
+        // if in EL1, both UXN and PXN bits are valid
+        else if ((ArmReadCurrentEL () == AARCH64_EL1)) {
+          // Xn is Uxn for EL1
+          if (ParentHeritableAttributes.Bits.XnTable != 0) {
+            ScratchEntry.Tteb.Bits.Xn = 1;
+          }
+
+          if (ParentHeritableAttributes.Bits.PxnTable != 0) {
+            ScratchEntry.Tteb.Bits.Pxn = 1;
+          }
+        }
+
+        // Check if the parent table entry has ApTable bits to pass down to the block entry
+        //
+        // This logic was derived from the Armv8 A Architecture Manual version H.a
+        // Section D5.4.5: Data access permission controls
+        // Subsection: Hierarchical control of data access permissions
+        //
+        // 0b01 -> Access from EL0 is not allowed, no effect on write permissions
+        if ((ParentHeritableAttributes.Bits.ApTable & TT_TABLE_AP_MASK) == TT_TABLE_AP_EL0_NO_ACCESS) {
+          // BIT6 toggles access from EL0
+          ScratchEntry.Tteb.Bits.AccessPermissions &= ~((UINT64)BIT6); // Clear BIT6
+          // 0b10 -> Access from EL0 is read-only, no write permissions at any EL
+        } else if ((ParentHeritableAttributes.Bits.ApTable & TT_TABLE_AP_MASK) == TT_TABLE_AP_NO_WRITE_ACCESS) {
+          // BIT7 toggles write access for all ELs
+          ScratchEntry.Tteb.Bits.AccessPermissions |= BIT7; // Set BIT7
+          // 0b11 -> Access from EL0 is not allowed, no write permissions at any EL
+        } else if ((ParentHeritableAttributes.Bits.ApTable & TT_TABLE_AP_MASK) == TT_TABLE_AP_MASK) {
+          ScratchEntry.Tteb.Bits.AccessPermissions |= BIT7;            // Set BIT7
+          ScratchEntry.Tteb.Bits.AccessPermissions &= ~((UINT64)BIT6); // Clear BIT6
+        }
+      }
+
+      if ((*LastEntry != NULL) &&
+          ((*LastEntry)->LinearAddress + (*LastEntry)->Length == RegionStart) &&
+          (ARM_TT_BASE_ADDRESS ((*LastEntry)->PageEntry) + (*LastEntry)->Length
+           == ARM_TT_BASE_ADDRESS (ScratchEntry.Uint64)) &&
+          (ARM_TT_BLOCK_ATTRIBUTES ((*LastEntry)->PageEntry) == ARM_TT_BLOCK_ATTRIBUTES (ScratchEntry.Uint64))
+          )
+      {
+        // Extend LastEntry.
+        (*LastEntry)->Length += RegionLength;
+      } else {
+        if (*MapCount < MapCapacity) {
+          // LastEntry points to next map entry in the array.
+          *LastEntry = &Map[*MapCount];
+        } else {
+          // LastEntry points to library internal map entry.
+          *LastEntry = OneEntry;
+        }
+
+        // Set LastEntry.
+        (*LastEntry)->LinearAddress = RegionStart;
+        (*LastEntry)->Length        = RegionLength;
+        (*LastEntry)->PageEntry     = ScratchEntry.Uint64;
+        (*MapCount)++;
+      }
+    } else {
+      ScratchEntry.Uint64 = PagingEntry[Index].Ttet.Uint64 & TT_HERITABLE_ATTRIBUTES_MASK;
+      // If the entry is a table and not the root, then pass the heritable access attributes
+      // from the parent.
+      if (Level > 0) {
+        ScratchEntry.Uint64 |= (ParentHeritableAttributes.Uint64 & TT_HERITABLE_ATTRIBUTES_MASK);
+      }
+
+      TranslationTableParseRecursive (
+        ARM_TT_BASE_ADDRESS (PagingEntry[Index].Ttet.Uint64),
+        Level + 1,
+        RegionStart,
+        ScratchEntry.Tteh,
+        Map,
+        MapCount,
+        MapCapacity,
+        LastEntry,
+        OneEntry
+        );
+    }
+  }
+}
+
+/**
+  Populate the input page/translation table map.
+
+  @param[in, out]      Map         Pointer to the PAGE_MAP struct to be populated.
+
+  @retval RETURN_SUCCESS           The translation table is parsed successfully.
+  @retval RETURN_INVALID_PARAMETER MapCount is NULL, or Map is NULL but *MapCount is nonzero.
+  @retval RETURN_BUFFER_TOO_SMALL  *MapCount is too small.
+                                   MapCount is updated to indicate the expected number of entries.
+                                   Caller may still get RETURN_BUFFER_TOO_SMALL with the new MapCount.
+**/
+EFI_STATUS
+EFIAPI
+CreateFlatPageTable (
+  IN OUT PAGE_MAP  *Map
+  )
+{
+  UINTN                              LocalEntryCount;
+  PAGE_MAP_ENTRY                     *LastEntry;
+  PAGE_MAP_ENTRY                     OneEntry;
+  TRANSLATION_TABLE_ENTRY_HERITABLE  HeritableAttributes;
+  UINTN                              T0SZ;
+
+  ASSERT (sizeof (OneEntry.PageEntry) == sizeof (AARCH64_PAGE_MAP_ENTRY));
+
+  if ((Map == NULL) || ((Map->Entries == NULL) && (Map->EntryCount != 0))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Map->ArchSignature = AARCH64_PAGE_MAP_SIGNATURE;
+
+  T0SZ = ArmGetTCR () & TCR_T0SZ_MASK;
+
+  mHierarchicalControlEnabled = IsHierarchicalControlEnabled ();
+  HeritableAttributes.Uint64  = 0;
+  LastEntry                   = NULL;
+  LocalEntryCount             = 0;
+
+  TranslationTableParseRecursive (
+    (UINTN)ArmGetTTBR0BaseAddress (),
+    0,
+    0,
+    HeritableAttributes,
+    Map->Entries,
+    &LocalEntryCount,
+    Map->EntryCount,
+    &LastEntry,
+    &OneEntry
+    );
+
+  if (LocalEntryCount > Map->EntryCount) {
+    return RETURN_BUFFER_TOO_SMALL;
+  }
+
+  Map->EntryCount = LocalEntryCount;
+  return RETURN_SUCCESS;
+}
+
+/**
+  Parses the input page to determine if it is writable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is writable.
+  @retval FALSE   The page is not writable.
+**/
+BOOLEAN
+EFIAPI
+IsPageWritable (
+  IN UINT64  Page
+  )
+{
+  return ((Page & TT_AP_RW_RW) != 0) || ((Page & TT_AP_MASK) == 0);
+}
+
+/**
+  Parses the input page to determine if it is executable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is executable.
+  @retval FALSE   The page is not executable.
+**/
+BOOLEAN
+EFIAPI
+IsPageExecutable (
+  IN UINT64  Page
+  )
+{
+  return (ArmReadCurrentEL () == AARCH64_EL2) ?
+         ((Page & TT_XN_MASK) == 0) : ((Page & TT_UXN_MASK) == 0 || (Page & TT_PXN_MASK) == 0);
+}
+
+/**
+  Parses the input page to determine if it is readable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is readable.
+  @retval FALSE   The page is not readable.
+**/
+BOOLEAN
+EFIAPI
+IsPageReadable (
+  IN UINT64  Page
+  )
+{
+  return (Page & TT_AF) != 0;
+}
diff --git a/UefiTestingPkg/Library/FlatPageTableLib/FlatPageTableLib.c b/UefiTestingPkg/Library/FlatPageTableLib/FlatPageTableLib.c
new file mode 100644
index 0000000000..13be261c7b
--- /dev/null
+++ b/UefiTestingPkg/Library/FlatPageTableLib/FlatPageTableLib.c
@@ -0,0 +1,93 @@
+/** @file
+  Library to parse page/translation table entries.
+
+  Copyright (c) Microsoft Corporation.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/SafeIntLib.h>
+#include <Library/FlatPageTableLib.h>
+
+// TRUE if A and B have overlapping intervals
+#define CHECK_OVERLAP(AStart, AEnd, BStart, BEnd) \
+  ((AStart <= BStart && AEnd > BStart) || \
+  (BStart <= AStart && BEnd > AStart))
+
+/**
+  Checks the input flat page/translation table for the input region and converts the associated
+  table entries to EFI access attributes.
+
+  @param[in]  Map                 Pointer to the PAGE_MAP struct to be parsed
+  @param[in]  Address             Start address of the region
+  @param[in]  Length              Length of the region
+  @param[out] Attributes          EFI Attributes of the region (EFI_MEMORY_XP, EFI_MEMORY_RO, EFI_MEMORY_RP)
+
+  @retval EFI_SUCCESS             The output Attributes is valid
+  @retval EFI_INVALID_PARAMETER   The flat translation table has not been built or
+                                  Attributes was NULL or Length was 0
+  @retval EFI_NOT_FOUND           The input region could not be found.
+**/
+EFI_STATUS
+EFIAPI
+GetRegionAccessAttributes (
+  IN PAGE_MAP  *Map,
+  IN UINT64    Address,
+  IN UINT64    Length,
+  OUT UINT64   *Attributes
+  )
+{
+  UINTN    Index;
+  UINT64   EntryStartAddress;
+  UINT64   EntryEndAddress;
+  UINT64   InputEndAddress;
+  BOOLEAN  FoundRange;
+
+  if ((Map->Entries == NULL) || (Map->EntryCount == 0) || (Attributes == NULL) || (Length == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  FoundRange      = FALSE;
+  Index           = 0;
+  InputEndAddress = 0;
+
+  if (EFI_ERROR (SafeUint64Add (Address, Length - 1, &InputEndAddress))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  do {
+    EntryStartAddress = Map->Entries[Index].LinearAddress;
+    if (EFI_ERROR (SafeUint64Add (Map->Entries[Index].LinearAddress, Map->Entries[Index].Length - 1, &EntryEndAddress))) {
+      return EFI_ABORTED;
+    }
+
+    if (CHECK_OVERLAP (Address, InputEndAddress, EntryStartAddress, EntryEndAddress)) {
+      if (!FoundRange) {
+        *Attributes = EFI_MEMORY_ACCESS_MASK;
+        FoundRange  = TRUE;
+      }
+
+      if (IsPageExecutable (Map->Entries[Index].PageEntry)) {
+        *Attributes &= ~EFI_MEMORY_XP;
+      }
+
+      if (IsPageWritable (Map->Entries[Index].PageEntry)) {
+        *Attributes &= ~EFI_MEMORY_RO;
+      }
+
+      if (IsPageReadable (Map->Entries[Index].PageEntry)) {
+        *Attributes &= ~EFI_MEMORY_RP;
+      }
+
+      Address = EntryEndAddress + 1;
+    }
+
+    if (EntryEndAddress >= InputEndAddress) {
+      break;
+    }
+  } while (++Index < Map->EntryCount);
+
+  return FoundRange ? EFI_SUCCESS : EFI_NOT_FOUND;
+}
diff --git a/UefiTestingPkg/Library/FlatPageTableLib/FlatPageTableLib.inf b/UefiTestingPkg/Library/FlatPageTableLib/FlatPageTableLib.inf
new file mode 100644
index 0000000000..8b3a6dc2ae
--- /dev/null
+++ b/UefiTestingPkg/Library/FlatPageTableLib/FlatPageTableLib.inf
@@ -0,0 +1,51 @@
+## @file
+#  Library to parse page/translation table entries.
+#
+#  Copyright (c) Microsoft Corporation.
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = FlatPageTableLib
+  FILE_GUID                      = 9ef87293-dd33-4d4e-aa2b-3a6c982f4665
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = FlatPageTableLib|UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64 AARCH64
+#
+
+[Sources]
+  FlatPageTableLib.c
+
+[Sources.X64]
+  X64/FlatPageTableX64.c
+
+[Sources.AARCH64]
+  AArch64/FlatPageTableAArch64.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiTestingPkg/UefiTestingPkg.dec
+
+[Packages.X64]
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[Packages.AARCH64]
+  ArmPkg/ArmPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  SafeIntLib
+  DebugLib
+
+[LibraryClasses.X64]
+  CpuPageTableLib
+
+[LibraryClasses.AARCH64]
+  ArmLib
diff --git a/UefiTestingPkg/Library/FlatPageTableLib/X64/FlatPageTableX64.c b/UefiTestingPkg/Library/FlatPageTableLib/X64/FlatPageTableX64.c
new file mode 100644
index 0000000000..bc20aa0d32
--- /dev/null
+++ b/UefiTestingPkg/Library/FlatPageTableLib/X64/FlatPageTableX64.c
@@ -0,0 +1,108 @@
+/** @file
+  X64 specific page table attribute library functions.
+
+  Copyright (c) Microsoft Corporation.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/CpuPageTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/FlatPageTableLib.h>
+
+#define X64_PRESENT_BIT  BIT0
+#define X64_RW_BIT       BIT1
+#define X64_NX_BIT       BIT63
+
+/**
+  Populate the input page/translation table map.
+
+  @param[in, out]      Map         Pointer to the PAGE_MAP struct to be populated.
+
+  @retval RETURN_SUCCESS           The translation table is parsed successfully.
+  @retval RETURN_INVALID_PARAMETER MapCount is NULL, or Map is NULL but *MapCount is nonzero.
+  @retval RETURN_BUFFER_TOO_SMALL  *MapCount is too small.
+                                   MapCount is updated to indicate the expected number of entries.
+                                   Caller may still get RETURN_BUFFER_TOO_SMALL with the new MapCount.
+**/
+EFI_STATUS
+EFIAPI
+CreateFlatPageTable (
+  IN OUT PAGE_MAP  *Map
+  )
+{
+  IA32_CR4     Cr4;
+  PAGING_MODE  PagingMode;
+
+  ASSERT (sizeof (PAGE_MAP_ENTRY) == sizeof (IA32_MAP_ENTRY));
+
+  if ((Map == NULL) || ((Map->Entries == NULL) && (Map->EntryCount != 0))) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Map->ArchSignature = X64_PAGE_MAP_SIGNATURE;
+
+  // Poll CR4 to deterimine the page table depth
+  Cr4.UintN = AsmReadCr4 ();
+
+  if (Cr4.Bits.LA57 != 0) {
+    PagingMode = Paging5Level;
+  } else {
+    PagingMode = Paging4Level;
+  }
+
+  return PageTableParse (AsmReadCr3 (), PagingMode, (IA32_MAP_ENTRY *)Map->Entries, &Map->EntryCount);
+}
+
+/**
+  Parses the input page to determine if it is writable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is writable.
+  @retval FALSE   The page is not writable.
+**/
+BOOLEAN
+EFIAPI
+IsPageWritable (
+  IN UINT64  Page
+  )
+{
+  return (Page & X64_RW_BIT) != 0;
+}
+
+/**
+  Parses the input page to determine if it is executable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is executable.
+  @retval FALSE   The page is not executable.
+**/
+BOOLEAN
+EFIAPI
+IsPageExecutable (
+  IN UINT64  Page
+  )
+{
+  return (Page & X64_NX_BIT) == 0;
+}
+
+/**
+  Parses the input page to determine if it is readable.
+
+  @param[in] Page The page entry to parse.
+
+  @retval TRUE    The page is readable.
+  @retval FALSE   The page is not readable.
+**/
+BOOLEAN
+EFIAPI
+IsPageReadable (
+  IN UINT64  Page
+  )
+{
+  return (Page & X64_PRESENT_BIT) != 0;
+}
diff --git a/UefiTestingPkg/UefiTestingPkg.dec b/UefiTestingPkg/UefiTestingPkg.dec
index ca15193c6e..d2216a25d3 100644
--- a/UefiTestingPkg/UefiTestingPkg.dec
+++ b/UefiTestingPkg/UefiTestingPkg.dec
@@ -20,6 +20,11 @@
   ##
   PlatformSmmProtectionsTestLib|Include/Library/PlatformSmmProtectionsTestLib.h
 
+  ## @libraryclass Provides a way to parse the page/translation table
+  ##               entries into a flat map.
+  ##
+  FlatPageTableLib|Include/Library/FlatPageTableLib.h
+
 [Protocols]
   ## Include/Protocol/MpManagement.h
   gMpManagementProtocolGuid = { 0x2b0a3788, 0xe602, 0x424f, { 0xa8, 0x32, 0xa1, 0x13, 0x77, 0xa7, 0x6d, 0x73 } }
diff --git a/UefiTestingPkg/UefiTestingPkg.dsc b/UefiTestingPkg/UefiTestingPkg.dsc
index c3e9dd14bf..3e79ee6523 100644
--- a/UefiTestingPkg/UefiTestingPkg.dsc
+++ b/UefiTestingPkg/UefiTestingPkg.dsc
@@ -68,6 +68,7 @@
   ExceptionPersistenceLib|MdeModulePkg/Library/BaseExceptionPersistenceLibNull/BaseExceptionPersistenceLibNull.inf
   CpuPageTableLib|UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf
   DxeMemoryProtectionHobLib|MdeModulePkg/Library/MemoryProtectionHobLibNull/DxeMemoryProtectionHobLibNull.inf
+  FlatPageTableLib|UefiTestingPkg/Library/FlatPageTableLib/FlatPageTableLib.inf
 
 [LibraryClasses.ARM, LibraryClasses.AARCH64]
   ArmDisassemblerLib|ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf
@@ -141,6 +142,7 @@
   UefiTestingPkg/FunctionalSystemTests/MorLockTestApp/MorLockTestApp.inf
   UefiTestingPkg/FunctionalSystemTests/MpManagement/App/MpManagementTestApp.inf
   UefiTestingPkg/FunctionalSystemTests/MemoryAttributeProtocolFuncTestApp/MemoryAttributeProtocolFuncTestApp.inf
+  UefiTestingPkg/Library/FlatPageTableLib/FlatPageTableLib.inf
 
 [Components.IA32, Components.X64]
   UefiTestingPkg/AuditTests/DMAProtectionAudit/UEFI/DMAIVRSProtectionUnitTestApp.inf