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