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