public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "maobibo" <maobibo@loongson.cn>
To: xianglai li <lixianglai@loongson.cn>, devel@edk2.groups.io
Cc: quic_llindhol@quicinc.com, michael.d.kinney@intel.com, ardb@kernel.org
Subject: Re: [edk2-platforms][PATCH V4 05/14] Platform/Loongson: Add MmuLib.
Date: Sat, 29 Oct 2022 14:45:23 +0800	[thread overview]
Message-ID: <eed21b78-113f-543f-d512-be4cbcdd981e@loongson.cn> (raw)
In-Reply-To: <1d54b72b110ab8a6aa5c0f3f029fd4cc43b85c0c.1666335216.git.lixianglai@loongson.cn>



在 2022/10/21 15:11, xianglai li 写道:
> Read the memory map information through the QemuFwCfg interface,
> then build the page table through the memory map information,
> and finally enable Mmu.
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054
> 
> Signed-off-by: xianglai li <lixianglai@loongson.cn>
> ---
>  .../LoongArchQemuPkg/Include/Library/MmuLib.h |  85 ++
>  .../LoongArchQemuPkg/Library/MmuLib/Mmu.S     |  35 +
>  .../Library/MmuLib/MmuBaseLib.inf             |  35 +
>  .../Library/MmuLib/MmuBaseLibPei.inf          |  42 +
>  .../Library/MmuLib/MmuLibCore.c               | 908 ++++++++++++++++++
>  .../Library/MmuLib/MmuLibCore.h               |  39 +
>  .../Library/MmuLib/MmuLibCorePei.c            | 236 +++++
>  .../LoongArchQemuPkg/Library/MmuLib/mmu.h     | 104 ++
>  .../LoongArchQemuPkg/Library/MmuLib/page.h    | 267 +++++
>  .../LoongArchQemuPkg/Library/MmuLib/pte.h     |  57 ++
>  10 files changed, 1808 insertions(+)
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
>  create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
> 
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
> new file mode 100644
> index 0000000000..6c501eca07
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
> @@ -0,0 +1,85 @@
> +/** @file
> +
> +  Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Glossary:
> +    - EXC     - execute
> +**/
> +#ifndef MMU_LIB_H_
> +#define MMU_LIB_H_
> +/**
> +  write operation is performed Count times from the first element of Buffer.
> +Convert EFI Attributes to Loongarch Attributes.
> +  @param[in]  EfiAttributes     Efi Attributes.
> +
> +  @retval  LoongArch Attributes.
> +**/
> +UINTN
> +EfiAttributeToLoongArchAttribute (
> +  IN UINTN  EfiAttributes
> +  );
> +
> +/**
> +  Finds the length and memory properties of the memory region corresponding to the specified base address.
> +
> +  @param[in]  BaseAddress    To find the base address of the memory region.
> +  @param[in]  EndAddress     To find the end address of the memory region.
> +  @param[out]  RegionLength    The length of the memory region found.
> +  @param[out]  RegionAttributes    Properties of the memory region found.
> +
> +  @retval  EFI_SUCCESS    The corresponding memory area was successfully found
> +           EFI_NOT_FOUND    No memory area found
> +**/
> +EFI_STATUS
> +GetLoongArchMemoryRegion (
> +  IN     UINTN  BaseAddress,
> +  IN     UINTN  EndAddress,
> +  OUT    UINTN  *RegionLength,
> +  OUT    UINTN  *RegionAttributes
> +  );
> +
> +/**
> +  Sets the Attributes  of the specified memory region
> +
> +  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
> +  @param[in]  Length       The length of the memory region to set the Attributes.
> +  @param[in]  Attributes   The Attributes to be set.
> +
> +  @retval  EFI_SUCCESS    The Attributes was set successfully
> +
> +**/
> +EFI_STATUS
> +LoongArchSetMemoryAttributes (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINTN                 Length,
> +  IN UINTN                 Attributes
> +  );
> +
> +/**
> +  Sets the non-executable Attributes for the specified memory region
> +
> +  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
> +  @param[in]  Length       The length of the memory region to set the Attributes.
> +
> +  @retval  EFI_SUCCESS    The Attributes was set successfully
> +**/
> +EFI_STATUS
> +LoongArchSetMemoryRegionNoExec (
> +  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN  UINTN                Length
> +  );
> +/**
> +  Create a page table and initialize the MMU.
> +
> +  @param[] VOID
> +
> +  @retval  VOID
> +**/
> +VOID
> +EFIAPI
> +ConfigureMmu (
> +  VOID
> +  );
> +#endif
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
> new file mode 100644
> index 0000000000..a697b54e65
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
> @@ -0,0 +1,35 @@
> +#------------------------------------------------------------------------------
> +#
> +# LoongArch for LoongArch
> +#
> +# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#-----------------------------------------------------------------------------
> +
> +#ifndef _KERNEL
> +#define _KERNEL
> +#endif
> +
> +#include "Library/Cpu.h"
> +#include "LoongArchAsmMacro.h"
> +
> +#  Query the page table.
> +#
> +#  @param  VOID
> +#
> +#  @retval  VOID
> +ASM_FUNC(HandleTlbRefill)
> +  csrwr T0, LOONGARCH_CSR_TLBRSAVE
> +  csrrd T0, LOONGARCH_CSR_PGD
> +  lddir T0, T0, 3   #Put pud BaseAddress into T0
> +  lddir T0, T0, 2   #Put pmd BaseAddress into T0
> +  lddir T0, T0, 1   #Put pte BaseAddress into T0
> +  ldpte T0, 0
> +  ldpte T0, 1
> +  tlbfill
> +  csrrd T0, LOONGARCH_CSR_TLBRSAVE
> +  ertn
> +.globl  HandleTlbRefillEnd
> +HandleTlbRefillEnd:
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
> new file mode 100644
> index 0000000000..d8cfe6776e
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
> @@ -0,0 +1,35 @@
> +## @file
> +#
> +#  Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = MmuBaseLib
> +  FILE_GUID                      = da8f0232-fb14-42f0-922c-63104d2c70be
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = MmuLib
> +
> +  CONSTRUCTOR                    = MmuInitialize
> +[Sources.common]
> +  MmuLibCore.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
> +
> +[PCD]
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
> +
> +[LibraryClasses]
> +  MemoryAllocationLib
> +  PcdLib
> +  DebugLib
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
> new file mode 100644
> index 0000000000..f6a3cab45f
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
> @@ -0,0 +1,42 @@
> +## @file
> +#
> +#  Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = MmuPeiLib
> +  FILE_GUID                      = da8f0232-fb14-42f0-922c-63104d2c70bd
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = MmuLib | SEC PEIM
> +
> +[Sources.common]
> +  MmuLibCorePei.c
> +  Mmu.S
> +  MmuLibCore.h
> +  MmuLibCore.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
> +  OvmfPkg/OvmfPkg.dec
> +
> +[PCD]
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase
> +  gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
> +
> +[LibraryClasses]
> +  MemoryAllocationLib
> +  PcdLib
> +  DebugLib
> +  QemuFwCfgLib
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
> new file mode 100644
> index 0000000000..d737759ad2
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
> @@ -0,0 +1,908 @@
> +/** @file
> +
> +  Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Glossary:
> +    - Pgd or Pgd or PGD    - Page Global Directory
> +    - Pud or Pud or PUD    - Page Upper Directory
> +    - Pmd or Pmd or PMD    - Page Middle Directory
> +    - Pte or pte or PTE    - Page Table Entry
> +    - Val or VAL or val    - Value
> +    - Dir    - Directory
> +**/
> +#include <Uefi.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include "Library/Cpu.h"
> +#include "pte.h"
> +#include "page.h"
> +#include "mmu.h"
> +
> +BOOLEAN  mMmuInited = FALSE;
> +/**
> +  Check to see if mmu successfully initializes.
> +
> +  @param  VOID.
> +
> +  @retval  TRUE  Initialization has been completed.
> +           FALSE Initialization did not complete.
> +**/
> +BOOLEAN
> +MmuIsInit (VOID) {
> +  if ((mMmuInited == TRUE) ||
> +      (PcdGet64 (PcdSwapPageDir) != 0)) {
> +    return TRUE;
> +  }
> +  return FALSE;
> +}
> +
> +/**
> +  Iterates through the page directory to initialize it.
> +
> +  @param  Dst  A pointer to the directory of the page to initialize.
> +  @param  Num  The number of page directories to initialize.
> +  @param  Src  A pointer to the data used to initialize the page directory.
> +
> +  @retval VOID.
> +**/
> +VOID
> +PageDirInit (
> +  IN VOID *Dst,
> +  IN UINTN Num,
> +  IN VOID *Src
> +  )
> +{
> +  UINTN *Ptr;
> +  UINTN *End;
> +  UINTN Entry;
> +
> +  Entry = (UINTN)Src;
> +  Ptr = (UINTN *)Dst;
> +  End = Ptr + Num;
> +
> +  for ( ;Ptr < End; Ptr++) {
> +    *Ptr = Entry;
> +  }
> +
> +  return ;
> +}
> +/**
> +  Gets the virtual address corresponding to the page global directory table entry.
> +
> +  @param  Address  the virtual address for the table entry.
> +
> +  @retval PGD A pointer to get the table item.
> +**/
> +PGD *
> +PgdOffset (
> +  IN UINTN Address
> +  )
> +{
> +  return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address);
> +}
> +/**
> +  Gets the virtual address corresponding to the page upper directory table entry.
> +
> +  @param  Pgd  A pointer to a page global directory table entry.
> +  @param  Address  the virtual address for the table entry.
> +
> +  @retval PUD A pointer to get the table item.
> +**/
> +PUD *
> +PudOffset (
> +  IN PGD *Pgd,
> +  IN UINTN Address
> +  )
> +{
> +  UINTN PgdVal = (UINTN)PGD_VAL (*Pgd);
> +  return (PUD *)PgdVal + PUD_INDEX (Address);
> +}
> +/**
> +  Gets the virtual address corresponding to the page middle directory table entry.
> +
> +  @param  Pud  A pointer to a page upper directory table entry.
> +  @param  Address  the virtual address for the table entry.
> +
> +  @retval PMD A pointer to get the table item.
> +**/
> +PMD *
> +PmdOffset (
> +  IN PUD *Pud,
> +  IN UINTN Address
> +  )
> +{
> +  UINTN PudVal = PUD_VAL (*Pud);
> +  return (PMD *)PudVal + PMD_INDEX (Address);
> +}
> +/**
> +  Gets the virtual address corresponding to the page table entry.
> +
> +  @param  Pmd  A pointer to a page middle directory table entry.
> +  @param  Address  the virtual address for the table entry.
> +
> +  @retval PTE A pointer to get the table item.
> +**/
> +PTE *
> +PteOffset (
> +  IN PMD *Pmd,
> +  IN UINTN Address
> +  )
> +{
> +  UINTN PmdVal = (UINTN)PMD_VAL (*Pmd);
> +  return (PTE *)PmdVal + PTE_INDEX (Address);
> +}
> +
> +/**
> +  Sets the value of the page table entry.
> +
> +  @param  Pte  A pointer to a page table entry.
> +  @param  PteVal  The value of the page table entry to set.
> +
> +  @retval VOID
> +**/
> +VOID
> +SetPte (
> +  IN PTE *Pte,
> +  IN PTE PteVal
> +  )
> +{
> +  *Pte = PteVal;
> +}
> +/**
> +  Sets the value of the page global directory.
> +
> +  @param  Pgd  A pointer to a page global directory.
> +  @param  Pud  The value of the page global directory to set.
> +
> +  @retval VOID
> +**/
> +VOID
> +SetPgd (
> +  IN PGD *Pgd,
> +  IN PUD *Pud
> +  )
> +{
> +  *Pgd = (PGD) {((UINTN)Pud)};
> +}
> +
> +/**
> +  Sets the value of the page upper directory.
> +
> +  @param  Pud  A pointer to a page upper directory.
> +  @param  Pmd  The value of the page upper directory to set.
> +
> +  @retval VOID
> +**/
> +VOID
> +SetPud (
> +  IN PUD *Pud,
> +  IN PMD *Pmd
> +  )
> +{
> +  *Pud = (PUD) {((UINTN)Pmd)};
> +}
> +
> +/**
> +  Sets the value of the page middle directory.
> +
> +  @param  Pmd  A pointer to a page middle directory.
> +  @param  Pte  The value of the page middle directory to set.
> +
> +  @retval VOID
> +**/
> +VOID
> +SetPmd (
> +  IN PMD *Pmd,
> +  IN PTE *Pte
> +  )
> +{
> +  *Pmd = (PMD) {((UINTN)Pte)};
> +}
> +/**
> +  Free up memory space occupied by page tables.
> +
> +  @param  Pte  A pointer to the page table.
> +
> +  @retval VOID
> +**/
> +VOID
> +PteFree (
> +  IN PTE *Pte
> +  )
> +{
> +  FreePages ((VOID *)Pte, 1);
> +}
> +/**
> +  Free up memory space occupied by page middle directory.
> +
> +  @param  Pmd  A pointer to the page middle directory.
> +
> +  @retval VOID
> +**/
> +VOID
> +PmdFree (
> +  IN PMD *Pmd
> +  )
> +{
> +  FreePages ((VOID *)Pmd, 1);
> +}
> +/**
> +  Free up memory space occupied by page upper directory.
> +
> +  @param  Pud  A pointer to the page upper directory.
> +
> +  @retval VOID
> +**/
> +VOID
> +PudFree (
> +  IN PUD *Pud
> +  )
> +{
> +  FreePages ((VOID *)Pud, 1);
> +}
> +/**
> +  Requests the memory space required for the page upper directory,
> +  initializes it, and places it in the specified page global directory
> +
> +  @param  Pgd  A pointer to the page global directory.
> +
> +  @retval  EFI_SUCCESS  Memory request successful.
> +  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
> +**/
> +INTN
> +PudAlloc (
> +  IN PGD *Pgd
> +  )
> +{
> +  PUD *Pud = (PUD *) AllocatePages (1);
> +  if (!Pud) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPmd));
> +
> +  if (pgd_none (*Pgd)) {
> +    SetPgd (Pgd, Pud);
> +  } else { /* Another has populated it */
> +    PudFree (Pud);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +/**
> +  Requests the memory space required for the page middle directory,
> +  initializes it, and places it in the specified page upper directory
> +
> +  @param  Pud  A pointer to the page upper directory.
> +
> +  @retval  EFI_SUCCESS  Memory request successful.
> +  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
> +**/
> +EFI_STATUS
> +PmdAlloc (
> +  IN PUD *Pud
> +  )
> +{
> +  PMD *Pmd;
> +
> +  Pmd = (PMD *) AllocatePages (1);
> +  if (!Pmd) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPte));
> +
> +  if (pud_none (*Pud)) {
> +    SetPud (Pud, Pmd);
> +  } else {/* Another has populated it */
> +    PmdFree (Pmd);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +/**
> +  Requests the memory space required for the page table,
> +  initializes it, and places it in the specified page middle directory
> +
> +  @param  Pmd  A pointer to the page middle directory.
> +
> +  @retval  EFI_SUCCESS  Memory request successful.
> +  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
> +**/
> +INTN
> +PteAlloc (
> +  IN PMD *Pmd
> +  )
> +{
> +  PTE *Pte;
> +
> +  Pte = (PTE *) AllocatePages (1);
> +  if (!Pte) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
> +
> +  if (pmd_none (*Pmd)) {
> +    SetPmd (Pmd, Pte);
> +  } else { /* Another has populated it */
> +    PteFree (Pte);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +/**
> +  Requests the memory space required for the page upper directory,
> +  initializes it, and places it in the specified page global directory,
> +  and get the page upper directory entry corresponding to the virtual address
> +
> +  @param  Pgd  A pointer to the page global directory.
> +
> +  @retval   Gets the page upper directory entry
> +**/
> +PUD *
> +PudAllocGet (
> +  IN PGD *Pgd,
> +  IN UINTN Address
> +  )
> +{
> +  return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ?
> +           NULL : PudOffset (Pgd, Address));
> +}
> +/**
> +  Requests the memory space required for the page middle directory,
> +  initializes it, and places it in the specified page upper directory,
> +  and get the page middle directory entry corresponding to the virtual address
> +
> +  @param  Pud  A pointer to the page upper directory.
> +
> +  @retval   Gets the page middle directory entry
> +**/
> +PMD *
> +PmdAllocGet (
> +  IN PUD *Pud,
> +  IN UINTN Address
> +  )
> +{
> +  PMD * ret =  (pud_none (*Pud) && PmdAlloc (Pud))?
> +            NULL: PmdOffset (Pud, Address);
> +  DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", __func__, __LINE__,
> +    Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) ));
> +
> +  return ret;
> +}
> +/**
> +  Requests the memory space required for the page table,
> +  initializes it, and places it in the specified page middle directory,
> +  and get the page table entry corresponding to the virtual address
> +
> +  @param  Pmd  A pointer to the page upper directory.
> +
> +  @retval   Gets the page table entry
> +**/
> +PTE *
> +PteAllocGet (
> +  IN PMD *Pmd,
> +  IN UINTN Address
> +  )
> +{
> +  return (pmd_none (*Pmd) && PteAlloc (Pmd))?
> +    NULL: PteOffset (Pmd, Address);
> +}
> + /**
> +  Convert page middle directory table entry  to tlb entry.
> +
> +  @param  PmdVal   page middle directory table entry value.
> +
> +  @retval  tlb entry value.
> + **/
> +UINTN
> +PmdToTlbEntry (
> +  UINTN PmdVal
> +  )
> +{
> +  UINTN Value;
> +
> +  Value = PmdVal ^ PAGE_HUGE;
> +  Value |= ((Value & PAGE_HGLOBAL) >>
> +           (PAGE_HGLOBAL_SHIFT - PAGE_GLOBAL_SHIFT));
> +
> +  return Value;
> +}
> +
> + /**
> +  Update huge tlb.
> +
> +  @param  address  The address corresponding to tlb.
> +  @param  Pte   A pointer to the page table entry.
> +
> +  @retval  VOID.
> + **/
> +VOID
> +UpdateHugeTlb (
> +  IN UINTN address,
> +  PTE *Pte)
> +{
> +  INTN Idx;
> +  UINTN TlbEntry;
> +  address &= (PAGE_MASK << 1);
> +  LOONGARCH_CSR_WRITEQ (address, LOONGARCH_CSR_TLBEHI);
> +  LOONGARCH_TLB_SRCH();
> +  LOONGARCH_CSR_READQ (Idx, LOONGARCH_CSR_TLBIDX);
> +
> +  if (Idx < 0) {
> +    return ;
> +  }
> +  WRITE_CSR_PAGE_SIZE (HUGE_PAGE_SIZE);
> +  TlbEntry = PmdToTlbEntry(PTE_VAL (*Pte));
> +  LOONGARCH_CSR_WRITEQ(TlbEntry, LOONGARCH_CSR_TLBELO0);
> +  LOONGARCH_CSR_WRITEQ(TlbEntry + (HUGE_PAGE_SIZE >> 1), LOONGARCH_CSR_TLBELO1);
> +  LOONGARCH_TLB_WR ();
> +
> +  WRITE_CSR_PAGE_SIZE (DEFAULT_PAGE_SIZE);
> +
> +  return ;
> +}
> + /**
> +  Update tlb.
> +
> +  @param  address  The address corresponding to tlb.
> +  @param  Pte   A pointer to the page table entry.
> +
> +  @retval  VOID.
> + **/
> +VOID
> +UpdateTlb (
> +  IN UINTN address,
> +  PTE *Pte)
> +{
> +  INTN Idx;
> +  if (IS_HUGE_PAGE (Pte->PteVal)) {
> +    return UpdateHugeTlb(address, Pte);
> +  }
> +
> +  address &= (PAGE_MASK << 1);
> +  LOONGARCH_CSR_WRITEQ (address, LOONGARCH_CSR_TLBEHI);
> +  LOONGARCH_TLB_SRCH();
> +  LOONGARCH_CSR_READQ (Idx, LOONGARCH_CSR_TLBIDX);
> +
> +  if (Idx < 0) {
> +    return ;
> +  }
> +
> +  if ((UINTN)Pte & sizeof(PTE)) {
> +    Pte--;
> +  }
> +
> +  WRITE_CSR_PAGE_SIZE (DEFAULT_PAGE_SIZE);
> +  LOONGARCH_CSR_WRITEQ(PTE_VAL (*Pte), LOONGARCH_CSR_TLBELO0);
> +  Pte++;
> +  LOONGARCH_CSR_WRITEQ(PTE_VAL (*Pte), LOONGARCH_CSR_TLBELO1);
> +  LOONGARCH_TLB_WR ();
> +
> +  return ;
> +}
> +
> +/**
> +  Gets the physical address of the page table entry corresponding to the specified virtual address.
> +
> +  @param  Address  the corresponding virtual address of the page table entry.
> +
> +  @retval     A pointer to the page table entry.
> +  @retval  NULL
> +**/
> +PTE *
> +GetPteAddress (
> +  IN UINTN Address
> +  )
> +{
> +  PGD *Pgd;
> +  PUD *Pud;
> +  PMD *Pmd;
> +
> +  Pgd = PgdOffset (Address);
> +
> +  if (pgd_none (*Pgd)) {
> +    return NULL;
> +  }
> +
> +  Pud = PudOffset (Pgd, Address);
> +
> +  if (pud_none (*Pud)) {
> +    return NULL;
> +  }
> +
> +  Pmd = PmdOffset (Pud, Address);
> +  if (pmd_none (*Pmd)) {
> +    return NULL;
> +  }
> +
> +  if (IS_HUGE_PAGE (Pmd->PmdVal)) {
> +    return ((PTE *)Pmd);
> +  }
> +
> +  return PteOffset (Pmd, Address);
> +}
> +/**
> +  Establishes a page table entry based on the specified memory region.
> +
> +  @param  Pmd  A pointer to the page middle directory.
> +  @param  Address  The memory space start address.
> +  @param  End  The end address of the memory space.
> +  @param  Attributes  Memory space Attributes.
> +
> +  @retval     EFI_SUCCESS   The page table entry was created successfully.
> +  @retval     EFI_OUT_OF_RESOURCES  Page table entry establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +MemoryMapPteRange (
> +  IN PMD *Pmd,
> +  IN UINTN Address,
> +  IN UINTN End,
> +  IN UINTN Attributes
> +  )
> +{
> +  PTE *Pte;
> +  PTE PteVal;
> +  BOOLEAN UpDate;
> +
> +  Pte = PteAllocGet (Pmd, Address);
> +  if (!Pte) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  do {
> +    UpDate = FALSE;
> +    PteVal = MAKE_PTE (Address, Attributes);
> +    DEBUG ((DEBUG_VERBOSE,
> +      "%a %d Address %p  PGD_INDEX %p PUD_INDEX   %p PMD_INDEX  %p PTE_INDEX  %p MAKE_PTE  %p\n",
> +      __func__, __LINE__,  Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
> +      PTE_INDEX (Address), PteVal));
> +
> +    if ((!pte_none (*Pte)) &&
> +        (PTE_VAL(*Pte) != PTE_VAL(PteVal)))
> +    {
> +      UpDate = TRUE;
> +    }
> +
> +    SetPte (Pte, PteVal);
> +    if (UpDate) {
> +      UpdateTlb (Address, Pte);
> +    }
> +  } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
> +
> +  return EFI_SUCCESS;
> +}
> +/**
> +  Establishes a page middle directory based on the specified memory region.
> +
> +  @param  Pud  A pointer to the page upper directory.
> +  @param  Address  The memory space start address.
> +  @param  End  The end address of the memory space.
> +  @param  Attributes  Memory space Attributes.
> +
> +  @retval     EFI_SUCCESS   The page middle directory was created successfully.
> +  @retval     EFI_OUT_OF_RESOURCES  Page middle directory establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +MemoryMapPmdRange (
> +  IN PUD *Pud,
> +  IN UINTN Address,
> +  IN UINTN End,
> +  IN UINTN Attributes
> +  )
> +{
> +  PMD *Pmd;
> +  PTE *Pte;
> +  UINTN Next;
> +  UINTN AddressStart_HugePage;
> +  UINTN AddressEnd_HugePage;
> +
> +  Pmd = PmdAllocGet (Pud, Address);
> +  if (!Pmd) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  do {
> +    Next = PMD_ADDRESS_END (Address, End);
> +    if (((Address & (~PMD_MASK)) == 0) &&
> +        ((Next &  (~PMD_MASK)) == 0) &&
> +        (pmd_none (*Pmd)))
> +    {
> +      DEBUG ((DEBUG_VERBOSE,
> +        "%a %d Address %p  PGD_INDEX %p PUD_INDEX   %p PMD_INDEX  %p MAKE_HUGE_PTE  %p\n",
> +        __func__, __LINE__,  Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
> +        MAKE_HUGE_PTE (Address, Attributes)));
> +
> +      SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes));
> +    } else {
> +       if ((pmd_none (*Pmd)) ||
> +          ((!pmd_none (*Pmd)) &&
> +           (!IS_HUGE_PAGE (Pmd->PmdVal))))
> +       {
> +         if (MemoryMapPteRange (Pmd, Address, Next, Attributes)) {
> +           return EFI_OUT_OF_RESOURCES;
> +         }
> +       } else {
> +         SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte));
> +         AddressStart_HugePage = Address & PMD_MASK;
> +         AddressEnd_HugePage = AddressStart_HugePage + HUGE_PAGE_SIZE;
> +         if (MemoryMapPteRange (Pmd, AddressStart_HugePage, AddressEnd_HugePage, Attributes)) {
> +           return EFI_OUT_OF_RESOURCES;
> +         }
> +         Pte = GetPteAddress (AddressStart_HugePage);
> +         if (Pte == NULL) {
> +           continue ;
> +         }
> +         UpdateTlb (AddressStart_HugePage, Pte);
> +         if (AddressEnd_HugePage > End) {
> +           Next = End;
> +         }
> +       }
> +    }
> +  } while (Pmd++, Address = Next, Address != End);
> +
> +  return 0;
> +}
> +/**
> +  Establishes a page upper directory based on the specified memory region.
> +
> +  @param  Pgd  A pointer to the page global directory.
> +  @param  Address  The memory space start address.
> +  @param  End  The end address of the memory space.
> +  @param  Attributes  Memory space Attributes.
> +
> +  @retval     EFI_SUCCESS   The page upper directory was created successfully.
> +  @retval     EFI_OUT_OF_RESOURCES  Page upper directory establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +MemoryMapPudRange (
> +  IN PGD *Pgd,
> +  IN UINTN Address,
> +  IN UINTN End,
> +  IN UINTN Attributes
> +  )
> +{
> +  PUD *Pud;
> +  UINTN Next;
> +
> +  Pud = PudAllocGet (Pgd, Address);
> +  if (!Pud) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  do {
> +    Next = PUD_ADDRESS_END (Address, End);
> +    if (MemoryMapPmdRange (Pud, Address, Next, Attributes)) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +  } while (Pud++, Address = Next, Address != End);
> +  return EFI_SUCCESS;
> +}
> +/**
> +  Establishes a page global directory based on the specified memory region.
> +
> +  @param  Start  The memory space start address.
> +  @param  End  The end address of the memory space.
> +  @param  Attributes  Memory space Attributes.
> +
> +  @retval     EFI_SUCCESS   The page global directory was created successfully.
> +  @retval     EFI_OUT_OF_RESOURCES  Page global directory establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +MemoryMapPageRange (
> +  IN UINTN Start,
> +  IN UINTN End,
> +  IN UINTN Attributes
> +  )
> +{
> +  PGD *Pgd;
> +  UINTN Next;
> +  UINTN Address = Start;
> +  EFI_STATUS Err;
> +
> +  Pgd = PgdOffset (Address);
> +  do {
> +    Next = PGD_ADDRESS_END (Address, End);
> +    Err = MemoryMapPudRange (Pgd, Address, Next, Attributes);
> +    if (Err) {
> +      return Err;
> +    }
> +  } while (Pgd++, Address = Next, Address != End);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Page tables are established from memory-mapped tables.
> +
> +  @param  MemoryRegion   A pointer to a memory-mapped table entry.
> +
> +  @retval     EFI_SUCCESS   The page table was created successfully.
> +  @retval     EFI_OUT_OF_RESOURCES  Page table  establishment failed due to resource exhaustion.
> +**/
> +EFI_STATUS
> +FillTranslationTable (
> +  IN  MEMORY_REGION_DESCRIPTOR  *MemoryRegion
> +  )
> +{
> +  return MemoryMapPageRange (MemoryRegion->VirtualBase,
> +           (MemoryRegion->Length + MemoryRegion->VirtualBase),
> +           MemoryRegion->Attributes);
> +}
> +
> +/**
> +  write operation is performed Count times from the first element of Buffer.
> +Convert EFI Attributes to Loongarch Attributes.
> +  @param[in]  EfiAttributes     Efi Attributes.
> +
> +  @retval  LoongArch Attributes.
> +**/
> +UINTN
> +EfiAttributeToLoongArchAttribute (
> +  IN UINTN  EfiAttributes
> +  )
> +{
> +  UINTN  LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | CACHE_CC | PAGE_USER;

I just think that PAGE_KERNEL need be used here rather than PAGE_USER,
it can only be accessed with kernel priviledge.


> +  switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
> +    case EFI_MEMORY_UC:
> +      LoongArchAttributes |= CACHE_SUC;
> +      break;
> +    case EFI_MEMORY_WC:
> +    case EFI_MEMORY_WT:
> +    case EFI_MEMORY_WB:
> +      LoongArchAttributes |= CACHE_CC;
> +      break;
> +    default :
> +       LoongArchAttributes |= CACHE_CC;
> +      break;
> +  }
> +
> +  // Write protection attributes
> +  if ((EfiAttributes & EFI_MEMORY_RO) != 0) {
> +    LoongArchAttributes &= ~PAGE_DIRTY;
> +  }
> +
> +  //eXecute protection attribute
> +  if ((EfiAttributes & EFI_MEMORY_XP) != 0) {
> +    LoongArchAttributes |= PAGE_NO_EXEC;
> +  }
> +
> +  return LoongArchAttributes;
> +}
> +
> +/**
> +  Finds the length and memory properties of the memory region corresponding to the specified base address.
> +
> +  @param[in]  BaseAddress    To find the base address of the memory region.
> +  @param[in]  EndAddress     To find the end address of the memory region.
> +  @param[out]  RegionLength    The length of the memory region found.
> +  @param[out]  RegionAttributes    Properties of the memory region found.
> +
> +  @retval  EFI_SUCCESS    The corresponding memory area was successfully found
> +           EFI_NOT_FOUND    No memory area found
> +**/
> +EFI_STATUS
> +GetLoongArchMemoryRegion (
> +  IN     UINTN  BaseAddress,
> +  IN     UINTN  EndAddress,
> +  OUT    UINTN  *RegionLength,
> +  OUT    UINTN  *RegionAttributes
> +  )
> +{
> +  PTE *Pte;
> +  UINTN Attributes;
> +  UINTN AttributesTmp;
> +  UINTN MaxAddress;
> +  MaxAddress     = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
> +  Pte = GetPteAddress (BaseAddress);
> +
> +  if (!MmuIsInit ()) {
> +    return EFI_SUCCESS;
> +  }
> +  if (Pte == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +  Attributes = GET_PAGE_ATTRIBUTES (*Pte);
> +  if (IS_HUGE_PAGE (Pte->PteVal)) {
> +    *RegionAttributes = Attributes & (~(PAGE_HUGE));
> +    *RegionLength += HUGE_PAGE_SIZE;
> +  } else {
> +    *RegionLength += EFI_PAGE_SIZE;
> +    *RegionAttributes = Attributes;
> +  }
> +
> +  while (BaseAddress <= MaxAddress) {
> +    Pte = GetPteAddress (BaseAddress);
> +    if (Pte == NULL) {
> +      return EFI_SUCCESS;
> +    }
> +    AttributesTmp = GET_PAGE_ATTRIBUTES (*Pte);
> +    if (IS_HUGE_PAGE (Pte->PteVal)) {
> +      if (AttributesTmp == Attributes) {
> +         *RegionLength += HUGE_PAGE_SIZE;
> +      }
> +      BaseAddress += HUGE_PAGE_SIZE;
> +    } else {
> +      if (AttributesTmp == Attributes) {
> +        *RegionLength += EFI_PAGE_SIZE;
> +      }
> +      BaseAddress += EFI_PAGE_SIZE;
> +    }
> +
> +    if (BaseAddress > EndAddress) {
> +      break;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Sets the Attributes  of the specified memory region
> +
> +  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
> +  @param[in]  Length       The length of the memory region to set the Attributes.
> +  @param[in]  Attributes   The Attributes to be set.
> +
> +  @retval  EFI_SUCCESS    The Attributes was set successfully
> +
> +**/
> +EFI_STATUS
> +LoongArchSetMemoryAttributes (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINTN                 Length,
> +  IN UINTN                 Attributes
> +  )
> +{
> +
> +  if (!MmuIsInit ()) {
> +    return EFI_SUCCESS;
> +  }
> +  Attributes = EfiAttributeToLoongArchAttribute (Attributes);
> +  DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes));
> +  MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Sets the non-executable Attributes for the specified memory region
> +
> +  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
> +  @param[in]  Length       The length of the memory region to set the Attributes.
> +
> +  @retval  EFI_SUCCESS    The Attributes was set successfully
> +**/
> +EFI_STATUS
> +LoongArchSetMemoryRegionNoExec (
> +  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN  UINTN                Length
> +  )
> +{
> +  if (MmuIsInit ()) {
> +    Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
> +    LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP);
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check to see if mmu successfully initializes and saves the result.
> +
> +  @param  VOID.
> +
> +  @retval  EFI_SUCCESS    Initialization succeeded.
> +**/
> +EFI_STATUS
> +MmuInitialize (VOID)
> +{
> +   if (PcdGet64 (PcdSwapPageDir) != 0) {
> +     mMmuInited = TRUE;
> +   }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
> new file mode 100644
> index 0000000000..e9f294b356
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
> @@ -0,0 +1,39 @@
> +/** @file
> +
> +  Copyright (c) 2021 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
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
> new file mode 100644
> index 0000000000..899f40fd94
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
> @@ -0,0 +1,236 @@
> +/** @file
> +  Platform PEI driver
> +
> +  Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Glossary:
> +    - FwCfg    - Firmeware Config
> +    - Tlb      - Translation Lookaside Buffer
> +**/
> +#include <Uefi.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include "Library/Cpu.h"
> +#include "pte.h"
> +#include "page.h"
> +#include "mmu.h"
> +#include <Library/QemuFwCfgLib.h>
> +#include "MmuLibCore.h"
> +
> +/**
> +  Return the Virtual Memory Map of your platform
> +
> +  This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
> +  on your platform.
> +
> +  @param[out]   VirtualMemoryMap    Array of MEMORY_REGION_DESCRIPTOR
> +                                    describing a Physical-to-Virtual Memory
> +                                    mapping. This array must be ended by a
> +                                    zero-filled entry. The allocated memory
> +                                    will not be freed.
> +
> +**/
> +VOID
> +GetMemoryMapFromFwCfg (
> +  OUT MEMORY_REGION_DESCRIPTOR  **VirtualMemoryMap
> +  )
> +{
> +
> +  EFI_STATUS           Status;
> +  FIRMWARE_CONFIG_ITEM FwCfgItem;
> +  UINTN                FwCfgSize;
> +  LOONGARCH_MEMMAP_ENTRY  MemoryMapEntry;
> +  LOONGARCH_MEMMAP_ENTRY  *StartEntry;
> +  LOONGARCH_MEMMAP_ENTRY  *pEntry;
> +  UINTN                Processed;
> +  MEMORY_REGION_DESCRIPTOR  *VirtualMemoryTable;
> +  UINTN  Index = 0;
> +  ASSERT (VirtualMemoryMap != NULL);
> +
> +  VirtualMemoryTable = AllocatePool (
> +                         sizeof (MEMORY_REGION_DESCRIPTOR) *
> +                         MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
> +                         );
> +  VirtualMemoryTable[Index].PhysicalBase = 0x10000000;
> +  VirtualMemoryTable[Index].VirtualBase  = VirtualMemoryTable[Index].PhysicalBase;
> +  VirtualMemoryTable[Index].Length       = 0x80000000;
> +  VirtualMemoryTable[Index].Attributes   = PAGE_VALID | PAGE_USER |  CACHE_CC | PAGE_DIRTY;
PAGE_KERNEL need be used here rather than PAGE_USER.
And the memory space from 0x10000000 -- 0x80000000 is mmio space, it should be uncachable. CACHE_SUC should be used here.

> +  ++Index;
> +
> +  Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status));
> +    ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
> +    *VirtualMemoryMap = VirtualMemoryTable;
> +    return ;
> +  }
> +  if (FwCfgSize % sizeof MemoryMapEntry != 0) {
> +    DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize));
> +  }
> +
> +  QemuFwCfgSelectItem (FwCfgItem);
> +  StartEntry = AllocatePages  (EFI_SIZE_TO_PAGES (FwCfgSize));
> +  QemuFwCfgReadBytes (FwCfgSize, StartEntry);
> +  for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) {
> +    pEntry = StartEntry + Processed;
> +    if (pEntry->Length == 0) {
> +      continue;
> +    }
> +
> +    DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p  type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type));
> +    VirtualMemoryTable[Index].PhysicalBase = pEntry->BaseAddr;
> +    VirtualMemoryTable[Index].VirtualBase  = VirtualMemoryTable[Index].PhysicalBase;
> +    VirtualMemoryTable[Index].Length       = pEntry->Length;
> +    VirtualMemoryTable[Index].Attributes   = PAGE_VALID | PAGE_USER |  CACHE_CC | PAGE_DIRTY;
> +    ++Index;
> +  }
> +
> +  FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize));
> +  // End of Table
> +  ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
> +  *VirtualMemoryMap = VirtualMemoryTable;
> +  return ;
> +}
> +
> +/**
> +  Create a page table and initialize the MMU.
> +
> +  @param[] VOID
> +
> +  @retval  VOID
> +**/
> +EFIAPI
> +VOID
> +ConfigureMmu (VOID)
> +{
> +  PGD *SwapperPageDir = NULL;
> +  PGD *InvalidPgd = NULL;
> +  PUD *InvalidPudTable = NULL;
> +  PMD *InvalidPmdTable = NULL;
> +  PTE *InvalidPteTable = NULL;
> +  MEMORY_REGION_DESCRIPTOR  *MemoryTable = NULL;
> +  RETURN_STATUS PcdStatus;
> +  UINTN PgdShift = PGD_SHIFT;
> +  UINTN PgdWide = PGD_WIDE;
> +  UINTN PudShift = PUD_SHIFT;
> +  UINTN PudWide = PUD_WIDE;
> +  UINTN PmdShift = PMD_SHIFT;
> +  UINTN PmdWide = PMD_WIDE;
> +  UINTN PteShift = PTE_SHIFT;
> +  UINTN PteWide = PTE_WIDE;
> +  UINTN PageEnable = 1 << 4;
> +  VOID *TlbReEntry;
> +  UINTN PageSize;
> +
> +  SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> +  InvalidPgd = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> +  InvalidPudTable = AllocatePages (EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
> +  InvalidPmdTable = AllocatePages (EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
> +  InvalidPteTable = AllocatePages (EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
> +  ZeroMem (InvalidPteTable, PTE_TABLE_SIZE);
> +
> +  if ((!InvalidPgd) ||
> +      (!InvalidPudTable) ||
> +      (!InvalidPmdTable) ||
> +      (!InvalidPteTable))
> +  {
> +    goto FreeTranslationTable;
> +  }
> +
> +  /*pgd init*/
> +  PageDirInit (SwapperPageDir , ENTRYS_PER_PGD, InvalidPudTable);
> +  /*pgd init*/
> +  PageDirInit (InvalidPgd, ENTRYS_PER_PGD, InvalidPudTable);
> +  /*pud init*/
> +  PageDirInit (InvalidPudTable, ENTRYS_PER_PUD, InvalidPmdTable);
> +  /*pmd init*/
> +  PageDirInit (InvalidPmdTable, ENTRYS_PER_PMD, InvalidPteTable);
> +  GetMemoryMapFromFwCfg (&MemoryTable);
> +
> +  PcdStatus |= PcdSet64S (PcdSwapPageDir, (UINTN)SwapperPageDir);
> +  PcdStatus |= PcdSet64S (PcdInvalidPgd, (UINTN)InvalidPgd);
> +  PcdStatus |= PcdSet64S (PcdInvalidPud, (UINTN)InvalidPudTable);
> +  PcdStatus |= PcdSet64S (PcdInvalidPmd, (UINTN)InvalidPmdTable);
> +  PcdStatus |= PcdSet64S (PcdInvalidPte, (UINTN)InvalidPteTable);
> +  ASSERT_RETURN_ERROR (PcdStatus);
> +
> +  while (MemoryTable->Length != 0) {
> +    DEBUG ((DEBUG_VERBOSE, "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", __func__, __LINE__,
> +      MemoryTable->VirtualBase,
> +      (MemoryTable->Length + MemoryTable->VirtualBase),
> +      MemoryTable->Attributes));
> +
> +    PcdStatus = FillTranslationTable (MemoryTable);
> +    if (EFI_ERROR (PcdStatus)) {
> +      goto FreeTranslationTable;
> +    }
> +    MemoryTable++;
> +  }
> +
> +  /*set page size*/
> +  WRITE_CSR_PAGE_SIZE (DEFAULT_PAGE_SIZE);
> +  WRITE_CSR_STLB_PAGE_SIZE (DEFAULT_PAGE_SIZE);
> +  WRITE_CSR_TLBREFILL_PAGE_SIZE (DEFAULT_PAGE_SIZE);
> +  READ_CSR_PAGE_SIZE (PageSize);
> +  if (PageSize != DEFAULT_PAGE_SIZE) {
> +    goto FreeTranslationTable;
> +  }
> +
> +  TlbReEntry = AllocatePages (1);
> +  if (TlbReEntry == NULL) {
> +    goto FreeTranslationTable;
> +  }
> +  CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - HandleTlbRefill));
> +  SET_REFILL_TLBBASE ((UINTN)HandleTlbRefill);
> +
> +  DEBUG ((DEBUG_VERBOSE,
> +    "%a  %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudWide %d PgdShift %d PgdWide %d.\n",
> +    __func__, __LINE__,
> +    PteShift, PteWide, PmdShift, PmdWide,PudShift, PudWide, PgdShift, PgdWide));
> +
> +  LOONGARCH_CSR_WRITEQ (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25,
> +    LOONGARCH_CSR_PWCTL0);
> +  LOONGARCH_CSR_WRITEQ (PgdShift | PgdWide << 6, LOONGARCH_CSR_PWCTL1);
> +  LOONGARCH_CSR_WRITEQ ((UINTN)SwapperPageDir, LOONGARCH_CSR_PGDL);
> +  LOONGARCH_CSR_WRITEQ ((UINTN)InvalidPgd, LOONGARCH_CSR_PGDH);
> +
> +  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
> +  LOONGARCH_CSR_XCHGQ ( PageEnable, 1 << 4, LOONGARCH_CSR_CRMD);
> +  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu End.\n", __func__, __LINE__));
> +
> +  return ;
> +
> +FreeTranslationTable:
> +  if (SwapperPageDir) {
> +    FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> +  }
> +
> +  if (InvalidPgd) {
> +    FreePages (InvalidPgd, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> +  }
> +
> +  if (InvalidPudTable) {
> +    FreePages (InvalidPudTable, EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
> +  }
> +
> +  if (InvalidPmdTable) {
> +    FreePages (InvalidPmdTable, EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
> +  }
> +
> +  if (InvalidPteTable) {
> +    FreePages (InvalidPteTable, EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
> +  }
> +
> +  PcdSet64S (PcdSwapPageDir, (UINTN)0);
> +  PcdSet64S (PcdInvalidPgd, (UINTN)0);
> +  PcdSet64S (PcdInvalidPud, (UINTN)0);
> +  PcdSet64S (PcdInvalidPmd, (UINTN)0);
> +  PcdSet64S (PcdInvalidPte, (UINTN)0);
> +
> +  return ;
> +}
> +
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
> new file mode 100644
> index 0000000000..50b785bb6e
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
> @@ -0,0 +1,104 @@
> +/** @file
> +
> +  Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Glossary:
> +    - Tlb or TLB     - Translation Lookaside Buffer
> +    - CSR            - Cpu State Register
> +    - PGDL           - Page Global Directory Low
> +    - PGDH           - Page Global Directory High
> +    - TLBIDX         - TLB Index
> +    - TLBREHI        - TLB Refill Entry High
> +    - PWCTL          - Page Walk Control
> +    - STLB           - Singular Page Size TLB
> +    - PS             - Page Size
> +**/
> +#ifndef MMU_H_
> +#define MMU_H_
> +/*page size 4k*/
> +#define DEFAULT_PAGE_SIZE         0x0c
> +#define LOONGARCH_CSR_PGDL        0x19 /* Page table base address when VA[47] = 0 */
> +#define LOONGARCH_CSR_PGDH        0x1a /* Page table base address when VA[47] = 1 */
> +#define LOONGARCH_CSR_TLBIDX      0x10 /* TLB Index, EHINV, PageSize, NP */
> +#define LOONGARCH_CSR_TLBEHI      0x11 /* TLB EntryHi */
> +#define LOONGARCH_CSR_TLBELO0     0x12 /* TLB EntryLo0 */
> +#define LOONGARCH_CSR_TLBELO1     0x13 /* TLB EntryLo1 */
> +#define LOONGARCH_CSR_TLBREHI     0x8e /* TLB refill entryhi */
> +#define LOONGARCH_CSR_PWCTL0      0x1c /* PWCtl0 */
> +#define LOONGARCH_CSR_PWCTL1      0x1d /* PWCtl1 */
> +#define LOONGARCH_CSR_STLBPGSIZE  0x1e
> +#define CSR_TLBIDX_SIZE_MASK      0x3f000000
> +#define CSR_TLBIDX_PS_SHIFT       24
> +#define CSR_TLBIDX_SIZE           CSR_TLBIDX_PS_SHIFT
> +
> +/*
> +  Set Cpu Status Register STLB Page Size.
> +
> +  @param val  Page Size.
> +
> +  @retval  VOID
> + */
> +#define WRITE_CSR_STLB_PAGE_SIZE(val)  LOONGARCH_CSR_WRITEQ((val), LOONGARCH_CSR_STLBPGSIZE)
> +/*
> +  Set Cpu Status Register Page Size.
> +
> +  @param size  Page Size.
> +
> +  @retval  VOID
> + */
> +#define WRITE_CSR_PAGE_SIZE(size)  LOONGARCH_CSR_XCHGQ((size) << CSR_TLBIDX_SIZE, CSR_TLBIDX_SIZE_MASK, LOONGARCH_CSR_TLBIDX)
> +/*
> +  Set Cpu Status Register TLBREFILL Page Size.
> +
> +  @param size  Page Size.
> +
> +  @retval  VOID
> + */
> +#define WRITE_CSR_TLBREFILL_PAGE_SIZE(size)  LOONGARCH_CSR_XCHGQ((size) << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI)
> +/*
> +  Set Cpu Status Register TLBREFILL Base Address.
> +
> +  @param BaseAddress the code base address of TLB refills .
> +
> +  @retval  VOID
> + */
> +#define SET_REFILL_TLBBASE(BaseAddress) LOONGARCH_CSR_WRITEQ((BaseAddress), LOONGARCH_CSR_TLBREBASE);
> +/*
> +  Get Cpu Status Register Page Size.
> +
> +  @param  val  Gets the page size.
> +
> +  @retval  VOID
> + */
> +#define READ_CSR_PAGE_SIZE(val)                               \
> +{                                                             \
> +  LOONGARCH_CSR_READQ ((val), LOONGARCH_CSR_TLBIDX);          \
> +  (val) = ((val) & CSR_TLBIDX_SIZE_MASK) >> CSR_TLBIDX_SIZE;  \
> +}
> +
> +
> +#define  CSR_TLBREHI_PS_SHIFT    0
> +#define  CSR_TLBREHI_PS      ((UINTN)(0x3f) << CSR_TLBREHI_PS_SHIFT)
> +
> +#define EFI_MEMORY_CACHETYPE_MASK     (EFI_MEMORY_UC  | \
> +                                       EFI_MEMORY_WC  | \
> +                                       EFI_MEMORY_WT  | \
> +                                       EFI_MEMORY_WB  | \
> +                                       EFI_MEMORY_UCE   \
> +                                       )
> +
> +
> +typedef struct {
> +  EFI_PHYSICAL_ADDRESS PhysicalBase;
> +  EFI_VIRTUAL_ADDRESS  VirtualBase;
> +  UINTN                Length;
> +  UINTN                Attributes;
> +} MEMORY_REGION_DESCRIPTOR;
> +
> +// The total number of descriptors, including the final "end-of-table" descriptor.
> +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)
> +
> +extern CHAR8 HandleTlbRefill[], HandleTlbRefillEnd[];
> +#endif
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
> new file mode 100644
> index 0000000000..3b3b0b72c3
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
> @@ -0,0 +1,267 @@
> +/** @file
> +
> +  Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Glossary:
> +    - Pgd or Pgd or PGD    - Page Global Directory
> +    - Pud or Pud or PUD    - Page Upper Directory
> +    - Pmd or Pmd or PMD    - Page Middle Directory
> +    - Pte or pte or PTE    - Page Table Entry
> +    - Val or VAL or val    - Value
> +    - Dir    - Directory
> +**/
> +#ifndef PAGE_H_
> +#define PAGE_H_
> +
> +#define MAX_VA_BITS                         47
> +#define PGD_WIDE                            (8)
> +#define PUD_WIDE                            (9)
> +#define PMD_WIDE                            (9)
> +#define PTE_WIDE                            (9)
> +
> +#define ENTRYS_PER_PGD                      (1 << PGD_WIDE)
> +#define ENTRYS_PER_PUD                      (1 << PUD_WIDE)
> +#define ENTRYS_PER_PMD                      (1 << PMD_WIDE)
> +#define ENTRYS_PER_PTE                      (1 << PTE_WIDE)
> +
> +#define PGD_SHIFT                           (PUD_SHIFT + PUD_WIDE)
> +#define PUD_SHIFT                           (PMD_SHIFT + PMD_WIDE)
> +#define PMD_SHIFT                           (EFI_PAGE_SHIFT + PTE_WIDE)
> +#define PTE_SHIFT                           (EFI_PAGE_SHIFT)
> +
> +#define PGD_SIZE                            (1UL << PGD_SHIFT)
> +#define PUD_SIZE                            (1UL << PUD_SHIFT)
> +#define PMD_SIZE                            (1UL << PMD_SHIFT)
> +
> +#define PGD_MASK                            (~(PGD_SIZE-1))
> +#define PUD_MASK                            (~(PUD_SIZE-1))
> +#define PMD_MASK                            (~(PMD_SIZE-1))
> +#define PAGE_MASK                           (~(EFI_PAGE_SIZE - 1))
> +#define PFN_MASK                            (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \
> +                                             (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
> +
> +typedef struct { UINTN PgdVal; } PGD;
> +typedef struct { UINTN PudVal; } PUD;
> +typedef struct { UINTN PmdVal; } PMD;
> +typedef struct { UINTN PteVal; } PTE;
> +/**
> +  Gets the value of the page global directory table entry.
> +
> +  @param  x    Page global directory struct variables.
> +
> +  @retval   the value of the page global directory table entry.
> + **/
> +#define PGD_VAL(x)                          ((x).PgdVal)
> +/**
> +  Gets the value of the page upper directory table entry.
> +
> +  @param  x    Page upper directory struct variables.
> +
> +  @retval  the value of the page upper directory table entry.
> + **/
> +#define PUD_VAL(x)                          ((x).PudVal)
> +/**
> +  Gets the value of the page middle directory table entry.
> +
> +  @param  x    Page middle directory struct variables.
> +
> +  @retval  the value of the page middle directory table entry.
> + **/
> +#define PMD_VAL(x)                          ((x).PmdVal)
> +/**
> +  Gets the value of the page table entry.
> +
> +  @param  x    Page table entry struct variables.
> +
> +  @retval  the value of the page table entry.
> + **/
> +#define PTE_VAL(x)                          ((x).PteVal)
> +
> +
> +#define PGD_TABLE_SIZE                      (ENTRYS_PER_PGD * sizeof(PGD))
> +#define PUD_TABLE_SIZE                      (ENTRYS_PER_PUD * sizeof(PUD))
> +#define PMD_TABLE_SIZE                      (ENTRYS_PER_PMD * sizeof(PMD))
> +#define PTE_TABLE_SIZE                      (ENTRYS_PER_PTE * sizeof(PTE))
> +/**
> +  Gets the physical address of the record in the page table entry.
> +
> +  @param  x    Page table entry struct variables.
> +
> +  @retval  the value of the physical address.
> + **/
> +#define GET_PAGE_ATTRIBUTES(x)              (UINTN) {(PTE_VAL(x) & ~PFN_MASK)}
> +/**
> +  Gets the virtual address of the next block of the specified virtual address
> +  that is aligned with the size of the global page directory mapping.
> +
> +  @param  Address  Specifies the virtual address.
> +  @param  End    The end address of the memory region.
> +
> +  @retval   the specified virtual address  of the next block.
> + **/
> +#define PGD_ADDRESS_END(Address, End)            \
> +({  UINTN Boundary = ((Address) + PGD_SIZE) & PGD_MASK;  \
> +  (Boundary - 1 < (End) - 1)? Boundary: (End);    \
> +})
> +/**
> +  Gets the virtual address of the next block of the specified virtual address
> +  that is aligned with the size of the page upper directory mapping.
> +
> +  @param  Address  Specifies the virtual address.
> +  @param  End    The end address of the memory region.
> +
> +  @retval   the specified virtual address  of the next block.
> + **/
> +#define PUD_ADDRESS_END(Address, End)            \
> +({  UINTN Boundary = ((Address) + PUD_SIZE) & PUD_MASK;  \
> +  (Boundary - 1 < (End) - 1)? Boundary: (End);    \
> +})
> +/**
> +  Gets the virtual address of the next block of the specified virtual address
> +  that is aligned with the size of the page middle directory mapping.
> +
> +  @param  Address  Specifies the virtual address.
> +  @param  End    The end address of the memory region.
> +
> +  @retval   the specified virtual address  of the next block.
> + **/
> +#define PMD_ADDRESS_END(Address, End)            \
> +({  UINTN Boundary = ((Address) + PMD_SIZE) & PMD_MASK;  \
> +  (Boundary - 1 < (End) - 1)? Boundary: (End);    \
> +})
> +/**
> +  Get Specifies the virtual address corresponding to the index of the page global directory table entry.
> +
> +  @param  Address  Specifies the virtual address.
> +
> +  @retval   the index of the page global directory table entry.
> + **/
> +#define PGD_INDEX(Address)                  (((Address) >> PGD_SHIFT) & (ENTRYS_PER_PGD-1))
> +/**
> +  Get Specifies the virtual address corresponding to the index of the page upper directory table entry.
> +
> +  @param  Address  Specifies the virtual address.
> +  @param  End    The end address of the memory region.
> +
> +  @retval   the index of the page upper directory table entry.
> + **/
> +#define PUD_INDEX(Address)                  (((Address) >> PUD_SHIFT) & (ENTRYS_PER_PUD - 1))
> +/**
> +  Get Specifies the virtual address corresponding to the index of the page middle directory table entry.
> +
> +  @param  Address  Specifies the virtual address.
> +
> +  @retval   the index of the page middle directory table entry.
> + **/
> +#define PMD_INDEX(Address)                  (((Address) >> PMD_SHIFT) & (ENTRYS_PER_PMD - 1))
> +/**
> +  Get Specifies the virtual address corresponding to the index of the page table entry.
> +
> +  @param  Address  Specifies the virtual address.
> +
> +  @retval   the index of the page table entry.
> + **/
> +#define PTE_INDEX(Address)                  (((Address) >> EFI_PAGE_SHIFT) & (ENTRYS_PER_PTE - 1))
> +
> +/**
> +  Calculates the value of the page table entry based on the specified virtual address and properties.
> +
> +  @param  Address  Specifies the virtual address.
> +  @param  Attributes  Specifies the Attributes.
> +
> +  @retval    the value of the page table entry.
> + **/
> +#define MAKE_PTE(Address, Attributes)       (PTE){((((Address) >> EFI_PAGE_SHIFT) << 12) | (Attributes))}
> +/**
> +  Calculates the value of the Huge page table entry based on the specified virtual address and properties.
> +
> +  @param  Address  Specifies the virtual address.
> +  @param  Attributes  Specifies the Attributes.
> +
> +  @retval    the value of the HUGE page table entry.
> + **/
> +#define MAKE_HUGE_PTE(Address, Attributes)  (((((Address) >> PMD_SHIFT) << PMD_SHIFT) | ((Attributes) | 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)
> +#define HUGE_PAGE_SIZE                      (PMD_SIZE)
> +
> + /**
> +  Check that the global page directory table entry is empty.
> +
> +  @param  pgd   the global page directory struct variables.
> +
> +  @retval    1   Is huge page table entry.
> +  @retval    0   Isn't huge page table entry.
> + **/
> +STATIC
> +inline
> +UINTN
> +pgd_none (
> +  IN PGD pgd
> +  )
> +{
> +  return (PGD_VAL(pgd) == (UINTN)PcdGet64(PcdInvalidPud));
> +}
> +
> + /**
> +  Check that the page upper directory table entry is empty.
> +
> +  @param  pud   Page upper directory struct variables.
> +
> +  @retval    1   Is huge page table entry.
> +  @retval    0   Isn't huge page table entry.
> + **/
> +STATIC
> +inline
> +UINTN
> +pud_none (
> +  IN PUD pud
> +  )
> +{
> +  return (PUD_VAL(pud) == (UINTN)PcdGet64 (PcdInvalidPmd));
> +}
> +
> + /**
> +  Check that the page middle directory table entry is empty.
> +
> +  @param  pmd   Page middle directory struct variables.
> +
> +  @retval    1   Is huge page table entry.
> +  @retval    0   Isn't huge page table entry.
> + **/
> +STATIC
> +inline
> +UINTN
> +pmd_none (
> +  IN PMD pmd
> +  )
> +{
> +  return (PMD_VAL(pmd) == (UINTN)PcdGet64(PcdInvalidPte));
> +}
> + /**
> +  Check that the page  table entry is empty.
> +
> +  @param  pmd   Page table entry struct variables.
> +
> +  @retval    1   Is huge page table entry.
> +  @retval    0   Isn't huge page table entry.
> + **/
> +STATIC
> +inline
> +UINTN
> +pte_none (
> +  IN PTE pte
> +  )
> +{
> +  return (!(PTE_VAL(pte) & (~PAGE_GLOBAL)));

PAGE_VALID represents the tlb is valid, PAGE_GLOBAL represents tlb entry is valid for all asid processes.
how about using PAGE_VALID bit rather than PAGE_GLOBAL:
     return (!(PTE_VAL(pte) & PAGE_VALID));


> +}
> +#endif
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
> new file mode 100644
> index 0000000000..d6ac74f9c9
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
> @@ -0,0 +1,57 @@
> +/** @file
> +
> +  Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Glossary:
> +    - Tlb or TLB     - Translation Lookaside Buffer
> +    - HGLOBAL     - Huge Global
> +    - PFN       - Page Frame number
> +    - EXEC       - Execute
> +    - PLV       - Privilege Level
> +    - RPLV       - Restricted Privilege Level
> +    - SUC       - Strong-ordered UnCached
> +    - CC       - Coherent Cached
> +    - WUC       - Weak-ordered UnCached
> +**/
> +#ifndef PTE_H_
> +#define PTE_H_
> +/*Page table property definitions */
> +#define  PAGE_VALID_SHIFT    0
> +#define  PAGE_DIRTY_SHIFT    1
> +#define  PAGE_PLV_SHIFT      2  /* 2~3, two bits */
> +#define  CACHE_SHIFT         4  /* 4~5, two bits */
> +#define  PAGE_GLOBAL_SHIFT   6
> +#define  PAGE_HUGE_SHIFT     6  /* HUGE is a PMD bit */
> +
> +#define  PAGE_HGLOBAL_SHIFT  12 /* HGlobal is a PMD bit */
> +#define  PAGE_PFN_SHIFT      12
> +#define  PAGE_PFN_END_SHIFT  48
> +#define  PAGE_NO_READ_SHIFT  61
> +#define  PAGE_NO_EXEC_SHIFT  62
> +#define  PAGE_RPLV_SHIFT     63
> +
> +/* Used by TLB hardware (placed in EntryLo*) */
> +#define PAGE_VALID           ((UINTN)(1) << PAGE_VALID_SHIFT)
> +#define PAGE_DIRTY           ((UINTN)(1) << PAGE_DIRTY_SHIFT)
> +#define PAGE_PLV             ((UINTN)(3) << PAGE_PLV_SHIFT)
> +#define PAGE_GLOBAL          ((UINTN)(1) << PAGE_GLOBAL_SHIFT)
> +#define PAGE_HUGE            ((UINTN)(1) << PAGE_HUGE_SHIFT)
> +#define PAGE_HGLOBAL         ((UINTN)(1) << PAGE_HGLOBAL_SHIFT)
> +#define PAGE_NO_READ         ((UINTN)(1) << PAGE_NO_READ_SHIFT)
> +#define PAGE_NO_EXEC         ((UINTN)(1) << PAGE_NO_EXEC_SHIFT)
> +#define PAGE_RPLV            ((UINTN)(1) << PAGE_RPLV_SHIFT)
> +#define CACHE_MASK           ((UINTN)(3) << CACHE_SHIFT)
> +#define PFN_SHIFT            (EFI_PAGE_SHIFT - 12 + PAGE_PFN_SHIFT)
> +
> +#define PLV_KERNEL           0
> +#define PLV_USER             3
> +
> +#define PAGE_USER            (PLV_USER << PAGE_PLV_SHIFT)
> +#define PAGE_KERNEL          (PLV_KERN << PAGE_PLV_SHIFT)
> +
> +#define CACHE_SUC            (0 << CACHE_SHIFT) /* Strong-ordered UnCached */
> +#define CACHE_CC             (1 << CACHE_SHIFT) /* Coherent Cached */
> +#define CACHE_WUC            (2 << CACHE_SHIFT) /* Weak-ordered UnCached */
> +#endif


  reply	other threads:[~2022-10-29  6:45 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-21  7:11 [edk2-platforms][PATCH V4 00/14] Platform: Add Loongson support xianglai
2022-10-21  7:11 ` [edk2-platforms][PATCH V4 07/14] Platform/Loongson: Support PEI phase xianglai
2022-10-21  7:11 ` [edk2-platforms][PATCH V4 08/14] Platform/Loongson: Add CPU DXE driver xianglai
2022-10-21  7:11 ` [edk2-platforms][PATCH V4 09/14] Platform/Loongson: Add PciCpuIoDxe driver xianglai
2022-10-21  7:11 ` [edk2-platforms][PATCH V4 10/14] Platform/Loongson: Add timer Dxe driver xianglai
2022-10-21  7:11 ` [edk2-platforms][PATCH V4 11/14] Platform/Loongson: Add RealTime Clock lib xianglai
2022-10-21  7:11 ` [edk2-platforms][PATCH V4 12/14] Platform/Loongson: Add Platform Boot Manager Lib xianglai
2022-10-21  7:11 ` [edk2-platforms][PATCH V4 13/14] Platform/Loongson: Add Reset System Lib xianglai
2022-10-21  7:11 ` [edk2-platforms][PATCH V4 14/14] Platform/Loongson: Support Dxe xianglai
2022-10-24  9:25 ` [edk2-platforms][PATCH V4 01/14] Platform/Loongson: Add Serial Port library xianglai
2022-10-29  3:01   ` maobibo
2022-10-24  9:25 ` [edk2-platforms][PATCH V4 02/14] Platform/Loongson: Support SEC And Add Readme.md xianglai
2022-10-24  9:25 ` [edk2-platforms][PATCH V4 03/14] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
2022-10-24  9:25 ` [edk2-platforms][PATCH V4 04/14] Platform/Loongson: Add QemuFwCfgLib xianglai
2022-10-24  9:25 ` [edk2-platforms][PATCH V4 05/14] Platform/Loongson: Add MmuLib xianglai
2022-10-29  6:45   ` maobibo [this message]
2022-10-24  9:25 ` [edk2-platforms][PATCH V4 06/14] Platform/Loongson: Add StableTimerLib xianglai

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=eed21b78-113f-543f-d512-be4cbcdd981e@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