[edk2-devel] [edk2-platforms][PATCH V5 05/15] Platform/Loongson: Add MmuLib.

xianglai posted 15 patches 2 years, 4 months ago
There is a newer version of this series
[edk2-devel] [edk2-platforms][PATCH V5 05/15] Platform/Loongson: Add MmuLib.
Posted by xianglai 2 years, 4 months ago
Read the memory map information through the QemuFwCfg interface,
then build the page table through the memory map information,
and finally enable Mmu.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../LoongArchQemuPkg/Include/Library/MmuLib.h |  85 ++
 .../LoongArchQemuPkg/Library/MmuLib/Mmu.S     | 155 ++++
 .../Library/MmuLib/MmuBaseLib.inf             |  40 +
 .../Library/MmuLib/MmuBaseLibPei.inf          |  47 +
 .../Library/MmuLib/MmuLibCore.c               | 831 ++++++++++++++++++
 .../Library/MmuLib/MmuLibCore.h               |  40 +
 .../Library/MmuLib/MmuLibCorePei.c            | 231 +++++
 .../LoongArchQemuPkg/Library/MmuLib/mmu.h     | 190 ++++
 .../LoongArchQemuPkg/Library/MmuLib/page.h    | 280 ++++++
 .../LoongArchQemuPkg/Library/MmuLib/pte.h     |  57 ++
 10 files changed, 1956 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h

diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
new file mode 100644
index 0000000000..9880fc385c
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
@@ -0,0 +1,85 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - EXC     - execute
+**/
+#ifndef MMU_LIB_H_
+#define MMU_LIB_H_
+/**
+  write operation is performed Count times from the first element of Buffer.
+  Convert EFI Attributes to Loongarch Attributes.
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  LoongArch Attributes.
+**/
+UINTN
+EfiAttributeToLoongArchAttribute (
+  IN UINTN  EfiAttributes
+  );
+
+/**
+  Finds the length and memory properties of the memory region corresponding to the specified base address.
+
+  @param[in]  BaseAddress    To find the base address of the memory region.
+  @param[in]  EndAddress     To find the end address of the memory region.
+  @param[out]  RegionLength    The length of the memory region found.
+  @param[out]  RegionAttributes    Properties of the memory region found.
+
+  @retval  EFI_SUCCESS    The corresponding memory area was successfully found
+           EFI_NOT_FOUND    No memory area found
+**/
+EFI_STATUS
+GetLoongArchMemoryRegion (
+  IN     UINTN  BaseAddress,
+  IN     UINTN  EndAddress,
+  OUT    UINTN  *RegionLength,
+  OUT    UINTN  *RegionAttributes
+  );
+
+/**
+  Sets the Attributes  of the specified memory region
+
+  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
+  @param[in]  Length       The length of the memory region to set the Attributes.
+  @param[in]  Attributes   The Attributes to be set.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN                 Length,
+  IN UINTN                 Attributes
+  );
+
+/**
+  Sets the non-executable Attributes for the specified memory region
+
+  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
+  @param[in]  Length       The length of the memory region to set the Attributes.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryRegionNoExec (
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN  UINTN                Length
+  );
+
+/**
+  Create a page table and initialize the MMU.
+
+  @param[] VOID
+
+  @retval  VOID
+**/
+VOID
+EFIAPI
+ConfigureMmu (
+  VOID
+  );
+#endif // MMU_LIB_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
new file mode 100644
index 0000000000..d5863de072
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
@@ -0,0 +1,155 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch for LoongArch
+#
+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-----------------------------------------------------------------------------
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include "Library/Cpu.h"
+#include "mmu.h"
+
+ASM_GLOBAL ASM_PFX(HandleTlbRefill)
+ASM_GLOBAL HandleTlbRefillEnd
+ASM_GLOBAL ASM_PFX(LoongarchInvalidTlb)
+ASM_GLOBAL ASM_PFX(SetTlbRefillFuncBase)
+ASM_GLOBAL ASM_PFX(WriteCsrPageSize)
+ASM_GLOBAL ASM_PFX(WriteCsrTlbRefillPageSize)
+ASM_GLOBAL ASM_PFX(WriteCsrStlbPageSize)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPwctl0)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPwctl1)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPgdl)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPgdh)
+ASM_GLOBAL ASM_PFX(LoongArchXchgCsrCrmd)
+
+#
+#  Refill the page table.
+#  @param  VOID
+#  @retval  VOID
+#
+
+ASM_PFX(HandleTlbRefill):
+  csrwr T0, LOONGARCH_CSR_TLBRSAVE
+  csrrd T0, LOONGARCH_CSR_PGD
+  lddir T0, T0, 3   #Put pud BaseAddress into T0
+  lddir T0, T0, 2   #Put pmd BaseAddress into T0
+  lddir T0, T0, 1   #Put pte BaseAddress into T0
+  ldpte T0, 0
+  ldpte T0, 1
+  tlbfill
+  csrrd T0, LOONGARCH_CSR_TLBRSAVE
+  ertn
+HandleTlbRefillEnd:
+
+#
+# Invalid corresponding TLB entries are based on the address given
+# @param A0 The address corresponding to the invalid page table entry
+# @retval  none
+#
+
+ASM_PFX(LoongarchInvalidTlb):
+    invtlb  INVTLB_ADDR_GTRUE_OR_ASID, ZERO, A0
+    jirl    ZERO, RA, 0
+
+#
+# Set Tlb Refill function to hardware
+# @param A0 The address of tlb refill function
+# @retval  none
+#
+
+ASM_PFX(SetTlbRefillFuncBase):
+    csrwr   A0, LOONGARCH_CSR_TLBREBASE
+    jirl    ZERO, RA,0
+
+#
+#  Set Cpu Status Register Page Size.
+#  @param  A0  Page Size.
+#  @retval  none
+#
+
+ASM_PFX(WriteCsrPageSize):
+    li.d    T0, CSR_TLBIDX_SIZE
+    sll.d   A0, A0, T0
+    li.d    T0, CSR_TLBIDX_SIZE_MASK
+    csrxchg A0, T0, LOONGARCH_CSR_TLBIDX
+    jirl    ZERO, RA,0
+
+#
+#  Set Cpu Status Register TLBREFILL Page Size.
+#  @param  A0  Page Size.
+#  @retval  none
+#
+
+ASM_PFX(WriteCsrTlbRefillPageSize):
+    li.d    T0, CSR_TLBREHI_PS_SHIFT
+    sll.d   A0, A0, T0
+    li.d    T0, CSR_TLBREHI_PS
+    csrxchg A0, T0, LOONGARCH_CSR_TLBREHI
+    jirl    ZERO, RA,0
+
+#
+#  Set Cpu Status Register STLB Page Size.
+#  @param val  Page Size.
+#  @retval  VOID
+#
+
+ASM_PFX(WriteCsrStlbPageSize):
+    csrwr  A0, LOONGARCH_CSR_STLBPGSIZE
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr PWCTL0 register.
+#  @param  A0  The value used to write to the PWCTL0 register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrPwctl0):
+    csrwr A0, LOONGARCH_CSR_PWCTL0
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr PWCTL1 register.
+#  @param  A0  The value used to write to the PWCTL1 register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrPwctl1):
+    csrwr A0, LOONGARCH_CSR_PWCTL1
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr PGDL register.
+#  @param  A0  The value used to write to the PGDL register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrPgdl):
+    csrwr A0, LOONGARCH_CSR_PGDL
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr PGDH register.
+#  @param  A0  The value used to write to the PGDH register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrPgdh):
+    csrwr A0, LOONGARCH_CSR_PGDH
+    jirl    ZERO, RA,0
+
+#
+#  Exchange specified bit data with the Csr CRMD register.
+#  @param[IN]  A0   The value Exchanged with the CSR CRMD register.
+#  @param[IN]  A1   Specifies the mask for swapping bits
+#  @retval  VOID
+#
+
+ASM_PFX(LoongArchXchgCsrCrmd):
+    csrxchg A0, A1, LOONGARCH_CSR_CRMD
+    jirl    ZERO, RA,0
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
new file mode 100644
index 0000000000..abd864a324
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
@@ -0,0 +1,40 @@
+## @file
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MmuBaseLib
+  FILE_GUID                      = da8f0232-fb14-42f0-922c-63104d2c70be
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MmuLib
+  CONSTRUCTOR                    = MmuInitialize
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  MmuLibCore.c
+  Mmu.S
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[PCD]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
+
+[LibraryClasses]
+  MemoryAllocationLib
+  PcdLib
+  DebugLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
new file mode 100644
index 0000000000..12848eecfe
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
@@ -0,0 +1,47 @@
+## @file
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MmuPeiLib
+  FILE_GUID                      = da8f0232-fb14-42f0-922c-63104d2c70bd
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MmuLib | SEC PEIM
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  MmuLibCorePei.c
+  Mmu.S
+  MmuLibCore.h
+  MmuLibCore.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  OvmfPkg/OvmfPkg.dec
+
+[PCD]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
+
+[LibraryClasses]
+  MemoryAllocationLib
+  CacheMaintenanceLib
+  PcdLib
+  DebugLib
+  QemuFwCfgLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
new file mode 100644
index 0000000000..b932e3d568
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
@@ -0,0 +1,831 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Pgd or Pgd or PGD    - Page Global Directory
+    - Pud or Pud or PUD    - Page Upper Directory
+    - Pmd or Pmd or PMD    - Page Middle Directory
+    - Pte or pte or PTE    - Page Table Entry
+    - Val or VAL or val    - Value
+    - Dir    - Directory
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "pte.h"
+#include "page.h"
+#include "mmu.h"
+
+BOOLEAN  mMmuInited = FALSE;
+/**
+  Check to see if mmu successfully initializes.
+
+  @param  VOID.
+
+  @retval  TRUE  Initialization has been completed.
+           FALSE Initialization did not complete.
+**/
+BOOLEAN
+MmuIsInit (VOID) {
+  if ((mMmuInited == TRUE) ||
+      (PcdGet64 (PcdSwapPageDir) != 0)) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+  Iterates through the page directory to initialize it.
+
+  @param  Dst  A pointer to the directory of the page to initialize.
+  @param  Num  The number of page directories to initialize.
+  @param  Src  A pointer to the data used to initialize the page directory.
+
+  @retval VOID.
+**/
+VOID
+PageDirInit (
+  IN VOID *Dst,
+  IN UINTN Num,
+  IN VOID *Src
+  )
+{
+  UINTN *Ptr;
+  UINTN *End;
+  UINTN Entry;
+
+  Entry = (UINTN)Src;
+  Ptr = (UINTN *)Dst;
+  End = Ptr + Num;
+
+  for ( ;Ptr < End; Ptr++) {
+    *Ptr = Entry;
+  }
+
+  return ;
+}
+
+/**
+  Gets the virtual address corresponding to the page global directory table entry.
+
+  @param  Address  the virtual address for the table entry.
+
+  @retval PGD A pointer to get the table item.
+**/
+PGD *
+PgdOffset (
+  IN UINTN Address
+  )
+{
+  return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address);
+}
+
+/**
+  Gets the virtual address corresponding to the page upper directory table entry.
+
+  @param  Pgd  A pointer to a page global directory table entry.
+  @param  Address  the virtual address for the table entry.
+
+  @retval PUD A pointer to get the table item.
+**/
+PUD *
+PudOffset (
+  IN PGD *Pgd,
+  IN UINTN Address
+  )
+{
+  UINTN PgdVal = (UINTN)PGD_VAL (*Pgd);
+  return (PUD *)PgdVal + PUD_INDEX (Address);
+}
+
+/**
+  Gets the virtual address corresponding to the page middle directory table entry.
+
+  @param  Pud  A pointer to a page upper directory table entry.
+  @param  Address  the virtual address for the table entry.
+
+  @retval PMD A pointer to get the table item.
+**/
+PMD *
+PmdOffset (
+  IN PUD *Pud,
+  IN UINTN Address
+  )
+{
+  UINTN PudVal = PUD_VAL (*Pud);
+  return (PMD *)PudVal + PMD_INDEX (Address);
+}
+
+/**
+  Gets the virtual address corresponding to the page table entry.
+
+  @param  Pmd  A pointer to a page middle directory table entry.
+  @param  Address  the virtual address for the table entry.
+
+  @retval PTE A pointer to get the table item.
+**/
+PTE *
+PteOffset (
+  IN PMD *Pmd,
+  IN UINTN Address
+  )
+{
+  UINTN PmdVal = (UINTN)PMD_VAL (*Pmd);
+  return (PTE *)PmdVal + PTE_INDEX (Address);
+}
+
+/**
+  Sets the value of the page table entry.
+
+  @param  Pte  A pointer to a page table entry.
+  @param  PteVal  The value of the page table entry to set.
+
+  @retval VOID
+**/
+VOID
+SetPte (
+  IN PTE *Pte,
+  IN PTE PteVal
+  )
+{
+  *Pte = PteVal;
+}
+
+/**
+  Sets the value of the page global directory.
+
+  @param  Pgd  A pointer to a page global directory.
+  @param  Pud  The value of the page global directory to set.
+
+  @retval VOID
+**/
+VOID
+SetPgd (
+  IN PGD *Pgd,
+  IN PUD *Pud
+  )
+{
+  *Pgd = (PGD) {((UINTN)Pud)};
+}
+
+/**
+  Sets the value of the page upper directory.
+
+  @param  Pud  A pointer to a page upper directory.
+  @param  Pmd  The value of the page upper directory to set.
+
+  @retval VOID
+**/
+VOID
+SetPud (
+  IN PUD *Pud,
+  IN PMD *Pmd
+  )
+{
+  *Pud = (PUD) {((UINTN)Pmd)};
+}
+
+/**
+  Sets the value of the page middle directory.
+
+  @param  Pmd  A pointer to a page middle directory.
+  @param  Pte  The value of the page middle directory to set.
+
+  @retval VOID
+**/
+VOID
+SetPmd (
+  IN PMD *Pmd,
+  IN PTE *Pte
+  )
+{
+  *Pmd = (PMD) {((UINTN)Pte)};
+}
+
+/**
+  Free up memory space occupied by page tables.
+
+  @param  Pte  A pointer to the page table.
+
+  @retval VOID
+**/
+VOID
+PteFree (
+  IN PTE *Pte
+  )
+{
+  FreePages ((VOID *)Pte, 1);
+}
+
+/**
+  Free up memory space occupied by page middle directory.
+
+  @param  Pmd  A pointer to the page middle directory.
+
+  @retval VOID
+**/
+VOID
+PmdFree (
+  IN PMD *Pmd
+  )
+{
+  FreePages ((VOID *)Pmd, 1);
+}
+
+/**
+  Free up memory space occupied by page upper directory.
+
+  @param  Pud  A pointer to the page upper directory.
+
+  @retval VOID
+**/
+VOID
+PudFree (
+  IN PUD *Pud
+  )
+{
+  FreePages ((VOID *)Pud, 1);
+}
+
+/**
+  Requests the memory space required for the page upper directory,
+  initializes it, and places it in the specified page global directory
+
+  @param  Pgd  A pointer to the page global directory.
+
+  @retval  EFI_SUCCESS  Memory request successful.
+  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
+**/
+INTN
+PudAlloc (
+  IN PGD *Pgd
+  )
+{
+  PUD *Pud = (PUD *) AllocatePages (1);
+  if (!Pud) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPmd));
+
+  if (pgd_none (*Pgd)) {
+    SetPgd (Pgd, Pud);
+  } else { /* Another has populated it */
+    PudFree (Pud);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Requests the memory space required for the page middle directory,
+  initializes it, and places it in the specified page upper directory
+
+  @param  Pud  A pointer to the page upper directory.
+
+  @retval  EFI_SUCCESS  Memory request successful.
+  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
+**/
+EFI_STATUS
+PmdAlloc (
+  IN PUD *Pud
+  )
+{
+  PMD *Pmd;
+
+  Pmd = (PMD *) AllocatePages (1);
+  if (!Pmd) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPte));
+
+  if (pud_none (*Pud)) {
+    SetPud (Pud, Pmd);
+  } else {/* Another has populated it */
+    PmdFree (Pmd);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Requests the memory space required for the page table,
+  initializes it, and places it in the specified page middle directory
+
+  @param  Pmd  A pointer to the page middle directory.
+
+  @retval  EFI_SUCCESS  Memory request successful.
+  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
+**/
+INTN
+PteAlloc (
+  IN PMD *Pmd
+  )
+{
+  PTE *Pte;
+
+  Pte = (PTE *) AllocatePages (1);
+  if (!Pte) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
+
+  if (pmd_none (*Pmd)) {
+    SetPmd (Pmd, Pte);
+  } else { /* Another has populated it */
+    PteFree (Pte);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Requests the memory space required for the page upper directory,
+  initializes it, and places it in the specified page global directory,
+  and get the page upper directory entry corresponding to the virtual address
+
+  @param  Pgd  A pointer to the page global directory.
+
+  @retval   Gets the page upper directory entry
+**/
+PUD *
+PudAllocGet (
+  IN PGD *Pgd,
+  IN UINTN Address
+  )
+{
+  return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ?
+           NULL : PudOffset (Pgd, Address));
+}
+
+/**
+  Requests the memory space required for the page middle directory,
+  initializes it, and places it in the specified page upper directory,
+  and get the page middle directory entry corresponding to the virtual address
+
+  @param  Pud  A pointer to the page upper directory.
+
+  @retval   Gets the page middle directory entry
+**/
+PMD *
+PmdAllocGet (
+  IN PUD *Pud,
+  IN UINTN Address
+  )
+{
+  PMD * ret =  (pud_none (*Pud) && PmdAlloc (Pud))?
+            NULL: PmdOffset (Pud, Address);
+  DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", __func__, __LINE__,
+    Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) ));
+
+  return ret;
+}
+
+/**
+  Requests the memory space required for the page table,
+  initializes it, and places it in the specified page middle directory,
+  and get the page table entry corresponding to the virtual address
+
+  @param  Pmd  A pointer to the page upper directory.
+
+  @retval   Gets the page table entry
+**/
+PTE *
+PteAllocGet (
+  IN PMD *Pmd,
+  IN UINTN Address
+  )
+{
+  return (pmd_none (*Pmd) && PteAlloc (Pmd))?
+    NULL: PteOffset (Pmd, Address);
+}
+
+/**
+  Gets the physical address of the page table entry corresponding to the specified virtual address.
+
+  @param  Address  the corresponding virtual address of the page table entry.
+
+  @retval     A pointer to the page table entry.
+  @retval  NULL
+**/
+PTE *
+GetPteAddress (
+  IN UINTN Address
+  )
+{
+  PGD *Pgd;
+  PUD *Pud;
+  PMD *Pmd;
+
+  Pgd = PgdOffset (Address);
+
+  if (pgd_none (*Pgd)) {
+    return NULL;
+  }
+
+  Pud = PudOffset (Pgd, Address);
+
+  if (pud_none (*Pud)) {
+    return NULL;
+  }
+
+  Pmd = PmdOffset (Pud, Address);
+  if (pmd_none (*Pmd)) {
+    return NULL;
+  }
+
+  if (IS_HUGE_PAGE (Pmd->PmdVal)) {
+    return ((PTE *)Pmd);
+  }
+
+  return PteOffset (Pmd, Address);
+}
+
+/**
+  Establishes a page table entry based on the specified memory region.
+
+  @param  Pmd  A pointer to the page middle directory.
+  @param  Address  The memory space start address.
+  @param  End  The end address of the memory space.
+  @param  Attributes  Memory space Attributes.
+
+  @retval     EFI_SUCCESS   The page table entry was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page table entry establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPteRange (
+  IN PMD *Pmd,
+  IN UINTN Address,
+  IN UINTN End,
+  IN UINTN Attributes
+  )
+{
+  PTE *Pte;
+  PTE PteVal;
+  BOOLEAN UpDate;
+
+  Pte = PteAllocGet (Pmd, Address);
+  if (!Pte) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    UpDate = FALSE;
+    PteVal = MAKE_PTE (Address, Attributes);
+    DEBUG ((DEBUG_VERBOSE,
+      "%a %d Address %p  PGD_INDEX %p PUD_INDEX   %p PMD_INDEX  %p PTE_INDEX  %p MAKE_PTE  %p\n",
+      __func__, __LINE__,  Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
+      PTE_INDEX (Address), PteVal));
+
+    if ((!pte_none (*Pte)) &&
+        (PTE_VAL(*Pte) != PTE_VAL(PteVal)))
+    {
+      UpDate = TRUE;
+    }
+
+    SetPte (Pte, PteVal);
+    if (UpDate) {
+      LoongarchInvalidTlb(Address);
+    }
+  } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Establishes a page middle directory based on the specified memory region.
+
+  @param  Pud  A pointer to the page upper directory.
+  @param  Address  The memory space start address.
+  @param  End  The end address of the memory space.
+  @param  Attributes  Memory space Attributes.
+
+  @retval     EFI_SUCCESS   The page middle directory was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page middle directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPmdRange (
+  IN PUD *Pud,
+  IN UINTN Address,
+  IN UINTN End,
+  IN UINTN Attributes
+  )
+{
+  PMD *Pmd;
+  PTE *Pte;
+  UINTN Next;
+  UINTN AddressStart_HugePage;
+  UINTN AddressEnd_HugePage;
+
+  Pmd = PmdAllocGet (Pud, Address);
+  if (!Pmd) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    Next = PMD_ADDRESS_END (Address, End);
+    if (((Address & (~PMD_MASK)) == 0) &&
+        ((Next &  (~PMD_MASK)) == 0) &&
+        (pmd_none (*Pmd)))
+    {
+      DEBUG ((DEBUG_VERBOSE,
+        "%a %d Address %p  PGD_INDEX %p PUD_INDEX   %p PMD_INDEX  %p MAKE_HUGE_PTE  %p\n",
+        __func__, __LINE__,  Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
+        MAKE_HUGE_PTE (Address, Attributes)));
+
+      SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes));
+    } else {
+       if ((pmd_none (*Pmd)) ||
+          ((!pmd_none (*Pmd)) &&
+           (!IS_HUGE_PAGE (Pmd->PmdVal))))
+       {
+         if (MemoryMapPteRange (Pmd, Address, Next, Attributes)) {
+           return EFI_OUT_OF_RESOURCES;
+         }
+       } else {
+         SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte));
+         AddressStart_HugePage = Address & PMD_MASK;
+         AddressEnd_HugePage = AddressStart_HugePage + HUGE_PAGE_SIZE;
+         if (MemoryMapPteRange (Pmd, AddressStart_HugePage, AddressEnd_HugePage, Attributes)) {
+           return EFI_OUT_OF_RESOURCES;
+         }
+         Pte = GetPteAddress (AddressStart_HugePage);
+         if (Pte == NULL) {
+           continue ;
+         }
+         if (AddressEnd_HugePage > End) {
+           Next = End;
+         }
+       }
+    }
+  } while (Pmd++, Address = Next, Address != End);
+
+  return 0;
+}
+
+/**
+  Establishes a page upper directory based on the specified memory region.
+
+  @param  Pgd  A pointer to the page global directory.
+  @param  Address  The memory space start address.
+  @param  End  The end address of the memory space.
+  @param  Attributes  Memory space Attributes.
+
+  @retval     EFI_SUCCESS   The page upper directory was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page upper directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPudRange (
+  IN PGD *Pgd,
+  IN UINTN Address,
+  IN UINTN End,
+  IN UINTN Attributes
+  )
+{
+  PUD *Pud;
+  UINTN Next;
+
+  Pud = PudAllocGet (Pgd, Address);
+  if (!Pud) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    Next = PUD_ADDRESS_END (Address, End);
+    if (MemoryMapPmdRange (Pud, Address, Next, Attributes)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } while (Pud++, Address = Next, Address != End);
+  return EFI_SUCCESS;
+}
+
+/**
+  Establishes a page global directory based on the specified memory region.
+
+  @param  Start  The memory space start address.
+  @param  End  The end address of the memory space.
+  @param  Attributes  Memory space Attributes.
+
+  @retval     EFI_SUCCESS   The page global directory was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page global directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPageRange (
+  IN UINTN Start,
+  IN UINTN End,
+  IN UINTN Attributes
+  )
+{
+  PGD *Pgd;
+  UINTN Next;
+  UINTN Address = Start;
+  EFI_STATUS Err;
+
+  Pgd = PgdOffset (Address);
+  do {
+    Next = PGD_ADDRESS_END (Address, End);
+    Err = MemoryMapPudRange (Pgd, Address, Next, Attributes);
+    if (Err) {
+      return Err;
+    }
+  } while (Pgd++, Address = Next, Address != End);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Page tables are established from memory-mapped tables.
+
+  @param  MemoryRegion   A pointer to a memory-mapped table entry.
+
+  @retval     EFI_SUCCESS   The page table was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page table  establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+FillTranslationTable (
+  IN  MEMORY_REGION_DESCRIPTOR  *MemoryRegion
+  )
+{
+  return MemoryMapPageRange (MemoryRegion->VirtualBase,
+           (MemoryRegion->Length + MemoryRegion->VirtualBase),
+           MemoryRegion->Attributes);
+}
+
+/**
+  write operation is performed Count times from the first element of Buffer.
+  Convert EFI Attributes to Loongarch Attributes.
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  LoongArch Attributes.
+**/
+UINTN
+EfiAttributeToLoongArchAttribute (
+  IN UINTN  EfiAttributes
+  )
+{
+  UINTN  LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | CACHE_CC | PAGE_USER | PAGE_GLOBAL;
+  switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
+    case EFI_MEMORY_UC:
+      LoongArchAttributes |= CACHE_SUC;
+      break;
+    case EFI_MEMORY_WC:
+    case EFI_MEMORY_WT:
+    case EFI_MEMORY_WB:
+      LoongArchAttributes |= CACHE_CC;
+      break;
+    default :
+       LoongArchAttributes |= CACHE_CC;
+      break;
+  }
+
+  // Write protection attributes
+  if ((EfiAttributes & EFI_MEMORY_RO) != 0) {
+    LoongArchAttributes &= ~PAGE_DIRTY;
+  }
+
+  //eXecute protection attribute
+  if ((EfiAttributes & EFI_MEMORY_XP) != 0) {
+    LoongArchAttributes |= PAGE_NO_EXEC;
+  }
+
+  return LoongArchAttributes;
+}
+
+/**
+  Finds the length and memory properties of the memory region corresponding to the specified base address.
+
+  @param[in]  BaseAddress    To find the base address of the memory region.
+  @param[in]  EndAddress     To find the end address of the memory region.
+  @param[out]  RegionLength    The length of the memory region found.
+  @param[out]  RegionAttributes    Properties of the memory region found.
+
+  @retval  EFI_SUCCESS    The corresponding memory area was successfully found
+           EFI_NOT_FOUND    No memory area found
+**/
+EFI_STATUS
+GetLoongArchMemoryRegion (
+  IN     UINTN  BaseAddress,
+  IN     UINTN  EndAddress,
+  OUT    UINTN  *RegionLength,
+  OUT    UINTN  *RegionAttributes
+  )
+{
+  PTE *Pte;
+  UINTN Attributes;
+  UINTN AttributesTmp;
+  UINTN MaxAddress;
+  MaxAddress     = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
+  Pte = GetPteAddress (BaseAddress);
+
+  if (!MmuIsInit ()) {
+    return EFI_SUCCESS;
+  }
+  if (Pte == NULL) {
+    return EFI_NOT_FOUND;
+  }
+  Attributes = GET_PAGE_ATTRIBUTES (*Pte);
+  if (IS_HUGE_PAGE (Pte->PteVal)) {
+    *RegionAttributes = Attributes & (~(PAGE_HUGE));
+    *RegionLength += HUGE_PAGE_SIZE;
+  } else {
+    *RegionLength += EFI_PAGE_SIZE;
+    *RegionAttributes = Attributes;
+  }
+
+  while (BaseAddress <= MaxAddress) {
+    Pte = GetPteAddress (BaseAddress);
+    if (Pte == NULL) {
+      return EFI_SUCCESS;
+    }
+    AttributesTmp = GET_PAGE_ATTRIBUTES (*Pte);
+    if (IS_HUGE_PAGE (Pte->PteVal)) {
+      if (AttributesTmp == Attributes) {
+         *RegionLength += HUGE_PAGE_SIZE;
+      }
+      BaseAddress += HUGE_PAGE_SIZE;
+    } else {
+      if (AttributesTmp == Attributes) {
+        *RegionLength += EFI_PAGE_SIZE;
+      }
+      BaseAddress += EFI_PAGE_SIZE;
+    }
+
+    if (BaseAddress > EndAddress) {
+      break;
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Sets the Attributes  of the specified memory region
+
+  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
+  @param[in]  Length       The length of the memory region to set the Attributes.
+  @param[in]  Attributes   The Attributes to be set.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN                 Length,
+  IN UINTN                 Attributes
+  )
+{
+
+  if (!MmuIsInit ()) {
+    return EFI_SUCCESS;
+  }
+  Attributes = EfiAttributeToLoongArchAttribute (Attributes);
+  DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes));
+  MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Sets the non-executable Attributes for the specified memory region
+
+  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
+  @param[in]  Length       The length of the memory region to set the Attributes.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryRegionNoExec (
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN  UINTN                Length
+  )
+{
+  if (MmuIsInit ()) {
+    Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
+    LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Check to see if mmu successfully initializes and saves the result.
+
+  @param  VOID.
+
+  @retval  EFI_SUCCESS    Initialization succeeded.
+**/
+EFI_STATUS
+MmuInitialize (VOID)
+{
+   if (PcdGet64 (PcdSwapPageDir) != 0) {
+     mMmuInited = TRUE;
+   }
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
new file mode 100644
index 0000000000..7a5e8ea0dd
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
@@ -0,0 +1,40 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Dir    - Directory
+**/
+#ifndef  MMU_LIB_CORE_H_
+#define  MMU_LIB_CORE_H_
+/**
+  Iterates through the page directory to initialize it.
+
+  @param  Dst  A pointer to the directory of the page to initialize.
+  @param  Num  The number of page directories to initialize.
+  @param  Src  A pointer to the data used to initialize the page directory.
+
+  @retval VOID.
+**/
+VOID
+PageDirInit (
+  IN VOID *dest,
+  IN UINTN Count,
+  IN VOID *src
+  );
+
+/**
+  Page tables are established from memory-mapped tables.
+
+  @param  MemoryRegion   A pointer to a memory-mapped table entry.
+
+  @retval     EFI_SUCCESS   The page table was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page table  establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+FillTranslationTable (
+  IN  MEMORY_REGION_DESCRIPTOR  *MemoryRegion
+  );
+#endif // MMU_LIB_CORE_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
new file mode 100644
index 0000000000..32a7fc0beb
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
@@ -0,0 +1,231 @@
+/** @file
+  Platform PEI driver
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - FwCfg    - Firmeware Config
+    - Tlb      - Translation Lookaside Buffer
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "pte.h"
+#include "page.h"
+#include "mmu.h"
+#include <Library/QemuFwCfgLib.h>
+#include "MmuLibCore.h"
+#include <Library/CacheMaintenanceLib.h>
+
+/**
+  Return the Virtual Memory Map of your platform
+
+  This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
+  on your platform.
+
+  @param[out]   VirtualMemoryMap    Array of MEMORY_REGION_DESCRIPTOR
+                                    describing a Physical-to-Virtual Memory
+                                    mapping. This array must be ended by a
+                                    zero-filled entry. The allocated memory
+                                    will not be freed.
+**/
+VOID
+GetMemoryMapFromFwCfg (
+  OUT MEMORY_REGION_DESCRIPTOR  **VirtualMemoryMap
+  )
+{
+
+  EFI_STATUS           Status;
+  FIRMWARE_CONFIG_ITEM FwCfgItem;
+  UINTN                FwCfgSize;
+  LOONGARCH_MEMMAP_ENTRY  MemoryMapEntry;
+  LOONGARCH_MEMMAP_ENTRY  *StartEntry;
+  LOONGARCH_MEMMAP_ENTRY  *pEntry;
+  UINTN                Processed;
+  MEMORY_REGION_DESCRIPTOR  *VirtualMemoryTable;
+  UINTN  Index = 0;
+  ASSERT (VirtualMemoryMap != NULL);
+
+  VirtualMemoryTable = AllocatePool (
+                         sizeof (MEMORY_REGION_DESCRIPTOR) *
+                         MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
+                         );
+  VirtualMemoryTable[Index].PhysicalBase = 0x10000000;
+  VirtualMemoryTable[Index].VirtualBase  = VirtualMemoryTable[Index].PhysicalBase;
+  VirtualMemoryTable[Index].Length       = 0x10000000;
+  VirtualMemoryTable[Index].Attributes   = PAGE_VALID | PLV_KERNEL |  CACHE_SUC | PAGE_DIRTY | PAGE_GLOBAL;
+  ++Index;
+
+  Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status));
+    ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
+    *VirtualMemoryMap = VirtualMemoryTable;
+    return ;
+  }
+  if (FwCfgSize % sizeof MemoryMapEntry != 0) {
+    DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize));
+  }
+
+  QemuFwCfgSelectItem (FwCfgItem);
+  StartEntry = AllocatePages  (EFI_SIZE_TO_PAGES (FwCfgSize));
+  QemuFwCfgReadBytes (FwCfgSize, StartEntry);
+  for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) {
+    pEntry = StartEntry + Processed;
+    if (pEntry->Length == 0) {
+      continue;
+    }
+
+    DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p  type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type));
+    VirtualMemoryTable[Index].PhysicalBase = pEntry->BaseAddr;
+    VirtualMemoryTable[Index].VirtualBase  = VirtualMemoryTable[Index].PhysicalBase;
+    VirtualMemoryTable[Index].Length       = pEntry->Length;
+    VirtualMemoryTable[Index].Attributes   = PAGE_VALID | PLV_KERNEL |  CACHE_CC | PAGE_DIRTY | PAGE_GLOBAL;
+    ++Index;
+  }
+
+  FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize));
+  // End of Table
+  ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
+  *VirtualMemoryMap = VirtualMemoryTable;
+  return ;
+}
+
+/**
+  Create a page table and initialize the MMU.
+
+  @param[] VOID
+
+  @retval  VOID
+**/
+EFIAPI
+VOID
+ConfigureMmu (VOID)
+{
+  PGD *SwapperPageDir = NULL;
+  PGD *InvalidPgd = NULL;
+  PUD *InvalidPudTable = NULL;
+  PMD *InvalidPmdTable = NULL;
+  PTE *InvalidPteTable = NULL;
+  MEMORY_REGION_DESCRIPTOR  *MemoryTable = NULL;
+  RETURN_STATUS PcdStatus;
+  UINTN PgdShift = PGD_SHIFT;
+  UINTN PgdWide = PGD_WIDE;
+  UINTN PudShift = PUD_SHIFT;
+  UINTN PudWide = PUD_WIDE;
+  UINTN PmdShift = PMD_SHIFT;
+  UINTN PmdWide = PMD_WIDE;
+  UINTN PteShift = PTE_SHIFT;
+  UINTN PteWide = PTE_WIDE;
+  UINTN PageEnable = 1 << 4;
+  VOID *TlbReEntry;
+
+  SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  InvalidPgd = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  InvalidPudTable = AllocatePages (EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
+  InvalidPmdTable = AllocatePages (EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
+  InvalidPteTable = AllocatePages (EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
+  ZeroMem (InvalidPteTable, PTE_TABLE_SIZE);
+
+  if ((!InvalidPgd) ||
+      (!InvalidPudTable) ||
+      (!InvalidPmdTable) ||
+      (!InvalidPteTable))
+  {
+    goto FreeTranslationTable;
+  }
+
+  /*pgd init*/
+  PageDirInit (SwapperPageDir , ENTRYS_PER_PGD, InvalidPudTable);
+  /*pgd init*/
+  PageDirInit (InvalidPgd, ENTRYS_PER_PGD, InvalidPudTable);
+  /*pud init*/
+  PageDirInit (InvalidPudTable, ENTRYS_PER_PUD, InvalidPmdTable);
+  /*pmd init*/
+  PageDirInit (InvalidPmdTable, ENTRYS_PER_PMD, InvalidPteTable);
+  GetMemoryMapFromFwCfg (&MemoryTable);
+
+  PcdStatus |= PcdSet64S (PcdSwapPageDir, (UINTN)SwapperPageDir);
+  PcdStatus |= PcdSet64S (PcdInvalidPgd, (UINTN)InvalidPgd);
+  PcdStatus |= PcdSet64S (PcdInvalidPud, (UINTN)InvalidPudTable);
+  PcdStatus |= PcdSet64S (PcdInvalidPmd, (UINTN)InvalidPmdTable);
+  PcdStatus |= PcdSet64S (PcdInvalidPte, (UINTN)InvalidPteTable);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  while (MemoryTable->Length != 0) {
+    DEBUG ((DEBUG_VERBOSE, "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", __func__, __LINE__,
+      MemoryTable->VirtualBase,
+      (MemoryTable->Length + MemoryTable->VirtualBase),
+      MemoryTable->Attributes));
+
+    PcdStatus = FillTranslationTable (MemoryTable);
+    if (EFI_ERROR (PcdStatus)) {
+      goto FreeTranslationTable;
+    }
+    MemoryTable++;
+  }
+
+  TlbReEntry = AllocatePages (1);
+  if (TlbReEntry == NULL) {
+    goto FreeTranslationTable;
+  }
+  CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - HandleTlbRefill));
+  InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefill, (UINTN)(HandleTlbRefillEnd - HandleTlbRefill));
+
+  DEBUG ((DEBUG_VERBOSE,
+    "%a  %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudWide %d PgdShift %d PgdWide %d.\n",
+    __func__, __LINE__,
+    PteShift, PteWide, PmdShift, PmdWide,PudShift, PudWide, PgdShift, PgdWide));
+
+  SetTlbRefillFuncBase ((UINTN)TlbReEntry);
+  /*set page size*/
+  WriteCsrPageSize (DEFAULT_PAGE_SIZE);
+  WriteCsrStlbPageSize (DEFAULT_PAGE_SIZE);
+  WriteCsrTlbRefillPageSize (DEFAULT_PAGE_SIZE);
+
+  LoongArchWriteqCsrPwctl0 ((PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25
+              ));
+  LoongArchWriteqCsrPwctl1 (PgdShift | PgdWide << 6);
+  LoongArchWriteqCsrPgdl ((UINTN)SwapperPageDir);
+  LoongArchWriteqCsrPgdh ((UINTN)InvalidPgd);
+
+  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
+  LoongArchXchgCsrCrmd ( PageEnable, 1 << 4);
+  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu End.\n", __func__, __LINE__));
+
+  return ;
+
+FreeTranslationTable:
+  if (SwapperPageDir) {
+    FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  }
+
+  if (InvalidPgd) {
+    FreePages (InvalidPgd, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  }
+
+  if (InvalidPudTable) {
+    FreePages (InvalidPudTable, EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
+  }
+
+  if (InvalidPmdTable) {
+    FreePages (InvalidPmdTable, EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
+  }
+
+  if (InvalidPteTable) {
+    FreePages (InvalidPteTable, EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
+  }
+
+  PcdSet64S (PcdSwapPageDir, (UINTN)0);
+  PcdSet64S (PcdInvalidPgd, (UINTN)0);
+  PcdSet64S (PcdInvalidPud, (UINTN)0);
+  PcdSet64S (PcdInvalidPmd, (UINTN)0);
+  PcdSet64S (PcdInvalidPte, (UINTN)0);
+
+  return ;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
new file mode 100644
index 0000000000..8e284a2ecd
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
@@ -0,0 +1,190 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Tlb or TLB     - Translation Lookaside Buffer
+    - CSR            - Cpu State Register
+    - PGDL           - Page Global Directory Low
+    - PGDH           - Page Global Directory High
+    - TLBIDX         - TLB Index
+    - TLBREHI        - TLB Refill Entry High
+    - PWCTL          - Page Walk Control
+    - STLB           - Singular Page Size TLB
+    - PS             - Page Size
+**/
+#ifndef MMU_H_
+#define MMU_H_
+/*page size 4k*/
+#define DEFAULT_PAGE_SIZE         0x0c
+#define LOONGARCH_CSR_PGDL        0x19 /* Page table base address when VA[47] = 0 */
+#define LOONGARCH_CSR_PGDH        0x1a /* Page table base address when VA[47] = 1 */
+#define LOONGARCH_CSR_TLBIDX      0x10 /* TLB Index, EHINV, PageSize, NP */
+#define LOONGARCH_CSR_TLBEHI      0x11 /* TLB EntryHi */
+#define LOONGARCH_CSR_TLBELO0     0x12 /* TLB EntryLo0 */
+#define LOONGARCH_CSR_TLBELO1     0x13 /* TLB EntryLo1 */
+#define LOONGARCH_CSR_TLBREHI     0x8e /* TLB refill entryhi */
+#define LOONGARCH_CSR_PWCTL0      0x1c /* PWCtl0 */
+#define LOONGARCH_CSR_PWCTL1      0x1d /* PWCtl1 */
+#define LOONGARCH_CSR_STLBPGSIZE  0x1e
+#define CSR_TLBIDX_SIZE_MASK      0x3f000000
+#define CSR_TLBIDX_PS_SHIFT       24
+#define CSR_TLBIDX_SIZE           CSR_TLBIDX_PS_SHIFT
+
+#define  CSR_TLBREHI_PS_SHIFT     0
+#define  CSR_TLBREHI_PS           0x3f
+
+#define EFI_MEMORY_CACHETYPE_MASK     (EFI_MEMORY_UC  | \
+                                       EFI_MEMORY_WC  | \
+                                       EFI_MEMORY_WT  | \
+                                       EFI_MEMORY_WB  | \
+                                       EFI_MEMORY_UCE   \
+                                       )
+
+typedef struct {
+  EFI_PHYSICAL_ADDRESS PhysicalBase;
+  EFI_VIRTUAL_ADDRESS  VirtualBase;
+  UINTN                Length;
+  UINTN                Attributes;
+} MEMORY_REGION_DESCRIPTOR;
+
+// The total number of descriptors, including the final "end-of-table" descriptor.
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)
+
+extern CHAR8 HandleTlbRefill[], HandleTlbRefillEnd[];
+
+/*
+ Invalid corresponding TLB entries are based on the address given
+
+ @param Address The address corresponding to the invalid page table entry
+
+ @retval  none
+*/
+extern
+VOID
+LoongarchInvalidTlb (
+  UINTN Address
+  );
+
+/*
+ Set Tlb Refill function to hardware
+
+ @param A0 The address of tlb refill function
+
+ @retval  none
+*/
+extern
+VOID
+SetTlbRefillFuncBase (
+  UINTN Address
+  );
+
+/*
+  Set Cpu Status Register Page Size.
+
+  @param  PageSize  Page Size.
+
+  @retval  none
+*/
+extern
+VOID
+WriteCsrPageSize (
+  UINTN PageSize
+  );
+
+/*
+  Set Cpu Status Register TLBREFILL Page Size.
+
+  @param  PageSize  Page Size.
+
+  @retval  none
+*/
+extern
+VOID
+WriteCsrTlbRefillPageSize (
+  UINTN PageSize
+  );
+
+/*
+  Set Cpu Status Register STLB Page Size.
+
+  @param PageSize  Page Size.
+
+  @retval  VOID
+*/
+extern
+VOID
+WriteCsrStlbPageSize (
+  UINTN PageSize
+);
+
+/*
+  Write Csr PWCTL0 register.
+
+  @param  Val  The value used to write to the PWCTL0 register
+
+  @retval  none
+*/
+extern
+VOID
+LoongArchWriteqCsrPwctl0 (
+  UINTN Val
+  );
+
+/*
+  Write Csr PWCTL1 register.
+
+  @param  Val  The value used to write to the PWCTL1 register
+
+  @retval  none
+*/
+extern
+VOID
+LoongArchWriteqCsrPwctl1 (
+  UINTN Val
+  );
+
+/*
+  Write Csr PGDL register.
+
+  @param  Val  The value used to write to the PGDL register
+
+  @retval  none
+*/
+extern
+VOID
+LoongArchWriteqCsrPgdl (
+  UINTN Val
+  );
+
+/*
+  Write Csr PGDH register.
+
+  @param  Val  The value used to write to the PGDH register
+
+  @retval  none
+*/
+extern
+VOID
+LoongArchWriteqCsrPgdh (
+  UINTN Val
+  );
+
+/*
+  Exchange specified bit data with the Csr CRMD register.
+
+  @param[IN]  Val   The value Exchanged with the CSR CRMD register.
+  @param[IN]  Mask   Specifies the mask for swapping bits
+
+  @retval  VOID
+*/
+extern
+VOID
+LoongArchXchgCsrCrmd (
+  UINTN Val,
+  UINTN Mask
+  );
+
+#endif // MMU_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
new file mode 100644
index 0000000000..6ab07e7900
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
@@ -0,0 +1,280 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Pgd or Pgd or PGD    - Page Global Directory
+    - Pud or Pud or PUD    - Page Upper Directory
+    - Pmd or Pmd or PMD    - Page Middle Directory
+    - Pte or pte or PTE    - Page Table Entry
+    - Val or VAL or val    - Value
+    - Dir    - Directory
+**/
+#ifndef PAGE_H_
+#define PAGE_H_
+
+#define MAX_VA_BITS                         47
+#define PGD_WIDE                            (8)
+#define PUD_WIDE                            (9)
+#define PMD_WIDE                            (9)
+#define PTE_WIDE                            (9)
+
+#define ENTRYS_PER_PGD                      (1 << PGD_WIDE)
+#define ENTRYS_PER_PUD                      (1 << PUD_WIDE)
+#define ENTRYS_PER_PMD                      (1 << PMD_WIDE)
+#define ENTRYS_PER_PTE                      (1 << PTE_WIDE)
+
+#define PGD_SHIFT                           (PUD_SHIFT + PUD_WIDE)
+#define PUD_SHIFT                           (PMD_SHIFT + PMD_WIDE)
+#define PMD_SHIFT                           (EFI_PAGE_SHIFT + PTE_WIDE)
+#define PTE_SHIFT                           (EFI_PAGE_SHIFT)
+
+#define PGD_SIZE                            (1UL << PGD_SHIFT)
+#define PUD_SIZE                            (1UL << PUD_SHIFT)
+#define PMD_SIZE                            (1UL << PMD_SHIFT)
+
+#define PGD_MASK                            (~(PGD_SIZE-1))
+#define PUD_MASK                            (~(PUD_SIZE-1))
+#define PMD_MASK                            (~(PMD_SIZE-1))
+#define PAGE_MASK                           (~(EFI_PAGE_SIZE - 1))
+#define PFN_MASK                            (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \
+                                             (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
+
+typedef struct { UINTN PgdVal; } PGD;
+typedef struct { UINTN PudVal; } PUD;
+typedef struct { UINTN PmdVal; } PMD;
+typedef struct { UINTN PteVal; } PTE;
+/**
+  Gets the value of the page global directory table entry.
+
+  @param  x    Page global directory struct variables.
+
+  @retval   the value of the page global directory table entry.
+ **/
+#define PGD_VAL(x)                          ((x).PgdVal)
+/**
+  Gets the value of the page upper directory table entry.
+
+  @param  x    Page upper directory struct variables.
+
+  @retval  the value of the page upper directory table entry.
+ **/
+#define PUD_VAL(x)                          ((x).PudVal)
+/**
+  Gets the value of the page middle directory table entry.
+
+  @param  x    Page middle directory struct variables.
+
+  @retval  the value of the page middle directory table entry.
+ **/
+#define PMD_VAL(x)                          ((x).PmdVal)
+/**
+  Gets the value of the page table entry.
+
+  @param  x    Page table entry struct variables.
+
+  @retval  the value of the page table entry.
+ **/
+#define PTE_VAL(x)                          ((x).PteVal)
+
+#define PGD_TABLE_SIZE                      (ENTRYS_PER_PGD * sizeof(PGD))
+#define PUD_TABLE_SIZE                      (ENTRYS_PER_PUD * sizeof(PUD))
+#define PMD_TABLE_SIZE                      (ENTRYS_PER_PMD * sizeof(PMD))
+#define PTE_TABLE_SIZE                      (ENTRYS_PER_PTE * sizeof(PTE))
+/**
+  Gets the physical address of the record in the page table entry.
+
+  @param  x    Page table entry struct variables.
+
+  @retval  the value of the physical address.
+ **/
+#define GET_PAGE_ATTRIBUTES(x)              (UINTN) {(PTE_VAL(x) & ~PFN_MASK)}
+/**
+  Gets the virtual address of the next block of the specified virtual address
+  that is aligned with the size of the global page directory mapping.
+
+  @param  Address  Specifies the virtual address.
+  @param  End    The end address of the memory region.
+
+  @retval   the specified virtual address  of the next block.
+ **/
+#define PGD_ADDRESS_END(Address, End)                  \
+({                                                     \
+  UINTN Boundary = ((Address) + PGD_SIZE) & PGD_MASK;  \
+  (Boundary - 1 < (End) - 1)? Boundary: (End);         \
+})
+/**
+  Gets the virtual address of the next block of the specified virtual address
+  that is aligned with the size of the page upper directory mapping.
+
+  @param  Address  Specifies the virtual address.
+  @param  End    The end address of the memory region.
+
+  @retval   the specified virtual address  of the next block.
+ **/
+#define PUD_ADDRESS_END(Address, End)                  \
+({                                                     \
+  UINTN Boundary = ((Address) + PUD_SIZE) & PUD_MASK;  \
+  (Boundary - 1 < (End) - 1)? Boundary: (End);         \
+})
+/**
+  Gets the virtual address of the next block of the specified virtual address
+  that is aligned with the size of the page middle directory mapping.
+
+  @param  Address  Specifies the virtual address.
+  @param  End    The end address of the memory region.
+
+  @retval   the specified virtual address  of the next block.
+ **/
+#define PMD_ADDRESS_END(Address, End)                  \
+({                                                     \
+  UINTN Boundary = ((Address) + PMD_SIZE) & PMD_MASK;  \
+  (Boundary - 1 < (End) - 1)? Boundary: (End);         \
+})
+/**
+  Get Specifies the virtual address corresponding to the index of the page global directory table entry.
+
+  @param  Address  Specifies the virtual address.
+
+  @retval   the index of the page global directory table entry.
+ **/
+#define PGD_INDEX(Address)                  (((Address) >> PGD_SHIFT) & (ENTRYS_PER_PGD-1))
+/**
+  Get Specifies the virtual address corresponding to the index of the page upper directory table entry.
+
+  @param  Address  Specifies the virtual address.
+  @param  End    The end address of the memory region.
+
+  @retval   the index of the page upper directory table entry.
+ **/
+#define PUD_INDEX(Address)                  (((Address) >> PUD_SHIFT) & (ENTRYS_PER_PUD - 1))
+/**
+  Get Specifies the virtual address corresponding to the index of the page middle directory table entry.
+
+  @param  Address  Specifies the virtual address.
+
+  @retval   the index of the page middle directory table entry.
+ **/
+#define PMD_INDEX(Address)                  (((Address) >> PMD_SHIFT) & (ENTRYS_PER_PMD - 1))
+/**
+  Get Specifies the virtual address corresponding to the index of the page table entry.
+
+  @param  Address  Specifies the virtual address.
+
+  @retval   the index of the page table entry.
+ **/
+#define PTE_INDEX(Address)                  (((Address) >> EFI_PAGE_SHIFT) & (ENTRYS_PER_PTE - 1))
+
+/**
+  Calculates the value of the page table entry based on the specified virtual address and properties.
+
+  @param  Address  Specifies the virtual address.
+  @param  Attributes  Specifies the Attributes.
+
+  @retval    the value of the page table entry.
+ **/
+#define MAKE_PTE(Address, Attributes)       (PTE){((((Address) >> EFI_PAGE_SHIFT) << 12) | (Attributes))}
+/**
+  Get Global bit from Attributes
+
+  @param  Attributes  Specifies the Attributes.
+ * */
+#define GET_GLOBALBIT(Attributes)           ((Attributes & PAGE_GLOBAL) >> PAGE_GLOBAL_SHIFT)
+/**
+  Calculates the value of the Huge page table entry based on the specified virtual address and properties.
+
+  @param  Address  Specifies the virtual address.
+  @param  Attributes  Specifies the Attributes.
+
+  @retval    the value of the HUGE page table entry.
+ **/
+#define MAKE_HUGE_PTE(Address, Attributes)  (((((Address) >> PMD_SHIFT) << PMD_SHIFT) | \
+                                             ((Attributes) | (GET_GLOBALBIT(Attributes) << PAGE_HGLOBAL_SHIFT) | \
+                                             PAGE_HUGE)))
+
+ /**
+  Check whether the large page table entry is.
+
+  @param  Val The value of the page table entry.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+#define IS_HUGE_PAGE(Val)                   ((((Val) & PAGE_HUGE) == PAGE_HUGE) && \
+                                             (((Val) & PAGE_HGLOBAL) == PAGE_HGLOBAL))
+
+#define HUGE_PAGE_SIZE                      (PMD_SIZE)
+
+ /**
+  Check that the global page directory table entry is empty.
+
+  @param  pgd   the global page directory struct variables.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pgd_none (
+  IN PGD pgd
+  )
+{
+  return (PGD_VAL(pgd) == (UINTN)PcdGet64(PcdInvalidPud));
+}
+
+ /**
+  Check that the page upper directory table entry is empty.
+
+  @param  pud   Page upper directory struct variables.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pud_none (
+  IN PUD pud
+  )
+{
+  return (PUD_VAL(pud) == (UINTN)PcdGet64 (PcdInvalidPmd));
+}
+
+ /**
+  Check that the page middle directory table entry is empty.
+
+  @param  pmd   Page middle directory struct variables.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pmd_none (
+  IN PMD pmd
+  )
+{
+  return (PMD_VAL(pmd) == (UINTN)PcdGet64(PcdInvalidPte));
+}
+ /**
+  Check that the page  table entry is empty.
+
+  @param  pmd   Page table entry struct variables.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pte_none (
+  IN PTE pte
+  )
+{
+  return (!(PTE_VAL(pte) & (~PAGE_GLOBAL)));
+}
+#endif // PAGE_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
new file mode 100644
index 0000000000..aacbf81744
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
@@ -0,0 +1,57 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Tlb or TLB     - Translation Lookaside Buffer
+    - HGLOBAL     - Huge Global
+    - PFN       - Page Frame number
+    - EXEC       - Execute
+    - PLV       - Privilege Level
+    - RPLV       - Restricted Privilege Level
+    - SUC       - Strong-ordered UnCached
+    - CC       - Coherent Cached
+    - WUC       - Weak-ordered UnCached
+**/
+#ifndef PTE_H_
+#define PTE_H_
+/*Page table property definitions */
+#define  PAGE_VALID_SHIFT    0
+#define  PAGE_DIRTY_SHIFT    1
+#define  PAGE_PLV_SHIFT      2  /* 2~3, two bits */
+#define  CACHE_SHIFT         4  /* 4~5, two bits */
+#define  PAGE_GLOBAL_SHIFT   6
+#define  PAGE_HUGE_SHIFT     6  /* HUGE is a PMD bit */
+
+#define  PAGE_HGLOBAL_SHIFT  12 /* HGlobal is a PMD bit */
+#define  PAGE_PFN_SHIFT      12
+#define  PAGE_PFN_END_SHIFT  48
+#define  PAGE_NO_READ_SHIFT  61
+#define  PAGE_NO_EXEC_SHIFT  62
+#define  PAGE_RPLV_SHIFT     63
+
+/* Used by TLB hardware (placed in EntryLo*) */
+#define PAGE_VALID           ((UINTN)(1) << PAGE_VALID_SHIFT)
+#define PAGE_DIRTY           ((UINTN)(1) << PAGE_DIRTY_SHIFT)
+#define PAGE_PLV             ((UINTN)(3) << PAGE_PLV_SHIFT)
+#define PAGE_GLOBAL          ((UINTN)(1) << PAGE_GLOBAL_SHIFT)
+#define PAGE_HUGE            ((UINTN)(1) << PAGE_HUGE_SHIFT)
+#define PAGE_HGLOBAL         ((UINTN)(1) << PAGE_HGLOBAL_SHIFT)
+#define PAGE_NO_READ         ((UINTN)(1) << PAGE_NO_READ_SHIFT)
+#define PAGE_NO_EXEC         ((UINTN)(1) << PAGE_NO_EXEC_SHIFT)
+#define PAGE_RPLV            ((UINTN)(1) << PAGE_RPLV_SHIFT)
+#define CACHE_MASK           ((UINTN)(3) << CACHE_SHIFT)
+#define PFN_SHIFT            (EFI_PAGE_SHIFT - 12 + PAGE_PFN_SHIFT)
+
+#define PLV_KERNEL           0
+#define PLV_USER             3
+
+#define PAGE_USER            (PLV_USER << PAGE_PLV_SHIFT)
+#define PAGE_KERNEL          (PLV_KERN << PAGE_PLV_SHIFT)
+
+#define CACHE_SUC            (0 << CACHE_SHIFT) /* Strong-ordered UnCached */
+#define CACHE_CC             (1 << CACHE_SHIFT) /* Coherent Cached */
+#define CACHE_WUC            (2 << CACHE_SHIFT) /* Weak-ordered UnCached */
+#endif // PTE_H_
-- 
2.31.1




-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#96276): https://edk2.groups.io/g/devel/message/96276
Mute This Topic: https://groups.io/mt/94955173/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [edk2-platforms][PATCH V5 05/15] Platform/Loongson: Add MmuLib.
Posted by Chao Li 2 years, 4 months ago
Reviewed-by: Chao Li <lichao@loongson.cn>

Thanks,
Chao
--------

On 11月 11 2022, at 5:12 下午, xianglai li <lixianglai@loongson.cn> wrote:
> Read the memory map information through the QemuFwCfg interface,
>
> then build the page table through the memory map information,
> and finally enable Mmu.
>
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054
>
>
> Cc: Bibo Mao <maobibo@loongson.cn>
> Cc: Chao Li <lichao@loongson.cn>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Signed-off-by: xianglai li <lixianglai@loongson.cn>
> ---
> .../LoongArchQemuPkg/Include/Library/MmuLib.h | 85 ++
> .../LoongArchQemuPkg/Library/MmuLib/Mmu.S | 155 ++++
> .../Library/MmuLib/MmuBaseLib.inf | 40 +
> .../Library/MmuLib/MmuBaseLibPei.inf | 47 +
> .../Library/MmuLib/MmuLibCore.c | 831 ++++++++++++++++++
> .../Library/MmuLib/MmuLibCore.h | 40 +
> .../Library/MmuLib/MmuLibCorePei.c | 231 +++++
> .../LoongArchQemuPkg/Library/MmuLib/mmu.h | 190 ++++
> .../LoongArchQemuPkg/Library/MmuLib/page.h | 280 ++++++
> .../LoongArchQemuPkg/Library/MmuLib/pte.h | 57 ++
> 10 files changed, 1956 insertions(+)
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
>
>
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
> new file mode 100644
> index 0000000000..9880fc385c
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
> @@ -0,0 +1,85 @@
> +/** @file
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - EXC - execute
> +**/
> +#ifndef MMU_LIB_H_
> +#define MMU_LIB_H_
> +/**
> + write operation is performed Count times from the first element of Buffer.
> + Convert EFI Attributes to Loongarch Attributes.
> + @param[in] EfiAttributes Efi Attributes.
> +
> + @retval LoongArch Attributes.
> +**/
> +UINTN
> +EfiAttributeToLoongArchAttribute (
> + IN UINTN EfiAttributes
> + );
> +
> +/**
> + Finds the length and memory properties of the memory region corresponding to the specified base address.
> +
> + @param[in] BaseAddress To find the base address of the memory region.
> + @param[in] EndAddress To find the end address of the memory region.
> + @param[out] RegionLength The length of the memory region found.
> + @param[out] RegionAttributes Properties of the memory region found.
> +
> + @retval EFI_SUCCESS The corresponding memory area was successfully found
> + EFI_NOT_FOUND No memory area found
> +**/
> +EFI_STATUS
> +GetLoongArchMemoryRegion (
> + IN UINTN BaseAddress,
> + IN UINTN EndAddress,
> + OUT UINTN *RegionLength,
> + OUT UINTN *RegionAttributes
> + );
> +
> +/**
> + Sets the Attributes of the specified memory region
> +
> + @param[in] BaseAddress The base address of the memory region to set the Attributes.
> + @param[in] Length The length of the memory region to set the Attributes.
> + @param[in] Attributes The Attributes to be set.
> +
> + @retval EFI_SUCCESS The Attributes was set successfully
> +**/
> +EFI_STATUS
> +LoongArchSetMemoryAttributes (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length,
> + IN UINTN Attributes
> + );
> +
> +/**
> + Sets the non-executable Attributes for the specified memory region
> +
> + @param[in] BaseAddress The base address of the memory region to set the Attributes.
> + @param[in] Length The length of the memory region to set the Attributes.
> +
> + @retval EFI_SUCCESS The Attributes was set successfully
> +**/
> +EFI_STATUS
> +LoongArchSetMemoryRegionNoExec (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length
> + );
> +
> +/**
> + Create a page table and initialize the MMU.
> +
> + @param[] VOID
> +
> + @retval VOID
> +**/
> +VOID
> +EFIAPI
> +ConfigureMmu (
> + VOID
> + );
> +#endif // MMU_LIB_H_
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
> new file mode 100644
> index 0000000000..d5863de072
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
> @@ -0,0 +1,155 @@
> +#------------------------------------------------------------------------------
> +#
> +# LoongArch for LoongArch
> +#
> +# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#-----------------------------------------------------------------------------
> +
> +#ifndef __ASSEMBLY__
> +#define __ASSEMBLY__
> +#endif
> +
> +#include "Library/Cpu.h"
> +#include "mmu.h"
> +
> +ASM_GLOBAL ASM_PFX(HandleTlbRefill)
> +ASM_GLOBAL HandleTlbRefillEnd
> +ASM_GLOBAL ASM_PFX(LoongarchInvalidTlb)
> +ASM_GLOBAL ASM_PFX(SetTlbRefillFuncBase)
> +ASM_GLOBAL ASM_PFX(WriteCsrPageSize)
> +ASM_GLOBAL ASM_PFX(WriteCsrTlbRefillPageSize)
> +ASM_GLOBAL ASM_PFX(WriteCsrStlbPageSize)
> +ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPwctl0)
> +ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPwctl1)
> +ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPgdl)
> +ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPgdh)
> +ASM_GLOBAL ASM_PFX(LoongArchXchgCsrCrmd)
> +
> +#
> +# Refill the page table.
> +# @param VOID
> +# @retval VOID
> +#
> +
> +ASM_PFX(HandleTlbRefill):
> + csrwr T0, LOONGARCH_CSR_TLBRSAVE
> + csrrd T0, LOONGARCH_CSR_PGD
> + lddir T0, T0, 3 #Put pud BaseAddress into T0
> + lddir T0, T0, 2 #Put pmd BaseAddress into T0
> + lddir T0, T0, 1 #Put pte BaseAddress into T0
> + ldpte T0, 0
> + ldpte T0, 1
> + tlbfill
> + csrrd T0, LOONGARCH_CSR_TLBRSAVE
> + ertn
> +HandleTlbRefillEnd:
> +
> +#
> +# Invalid corresponding TLB entries are based on the address given
> +# @param A0 The address corresponding to the invalid page table entry
> +# @retval none
> +#
> +
> +ASM_PFX(LoongarchInvalidTlb):
> + invtlb INVTLB_ADDR_GTRUE_OR_ASID, ZERO, A0
> + jirl ZERO, RA, 0
> +
> +#
> +# Set Tlb Refill function to hardware
> +# @param A0 The address of tlb refill function
> +# @retval none
> +#
> +
> +ASM_PFX(SetTlbRefillFuncBase):
> + csrwr A0, LOONGARCH_CSR_TLBREBASE
> + jirl ZERO, RA,0
> +
> +#
> +# Set Cpu Status Register Page Size.
> +# @param A0 Page Size.
> +# @retval none
> +#
> +
> +ASM_PFX(WriteCsrPageSize):
> + li.d T0, CSR_TLBIDX_SIZE
> + sll.d A0, A0, T0
> + li.d T0, CSR_TLBIDX_SIZE_MASK
> + csrxchg A0, T0, LOONGARCH_CSR_TLBIDX
> + jirl ZERO, RA,0
> +
> +#
> +# Set Cpu Status Register TLBREFILL Page Size.
> +# @param A0 Page Size.
> +# @retval none
> +#
> +
> +ASM_PFX(WriteCsrTlbRefillPageSize):
> + li.d T0, CSR_TLBREHI_PS_SHIFT
> + sll.d A0, A0, T0
> + li.d T0, CSR_TLBREHI_PS
> + csrxchg A0, T0, LOONGARCH_CSR_TLBREHI
> + jirl ZERO, RA,0
> +
> +#
> +# Set Cpu Status Register STLB Page Size.
> +# @param val Page Size.
> +# @retval VOID
> +#
> +
> +ASM_PFX(WriteCsrStlbPageSize):
> + csrwr A0, LOONGARCH_CSR_STLBPGSIZE
> + jirl ZERO, RA,0
> +
> +#
> +# Write Csr PWCTL0 register.
> +# @param A0 The value used to write to the PWCTL0 register
> +# @retval none
> +#
> +
> +ASM_PFX(LoongArchWriteqCsrPwctl0):
> + csrwr A0, LOONGARCH_CSR_PWCTL0
> + jirl ZERO, RA,0
> +
> +#
> +# Write Csr PWCTL1 register.
> +# @param A0 The value used to write to the PWCTL1 register
> +# @retval none
> +#
> +
> +ASM_PFX(LoongArchWriteqCsrPwctl1):
> + csrwr A0, LOONGARCH_CSR_PWCTL1
> + jirl ZERO, RA,0
> +
> +#
> +# Write Csr PGDL register.
> +# @param A0 The value used to write to the PGDL register
> +# @retval none
> +#
> +
> +ASM_PFX(LoongArchWriteqCsrPgdl):
> + csrwr A0, LOONGARCH_CSR_PGDL
> + jirl ZERO, RA,0
> +
> +#
> +# Write Csr PGDH register.
> +# @param A0 The value used to write to the PGDH register
> +# @retval none
> +#
> +
> +ASM_PFX(LoongArchWriteqCsrPgdh):
> + csrwr A0, LOONGARCH_CSR_PGDH
> + jirl ZERO, RA,0
> +
> +#
> +# Exchange specified bit data with the Csr CRMD register.
> +# @param[IN] A0 The value Exchanged with the CSR CRMD register.
> +# @param[IN] A1 Specifies the mask for swapping bits
> +# @retval VOID
> +#
> +
> +ASM_PFX(LoongArchXchgCsrCrmd):
> + csrxchg A0, A1, LOONGARCH_CSR_CRMD
> + jirl ZERO, RA,0
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
> new file mode 100644
> index 0000000000..abd864a324
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
> @@ -0,0 +1,40 @@
> +## @file
> +#
> +# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = MmuBaseLib
> + FILE_GUID = da8f0232-fb14-42f0-922c-63104d2c70be
> + MODULE_TYPE = BASE
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = MmuLib
> + CONSTRUCTOR = MmuInitialize
> +
> +#
> +# VALID_ARCHITECTURES = LOONGARCH64
> +#
> +
> +[Sources]
> + MmuLibCore.c
> + Mmu.S
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + Platform/Loongson/LoongArchQemuPkg/Loongson.dec
> +
> +[PCD]
> + gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
> + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
> + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
> + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
> + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
> +
> +[LibraryClasses]
> + MemoryAllocationLib
> + PcdLib
> + DebugLib
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
> new file mode 100644
> index 0000000000..12848eecfe
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
> @@ -0,0 +1,47 @@
> +## @file
> +#
> +# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = MmuPeiLib
> + FILE_GUID = da8f0232-fb14-42f0-922c-63104d2c70bd
> + MODULE_TYPE = BASE
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = MmuLib | SEC PEIM
> +
> +#
> +# VALID_ARCHITECTURES = LOONGARCH64
> +#
> +
> +[Sources]
> + MmuLibCorePei.c
> + Mmu.S
> + MmuLibCore.h
> + MmuLibCore.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + Platform/Loongson/LoongArchQemuPkg/Loongson.dec
> + OvmfPkg/OvmfPkg.dec
> +
> +[PCD]
> + gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
> + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
> + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
> + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
> + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
> + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
> + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase
> + gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
> +
> +[LibraryClasses]
> + MemoryAllocationLib
> + CacheMaintenanceLib
> + PcdLib
> + DebugLib
> + QemuFwCfgLib
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
> new file mode 100644
> index 0000000000..b932e3d568
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
> @@ -0,0 +1,831 @@
> +/** @file
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - Pgd or Pgd or PGD - Page Global Directory
> + - Pud or Pud or PUD - Page Upper Directory
> + - Pmd or Pmd or PMD - Page Middle Directory
> + - Pte or pte or PTE - Page Table Entry
> + - Val or VAL or val - Value
> + - Dir - Directory
> +**/
> +#include <Uefi.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include "Library/Cpu.h"
> +#include "pte.h"
> +#include "page.h"
> +#include "mmu.h"
> +
> +BOOLEAN mMmuInited = FALSE;
> +/**
> + Check to see if mmu successfully initializes.
> +
> + @param VOID.
> +
> + @retval TRUE Initialization has been completed.
> + FALSE Initialization did not complete.
> +**/
> +BOOLEAN
> +MmuIsInit (VOID) {
> + if ((mMmuInited == TRUE) ||
> + (PcdGet64 (PcdSwapPageDir) != 0)) {
> + return TRUE;
> + }
> + return FALSE;
> +}
> +
> +/**
> + Iterates through the page directory to initialize it.
> +
> + @param Dst A pointer to the directory of the page to initialize.
> + @param Num The number of page directories to initialize.
> + @param Src A pointer to the data used to initialize the page directory.
> +
> + @retval VOID.
> +**/
> +VOID
> +PageDirInit (
> + IN VOID *Dst,
> + IN UINTN Num,
> + IN VOID *Src
> + )
> +{
> + UINTN *Ptr;
> + UINTN *End;
> + UINTN Entry;
> +
> + Entry = (UINTN)Src;
> + Ptr = (UINTN *)Dst;
> + End = Ptr + Num;
> +
> + for ( ;Ptr < End; Ptr++) {
> + *Ptr = Entry;
> + }
> +
> + return ;
> +}
> +
> +/**
> + Gets the virtual address corresponding to the page global directory table entry.
> +
> + @param Address the virtual address for the table entry.
> +
> + @retval PGD A pointer to get the table item.
> +**/
> +PGD *
> +PgdOffset (
> + IN UINTN Address
> + )
> +{
> + return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address);
> +}
> +
> +/**
> + Gets the virtual address corresponding to the page upper directory table entry.
> +
> + @param Pgd A pointer to a page global directory table entry.
> + @param Address the virtual address for the table entry.
> +
> + @retval PUD A pointer to get the table item.
> +**/
> +PUD *
> +PudOffset (
> + IN PGD *Pgd,
> + IN UINTN Address
> + )
> +{
> + UINTN PgdVal = (UINTN)PGD_VAL (*Pgd);
> + return (PUD *)PgdVal + PUD_INDEX (Address);
> +}
> +
> +/**
> + Gets the virtual address corresponding to the page middle directory table entry.
> +
> + @param Pud A pointer to a page upper directory table entry.
> + @param Address the virtual address for the table entry.
> +
> + @retval PMD A pointer to get the table item.
> +**/
> +PMD *
> +PmdOffset (
> + IN PUD *Pud,
> + IN UINTN Address
> + )
> +{
> + UINTN PudVal = PUD_VAL (*Pud);
> + return (PMD *)PudVal + PMD_INDEX (Address);
> +}
> +
> +/**
> + Gets the virtual address corresponding to the page table entry.
> +
> + @param Pmd A pointer to a page middle directory table entry.
> + @param Address the virtual address for the table entry.
> +
> + @retval PTE A pointer to get the table item.
> +**/
> +PTE *
> +PteOffset (
> + IN PMD *Pmd,
> + IN UINTN Address
> + )
> +{
> + UINTN PmdVal = (UINTN)PMD_VAL (*Pmd);
> + return (PTE *)PmdVal + PTE_INDEX (Address);
> +}
> +
> +/**
> + Sets the value of the page table entry.
> +
> + @param Pte A pointer to a page table entry.
> + @param PteVal The value of the page table entry to set.
> +
> + @retval VOID
> +**/
> +VOID
> +SetPte (
> + IN PTE *Pte,
> + IN PTE PteVal
> + )
> +{
> + *Pte = PteVal;
> +}
> +
> +/**
> + Sets the value of the page global directory.
> +
> + @param Pgd A pointer to a page global directory.
> + @param Pud The value of the page global directory to set.
> +
> + @retval VOID
> +**/
> +VOID
> +SetPgd (
> + IN PGD *Pgd,
> + IN PUD *Pud
> + )
> +{
> + *Pgd = (PGD) {((UINTN)Pud)};
> +}
> +
> +/**
> + Sets the value of the page upper directory.
> +
> + @param Pud A pointer to a page upper directory.
> + @param Pmd The value of the page upper directory to set.
> +
> + @retval VOID
> +**/
> +VOID
> +SetPud (
> + IN PUD *Pud,
> + IN PMD *Pmd
> + )
> +{
> + *Pud = (PUD) {((UINTN)Pmd)};
> +}
> +
> +/**
> + Sets the value of the page middle directory.
> +
> + @param Pmd A pointer to a page middle directory.
> + @param Pte The value of the page middle directory to set.
> +
> + @retval VOID
> +**/
> +VOID
> +SetPmd (
> + IN PMD *Pmd,
> + IN PTE *Pte
> + )
> +{
> + *Pmd = (PMD) {((UINTN)Pte)};
> +}
> +
> +/**
> + Free up memory space occupied by page tables.
> +
> + @param Pte A pointer to the page table.
> +
> + @retval VOID
> +**/
> +VOID
> +PteFree (
> + IN PTE *Pte
> + )
> +{
> + FreePages ((VOID *)Pte, 1);
> +}
> +
> +/**
> + Free up memory space occupied by page middle directory.
> +
> + @param Pmd A pointer to the page middle directory.
> +
> + @retval VOID
> +**/
> +VOID
> +PmdFree (
> + IN PMD *Pmd
> + )
> +{
> + FreePages ((VOID *)Pmd, 1);
> +}
> +
> +/**
> + Free up memory space occupied by page upper directory.
> +
> + @param Pud A pointer to the page upper directory.
> +
> + @retval VOID
> +**/
> +VOID
> +PudFree (
> + IN PUD *Pud
> + )
> +{
> + FreePages ((VOID *)Pud, 1);
> +}
> +
> +/**
> + Requests the memory space required for the page upper directory,
> + initializes it, and places it in the specified page global directory
> +
> + @param Pgd A pointer to the page global directory.
> +
> + @retval EFI_SUCCESS Memory request successful.
> + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
> +**/
> +INTN
> +PudAlloc (
> + IN PGD *Pgd
> + )
> +{
> + PUD *Pud = (PUD *) AllocatePages (1);
> + if (!Pud) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPmd));
> +
> + if (pgd_none (*Pgd)) {
> + SetPgd (Pgd, Pud);
> + } else { /* Another has populated it */
> + PudFree (Pud);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Requests the memory space required for the page middle directory,
> + initializes it, and places it in the specified page upper directory
> +
> + @param Pud A pointer to the page upper directory.
> +
> + @retval EFI_SUCCESS Memory request successful.
> + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
> +**/
> +EFI_STATUS
> +PmdAlloc (
> + IN PUD *Pud
> + )
> +{
> + PMD *Pmd;
> +
> + Pmd = (PMD *) AllocatePages (1);
> + if (!Pmd) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPte));
> +
> + if (pud_none (*Pud)) {
> + SetPud (Pud, Pmd);
> + } else {/* Another has populated it */
> + PmdFree (Pmd);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Requests the memory space required for the page table,
> + initializes it, and places it in the specified page middle directory
> +
> + @param Pmd A pointer to the page middle directory.
> +
> + @retval EFI_SUCCESS Memory request successful.
> + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
> +**/
> +INTN
> +PteAlloc (
> + IN PMD *Pmd
> + )
> +{
> + PTE *Pte;
> +
> + Pte = (PTE *) AllocatePages (1);
> + if (!Pte) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
> +
> + if (pmd_none (*Pmd)) {
> + SetPmd (Pmd, Pte);
> + } else { /* Another has populated it */
> + PteFree (Pte);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Requests the memory space required for the page upper directory,
> + initializes it, and places it in the specified page global directory,
> + and get the page upper directory entry corresponding to the virtual address
> +
> + @param Pgd A pointer to the page global directory.
> +
> + @retval Gets the page upper directory entry
> +**/
> +PUD *
> +PudAllocGet (
> + IN PGD *Pgd,
> + IN UINTN Address
> + )
> +{
> + return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ?
> + NULL : PudOffset (Pgd, Address));
> +}
> +
> +/**
> + Requests the memory space required for the page middle directory,
> + initializes it, and places it in the specified page upper directory,
> + and get the page middle directory entry corresponding to the virtual address
> +
> + @param Pud A pointer to the page upper directory.
> +
> + @retval Gets the page middle directory entry
> +**/
> +PMD *
> +PmdAllocGet (
> + IN PUD *Pud,
> + IN UINTN Address
> + )
> +{
> + PMD * ret = (pud_none (*Pud) && PmdAlloc (Pud))?
> + NULL: PmdOffset (Pud, Address);
> + DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", __func__, __LINE__,
> + Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) ));
> +
> + return ret;
> +}
> +
> +/**
> + Requests the memory space required for the page table,
> + initializes it, and places it in the specified page middle directory,
> + and get the page table entry corresponding to the virtual address
> +
> + @param Pmd A pointer to the page upper directory.
> +
> + @retval Gets the page table entry
> +**/
> +PTE *
> +PteAllocGet (
> + IN PMD *Pmd,
> + IN UINTN Address
> + )
> +{
> + return (pmd_none (*Pmd) && PteAlloc (Pmd))?
> + NULL: PteOffset (Pmd, Address);
> +}
> +
> +/**
> + Gets the physical address of the page table entry corresponding to the specified virtual address.
> +
> + @param Address the corresponding virtual address of the page table entry.
> +
> + @retval A pointer to the page table entry.
> + @retval NULL
> +**/
> +PTE *
> +GetPteAddress (
> + IN UINTN Address
> + )
> +{
> + PGD *Pgd;
> + PUD *Pud;
> + PMD *Pmd;
> +
> + Pgd = PgdOffset (Address);
> +
> + if (pgd_none (*Pgd)) {
> + return NULL;
> + }
> +
> + Pud = PudOffset (Pgd, Address);
> +
> + if (pud_none (*Pud)) {
> + return NULL;
> + }
> +
> + Pmd = PmdOffset (Pud, Address);
> + if (pmd_none (*Pmd)) {
> + return NULL;
> + }
> +
> + if (IS_HUGE_PAGE (Pmd->PmdVal)) {
> + return ((PTE *)Pmd);
> + }
> +
> + return PteOffset (Pmd, Address);
> +}
> +
> +/**
> + Establishes a page table entry based on the specified memory region.
> +
> + @param Pmd A pointer to the page middle directory.
> + @param Address The memory space start address.
> + @param End The end address of the memory space.
> + @param Attributes Memory space Attributes.
> +
> + @retval EFI_SUCCESS The page table entry was created successfully.
> + @retval EFI_OUT_OF_RESOURCES Page table entry establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +MemoryMapPteRange (
> + IN PMD *Pmd,
> + IN UINTN Address,
> + IN UINTN End,
> + IN UINTN Attributes
> + )
> +{
> + PTE *Pte;
> + PTE PteVal;
> + BOOLEAN UpDate;
> +
> + Pte = PteAllocGet (Pmd, Address);
> + if (!Pte) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + do {
> + UpDate = FALSE;
> + PteVal = MAKE_PTE (Address, Attributes);
> + DEBUG ((DEBUG_VERBOSE,
> + "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p PTE_INDEX %p MAKE_PTE %p\n",
> + __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
> + PTE_INDEX (Address), PteVal));
> +
> + if ((!pte_none (*Pte)) &&
> + (PTE_VAL(*Pte) != PTE_VAL(PteVal)))
> + {
> + UpDate = TRUE;
> + }
> +
> + SetPte (Pte, PteVal);
> + if (UpDate) {
> + LoongarchInvalidTlb(Address);
> + }
> + } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Establishes a page middle directory based on the specified memory region.
> +
> + @param Pud A pointer to the page upper directory.
> + @param Address The memory space start address.
> + @param End The end address of the memory space.
> + @param Attributes Memory space Attributes.
> +
> + @retval EFI_SUCCESS The page middle directory was created successfully.
> + @retval EFI_OUT_OF_RESOURCES Page middle directory establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +MemoryMapPmdRange (
> + IN PUD *Pud,
> + IN UINTN Address,
> + IN UINTN End,
> + IN UINTN Attributes
> + )
> +{
> + PMD *Pmd;
> + PTE *Pte;
> + UINTN Next;
> + UINTN AddressStart_HugePage;
> + UINTN AddressEnd_HugePage;
> +
> + Pmd = PmdAllocGet (Pud, Address);
> + if (!Pmd) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + do {
> + Next = PMD_ADDRESS_END (Address, End);
> + if (((Address & (~PMD_MASK)) == 0) &&
> + ((Next & (~PMD_MASK)) == 0) &&
> + (pmd_none (*Pmd)))
> + {
> + DEBUG ((DEBUG_VERBOSE,
> + "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p MAKE_HUGE_PTE %p\n",
> + __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
> + MAKE_HUGE_PTE (Address, Attributes)));
> +
> + SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes));
> + } else {
> + if ((pmd_none (*Pmd)) ||
> + ((!pmd_none (*Pmd)) &&
> + (!IS_HUGE_PAGE (Pmd->PmdVal))))
> + {
> + if (MemoryMapPteRange (Pmd, Address, Next, Attributes)) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + } else {
> + SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte));
> + AddressStart_HugePage = Address & PMD_MASK;
> + AddressEnd_HugePage = AddressStart_HugePage + HUGE_PAGE_SIZE;
> + if (MemoryMapPteRange (Pmd, AddressStart_HugePage, AddressEnd_HugePage, Attributes)) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + Pte = GetPteAddress (AddressStart_HugePage);
> + if (Pte == NULL) {
> + continue ;
> + }
> + if (AddressEnd_HugePage > End) {
> + Next = End;
> + }
> + }
> + }
> + } while (Pmd++, Address = Next, Address != End);
> +
> + return 0;
> +}
> +
> +/**
> + Establishes a page upper directory based on the specified memory region.
> +
> + @param Pgd A pointer to the page global directory.
> + @param Address The memory space start address.
> + @param End The end address of the memory space.
> + @param Attributes Memory space Attributes.
> +
> + @retval EFI_SUCCESS The page upper directory was created successfully.
> + @retval EFI_OUT_OF_RESOURCES Page upper directory establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +MemoryMapPudRange (
> + IN PGD *Pgd,
> + IN UINTN Address,
> + IN UINTN End,
> + IN UINTN Attributes
> + )
> +{
> + PUD *Pud;
> + UINTN Next;
> +
> + Pud = PudAllocGet (Pgd, Address);
> + if (!Pud) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + do {
> + Next = PUD_ADDRESS_END (Address, End);
> + if (MemoryMapPmdRange (Pud, Address, Next, Attributes)) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + } while (Pud++, Address = Next, Address != End);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Establishes a page global directory based on the specified memory region.
> +
> + @param Start The memory space start address.
> + @param End The end address of the memory space.
> + @param Attributes Memory space Attributes.
> +
> + @retval EFI_SUCCESS The page global directory was created successfully.
> + @retval EFI_OUT_OF_RESOURCES Page global directory establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +MemoryMapPageRange (
> + IN UINTN Start,
> + IN UINTN End,
> + IN UINTN Attributes
> + )
> +{
> + PGD *Pgd;
> + UINTN Next;
> + UINTN Address = Start;
> + EFI_STATUS Err;
> +
> + Pgd = PgdOffset (Address);
> + do {
> + Next = PGD_ADDRESS_END (Address, End);
> + Err = MemoryMapPudRange (Pgd, Address, Next, Attributes);
> + if (Err) {
> + return Err;
> + }
> + } while (Pgd++, Address = Next, Address != End);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Page tables are established from memory-mapped tables.
> +
> + @param MemoryRegion A pointer to a memory-mapped table entry.
> +
> + @retval EFI_SUCCESS The page table was created successfully.
> + @retval EFI_OUT_OF_RESOURCES Page table establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +FillTranslationTable (
> + IN MEMORY_REGION_DESCRIPTOR *MemoryRegion
> + )
> +{
> + return MemoryMapPageRange (MemoryRegion->VirtualBase,
> + (MemoryRegion->Length + MemoryRegion->VirtualBase),
> + MemoryRegion->Attributes);
> +}
> +
> +/**
> + write operation is performed Count times from the first element of Buffer.
> + Convert EFI Attributes to Loongarch Attributes.
> + @param[in] EfiAttributes Efi Attributes.
> +
> + @retval LoongArch Attributes.
> +**/
> +UINTN
> +EfiAttributeToLoongArchAttribute (
> + IN UINTN EfiAttributes
> + )
> +{
> + UINTN LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | CACHE_CC | PAGE_USER | PAGE_GLOBAL;
> + switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
> + case EFI_MEMORY_UC:
> + LoongArchAttributes |= CACHE_SUC;
> + break;
> + case EFI_MEMORY_WC:
> + case EFI_MEMORY_WT:
> + case EFI_MEMORY_WB:
> + LoongArchAttributes |= CACHE_CC;
> + break;
> + default :
> + LoongArchAttributes |= CACHE_CC;
> + break;
> + }
> +
> + // Write protection attributes
> + if ((EfiAttributes & EFI_MEMORY_RO) != 0) {
> + LoongArchAttributes &= ~PAGE_DIRTY;
> + }
> +
> + //eXecute protection attribute
> + if ((EfiAttributes & EFI_MEMORY_XP) != 0) {
> + LoongArchAttributes |= PAGE_NO_EXEC;
> + }
> +
> + return LoongArchAttributes;
> +}
> +
> +/**
> + Finds the length and memory properties of the memory region corresponding to the specified base address.
> +
> + @param[in] BaseAddress To find the base address of the memory region.
> + @param[in] EndAddress To find the end address of the memory region.
> + @param[out] RegionLength The length of the memory region found.
> + @param[out] RegionAttributes Properties of the memory region found.
> +
> + @retval EFI_SUCCESS The corresponding memory area was successfully found
> + EFI_NOT_FOUND No memory area found
> +**/
> +EFI_STATUS
> +GetLoongArchMemoryRegion (
> + IN UINTN BaseAddress,
> + IN UINTN EndAddress,
> + OUT UINTN *RegionLength,
> + OUT UINTN *RegionAttributes
> + )
> +{
> + PTE *Pte;
> + UINTN Attributes;
> + UINTN AttributesTmp;
> + UINTN MaxAddress;
> + MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
> + Pte = GetPteAddress (BaseAddress);
> +
> + if (!MmuIsInit ()) {
> + return EFI_SUCCESS;
> + }
> + if (Pte == NULL) {
> + return EFI_NOT_FOUND;
> + }
> + Attributes = GET_PAGE_ATTRIBUTES (*Pte);
> + if (IS_HUGE_PAGE (Pte->PteVal)) {
> + *RegionAttributes = Attributes & (~(PAGE_HUGE));
> + *RegionLength += HUGE_PAGE_SIZE;
> + } else {
> + *RegionLength += EFI_PAGE_SIZE;
> + *RegionAttributes = Attributes;
> + }
> +
> + while (BaseAddress <= MaxAddress) {
> + Pte = GetPteAddress (BaseAddress);
> + if (Pte == NULL) {
> + return EFI_SUCCESS;
> + }
> + AttributesTmp = GET_PAGE_ATTRIBUTES (*Pte);
> + if (IS_HUGE_PAGE (Pte->PteVal)) {
> + if (AttributesTmp == Attributes) {
> + *RegionLength += HUGE_PAGE_SIZE;
> + }
> + BaseAddress += HUGE_PAGE_SIZE;
> + } else {
> + if (AttributesTmp == Attributes) {
> + *RegionLength += EFI_PAGE_SIZE;
> + }
> + BaseAddress += EFI_PAGE_SIZE;
> + }
> +
> + if (BaseAddress > EndAddress) {
> + break;
> + }
> + }
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Sets the Attributes of the specified memory region
> +
> + @param[in] BaseAddress The base address of the memory region to set the Attributes.
> + @param[in] Length The length of the memory region to set the Attributes.
> + @param[in] Attributes The Attributes to be set.
> +
> + @retval EFI_SUCCESS The Attributes was set successfully
> +**/
> +EFI_STATUS
> +LoongArchSetMemoryAttributes (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length,
> + IN UINTN Attributes
> + )
> +{
> +
> + if (!MmuIsInit ()) {
> + return EFI_SUCCESS;
> + }
> + Attributes = EfiAttributeToLoongArchAttribute (Attributes);
> + DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes));
> + MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Sets the non-executable Attributes for the specified memory region
> +
> + @param[in] BaseAddress The base address of the memory region to set the Attributes.
> + @param[in] Length The length of the memory region to set the Attributes.
> +
> + @retval EFI_SUCCESS The Attributes was set successfully
> +**/
> +EFI_STATUS
> +LoongArchSetMemoryRegionNoExec (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length
> + )
> +{
> + if (MmuIsInit ()) {
> + Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
> + LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP);
> + }
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Check to see if mmu successfully initializes and saves the result.
> +
> + @param VOID.
> +
> + @retval EFI_SUCCESS Initialization succeeded.
> +**/
> +EFI_STATUS
> +MmuInitialize (VOID)
> +{
> + if (PcdGet64 (PcdSwapPageDir) != 0) {
> + mMmuInited = TRUE;
> + }
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
> new file mode 100644
> index 0000000000..7a5e8ea0dd
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
> @@ -0,0 +1,40 @@
> +/** @file
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - Dir - Directory
> +**/
> +#ifndef MMU_LIB_CORE_H_
> +#define MMU_LIB_CORE_H_
> +/**
> + Iterates through the page directory to initialize it.
> +
> + @param Dst A pointer to the directory of the page to initialize.
> + @param Num The number of page directories to initialize.
> + @param Src A pointer to the data used to initialize the page directory.
> +
> + @retval VOID.
> +**/
> +VOID
> +PageDirInit (
> + IN VOID *dest,
> + IN UINTN Count,
> + IN VOID *src
> + );
> +
> +/**
> + Page tables are established from memory-mapped tables.
> +
> + @param MemoryRegion A pointer to a memory-mapped table entry.
> +
> + @retval EFI_SUCCESS The page table was created successfully.
> + @retval EFI_OUT_OF_RESOURCES Page table establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +FillTranslationTable (
> + IN MEMORY_REGION_DESCRIPTOR *MemoryRegion
> + );
> +#endif // MMU_LIB_CORE_H_
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
> new file mode 100644
> index 0000000000..32a7fc0beb
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
> @@ -0,0 +1,231 @@
> +/** @file
> + Platform PEI driver
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - FwCfg - Firmeware Config
> + - Tlb - Translation Lookaside Buffer
> +**/
> +#include <Uefi.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include "Library/Cpu.h"
> +#include "pte.h"
> +#include "page.h"
> +#include "mmu.h"
> +#include <Library/QemuFwCfgLib.h>
> +#include "MmuLibCore.h"
> +#include <Library/CacheMaintenanceLib.h>
> +
> +/**
> + Return the Virtual Memory Map of your platform
> +
> + This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
> + on your platform.
> +
> + @param[out] VirtualMemoryMap Array of MEMORY_REGION_DESCRIPTOR
> + describing a Physical-to-Virtual Memory
> + mapping. This array must be ended by a
> + zero-filled entry. The allocated memory
> + will not be freed.
> +**/
> +VOID
> +GetMemoryMapFromFwCfg (
> + OUT MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
> + )
> +{
> +
> + EFI_STATUS Status;
> + FIRMWARE_CONFIG_ITEM FwCfgItem;
> + UINTN FwCfgSize;
> + LOONGARCH_MEMMAP_ENTRY MemoryMapEntry;
> + LOONGARCH_MEMMAP_ENTRY *StartEntry;
> + LOONGARCH_MEMMAP_ENTRY *pEntry;
> + UINTN Processed;
> + MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;
> + UINTN Index = 0;
> + ASSERT (VirtualMemoryMap != NULL);
> +
> + VirtualMemoryTable = AllocatePool (
> + sizeof (MEMORY_REGION_DESCRIPTOR) *
> + MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
> + );
> + VirtualMemoryTable[Index].PhysicalBase = 0x10000000;
> + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
> + VirtualMemoryTable[Index].Length = 0x10000000;
> + VirtualMemoryTable[Index].Attributes = PAGE_VALID | PLV_KERNEL | CACHE_SUC | PAGE_DIRTY | PAGE_GLOBAL;
> + ++Index;
> +
> + Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status));
> + ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
> + *VirtualMemoryMap = VirtualMemoryTable;
> + return ;
> + }
> + if (FwCfgSize % sizeof MemoryMapEntry != 0) {
> + DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize));
> + }
> +
> + QemuFwCfgSelectItem (FwCfgItem);
> + StartEntry = AllocatePages (EFI_SIZE_TO_PAGES (FwCfgSize));
> + QemuFwCfgReadBytes (FwCfgSize, StartEntry);
> + for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) {
> + pEntry = StartEntry + Processed;
> + if (pEntry->Length == 0) {
> + continue;
> + }
> +
> + DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type));
> + VirtualMemoryTable[Index].PhysicalBase = pEntry->BaseAddr;
> + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
> + VirtualMemoryTable[Index].Length = pEntry->Length;
> + VirtualMemoryTable[Index].Attributes = PAGE_VALID | PLV_KERNEL | CACHE_CC | PAGE_DIRTY | PAGE_GLOBAL;
> + ++Index;
> + }
> +
> + FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize));
> + // End of Table
> + ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
> + *VirtualMemoryMap = VirtualMemoryTable;
> + return ;
> +}
> +
> +/**
> + Create a page table and initialize the MMU.
> +
> + @param[] VOID
> +
> + @retval VOID
> +**/
> +EFIAPI
> +VOID
> +ConfigureMmu (VOID)
> +{
> + PGD *SwapperPageDir = NULL;
> + PGD *InvalidPgd = NULL;
> + PUD *InvalidPudTable = NULL;
> + PMD *InvalidPmdTable = NULL;
> + PTE *InvalidPteTable = NULL;
> + MEMORY_REGION_DESCRIPTOR *MemoryTable = NULL;
> + RETURN_STATUS PcdStatus;
> + UINTN PgdShift = PGD_SHIFT;
> + UINTN PgdWide = PGD_WIDE;
> + UINTN PudShift = PUD_SHIFT;
> + UINTN PudWide = PUD_WIDE;
> + UINTN PmdShift = PMD_SHIFT;
> + UINTN PmdWide = PMD_WIDE;
> + UINTN PteShift = PTE_SHIFT;
> + UINTN PteWide = PTE_WIDE;
> + UINTN PageEnable = 1 << 4;
> + VOID *TlbReEntry;
> +
> + SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> + InvalidPgd = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> + InvalidPudTable = AllocatePages (EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
> + InvalidPmdTable = AllocatePages (EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
> + InvalidPteTable = AllocatePages (EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
> + ZeroMem (InvalidPteTable, PTE_TABLE_SIZE);
> +
> + if ((!InvalidPgd) ||
> + (!InvalidPudTable) ||
> + (!InvalidPmdTable) ||
> + (!InvalidPteTable))
> + {
> + goto FreeTranslationTable;
> + }
> +
> + /*pgd init*/
> + PageDirInit (SwapperPageDir , ENTRYS_PER_PGD, InvalidPudTable);
> + /*pgd init*/
> + PageDirInit (InvalidPgd, ENTRYS_PER_PGD, InvalidPudTable);
> + /*pud init*/
> + PageDirInit (InvalidPudTable, ENTRYS_PER_PUD, InvalidPmdTable);
> + /*pmd init*/
> + PageDirInit (InvalidPmdTable, ENTRYS_PER_PMD, InvalidPteTable);
> + GetMemoryMapFromFwCfg (&MemoryTable);
> +
> + PcdStatus |= PcdSet64S (PcdSwapPageDir, (UINTN)SwapperPageDir);
> + PcdStatus |= PcdSet64S (PcdInvalidPgd, (UINTN)InvalidPgd);
> + PcdStatus |= PcdSet64S (PcdInvalidPud, (UINTN)InvalidPudTable);
> + PcdStatus |= PcdSet64S (PcdInvalidPmd, (UINTN)InvalidPmdTable);
> + PcdStatus |= PcdSet64S (PcdInvalidPte, (UINTN)InvalidPteTable);
> + ASSERT_RETURN_ERROR (PcdStatus);
> +
> + while (MemoryTable->Length != 0) {
> + DEBUG ((DEBUG_VERBOSE, "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", __func__, __LINE__,
> + MemoryTable->VirtualBase,
> + (MemoryTable->Length + MemoryTable->VirtualBase),
> + MemoryTable->Attributes));
> +
> + PcdStatus = FillTranslationTable (MemoryTable);
> + if (EFI_ERROR (PcdStatus)) {
> + goto FreeTranslationTable;
> + }
> + MemoryTable++;
> + }
> +
> + TlbReEntry = AllocatePages (1);
> + if (TlbReEntry == NULL) {
> + goto FreeTranslationTable;
> + }
> + CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - HandleTlbRefill));
> + InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefill, (UINTN)(HandleTlbRefillEnd - HandleTlbRefill));
> +
> + DEBUG ((DEBUG_VERBOSE,
> + "%a %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudWide %d PgdShift %d PgdWide %d.\n",
> + __func__, __LINE__,
> + PteShift, PteWide, PmdShift, PmdWide,PudShift, PudWide, PgdShift, PgdWide));
> +
> + SetTlbRefillFuncBase ((UINTN)TlbReEntry);
> + /*set page size*/
> + WriteCsrPageSize (DEFAULT_PAGE_SIZE);
> + WriteCsrStlbPageSize (DEFAULT_PAGE_SIZE);
> + WriteCsrTlbRefillPageSize (DEFAULT_PAGE_SIZE);
> +
> + LoongArchWriteqCsrPwctl0 ((PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25
> + ));
> + LoongArchWriteqCsrPwctl1 (PgdShift | PgdWide << 6);
> + LoongArchWriteqCsrPgdl ((UINTN)SwapperPageDir);
> + LoongArchWriteqCsrPgdh ((UINTN)InvalidPgd);
> +
> + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
> + LoongArchXchgCsrCrmd ( PageEnable, 1 << 4);
> + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu End.\n", __func__, __LINE__));
> +
> + return ;
> +
> +FreeTranslationTable:
> + if (SwapperPageDir) {
> + FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> + }
> +
> + if (InvalidPgd) {
> + FreePages (InvalidPgd, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> + }
> +
> + if (InvalidPudTable) {
> + FreePages (InvalidPudTable, EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
> + }
> +
> + if (InvalidPmdTable) {
> + FreePages (InvalidPmdTable, EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
> + }
> +
> + if (InvalidPteTable) {
> + FreePages (InvalidPteTable, EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
> + }
> +
> + PcdSet64S (PcdSwapPageDir, (UINTN)0);
> + PcdSet64S (PcdInvalidPgd, (UINTN)0);
> + PcdSet64S (PcdInvalidPud, (UINTN)0);
> + PcdSet64S (PcdInvalidPmd, (UINTN)0);
> + PcdSet64S (PcdInvalidPte, (UINTN)0);
> +
> + return ;
> +}
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
> new file mode 100644
> index 0000000000..8e284a2ecd
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
> @@ -0,0 +1,190 @@
> +/** @file
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - Tlb or TLB - Translation Lookaside Buffer
> + - CSR - Cpu State Register
> + - PGDL - Page Global Directory Low
> + - PGDH - Page Global Directory High
> + - TLBIDX - TLB Index
> + - TLBREHI - TLB Refill Entry High
> + - PWCTL - Page Walk Control
> + - STLB - Singular Page Size TLB
> + - PS - Page Size
> +**/
> +#ifndef MMU_H_
> +#define MMU_H_
> +/*page size 4k*/
> +#define DEFAULT_PAGE_SIZE 0x0c
> +#define LOONGARCH_CSR_PGDL 0x19 /* Page table base address when VA[47] = 0 */
> +#define LOONGARCH_CSR_PGDH 0x1a /* Page table base address when VA[47] = 1 */
> +#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP */
> +#define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi */
> +#define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */
> +#define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */
> +#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */
> +#define LOONGARCH_CSR_PWCTL0 0x1c /* PWCtl0 */
> +#define LOONGARCH_CSR_PWCTL1 0x1d /* PWCtl1 */
> +#define LOONGARCH_CSR_STLBPGSIZE 0x1e
> +#define CSR_TLBIDX_SIZE_MASK 0x3f000000
> +#define CSR_TLBIDX_PS_SHIFT 24
> +#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT
> +
> +#define CSR_TLBREHI_PS_SHIFT 0
> +#define CSR_TLBREHI_PS 0x3f
> +
> +#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \
> + EFI_MEMORY_WC | \
> + EFI_MEMORY_WT | \
> + EFI_MEMORY_WB | \
> + EFI_MEMORY_UCE \
> + )
> +
> +typedef struct {
> + EFI_PHYSICAL_ADDRESS PhysicalBase;
> + EFI_VIRTUAL_ADDRESS VirtualBase;
> + UINTN Length;
> + UINTN Attributes;
> +} MEMORY_REGION_DESCRIPTOR;
> +
> +// The total number of descriptors, including the final "end-of-table" descriptor.
> +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)
> +
> +extern CHAR8 HandleTlbRefill[], HandleTlbRefillEnd[];
> +
> +/*
> + Invalid corresponding TLB entries are based on the address given
> +
> + @param Address The address corresponding to the invalid page table entry
> +
> + @retval none
> +*/
> +extern
> +VOID
> +LoongarchInvalidTlb (
> + UINTN Address
> + );
> +
> +/*
> + Set Tlb Refill function to hardware
> +
> + @param A0 The address of tlb refill function
> +
> + @retval none
> +*/
> +extern
> +VOID
> +SetTlbRefillFuncBase (
> + UINTN Address
> + );
> +
> +/*
> + Set Cpu Status Register Page Size.
> +
> + @param PageSize Page Size.
> +
> + @retval none
> +*/
> +extern
> +VOID
> +WriteCsrPageSize (
> + UINTN PageSize
> + );
> +
> +/*
> + Set Cpu Status Register TLBREFILL Page Size.
> +
> + @param PageSize Page Size.
> +
> + @retval none
> +*/
> +extern
> +VOID
> +WriteCsrTlbRefillPageSize (
> + UINTN PageSize
> + );
> +
> +/*
> + Set Cpu Status Register STLB Page Size.
> +
> + @param PageSize Page Size.
> +
> + @retval VOID
> +*/
> +extern
> +VOID
> +WriteCsrStlbPageSize (
> + UINTN PageSize
> +);
> +
> +/*
> + Write Csr PWCTL0 register.
> +
> + @param Val The value used to write to the PWCTL0 register
> +
> + @retval none
> +*/
> +extern
> +VOID
> +LoongArchWriteqCsrPwctl0 (
> + UINTN Val
> + );
> +
> +/*
> + Write Csr PWCTL1 register.
> +
> + @param Val The value used to write to the PWCTL1 register
> +
> + @retval none
> +*/
> +extern
> +VOID
> +LoongArchWriteqCsrPwctl1 (
> + UINTN Val
> + );
> +
> +/*
> + Write Csr PGDL register.
> +
> + @param Val The value used to write to the PGDL register
> +
> + @retval none
> +*/
> +extern
> +VOID
> +LoongArchWriteqCsrPgdl (
> + UINTN Val
> + );
> +
> +/*
> + Write Csr PGDH register.
> +
> + @param Val The value used to write to the PGDH register
> +
> + @retval none
> +*/
> +extern
> +VOID
> +LoongArchWriteqCsrPgdh (
> + UINTN Val
> + );
> +
> +/*
> + Exchange specified bit data with the Csr CRMD register.
> +
> + @param[IN] Val The value Exchanged with the CSR CRMD register.
> + @param[IN] Mask Specifies the mask for swapping bits
> +
> + @retval VOID
> +*/
> +extern
> +VOID
> +LoongArchXchgCsrCrmd (
> + UINTN Val,
> + UINTN Mask
> + );
> +
> +#endif // MMU_H_
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
> new file mode 100644
> index 0000000000..6ab07e7900
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
> @@ -0,0 +1,280 @@
> +/** @file
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - Pgd or Pgd or PGD - Page Global Directory
> + - Pud or Pud or PUD - Page Upper Directory
> + - Pmd or Pmd or PMD - Page Middle Directory
> + - Pte or pte or PTE - Page Table Entry
> + - Val or VAL or val - Value
> + - Dir - Directory
> +**/
> +#ifndef PAGE_H_
> +#define PAGE_H_
> +
> +#define MAX_VA_BITS 47
> +#define PGD_WIDE (8)
> +#define PUD_WIDE (9)
> +#define PMD_WIDE (9)
> +#define PTE_WIDE (9)
> +
> +#define ENTRYS_PER_PGD (1 << PGD_WIDE)
> +#define ENTRYS_PER_PUD (1 << PUD_WIDE)
> +#define ENTRYS_PER_PMD (1 << PMD_WIDE)
> +#define ENTRYS_PER_PTE (1 << PTE_WIDE)
> +
> +#define PGD_SHIFT (PUD_SHIFT + PUD_WIDE)
> +#define PUD_SHIFT (PMD_SHIFT + PMD_WIDE)
> +#define PMD_SHIFT (EFI_PAGE_SHIFT + PTE_WIDE)
> +#define PTE_SHIFT (EFI_PAGE_SHIFT)
> +
> +#define PGD_SIZE (1UL << PGD_SHIFT)
> +#define PUD_SIZE (1UL << PUD_SHIFT)
> +#define PMD_SIZE (1UL << PMD_SHIFT)
> +
> +#define PGD_MASK (~(PGD_SIZE-1))
> +#define PUD_MASK (~(PUD_SIZE-1))
> +#define PMD_MASK (~(PMD_SIZE-1))
> +#define PAGE_MASK (~(EFI_PAGE_SIZE - 1))
> +#define PFN_MASK (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \
> + (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
> +
> +typedef struct { UINTN PgdVal; } PGD;
> +typedef struct { UINTN PudVal; } PUD;
> +typedef struct { UINTN PmdVal; } PMD;
> +typedef struct { UINTN PteVal; } PTE;
> +/**
> + Gets the value of the page global directory table entry.
> +
> + @param x Page global directory struct variables.
> +
> + @retval the value of the page global directory table entry.
> + **/
> +#define PGD_VAL(x) ((x).PgdVal)
> +/**
> + Gets the value of the page upper directory table entry.
> +
> + @param x Page upper directory struct variables.
> +
> + @retval the value of the page upper directory table entry.
> + **/
> +#define PUD_VAL(x) ((x).PudVal)
> +/**
> + Gets the value of the page middle directory table entry.
> +
> + @param x Page middle directory struct variables.
> +
> + @retval the value of the page middle directory table entry.
> + **/
> +#define PMD_VAL(x) ((x).PmdVal)
> +/**
> + Gets the value of the page table entry.
> +
> + @param x Page table entry struct variables.
> +
> + @retval the value of the page table entry.
> + **/
> +#define PTE_VAL(x) ((x).PteVal)
> +
> +#define PGD_TABLE_SIZE (ENTRYS_PER_PGD * sizeof(PGD))
> +#define PUD_TABLE_SIZE (ENTRYS_PER_PUD * sizeof(PUD))
> +#define PMD_TABLE_SIZE (ENTRYS_PER_PMD * sizeof(PMD))
> +#define PTE_TABLE_SIZE (ENTRYS_PER_PTE * sizeof(PTE))
> +/**
> + Gets the physical address of the record in the page table entry.
> +
> + @param x Page table entry struct variables.
> +
> + @retval the value of the physical address.
> + **/
> +#define GET_PAGE_ATTRIBUTES(x) (UINTN) {(PTE_VAL(x) & ~PFN_MASK)}
> +/**
> + Gets the virtual address of the next block of the specified virtual address
> + that is aligned with the size of the global page directory mapping.
> +
> + @param Address Specifies the virtual address.
> + @param End The end address of the memory region.
> +
> + @retval the specified virtual address of the next block.
> + **/
> +#define PGD_ADDRESS_END(Address, End) \
> +({ \
> + UINTN Boundary = ((Address) + PGD_SIZE) & PGD_MASK; \
> + (Boundary - 1 < (End) - 1)? Boundary: (End); \
> +})
> +/**
> + Gets the virtual address of the next block of the specified virtual address
> + that is aligned with the size of the page upper directory mapping.
> +
> + @param Address Specifies the virtual address.
> + @param End The end address of the memory region.
> +
> + @retval the specified virtual address of the next block.
> + **/
> +#define PUD_ADDRESS_END(Address, End) \
> +({ \
> + UINTN Boundary = ((Address) + PUD_SIZE) & PUD_MASK; \
> + (Boundary - 1 < (End) - 1)? Boundary: (End); \
> +})
> +/**
> + Gets the virtual address of the next block of the specified virtual address
> + that is aligned with the size of the page middle directory mapping.
> +
> + @param Address Specifies the virtual address.
> + @param End The end address of the memory region.
> +
> + @retval the specified virtual address of the next block.
> + **/
> +#define PMD_ADDRESS_END(Address, End) \
> +({ \
> + UINTN Boundary = ((Address) + PMD_SIZE) & PMD_MASK; \
> + (Boundary - 1 < (End) - 1)? Boundary: (End); \
> +})
> +/**
> + Get Specifies the virtual address corresponding to the index of the page global directory table entry.
> +
> + @param Address Specifies the virtual address.
> +
> + @retval the index of the page global directory table entry.
> + **/
> +#define PGD_INDEX(Address) (((Address) >> PGD_SHIFT) & (ENTRYS_PER_PGD-1))
> +/**
> + Get Specifies the virtual address corresponding to the index of the page upper directory table entry.
> +
> + @param Address Specifies the virtual address.
> + @param End The end address of the memory region.
> +
> + @retval the index of the page upper directory table entry.
> + **/
> +#define PUD_INDEX(Address) (((Address) >> PUD_SHIFT) & (ENTRYS_PER_PUD - 1))
> +/**
> + Get Specifies the virtual address corresponding to the index of the page middle directory table entry.
> +
> + @param Address Specifies the virtual address.
> +
> + @retval the index of the page middle directory table entry.
> + **/
> +#define PMD_INDEX(Address) (((Address) >> PMD_SHIFT) & (ENTRYS_PER_PMD - 1))
> +/**
> + Get Specifies the virtual address corresponding to the index of the page table entry.
> +
> + @param Address Specifies the virtual address.
> +
> + @retval the index of the page table entry.
> + **/
> +#define PTE_INDEX(Address) (((Address) >> EFI_PAGE_SHIFT) & (ENTRYS_PER_PTE - 1))
> +
> +/**
> + Calculates the value of the page table entry based on the specified virtual address and properties.
> +
> + @param Address Specifies the virtual address.
> + @param Attributes Specifies the Attributes.
> +
> + @retval the value of the page table entry.
> + **/
> +#define MAKE_PTE(Address, Attributes) (PTE){((((Address) >> EFI_PAGE_SHIFT) << 12) | (Attributes))}
> +/**
> + Get Global bit from Attributes
> +
> + @param Attributes Specifies the Attributes.
> + * */
> +#define GET_GLOBALBIT(Attributes) ((Attributes & PAGE_GLOBAL) >> PAGE_GLOBAL_SHIFT)
> +/**
> + Calculates the value of the Huge page table entry based on the specified virtual address and properties.
> +
> + @param Address Specifies the virtual address.
> + @param Attributes Specifies the Attributes.
> +
> + @retval the value of the HUGE page table entry.
> + **/
> +#define MAKE_HUGE_PTE(Address, Attributes) (((((Address) >> PMD_SHIFT) << PMD_SHIFT) | \
> + ((Attributes) | (GET_GLOBALBIT(Attributes) << PAGE_HGLOBAL_SHIFT) | \
> + PAGE_HUGE)))
> +
> + /**
> + Check whether the large page table entry is.
> +
> + @param Val The value of the page table entry.
> +
> + @retval 1 Is huge page table entry.
> + @retval 0 Isn't huge page table entry.
> + **/
> +#define IS_HUGE_PAGE(Val) ((((Val) & PAGE_HUGE) == PAGE_HUGE) && \
> + (((Val) & PAGE_HGLOBAL) == PAGE_HGLOBAL))
> +
> +#define HUGE_PAGE_SIZE (PMD_SIZE)
> +
> + /**
> + Check that the global page directory table entry is empty.
> +
> + @param pgd the global page directory struct variables.
> +
> + @retval 1 Is huge page table entry.
> + @retval 0 Isn't huge page table entry.
> + **/
> +STATIC
> +inline
> +UINTN
> +pgd_none (
> + IN PGD pgd
> + )
> +{
> + return (PGD_VAL(pgd) == (UINTN)PcdGet64(PcdInvalidPud));
> +}
> +
> + /**
> + Check that the page upper directory table entry is empty.
> +
> + @param pud Page upper directory struct variables.
> +
> + @retval 1 Is huge page table entry.
> + @retval 0 Isn't huge page table entry.
> + **/
> +STATIC
> +inline
> +UINTN
> +pud_none (
> + IN PUD pud
> + )
> +{
> + return (PUD_VAL(pud) == (UINTN)PcdGet64 (PcdInvalidPmd));
> +}
> +
> + /**
> + Check that the page middle directory table entry is empty.
> +
> + @param pmd Page middle directory struct variables.
> +
> + @retval 1 Is huge page table entry.
> + @retval 0 Isn't huge page table entry.
> + **/
> +STATIC
> +inline
> +UINTN
> +pmd_none (
> + IN PMD pmd
> + )
> +{
> + return (PMD_VAL(pmd) == (UINTN)PcdGet64(PcdInvalidPte));
> +}
> + /**
> + Check that the page table entry is empty.
> +
> + @param pmd Page table entry struct variables.
> +
> + @retval 1 Is huge page table entry.
> + @retval 0 Isn't huge page table entry.
> + **/
> +STATIC
> +inline
> +UINTN
> +pte_none (
> + IN PTE pte
> + )
> +{
> + return (!(PTE_VAL(pte) & (~PAGE_GLOBAL)));
> +}
> +#endif // PAGE_H_
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
> new file mode 100644
> index 0000000000..aacbf81744
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
> @@ -0,0 +1,57 @@
> +/** @file
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - Tlb or TLB - Translation Lookaside Buffer
> + - HGLOBAL - Huge Global
> + - PFN - Page Frame number
> + - EXEC - Execute
> + - PLV - Privilege Level
> + - RPLV - Restricted Privilege Level
> + - SUC - Strong-ordered UnCached
> + - CC - Coherent Cached
> + - WUC - Weak-ordered UnCached
> +**/
> +#ifndef PTE_H_
> +#define PTE_H_
> +/*Page table property definitions */
> +#define PAGE_VALID_SHIFT 0
> +#define PAGE_DIRTY_SHIFT 1
> +#define PAGE_PLV_SHIFT 2 /* 2~3, two bits */
> +#define CACHE_SHIFT 4 /* 4~5, two bits */
> +#define PAGE_GLOBAL_SHIFT 6
> +#define PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */
> +
> +#define PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */
> +#define PAGE_PFN_SHIFT 12
> +#define PAGE_PFN_END_SHIFT 48
> +#define PAGE_NO_READ_SHIFT 61
> +#define PAGE_NO_EXEC_SHIFT 62
> +#define PAGE_RPLV_SHIFT 63
> +
> +/* Used by TLB hardware (placed in EntryLo*) */
> +#define PAGE_VALID ((UINTN)(1) << PAGE_VALID_SHIFT)
> +#define PAGE_DIRTY ((UINTN)(1) << PAGE_DIRTY_SHIFT)
> +#define PAGE_PLV ((UINTN)(3) << PAGE_PLV_SHIFT)
> +#define PAGE_GLOBAL ((UINTN)(1) << PAGE_GLOBAL_SHIFT)
> +#define PAGE_HUGE ((UINTN)(1) << PAGE_HUGE_SHIFT)
> +#define PAGE_HGLOBAL ((UINTN)(1) << PAGE_HGLOBAL_SHIFT)
> +#define PAGE_NO_READ ((UINTN)(1) << PAGE_NO_READ_SHIFT)
> +#define PAGE_NO_EXEC ((UINTN)(1) << PAGE_NO_EXEC_SHIFT)
> +#define PAGE_RPLV ((UINTN)(1) << PAGE_RPLV_SHIFT)
> +#define CACHE_MASK ((UINTN)(3) << CACHE_SHIFT)
> +#define PFN_SHIFT (EFI_PAGE_SHIFT - 12 + PAGE_PFN_SHIFT)
> +
> +#define PLV_KERNEL 0
> +#define PLV_USER 3
> +
> +#define PAGE_USER (PLV_USER << PAGE_PLV_SHIFT)
> +#define PAGE_KERNEL (PLV_KERN << PAGE_PLV_SHIFT)
> +
> +#define CACHE_SUC (0 << CACHE_SHIFT) /* Strong-ordered UnCached */
> +#define CACHE_CC (1 << CACHE_SHIFT) /* Coherent Cached */
> +#define CACHE_WUC (2 << CACHE_SHIFT) /* Weak-ordered UnCached */
> +#endif // PTE_H_
> --
> 2.31.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#96290): https://edk2.groups.io/g/devel/message/96290
Mute This Topic: https://groups.io/mt/94955173/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-