public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chao Li" <lichao@loongson.cn>
To: devel@edk2.groups.io
Cc: Eric Dong <eric.dong@intel.com>, Ray Ni <ray.ni@intel.com>,
	Rahul Kumar <rahul1.kumar@intel.com>,
	Gerd Hoffmann <kraxel@redhat.com>,
	Baoqi Zhang <zhangbaoqi@loongson.cn>,
	Dongyan Qian <qiandongyan@loongson.cn>,
	Xianglai Li <lixianglai@loongson.cn>,
	Bibo Mao <maobibo@loongson.cn>
Subject: Re: [edk2-devel] [PATCH v3 14/39] UefiCpuPkg: Add LoongArch64CpuMmuLib to UefiCpuPkg
Date: Mon, 20 Nov 2023 17:55:26 +0800	[thread overview]
Message-ID: <2850cbb7-ab9a-4192-ac83-15e0d1193425@loongson.cn> (raw)
In-Reply-To: <179860C0A131BC70.3002@groups.io>

[-- Attachment #1: Type: text/plain, Size: 105494 bytes --]

This patch includes two folder, both named LoongArch64CpuMmuLib. This 
was a mistak when creating the patch, I will fix it in the V4.


Thanks,
Chao
On 2023/11/17 18:00, Chao Li wrote:
> Add a new library LoongArch64CpuMmuLib. It provides two-stage MMU library
> instances, PEI and DXE.
>
> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Eric Dong<eric.dong@intel.com>
> Cc: Ray Ni<ray.ni@intel.com>
> Cc: Rahul Kumar<rahul1.kumar@intel.com>
> Cc: Gerd Hoffmann<kraxel@redhat.com>
> Signed-off-by: Chao Li<lichao@loongson.cn>
> Co-authored-by: Baoqi Zhang<zhangbaoqi@loongson.cn>
> Co-authored-by: Dongyan Qian<qiandongyan@loongson.cn>
> Co-authored-by: Xianglai Li<lixianglai@loongson.cn>
> Co-authored-by: Bibo Mao<maobibo@loongson.cn>
> ---
>   .../LoongArch64CpuMmuLib/CommonMmuLib.c       | 965 ++++++++++++++++++
>   .../LoongArch64CpuMmuLib/CommonMmuLib.h       |  43 +
>   .../LoongArch64CpuMmuLib/DxeCpuMmuLib.inf     |  37 +
>   .../LoongArch64CpuMmuLib/DxeCpuMmuLib.uni     |  14 +
>   .../LoongArch64CpuMmuLib/CommonMmuLib.c       | 964 +++++++++++++++++
>   .../LoongArch64CpuMmuLib/CommonMmuLib.h       |  43 +
>   .../LoongArch64CpuMmuLib/DxeCpuMmuLib.inf     |  37 +
>   .../LoongArch64CpuMmuLib/DxeCpuMmuLib.uni     |  14 +
>   .../LoongArch64CpuMmuLib/Page.h               | 279 +++++
>   .../LoongArch64CpuMmuLib/PeiCpuMmuLib.c       | 165 +++
>   .../LoongArch64CpuMmuLib/PeiCpuMmuLib.inf     |  44 +
>   .../LoongArch64CpuMmuLib/PeiCpuMmuLib.uni     |  14 +
>   .../LoongArch64CpuMmuLib/Tlb.h                |  48 +
>   .../LoongArch64CpuMmuLib/TlbOperation.S       |  44 +
>   .../Library/LoongArch64CpuMmuLib/Page.h       | 279 +++++
>   .../LoongArch64CpuMmuLib/PeiCpuMmuLib.c       | 165 +++
>   .../LoongArch64CpuMmuLib/PeiCpuMmuLib.inf     |  44 +
>   .../LoongArch64CpuMmuLib/PeiCpuMmuLib.uni     |  14 +
>   UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h |  48 +
>   .../LoongArch64CpuMmuLib/TlbOperation.S       |  44 +
>   UefiCpuPkg/UefiCpuPkg.dsc                     |   2 +
>   21 files changed, 3307 insertions(+)
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
>   create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
>
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
> new file mode 100644
> index 0000000000..bd5c7e55b6
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
> @@ -0,0 +1,965 @@
> +/** @file
> +
> +  CPU Memory Map Unit Handler Library common functions.
> +
> +  Copyright (c) 2023 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/CpuMmuLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +#include "Tlb.h"
> +#include "Page.h"
> +
> +BOOLEAN  mMmuInited = FALSE;
> +#define  SWAP_PAGE_DIR  CsrRead(LOONGARCH_CSR_PGDL)
> +
> +/**
> +  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 || (SWAP_PAGE_DIR != 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.
> +
> +  @return 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 *)(SWAP_PAGE_DIR) + 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;
> +
> +  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;
> +
> +  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;
> +
> +  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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +**/
> +EFI_STATUS
> +PudAlloc (
> +  IN PGD  *Pgd
> +  )
> +{
> +  PUD  *Pud;
> +
> +  Pud = (PUD *)AllocatePages (1);
> +  if (Pud == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)INVALID_PAGE);
> +
> +  SetPgd (Pgd, 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 *)INVALID_PAGE);
> +
> +  SetPud (Pud, 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.
> +**/
> +EFI_STATUS
> +PteAlloc (
> +  IN PMD  *Pmd
> +  )
> +{
> +  PTE  *Pte;
> +
> +  Pte = (PTE *)AllocatePages (1);
> +  if (!Pte) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
> +
> +  SetPmd (Pmd, 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.
> +  @param  Address  The corresponding virtual address of the page table entry.
> +
> +  @retval          A pointer to the page upper directory entry. Return NULL, if
> +                   allocate the memory buffer is fail.
> +**/
> +PUD *
> +PudAllocGet (
> +  IN PGD    *Pgd,
> +  IN UINTN  Address
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (PGD_IS_EMPTY (*Pgd)) {
> +    Status = PudAlloc (Pgd);
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      return NULL;
> +    }
> +  }
> +
> +  return 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.
> +  @param  Address  The corresponding virtual address of the page table entry.
> +
> +  @retval          A pointer to the page middle directory entry. Return NULL, if
> +                   allocate the memory buffer is fail.
> +**/
> +PMD *
> +PmdAllocGet (
> +  IN PUD    *Pud,
> +  IN UINTN  Address
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (PUD_IS_EMPTY (*Pud)) {
> +    Status = PmdAlloc (Pud);
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      return NULL;
> +    }
> +  }
> +
> +  return PmdOffset (Pud, Address);
> +}
> +
> +/**
> +  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.
> +  @param  Address  The corresponding virtual address of the page table entry.
> +
> +  @retval          A pointer to the page table entry. Return NULL, if allocate
> +                   the memory buffer is fail.
> +**/
> +PTE *
> +PteAllocGet (
> +  IN PMD    *Pmd,
> +  IN UINTN  Address
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (PMD_IS_EMPTY (*Pmd)) {
> +    Status = PteAlloc (Pmd);
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      return NULL;
> +    }
> +  }
> +
> +  return 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_IS_EMPTY (*Pgd)) {
> +    return NULL;
> +  }
> +
> +  Pud = PudOffset (Pgd, Address);
> +
> +  if (PUD_IS_EMPTY (*Pud)) {
> +    return NULL;
> +  }
> +
> +  Pmd = PmdOffset (Pud, Address);
> +  if (PMD_IS_EMPTY (*Pmd)) {
> +    return NULL;
> +  }
> +
> +  if (IS_HUGE_PAGE (Pmd->PmdVal)) {
> +    return ((PTE *)Pmd);
> +  }
> +
> +  return PteOffset (Pmd, Address);
> +}
> +
> +/**
> +  Gets the Attributes of Huge Page.
> +
> +  @param  Pmd  A pointer to the page middle directory.
> +
> +  @retval     Value of Attributes.
> +**/
> +UINTN
> +GetHugePageAttributes (
> +  IN  PMD  *Pmd
> +  )
> +{
> +  UINTN  Attributes;
> +  UINTN  GlobalFlag;
> +  UINTN  HugeVal;
> +
> +  HugeVal     = PMD_VAL (*Pmd);
> +  Attributes  = HugeVal & (~HUGEP_PAGE_MASK);
> +  GlobalFlag  = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT;
> +  Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT);
> +  Attributes |= GlobalFlag;
> +  return Attributes;
> +}
> +
> +/**
> +  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;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "%a %d Address %p End %p  Attributes %llx\n",
> +    __func__,
> +    __LINE__,
> +    Address,
> +    End,
> +    Attributes
> +    ));
> +
> +  do {
> +    UpDate = FALSE;
> +    PteVal = MAKE_PTE (Address, Attributes);
> +
> +    if ((!PTE_IS_EMPTY (*Pte)) &&
> +        (PTE_VAL (*Pte) != PTE_VAL (PteVal)))
> +    {
> +      UpDate = TRUE;
> +    }
> +
> +    SetPte (Pte, PteVal);
> +    if (UpDate) {
> +      InvalidTlb (Address);
> +    }
> +  } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Convert Huge Page to Page.
> +
> +  @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
> +ConvertHugePageToPage (
> +  IN  PMD   *Pmd,
> +  IN UINTN  Address,
> +  IN UINTN  End,
> +  IN UINTN  Attributes
> +  )
> +{
> +  UINTN       OldAttributes;
> +  UINTN       HugePageEnd;
> +  UINTN       HugePageStart;
> +  EFI_STATUS  Status;
> +
> +  Status = EFI_SUCCESS;
> +
> +  if ((PMD_IS_EMPTY (*Pmd)) ||
> +      (!IS_HUGE_PAGE (Pmd->PmdVal)))
> +  {
> +    Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
> +  } else {
> +    OldAttributes = GetHugePageAttributes (Pmd);
> +    if (Attributes == OldAttributes) {
> +      return Status;
> +    }
> +
> +    SetPmd (Pmd, (PTE *)(INVALID_PAGE));
> +    HugePageStart = Address & PMD_MASK;
> +    HugePageEnd   = HugePageStart + HUGE_PAGE_SIZE;
> +    ASSERT (HugePageEnd >= End);
> +
> +    if (Address > HugePageStart) {
> +      Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes);
> +    }
> +
> +    Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
> +
> +    if (End < HugePageEnd) {
> +      Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes);
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  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;
> +  UINTN    Next;
> +  PTE      PteVal;
> +  BOOLEAN  UpDate;
> +
> +  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_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal)))
> +    {
> +      UpDate = FALSE;
> +      PteVal = MAKE_HUGE_PTE (Address, Attributes);
> +
> +      if ((!PMD_IS_EMPTY (*Pmd)) &&
> +          (PMD_VAL (*Pmd) != PTE_VAL (PteVal)))
> +      {
> +        UpDate = TRUE;
> +      }
> +
> +      SetPmd (Pmd, (PTE *)PteVal.PteVal);
> +      if (UpDate) {
> +        InvalidTlb (Address);
> +      }
> +    } else {
> +      ConvertHugePageToPage (Pmd, Address, Next, Attributes);
> +    }
> +  } while (Pmd++, Address = Next, Address != End);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  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 (EFI_ERROR (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;
> +  EFI_STATUS  Err;
> +
> +  Address = Start;
> +
> +  /* Get PGD(PTE PMD PUD PGD) in PageTables */
> +  Pgd = PgdOffset (Address);
> +  do {
> +    Next = PGD_ADDRESS_END (Address, End);
> +    /* Get Next Align Page to Map */
> +    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
> +           );
> +}
> +
> +/**
> +  Convert EFI Attributes to Loongarch Attributes.
> +
> +  @param[in]  EfiAttributes     Efi Attributes.
> +
> +  @retval  Corresponding architecture attributes.
> +**/
> +UINTN
> +EfiAttributeConverse (
> +  IN UINTN  EfiAttributes
> +  )
> +{
> +  UINTN  LoongArchAttributes;
> +
> +  LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | 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) ||
> +      ((EfiAttributes & EFI_MEMORY_WP) != 0))
> +  {
> +    LoongArchAttributes &= ~PAGE_DIRTY;
> +  }
> +
> +  if ((EfiAttributes & EFI_MEMORY_RP) != 0) {
> +    LoongArchAttributes |= PAGE_NO_READ;
> +  }
> +
> +  // 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
> +GetMemoryRegionAttribute (
> +  IN     UINTN  BaseAddress,
> +  IN     UINTN  EndAddress,
> +  OUT    UINTN  *RegionLength,
> +  OUT    UINTN  *RegionAttributes
> +  )
> +{
> +  PTE    *Pte;
> +  UINTN  Attributes;
> +  UINTN  AttributesTmp;
> +  UINTN  MaxAddress;
> +
> +  if (!MmuIsInit ()) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
> +  Pte        = GetPteAddress (BaseAddress);
> +
> +  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.
> +  @param[in]  AttributeMask  Mask of memory attributes to take into account.
> +
> +  @retval  EFI_SUCCESS    The Attributes was set successfully
> +**/
> +EFI_STATUS
> +SetMemoryRegionAttributes (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINTN                 Length,
> +  IN UINTN                 Attributes,
> +  IN UINT64                AttributeMask
> +  )
> +{
> +  if (!MmuIsInit ()) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Attributes = EfiAttributeConverse (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
> +SetMemoryRegionNoExec (
> +  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN  UINTN                 Length
> +  )
> +{
> +  if (MmuIsInit ()) {
> +    Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
> +    SetMemoryRegionAttributes (BaseAddress, Length, EFI_MEMORY_XP, 0x0);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check to see if mmu successfully initializes and saves the result.
> +
> +  @param[in]  ImageHandle  The firmware allocated handle for the EFI image.
> +  @param[in]  SystemTable  A pointer to the EFI System Table.
> +
> +  @retval  RETURN_SUCCESS    Initialization succeeded.
> +**/
> +RETURN_STATUS
> +EFIAPI
> +MmuInitialize (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  if (SWAP_PAGE_DIR != 0) {
> +    mMmuInited = TRUE;
> +  }
> +
> +  return RETURN_SUCCESS;
> +}
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
> new file mode 100644
> index 0000000000..aa96f5143c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
> @@ -0,0 +1,43 @@
> +/** @file
> +
> +  Copyright (c) 2023 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/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> new file mode 100644
> index 0000000000..d153354dd2
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> @@ -0,0 +1,37 @@
> +## @file
> +#  CPU Memory Map Unit DXE phase driver.
> +#
> +#  Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = DxeCpuMmuLib
> +  MODULE_UNI_FILE                = DxeCpuMmuLib.uni
> +  FILE_GUID                      = DA8F0232-FB14-42F0-922C-63104D2C70BE
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = CpuMmuLib | DXE_DRIVER
> +  CONSTRUCTOR                    = MmuInitialize
> +
> +#
> +#  VALID_ARCHITECTURES           = LOONGARCH64
> +#
> +
> +[Sources]
> +  TlbOperation.S   | GCC
> +  CommonMmuLib.c
> +  Tlb.h
> +  Page.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
> +
> +[LibraryClasses]
> +  MemoryAllocationLib
> +  PcdLib
> +  DebugLib
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> new file mode 100644
> index 0000000000..2e841d714c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// CPU Memory Manager Unit library instance for DXE modules.
> +//
> +// CPU Memory Manager Unit library instance for DXE modules.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "CPU Memory Manager Unit library instance for DXE modules."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "CPU Memory Manager Unit library instance for DXE modules."
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
> new file mode 100644
> index 0000000000..f5e632a237
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
> @@ -0,0 +1,964 @@
> +/** @file
> +
> +  CPU Memory Map Unit Handler Library common functions.
> +
> +  Copyright (c) 2023 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/CpuMmuLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +#include "Tlb.h"
> +#include "Page.h"
> +
> +BOOLEAN  mMmuInited = FALSE;
> +#define  SWAP_PAGE_DIR  CsrRead(LOONGARCH_CSR_PGDL)
> +
> +/**
> +  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 || (SWAP_PAGE_DIR != 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.
> +
> +  @return 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 *)(SWAP_PAGE_DIR) + 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;
> +
> +  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;
> +
> +  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;
> +
> +  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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +**/
> +EFI_STATUS
> +PudAlloc (
> +  IN PGD  *Pgd
> +  )
> +{
> +  PUD  *Pud;
> +
> +  Pud = (PUD *)AllocatePages (1);
> +  if (Pud == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)INVALID_PAGE);
> +
> +  SetPgd (Pgd, 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 *)INVALID_PAGE);
> +
> +  SetPud (Pud, 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.
> +**/
> +EFI_STATUS
> +PteAlloc (
> +  IN PMD  *Pmd
> +  )
> +{
> +  PTE  *Pte;
> +
> +  Pte = (PTE *)AllocatePages (1);
> +  if (!Pte) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
> +
> +  SetPmd (Pmd, 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.
> +  @param  Address  The corresponding virtual address of the page table entry.
> +
> +  @retval          A pointer to the page upper directory entry. Return NULL, if
> +                   allocate the memory buffer is fail.
> +**/
> +PUD *
> +PudAllocGet (
> +  IN PGD    *Pgd,
> +  IN UINTN  Address
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (PGD_IS_EMPTY (*Pgd)) {
> +    Status = PudAlloc (Pgd);
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      return NULL;
> +    }
> +  }
> +
> +  return 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.
> +  @param  Address  The corresponding virtual address of the page table entry.
> +
> +  @retval          A pointer to the page middle directory entry. Return NULL, if
> +                   allocate the memory buffer is fail.
> +**/
> +PMD *
> +PmdAllocGet (
> +  IN PUD    *Pud,
> +  IN UINTN  Address
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (PUD_IS_EMPTY (*Pud)) {
> +    Status = PmdAlloc (Pud);
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      return NULL;
> +    }
> +  }
> +
> +  return PmdOffset (Pud, Address);
> +}
> +
> +/**
> +  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.
> +  @param  Address  The corresponding virtual address of the page table entry.
> +
> +  @retval          A pointer to the page table entry. Return NULL, if allocate
> +                   the memory buffer is fail.
> +**/
> +PTE *
> +PteAllocGet (
> +  IN PMD    *Pmd,
> +  IN UINTN  Address
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (PMD_IS_EMPTY (*Pmd)) {
> +    Status = PteAlloc (Pmd);
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      return NULL;
> +    }
> +  }
> +
> +  return 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_IS_EMPTY (*Pgd)) {
> +    return NULL;
> +  }
> +
> +  Pud = PudOffset (Pgd, Address);
> +
> +  if (PUD_IS_EMPTY (*Pud)) {
> +    return NULL;
> +  }
> +
> +  Pmd = PmdOffset (Pud, Address);
> +  if (PMD_IS_EMPTY (*Pmd)) {
> +    return NULL;
> +  }
> +
> +  if (IS_HUGE_PAGE (Pmd->PmdVal)) {
> +    return ((PTE *)Pmd);
> +  }
> +
> +  return PteOffset (Pmd, Address);
> +}
> +
> +/**
> +  Gets the Attributes of Huge Page.
> +
> +  @param  Pmd  A pointer to the page middle directory.
> +
> +  @retval     Value of Attributes.
> +**/
> +UINTN
> +GetHugePageAttributes (
> +  IN  PMD  *Pmd
> +  )
> +{
> +  UINTN  Attributes;
> +  UINTN  GlobalFlag;
> +  UINTN  HugeVal;
> +
> +  HugeVal     = PMD_VAL (*Pmd);
> +  Attributes  = HugeVal & (~HUGEP_PAGE_MASK);
> +  GlobalFlag  = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT;
> +  Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT);
> +  Attributes |= GlobalFlag;
> +  return Attributes;
> +}
> +
> +/**
> +  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;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "%a %d Address %p End %p  Attributes %llx\n",
> +    __func__,
> +    __LINE__,
> +    Address,
> +    End,
> +    Attributes
> +    ));
> +
> +  do {
> +    UpDate = FALSE;
> +    PteVal = MAKE_PTE (Address, Attributes);
> +
> +    if ((!PTE_IS_EMPTY (*Pte)) &&
> +        (PTE_VAL (*Pte) != PTE_VAL (PteVal)))
> +    {
> +      UpDate = TRUE;
> +    }
> +
> +    SetPte (Pte, PteVal);
> +    if (UpDate) {
> +      InvalidTlb (Address);
> +    }
> +  } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Convert Huge Page to Page.
> +
> +  @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
> +ConvertHugePageToPage (
> +  IN  PMD   *Pmd,
> +  IN UINTN  Address,
> +  IN UINTN  End,
> +  IN UINTN  Attributes
> +  )
> +{
> +  UINTN       OldAttributes;
> +  UINTN       HugePageEnd;
> +  UINTN       HugePageStart;
> +  EFI_STATUS  Status;
> +
> +  Status = EFI_SUCCESS;
> +
> +  if ((PMD_IS_EMPTY (*Pmd)) ||
> +      (!IS_HUGE_PAGE (Pmd->PmdVal)))
> +  {
> +    Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
> +  } else {
> +    OldAttributes = GetHugePageAttributes (Pmd);
> +    if (Attributes == OldAttributes) {
> +      return Status;
> +    }
> +
> +    SetPmd (Pmd, (PTE *)(INVALID_PAGE));
> +    HugePageStart = Address & PMD_MASK;
> +    HugePageEnd   = HugePageStart + HUGE_PAGE_SIZE;
> +    ASSERT (HugePageEnd >= End);
> +
> +    if (Address > HugePageStart) {
> +      Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes);
> +    }
> +
> +    Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
> +
> +    if (End < HugePageEnd) {
> +      Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes);
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  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;
> +  UINTN    Next;
> +  PTE      PteVal;
> +  BOOLEAN  UpDate;
> +
> +  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_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal)))
> +    {
> +      UpDate = FALSE;
> +      PteVal = MAKE_HUGE_PTE (Address, Attributes);
> +
> +      if ((!PMD_IS_EMPTY (*Pmd)) &&
> +          (PMD_VAL (*Pmd) != PTE_VAL (PteVal)))
> +      {
> +        UpDate = TRUE;
> +      }
> +
> +      SetPmd (Pmd, (PTE *)PteVal.PteVal);
> +      if (UpDate) {
> +        InvalidTlb (Address);
> +      }
> +    } else {
> +      ConvertHugePageToPage (Pmd, Address, Next, Attributes);
> +    }
> +  } while (Pmd++, Address = Next, Address != End);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  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 (EFI_ERROR (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;
> +  EFI_STATUS  Err;
> +
> +  Address = Start;
> +
> +  /* Get PGD(PTE PMD PUD PGD) in PageTables */
> +  Pgd = PgdOffset (Address);
> +  do {
> +    Next = PGD_ADDRESS_END (Address, End);
> +    /* Get Next Align Page to Map */
> +    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
> +           );
> +}
> +
> +/**
> +  Convert EFI Attributes to Loongarch Attributes.
> +
> +  @param[in]  EfiAttributes     Efi Attributes.
> +
> +  @retval  Corresponding architecture attributes.
> +**/
> +UINTN
> +EfiAttributeConverse (
> +  IN UINTN  EfiAttributes
> +  )
> +{
> +  UINTN  LoongArchAttributes;
> +
> +  LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | 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) ||
> +      ((EfiAttributes & EFI_MEMORY_WP) != 0))
> +  {
> +    LoongArchAttributes &= ~PAGE_DIRTY;
> +  }
> +
> +  if ((EfiAttributes & EFI_MEMORY_RP) != 0) {
> +    LoongArchAttributes |= PAGE_NO_READ;
> +  }
> +
> +  // 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
> +GetMemoryRegionAttribute (
> +  IN     UINTN  BaseAddress,
> +  IN     UINTN  EndAddress,
> +  OUT    UINTN  *RegionLength,
> +  OUT    UINTN  *RegionAttributes
> +  )
> +{
> +  PTE    *Pte;
> +  UINTN  Attributes;
> +  UINTN  AttributesTmp;
> +  UINTN  MaxAddress;
> +
> +  if (!MmuIsInit ()) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
> +  Pte        = GetPteAddress (BaseAddress);
> +
> +  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
> +SetMemoryRegionAttributes (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINTN                 Length,
> +  IN UINTN                 Attributes,
> +  IN UINT64                AttributeMask
> +  )
> +{
> +  if (!MmuIsInit ()) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Attributes = EfiAttributeConverse (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
> +SetMemoryRegionNoExec (
> +  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN  UINTN                 Length
> +  )
> +{
> +  if (MmuIsInit ()) {
> +    Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
> +    SetMemoryRegionAttributes (BaseAddress, Length, EFI_MEMORY_XP, 0x0);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check to see if mmu successfully initializes and saves the result.
> +
> +  @param[in]  ImageHandle  The firmware allocated handle for the EFI image.
> +  @param[in]  SystemTable  A pointer to the EFI System Table.
> +
> +  @retval  RETURN_SUCCESS    Initialization succeeded.
> +**/
> +RETURN_STATUS
> +EFIAPI
> +MmuInitialize (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  if (SWAP_PAGE_DIR != 0) {
> +    mMmuInited = TRUE;
> +  }
> +
> +  return RETURN_SUCCESS;
> +}
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
> new file mode 100644
> index 0000000000..aa96f5143c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
> @@ -0,0 +1,43 @@
> +/** @file
> +
> +  Copyright (c) 2023 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/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> new file mode 100644
> index 0000000000..d153354dd2
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> @@ -0,0 +1,37 @@
> +## @file
> +#  CPU Memory Map Unit DXE phase driver.
> +#
> +#  Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = DxeCpuMmuLib
> +  MODULE_UNI_FILE                = DxeCpuMmuLib.uni
> +  FILE_GUID                      = DA8F0232-FB14-42F0-922C-63104D2C70BE
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = CpuMmuLib | DXE_DRIVER
> +  CONSTRUCTOR                    = MmuInitialize
> +
> +#
> +#  VALID_ARCHITECTURES           = LOONGARCH64
> +#
> +
> +[Sources]
> +  TlbOperation.S   | GCC
> +  CommonMmuLib.c
> +  Tlb.h
> +  Page.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
> +
> +[LibraryClasses]
> +  MemoryAllocationLib
> +  PcdLib
> +  DebugLib
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> new file mode 100644
> index 0000000000..2e841d714c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// CPU Memory Manager Unit library instance for DXE modules.
> +//
> +// CPU Memory Manager Unit library instance for DXE modules.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "CPU Memory Manager Unit library instance for DXE modules."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "CPU Memory Manager Unit library instance for DXE modules."
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
> new file mode 100644
> index 0000000000..ad8f751ad7
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
> @@ -0,0 +1,279 @@
> +/** @file
> +
> +  Copyright (c) 2023 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_
> +
> +#include <Library/CpuMmuLib.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))
> +
> +#define HUGEP_PAGE_MASK  (~(((UINTN)(1) << (PMD_SHIFT)) - 1) & \
> +                          (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
> +
> +#define INVALID_PAGE  0
> +
> +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)  (PTE){(((((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   The page table is invalid.
> +  @retval    0   The page table is valid.
> +**/
> +#define PGD_IS_EMPTY(Val)  (PGD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> +  Check that the page upper directory table entry is empty.
> +
> +  @param  pud   Page upper directory struct variables.
> +
> +  @retval    1   The page table is invalid.
> +  @retval    0   The page table is valid.
> +**/
> +#define PUD_IS_EMPTY(Val)  (PUD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> +  Check that the page middle directory table entry is empty.
> +
> +  @param  pmd   Page middle directory struct variables.
> +
> +  @retval    1   The page table is invalid.
> +  @retval    0   The page table is valid.
> +**/
> +#define PMD_IS_EMPTY(Val)  (PMD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> +  Check that the page the page table entry is empty.
> +
> +  @param  pte   Page table entry struct variables.
> +
> +  @retval    1   The page table is invalid.
> +  @retval    0   The page table is valid.
> +**/
> +#define PTE_IS_EMPTY(Val)  (!(PTE_VAL(Val) & (~PAGE_VALID)))
> +#endif // PAGE_H_
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> new file mode 100644
> index 0000000000..42a424b84d
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> @@ -0,0 +1,165 @@
> +/** @file
> +  CPU Memory Map Unit PEI phase driver.
> +
> +  Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Glossary:
> +    - 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/CpuMmuLib.h>
> +#include <Library/CacheMaintenanceLib.h>
> +#include <Library/CpuMmuLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +
> +#include "Page.h"
> +#include "Tlb.h"
> +#include "CommonMmuLib.h"
> +
> +/**
> +  Create a page table and initialize the memory management unit(MMU).
> +
> +  @param[in]   MemoryTable           A pointer to a memory ragion table.
> +  @param[out]  TranslationTableBase  A pointer to a translation table base address.
> +  @param[out]  TranslationTableSize  A pointer to a translation table base size.
> +
> +  @retval  EFI_SUCCESS                Configure MMU successfully.
> +           EFI_INVALID_PARAMETER      MemoryTable is NULL.
> +           EFI_UNSUPPORTED            Out of memory space or size not aligned.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ConfigureMemoryManagementUint (
> +  IN  MEMORY_REGION_DESCRIPTOR  *MemoryTable,
> +  OUT VOID                      **TranslationTableBase OPTIONAL,
> +  OUT UINTN                     *TranslationTableSize  OPTIONAL
> +  )
> +{
> +  PGD            *SwapperPageDir;
> +  UINTN          PgdShift;
> +  UINTN          PgdWide;
> +  UINTN          PudShift;
> +  UINTN          PudWide;
> +  UINTN          PmdShift;
> +  UINTN          PmdWide;
> +  UINTN          PteShift;
> +  UINTN          PteWide;
> +  UINTN          Length;
> +  UINTN          TlbReEntry;
> +  UINTN          TlbReEntryOffset;
> +  RETURN_STATUS  Status;
> +
> +  SwapperPageDir = NULL;
> +  PgdShift       = PGD_SHIFT;
> +  PgdWide        = PGD_WIDE;
> +  PudShift       = PUD_SHIFT;
> +  PudWide        = PUD_WIDE;
> +  PmdShift       = PMD_SHIFT;
> +  PmdWide        = PMD_WIDE;
> +  PteShift       = PTE_SHIFT;
> +  PteWide        = PTE_WIDE;
> +
> +  if (MemoryTable == NULL) {
> +    ASSERT (MemoryTable != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> +  ZeroMem (SwapperPageDir, PGD_TABLE_SIZE);
> +
> +  if (SwapperPageDir == NULL) {
> +    goto FreeTranslationTable;
> +  }
> +
> +  CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir);
> +
> +  while (MemoryTable->Length != 0) {
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n",
> +      __func__,
> +      __LINE__,
> +      MemoryTable->VirtualBase,
> +      (MemoryTable->Length + MemoryTable->VirtualBase),
> +      MemoryTable->Attributes
> +      ));
> +
> +    Status = FillTranslationTable (MemoryTable);
> +    if (EFI_ERROR (Status)) {
> +      goto FreeTranslationTable;
> +    }
> +
> +    MemoryTable++;
> +  }
> +
> +  //
> +  // TLB Re-entry address at the end of exception vector, a vector is up to 512 bytes,
> +  // so the starting address is: total exception vector size + total interrupt vector size + base.
> +  // The total size of TLB handler and exception vector size and interrupt vector size should not
> +  // be lager than 64KB.
> +  //
> +  Length           = (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart;
> +  TlbReEntryOffset = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512;
> +  TlbReEntry       = PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryOffset;
> +  if ((TlbReEntryOffset + Length) > SIZE_64KB) {
> +    goto FreeTranslationTable;
> +  }
> +
> +  //
> +  // Make sure TLB refill exception base address alignment is greater than or equal to 4KB and valid
> +  //
> +  if (TlbReEntry & (SIZE_4KB - 1)) {
> +    goto FreeTranslationTable;
> +  }
> +
> +  CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
> +  InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length);
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "%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
> +    ));
> +
> +  //
> +  // Set the address of TLB refill exception handler
> +  //
> +  SetTlbRebaseAddress ((UINTN)TlbReEntry);
> +
> +  //
> +  // Set page size
> +  //
> +  CsrXChg (LOONGARCH_CSR_TLBIDX, (DEFAULT_PAGE_SIZE << CSR_TLBIDX_SIZE), CSR_TLBIDX_SIZE_MASK);
> +  CsrWrite (LOONGARCH_CSR_STLBPGSIZE, DEFAULT_PAGE_SIZE);
> +  CsrXChg (LOONGARCH_CSR_TLBREHI, (DEFAULT_PAGE_SIZE << CSR_TLBREHI_PS_SHIFT), CSR_TLBREHI_PS);
> +
> +  CsrWrite (LOONGARCH_CSR_PWCTL0, (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25));
> +  CsrWrite (LOONGARCH_CSR_PWCTL1, (PgdShift | PgdWide << 6));
> +
> +  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
> +
> +  return EFI_SUCCESS;
> +
> +FreeTranslationTable:
> +  if (SwapperPageDir != NULL) {
> +    FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> +  }
> +
> +  return EFI_UNSUPPORTED;
> +}
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> new file mode 100644
> index 0000000000..e746c3b1a7
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> @@ -0,0 +1,44 @@
> +## @file
> +#  CPU Memory Map Unit PEI phase driver.
> +#
> +#  Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = PeiCpuMmuLib
> +  MODULE_UNI_FILE                = PeiCpuMmuLib.uni
> +  FILE_GUID                      = F67EB983-AC2A-7550-AB69-3BC51A1C895B
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = CpuMmuLib | SEC PEIM
> +
> +#
> +#  VALID_ARCHITECTURES           = LOONGARCH64
> +#
> +
> +[Sources]
> +  TlbOperation.S   | GCC
> +  PeiCpuMmuLib.c
> +  CommonMmuLib.c
> +  CommonMmuLib.h
> +  Tlb.h
> +  Page.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
> +
> +[PCD]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
> +
> +[LibraryClasses]
> +  MemoryAllocationLib
> +  CacheMaintenanceLib
> +  PcdLib
> +  DebugLib
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> new file mode 100644
> index 0000000000..331500543c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// CPU Memory Manager Unit library instance for PEI modules.
> +//
> +// CPU Memory Manager Unit library instance for PEI modules.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "CPU Memory Manager Unit library instance for PEI modules."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "CPU Memory Manager Unit library instance for PEI modules."
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
> new file mode 100644
> index 0000000000..5d3f80fe34
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
> @@ -0,0 +1,48 @@
> +/** @file
> +
> +  Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef TLB_H_
> +#define TLB_H_
> +
> +/**
> +  Invalid corresponding TLB entries are based on the address given
> +
> +  @param Address The address corresponding to the invalid page table entry
> +
> +  @retval  none
> +**/
> +VOID
> +InvalidTlb (
> +  UINTN  Address
> +  );
> +
> +/**
> +  TLB refill handler start.
> +
> +  @param  none
> +
> +  @retval none
> +**/
> +VOID
> +HandleTlbRefillStart (
> +  VOID
> +  );
> +
> +/**
> +  TLB refill handler end.
> +
> +  @param  none
> +
> +  @retval none
> +**/
> +VOID
> +HandleTlbRefillEnd (
> +  VOID
> +  );
> +
> +#endif // TLB_H_
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
> new file mode 100644
> index 0000000000..e446f0839c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
> @@ -0,0 +1,44 @@
> +#------------------------------------------------------------------------------
> +#
> +# TLB operation functions
> +#
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#-----------------------------------------------------------------------------
> +
> +#include <Register/LoongArch64/Csr.h>
> +
> +ASM_GLOBAL ASM_PFX(HandleTlbRefillStart)
> +ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd)
> +ASM_GLOBAL ASM_PFX(InvalidTlb)
> +
> +#
> +#  Refill the page table.
> +#  @param  VOID
> +#  @retval  VOID
> +#
> +ASM_PFX(HandleTlbRefillStart):
> +  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   // refill hi,lo0,lo1
> +  csrrd   $t0, LOONGARCH_CSR_TLBRSAVE
> +  ertn
> +ASM_PFX(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(InvalidTlb):
> +    invtlb  INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0
> +    jirl    $zero, $ra, 0
> +
> +    .end
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
> new file mode 100644
> index 0000000000..ad8f751ad7
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
> @@ -0,0 +1,279 @@
> +/** @file
> +
> +  Copyright (c) 2023 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_
> +
> +#include <Library/CpuMmuLib.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))
> +
> +#define HUGEP_PAGE_MASK  (~(((UINTN)(1) << (PMD_SHIFT)) - 1) & \
> +                          (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
> +
> +#define INVALID_PAGE  0
> +
> +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)  (PTE){(((((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   The page table is invalid.
> +  @retval    0   The page table is valid.
> +**/
> +#define PGD_IS_EMPTY(Val)  (PGD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> +  Check that the page upper directory table entry is empty.
> +
> +  @param  pud   Page upper directory struct variables.
> +
> +  @retval    1   The page table is invalid.
> +  @retval    0   The page table is valid.
> +**/
> +#define PUD_IS_EMPTY(Val)  (PUD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> +  Check that the page middle directory table entry is empty.
> +
> +  @param  pmd   Page middle directory struct variables.
> +
> +  @retval    1   The page table is invalid.
> +  @retval    0   The page table is valid.
> +**/
> +#define PMD_IS_EMPTY(Val)  (PMD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> +  Check that the page the page table entry is empty.
> +
> +  @param  pte   Page table entry struct variables.
> +
> +  @retval    1   The page table is invalid.
> +  @retval    0   The page table is valid.
> +**/
> +#define PTE_IS_EMPTY(Val)  (!(PTE_VAL(Val) & (~PAGE_VALID)))
> +#endif // PAGE_H_
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> new file mode 100644
> index 0000000000..42a424b84d
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> @@ -0,0 +1,165 @@
> +/** @file
> +  CPU Memory Map Unit PEI phase driver.
> +
> +  Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Glossary:
> +    - 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/CpuMmuLib.h>
> +#include <Library/CacheMaintenanceLib.h>
> +#include <Library/CpuMmuLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +
> +#include "Page.h"
> +#include "Tlb.h"
> +#include "CommonMmuLib.h"
> +
> +/**
> +  Create a page table and initialize the memory management unit(MMU).
> +
> +  @param[in]   MemoryTable           A pointer to a memory ragion table.
> +  @param[out]  TranslationTableBase  A pointer to a translation table base address.
> +  @param[out]  TranslationTableSize  A pointer to a translation table base size.
> +
> +  @retval  EFI_SUCCESS                Configure MMU successfully.
> +           EFI_INVALID_PARAMETER      MemoryTable is NULL.
> +           EFI_UNSUPPORTED            Out of memory space or size not aligned.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ConfigureMemoryManagementUint (
> +  IN  MEMORY_REGION_DESCRIPTOR  *MemoryTable,
> +  OUT VOID                      **TranslationTableBase OPTIONAL,
> +  OUT UINTN                     *TranslationTableSize  OPTIONAL
> +  )
> +{
> +  PGD            *SwapperPageDir;
> +  UINTN          PgdShift;
> +  UINTN          PgdWide;
> +  UINTN          PudShift;
> +  UINTN          PudWide;
> +  UINTN          PmdShift;
> +  UINTN          PmdWide;
> +  UINTN          PteShift;
> +  UINTN          PteWide;
> +  UINTN          Length;
> +  UINTN          TlbReEntry;
> +  UINTN          TlbReEntryOffset;
> +  RETURN_STATUS  Status;
> +
> +  SwapperPageDir = NULL;
> +  PgdShift       = PGD_SHIFT;
> +  PgdWide        = PGD_WIDE;
> +  PudShift       = PUD_SHIFT;
> +  PudWide        = PUD_WIDE;
> +  PmdShift       = PMD_SHIFT;
> +  PmdWide        = PMD_WIDE;
> +  PteShift       = PTE_SHIFT;
> +  PteWide        = PTE_WIDE;
> +
> +  if (MemoryTable == NULL) {
> +    ASSERT (MemoryTable != NULL);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> +  ZeroMem (SwapperPageDir, PGD_TABLE_SIZE);
> +
> +  if (SwapperPageDir == NULL) {
> +    goto FreeTranslationTable;
> +  }
> +
> +  CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir);
> +
> +  while (MemoryTable->Length != 0) {
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n",
> +      __func__,
> +      __LINE__,
> +      MemoryTable->VirtualBase,
> +      (MemoryTable->Length + MemoryTable->VirtualBase),
> +      MemoryTable->Attributes
> +      ));
> +
> +    Status = FillTranslationTable (MemoryTable);
> +    if (EFI_ERROR (Status)) {
> +      goto FreeTranslationTable;
> +    }
> +
> +    MemoryTable++;
> +  }
> +
> +  //
> +  // TLB Re-entry address at the end of exception vector, a vector is up to 512 bytes,
> +  // so the starting address is: total exception vector size + total interrupt vector size + base.
> +  // The total size of TLB handler and exception vector size and interrupt vector size should not
> +  // be lager than 64KB.
> +  //
> +  Length           = (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart;
> +  TlbReEntryOffset = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512;
> +  TlbReEntry       = PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryOffset;
> +  if ((TlbReEntryOffset + Length) > SIZE_64KB) {
> +    goto FreeTranslationTable;
> +  }
> +
> +  //
> +  // Make sure TLB refill exception base address alignment is greater than or equal to 4KB and valid
> +  //
> +  if (TlbReEntry & (SIZE_4KB - 1)) {
> +    goto FreeTranslationTable;
> +  }
> +
> +  CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
> +  InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length);
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "%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
> +    ));
> +
> +  //
> +  // Set the address of TLB refill exception handler
> +  //
> +  SetTlbRebaseAddress ((UINTN)TlbReEntry);
> +
> +  //
> +  // Set page size
> +  //
> +  CsrXChg (LOONGARCH_CSR_TLBIDX, (DEFAULT_PAGE_SIZE << CSR_TLBIDX_SIZE), CSR_TLBIDX_SIZE_MASK);
> +  CsrWrite (LOONGARCH_CSR_STLBPGSIZE, DEFAULT_PAGE_SIZE);
> +  CsrXChg (LOONGARCH_CSR_TLBREHI, (DEFAULT_PAGE_SIZE << CSR_TLBREHI_PS_SHIFT), CSR_TLBREHI_PS);
> +
> +  CsrWrite (LOONGARCH_CSR_PWCTL0, (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25));
> +  CsrWrite (LOONGARCH_CSR_PWCTL1, (PgdShift | PgdWide << 6));
> +
> +  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
> +
> +  return EFI_SUCCESS;
> +
> +FreeTranslationTable:
> +  if (SwapperPageDir != NULL) {
> +    FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> +  }
> +
> +  return EFI_UNSUPPORTED;
> +}
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> new file mode 100644
> index 0000000000..e746c3b1a7
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> @@ -0,0 +1,44 @@
> +## @file
> +#  CPU Memory Map Unit PEI phase driver.
> +#
> +#  Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = PeiCpuMmuLib
> +  MODULE_UNI_FILE                = PeiCpuMmuLib.uni
> +  FILE_GUID                      = F67EB983-AC2A-7550-AB69-3BC51A1C895B
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = CpuMmuLib | SEC PEIM
> +
> +#
> +#  VALID_ARCHITECTURES           = LOONGARCH64
> +#
> +
> +[Sources]
> +  TlbOperation.S   | GCC
> +  PeiCpuMmuLib.c
> +  CommonMmuLib.c
> +  CommonMmuLib.h
> +  Tlb.h
> +  Page.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  UefiCpuPkg/UefiCpuPkg.dec
> +
> +[PCD]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
> +  gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
> +
> +[LibraryClasses]
> +  MemoryAllocationLib
> +  CacheMaintenanceLib
> +  PcdLib
> +  DebugLib
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> new file mode 100644
> index 0000000000..331500543c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// CPU Memory Manager Unit library instance for PEI modules.
> +//
> +// CPU Memory Manager Unit library instance for PEI modules.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "CPU Memory Manager Unit library instance for PEI modules."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "CPU Memory Manager Unit library instance for PEI modules."
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
> new file mode 100644
> index 0000000000..5d3f80fe34
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
> @@ -0,0 +1,48 @@
> +/** @file
> +
> +  Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef TLB_H_
> +#define TLB_H_
> +
> +/**
> +  Invalid corresponding TLB entries are based on the address given
> +
> +  @param Address The address corresponding to the invalid page table entry
> +
> +  @retval  none
> +**/
> +VOID
> +InvalidTlb (
> +  UINTN  Address
> +  );
> +
> +/**
> +  TLB refill handler start.
> +
> +  @param  none
> +
> +  @retval none
> +**/
> +VOID
> +HandleTlbRefillStart (
> +  VOID
> +  );
> +
> +/**
> +  TLB refill handler end.
> +
> +  @param  none
> +
> +  @retval none
> +**/
> +VOID
> +HandleTlbRefillEnd (
> +  VOID
> +  );
> +
> +#endif // TLB_H_
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
> new file mode 100644
> index 0000000000..e446f0839c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
> @@ -0,0 +1,44 @@
> +#------------------------------------------------------------------------------
> +#
> +# TLB operation functions
> +#
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#-----------------------------------------------------------------------------
> +
> +#include <Register/LoongArch64/Csr.h>
> +
> +ASM_GLOBAL ASM_PFX(HandleTlbRefillStart)
> +ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd)
> +ASM_GLOBAL ASM_PFX(InvalidTlb)
> +
> +#
> +#  Refill the page table.
> +#  @param  VOID
> +#  @retval  VOID
> +#
> +ASM_PFX(HandleTlbRefillStart):
> +  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   // refill hi,lo0,lo1
> +  csrrd   $t0, LOONGARCH_CSR_TLBRSAVE
> +  ertn
> +ASM_PFX(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(InvalidTlb):
> +    invtlb  INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0
> +    jirl    $zero, $ra, 0
> +
> +    .end
> diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
> index 872f20fc36..709992d327 100644
> --- a/UefiCpuPkg/UefiCpuPkg.dsc
> +++ b/UefiCpuPkg/UefiCpuPkg.dsc
> @@ -209,6 +209,8 @@
>     UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
>     UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
>     UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
> +  UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> +  UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
>   
>   [BuildOptions]
>     *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES


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



[-- Attachment #2: Type: text/html, Size: 101532 bytes --]

  parent reply	other threads:[~2023-11-20  9:55 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20231117095742.3605778-1-lichao@loongs>
2023-11-17  9:58 ` [edk2-devel] [PATCH v3 01/39] MdePkg: Add the header file named Csr.h for LoongArch64 Chao Li
2023-11-17  9:58 ` [edk2-devel] [PATCH v3 02/39] MdePkg: Add LoongArch64 FPU function set into BaseCpuLib Chao Li
2023-11-17  9:59 ` [edk2-devel] [PATCH v3 03/39] MdePkg: Add LoongArch64 exception function set into BaseLib Chao Li
2023-11-17  9:59 ` [edk2-devel] [PATCH v3 04/39] MdePkg: Add LoongArch64 local interrupt " Chao Li
2023-11-17  9:59 ` [edk2-devel] [PATCH v3 05/39] MdePkg: Add LoongArch Cpucfg function Chao Li
2023-11-17  9:59 ` [edk2-devel] [PATCH v3 06/39] MdePkg: Add read stable counter operation for LoongArch Chao Li
2023-11-17  9:59 ` [edk2-devel] [PATCH v3 07/39] MdePkg: Add CSR " Chao Li
2023-11-17  9:59 ` [edk2-devel] [PATCH v3 08/39] MdePkg: Add IOCSR " Chao Li
2023-11-17  9:59 ` [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg Chao Li
2023-11-17 11:35   ` Leif Lindholm
2023-11-20  3:07     ` Chao Li
2023-11-21 14:37   ` Laszlo Ersek
2023-11-22  1:47     ` Chao Li
2023-11-24 11:35       ` Laszlo Ersek
2023-11-27  3:27         ` Chao Li
2023-12-01  0:32           ` 回复: " gaoliming via groups.io
2023-12-01  8:20             ` Chao Li
     [not found]         ` <179B5D231F190982.32091@groups.io>
2023-11-29  1:35           ` Chao Li
2023-11-17  9:59 ` [edk2-devel] [PATCH v3 10/39] MdePkg: Add method of LoongArch64 to PeiServicesTablePointerLibReg Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library Chao Li
2023-11-22 16:12   ` Laszlo Ersek
2023-11-22 16:13     ` Laszlo Ersek
2023-11-23 11:43     ` Chao Li
2023-12-11 17:16       ` Laszlo Ersek
2023-12-12  3:45         ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 12/39] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
2023-11-17 20:18   ` Andrei Warkentin
2023-11-20  3:26     ` Chao Li
2023-11-30  0:59   ` Ni, Ray
2023-11-30  2:25     ` Chao Li
     [not found]     ` <179C457B5B852375.31732@groups.io>
2023-12-04  7:31       ` Chao Li
2023-12-05  8:27         ` Ni, Ray
2023-12-05 12:27           ` Chao Li
     [not found]           ` <179DEF40376B662A.18076@groups.io>
2023-12-08  2:10             ` Chao Li
2023-12-11  8:13               ` Ni, Ray
2023-12-11  8:19                 ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 14/39] UefiCpuPkg: Add LoongArch64CpuMmuLib " Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 15/39] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 16/39] UefiCpuPkg: Add CpuDxe driver " Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 17/39] EmbeddedPkg: Add PcdPrePiCpuIoSize width for LOONGARCH64 Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 18/39] ArmVirtPkg: Move PCD of FDT base address and FDT padding to OvmfPkg Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 19/39] MdePkg: Add a PCD feature flag named PcdPciIoTranslationIsEnabled Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 20/39] UefiCpuPkg: Add MMIO method in CpuIo2Dxe Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 21/39] ArmVirtPkg: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg Chao Li
2023-11-17 13:13   ` Leif Lindholm
2023-11-20  3:24     ` Chao Li
2023-11-20 18:47       ` Leif Lindholm
2023-11-21  1:10         ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
2023-11-17 20:15   ` Andrei Warkentin
2023-11-20  3:04     ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 24/39] OvmfPkg/RiscVVirt: Remove PciCpuIo2Dxe from RiscVVirt Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 25/39] ArmVirtPkg: Move the FdtSerialPortAddressLib to OvmfPkg Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 26/39] ArmVirtPkg: Move the PcdTerminalTypeGuidBuffer into OvmfPkg Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 27/39] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 28/39] OvmfPkg/LoongArchVirt: Add stable timer driver Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 29/39] OvmfPkg/LoongArchVirt: Add a NULL library named CollectApResouceLibNull Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 30/39] OvmfPkg/LoongArchVirt: Add serial port hook library Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 31/39] OvmfPkg/LoongArchVirt: Add the early serial port output library Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 32/39] OvmfPkg/LoongArchVirt: Add real time clock library Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 33/39] OvmfPkg/LoongArchVirt: Add NorFlashQemuLib Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 34/39] OvmfPkg/LoongArchVirt: Add FdtQemuFwCfgLib Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 35/39] OvmfPkg/LoongArchVirt: Add reset system library Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 36/39] OvmfPkg/LoongArchVirt: Support SEC phase Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 37/39] OvmfPkg/LoongArchVirt: Support PEI phase Chao Li
2023-11-17 10:04 ` [edk2-devel] [PATCH v3 38/39] OvmfPkg/LoongArchVirt: Add build file Chao Li
2023-11-17 10:04 ` [edk2-devel] [PATCH v3 39/39] OvmfPkg/LoongArchVirt: Add self introduction file Chao Li
     [not found] ` <179860C0A131BC70.3002@groups.io>
2023-11-20  9:55   ` Chao Li [this message]
     [not found] ` <179860DB0A3E8D83.6542@groups.io>
2023-11-21  6:39   ` [edk2-devel] [PATCH v3 27/39] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg Chao Li

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=2850cbb7-ab9a-4192-ac83-15e0d1193425@loongson.cn \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

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

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