From: "xianglai" <lixianglai@loongson.cn>
To: devel@edk2.groups.io
Subject: [edk2-platforms][PATCH V1 06/15] Platform/Loongson: Add MmuLib.
Date: Wed, 2 Mar 2022 03:44:38 -0500 [thread overview]
Message-ID: <20220302084447.2991355-7-lixianglai@loongson.cn> (raw)
In-Reply-To: <20220302084447.2991355-1-lixianglai@loongson.cn>
Read the memory map information through the QemuFwCfg interface,
then build the page table through the memory map information,
and finally enable Mmu.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../LoongArchQemuPkg/Include/Library/MmuLib.h | 85 ++
.../LoongArchQemuPkg/Library/MmuLib/Mmu.S | 35 +
.../Library/MmuLib/MmuBaseLib.inf | 35 +
.../Library/MmuLib/MmuBaseLibPei.inf | 45 +
.../Library/MmuLib/MmuLibCore.c | 790 ++++++++++++++++++
.../Library/MmuLib/MmuLibCore.h | 39 +
.../Library/MmuLib/MmuLibCorePei.c | 237 ++++++
.../LoongArchQemuPkg/Library/MmuLib/mmu.h | 101 +++
.../LoongArchQemuPkg/Library/MmuLib/page.h | 267 ++++++
.../LoongArchQemuPkg/Library/MmuLib/pte.h | 57 ++
10 files changed, 1691 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
new file mode 100644
index 0000000000..6c501eca07
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
@@ -0,0 +1,85 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - EXC - execute
+**/
+#ifndef MMU_LIB_H_
+#define MMU_LIB_H_
+/**
+ write operation is performed Count times from the first element of Buffer.
+Convert EFI Attributes to Loongarch Attributes.
+ @param[in] EfiAttributes Efi Attributes.
+
+ @retval LoongArch Attributes.
+**/
+UINTN
+EfiAttributeToLoongArchAttribute (
+ IN UINTN EfiAttributes
+ );
+
+/**
+ Finds the length and memory properties of the memory region corresponding to the specified base address.
+
+ @param[in] BaseAddress To find the base address of the memory region.
+ @param[in] EndAddress To find the end address of the memory region.
+ @param[out] RegionLength The length of the memory region found.
+ @param[out] RegionAttributes Properties of the memory region found.
+
+ @retval EFI_SUCCESS The corresponding memory area was successfully found
+ EFI_NOT_FOUND No memory area found
+**/
+EFI_STATUS
+GetLoongArchMemoryRegion (
+ IN UINTN BaseAddress,
+ IN UINTN EndAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ );
+
+/**
+ Sets the Attributes of the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to set the Attributes.
+ @param[in] Length The length of the memory region to set the Attributes.
+ @param[in] Attributes The Attributes to be set.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+
+**/
+EFI_STATUS
+LoongArchSetMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length,
+ IN UINTN Attributes
+ );
+
+/**
+ Sets the non-executable Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to set the Attributes.
+ @param[in] Length The length of the memory region to set the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ );
+/**
+ Create a page table and initialize the MMU.
+
+ @param[] VOID
+
+ @retval VOID
+**/
+VOID
+EFIAPI
+ConfigureMmu (
+ VOID
+ );
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
new file mode 100644
index 0000000000..a697b54e65
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
@@ -0,0 +1,35 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch for LoongArch
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-----------------------------------------------------------------------------
+
+#ifndef _KERNEL
+#define _KERNEL
+#endif
+
+#include "Library/Cpu.h"
+#include "LoongArchAsmMacro.h"
+
+# Query the page table.
+#
+# @param VOID
+#
+# @retval VOID
+ASM_FUNC(HandleTlbRefill)
+ csrwr T0, LOONGARCH_CSR_TLBRSAVE
+ csrrd T0, LOONGARCH_CSR_PGD
+ lddir T0, T0, 3 #Put pud BaseAddress into T0
+ lddir T0, T0, 2 #Put pmd BaseAddress into T0
+ lddir T0, T0, 1 #Put pte BaseAddress into T0
+ ldpte T0, 0
+ ldpte T0, 1
+ tlbfill
+ csrrd T0, LOONGARCH_CSR_TLBRSAVE
+ ertn
+.globl HandleTlbRefillEnd
+HandleTlbRefillEnd:
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
new file mode 100644
index 0000000000..d8cfe6776e
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
@@ -0,0 +1,35 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MmuBaseLib
+ FILE_GUID = da8f0232-fb14-42f0-922c-63104d2c70be
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MmuLib
+
+ CONSTRUCTOR = MmuInitialize
+[Sources.common]
+ MmuLibCore.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[PCD]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
+
+[LibraryClasses]
+ MemoryAllocationLib
+ PcdLib
+ DebugLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
new file mode 100644
index 0000000000..20e50218af
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
@@ -0,0 +1,45 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MmuPeiLib
+ FILE_GUID = da8f0232-fb14-42f0-922c-63104d2c70bd
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MmuLib | SEC PEIM
+
+[Sources.common]
+ MmuLibCorePei.c
+ Mmu.S
+ MmuLibCore.h
+ MmuLibCore.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ OvmfPkg/OvmfPkg.dec
+
+[PCD]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
+
+[FixedPcd]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamRegionsBottom
+
+[LibraryClasses]
+ MemoryAllocationLib
+ PcdLib
+ DebugLib
+ QemuFwCfgLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
new file mode 100644
index 0000000000..8039955bb4
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
@@ -0,0 +1,790 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Pgd or Pgd or PGD - Page Global Directory
+ - Pud or Pud or PUD - Page Upper Directory
+ - Pmd or Pmd or PMD - Page Middle Directory
+ - Pte or pte or PTE - Page Table Entry
+ - Val or VAL or val - Value
+ - Dir - Directory
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "pte.h"
+#include "page.h"
+#include "mmu.h"
+
+BOOLEAN mMmuInited = FALSE;
+/**
+ Check to see if mmu successfully initializes.
+
+ @param VOID.
+
+ @retval TRUE Initialization has been completed.
+ FALSE Initialization did not complete.
+**/
+BOOLEAN
+MmuIsInit (VOID) {
+ if ((mMmuInited == TRUE) ||
+ (PcdGet64 (PcdSwapPageDir) != 0)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Iterates through the page directory to initialize it.
+
+ @param Dst A pointer to the directory of the page to initialize.
+ @param Num The number of page directories to initialize.
+ @param Src A pointer to the data used to initialize the page directory.
+
+ @retval VOID.
+**/
+VOID
+PageDirInit (
+ IN VOID *Dst,
+ IN UINTN Num,
+ IN VOID *Src
+ )
+{
+ UINTN *Ptr;
+ UINTN *End;
+ UINTN Entry;
+
+ Entry = (UINTN)Src;
+ Ptr = (UINTN *)Dst;
+ End = Ptr + Num;
+
+ for ( ;Ptr < End; Ptr++) {
+ *Ptr = Entry;
+ }
+
+ return ;
+}
+/**
+ Gets the virtual address corresponding to the page global directory table entry.
+
+ @param Address the virtual address for the table entry.
+
+ @retval PGD A pointer to get the table item.
+**/
+PGD *
+PgdOffset (
+ IN UINTN Address
+ )
+{
+ return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address);
+}
+/**
+ Gets the virtual address corresponding to the page upper directory table entry.
+
+ @param Pgd A pointer to a page global directory table entry.
+ @param Address the virtual address for the table entry.
+
+ @retval PUD A pointer to get the table item.
+**/
+PUD *
+PudOffset (
+ IN PGD *Pgd,
+ IN UINTN Address
+ )
+{
+ UINTN PgdVal = (UINTN)PGD_VAL (*Pgd);
+ return (PUD *)PgdVal + PUD_INDEX (Address);
+}
+/**
+ Gets the virtual address corresponding to the page middle directory table entry.
+
+ @param Pud A pointer to a page upper directory table entry.
+ @param Address the virtual address for the table entry.
+
+ @retval PMD A pointer to get the table item.
+**/
+PMD *
+PmdOffset (
+ IN PUD *Pud,
+ IN UINTN Address
+ )
+{
+ UINTN PudVal = PUD_VAL (*Pud);
+ return (PMD *)PudVal + PMD_INDEX (Address);
+}
+/**
+ Gets the virtual address corresponding to the page table entry.
+
+ @param Pmd A pointer to a page middle directory table entry.
+ @param Address the virtual address for the table entry.
+
+ @retval PTE A pointer to get the table item.
+**/
+PTE *
+PteOffset (
+ IN PMD *Pmd,
+ IN UINTN Address
+ )
+{
+ UINTN PmdVal = (UINTN)PMD_VAL (*Pmd);
+ return (PTE *)PmdVal + PTE_INDEX (Address);
+}
+
+/**
+ Sets the value of the page table entry.
+
+ @param Pte A pointer to a page table entry.
+ @param PteVal The value of the page table entry to set.
+
+ @retval VOID
+**/
+VOID
+SetPte (
+ IN PTE *Pte,
+ IN PTE PteVal
+ )
+{
+ *Pte = PteVal;
+}
+/**
+ Sets the value of the page global directory.
+
+ @param Pgd A pointer to a page global directory.
+ @param Pud The value of the page global directory to set.
+
+ @retval VOID
+**/
+VOID
+SetPgd (
+ IN PGD *Pgd,
+ IN PUD *Pud
+ )
+{
+ *Pgd = (PGD) {((UINTN)Pud)};
+}
+
+/**
+ Sets the value of the page upper directory.
+
+ @param Pud A pointer to a page upper directory.
+ @param Pmd The value of the page upper directory to set.
+
+ @retval VOID
+**/
+VOID
+SetPud (
+ IN PUD *Pud,
+ IN PMD *Pmd
+ )
+{
+ *Pud = (PUD) {((UINTN)Pmd)};
+}
+
+/**
+ Sets the value of the page middle directory.
+
+ @param Pmd A pointer to a page middle directory.
+ @param Pte The value of the page middle directory to set.
+
+ @retval VOID
+**/
+VOID
+SetPmd (
+ IN PMD *Pmd,
+ IN PTE *Pte
+ )
+{
+ *Pmd = (PMD) {((UINTN)Pte)};
+}
+/**
+ Free up memory space occupied by page tables.
+
+ @param Pte A pointer to the page table.
+
+ @retval VOID
+**/
+VOID
+PteFree (
+ IN PTE *Pte
+ )
+{
+ FreePages ((VOID *)Pte, 1);
+}
+/**
+ Free up memory space occupied by page middle directory.
+
+ @param Pmd A pointer to the page middle directory.
+
+ @retval VOID
+**/
+VOID
+PmdFree (
+ IN PMD *Pmd
+ )
+{
+ FreePages ((VOID *)Pmd, 1);
+}
+/**
+ Free up memory space occupied by page upper directory.
+
+ @param Pud A pointer to the page upper directory.
+
+ @retval VOID
+**/
+VOID
+PudFree (
+ IN PUD *Pud
+ )
+{
+ FreePages ((VOID *)Pud, 1);
+}
+/**
+ Requests the memory space required for the page upper directory,
+ initializes it, and places it in the specified page global directory
+
+ @param Pgd A pointer to the page global directory.
+
+ @retval EFI_SUCCESS Memory request successful.
+ @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
+**/
+INTN
+PudAlloc (
+ IN PGD *Pgd
+ )
+{
+ PUD *Pud = (PUD *) AllocatePages (1);
+ if (!Pud) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPmd));
+
+ if (pgd_none (*Pgd)) {
+ SetPgd (Pgd, Pud);
+ } else { /* Another has populated it */
+ PudFree (Pud);
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Requests the memory space required for the page middle directory,
+ initializes it, and places it in the specified page upper directory
+
+ @param Pud A pointer to the page upper directory.
+
+ @retval EFI_SUCCESS Memory request successful.
+ @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
+**/
+EFI_STATUS
+PmdAlloc (
+ IN PUD *Pud
+ )
+{
+ PMD *Pmd;
+
+ Pmd = (PMD *) AllocatePages (1);
+ if (!Pmd) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPte));
+
+ if (pud_none (*Pud)) {
+ SetPud (Pud, Pmd);
+ } else {/* Another has populated it */
+ PmdFree (Pmd);
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Requests the memory space required for the page table,
+ initializes it, and places it in the specified page middle directory
+
+ @param Pmd A pointer to the page middle directory.
+
+ @retval EFI_SUCCESS Memory request successful.
+ @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
+**/
+INTN
+PteAlloc (
+ IN PMD *Pmd
+ )
+{
+ PTE *Pte;
+
+ Pte = (PTE *) AllocatePages (1);
+ if (!Pte) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
+
+ if (pmd_none (*Pmd)) {
+ SetPmd (Pmd, Pte);
+ } else { /* Another has populated it */
+ PteFree (Pte);
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Requests the memory space required for the page upper directory,
+ initializes it, and places it in the specified page global directory,
+ and get the page upper directory entry corresponding to the virtual address
+
+ @param Pgd A pointer to the page global directory.
+
+ @retval Gets the page upper directory entry
+**/
+PUD *
+PudAllocGet (
+ IN PGD *Pgd,
+ IN UINTN Address
+ )
+{
+ return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ?
+ NULL : PudOffset (Pgd, Address));
+}
+/**
+ Requests the memory space required for the page middle directory,
+ initializes it, and places it in the specified page upper directory,
+ and get the page middle directory entry corresponding to the virtual address
+
+ @param Pud A pointer to the page upper directory.
+
+ @retval Gets the page middle directory entry
+**/
+PMD *
+PmdAllocGet (
+ IN PUD *Pud,
+ IN UINTN Address
+ )
+{
+ PMD * ret = (pud_none (*Pud) && PmdAlloc (Pud))?
+ NULL: PmdOffset (Pud, Address);
+ DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", __func__, __LINE__,
+ Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) ));
+
+ return ret;
+}
+/**
+ Requests the memory space required for the page table,
+ initializes it, and places it in the specified page middle directory,
+ and get the page table entry corresponding to the virtual address
+
+ @param Pmd A pointer to the page upper directory.
+
+ @retval Gets the page table entry
+**/
+PTE *
+PteAllocGet (
+ IN PMD *Pmd,
+ IN UINTN Address
+ )
+{
+ return (pmd_none (*Pmd) && PteAlloc (Pmd))?
+ NULL: PteOffset (Pmd, Address);
+}
+/**
+ 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;
+ UINTN Num = 0;
+ Pte = PteAllocGet (Pmd, Address);
+ if (!Pte) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ do {
+ DEBUG ((DEBUG_VERBOSE,
+ "%a %d Address %p PGD_INDEX %p PGD_INDEX %p PMD_INDEX %p PTE_INDEX %p MAKE_PTE %p Num %p \n",
+ __func__, __LINE__, Address, PGD_INDEX (Address), PGD_INDEX (Address), PMD_INDEX (Address),
+ PTE_INDEX (Address), MAKE_PTE (Address, Attributes), Num));
+ SetPte (Pte, MAKE_PTE (Address, Attributes));
+ Num++;
+ } 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;
+ UINTN Next;
+ UINTN Num = 0;
+ UINTN AddressStart_HugePage;
+ UINTN AddressEnd_HugePage;
+
+ Pmd = PmdAllocGet (Pud, Address);
+ if (!Pmd) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ do {
+ Next = PMD_ADDRESS_END (Address, End);
+ Num++;
+ if (((Address & (~PMD_MASK)) == 0) &&
+ ((Next & (~PMD_MASK)) == 0))
+ {
+ DEBUG ((DEBUG_VERBOSE,
+ "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p MAKE_HUGE_PTE %p Num %p \n",
+ __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
+ MAKE_HUGE_PTE (Address, Attributes), Num));
+ 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 {
+ 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;
+ }
+ }
+ }
+ } 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;
+}
+/**
+ 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);
+}
+/**
+ 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;
+ 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 0
+ if (!MmuIsInit ()) {
+ return EFI_SUCCESS;
+ }
+ PGPROT_VAL (Attributes) = EfiAttributeToLoongArchAttribute (Attributes);
+ DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes));
+ MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes);
+#endif
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the non-executable Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to set the Attributes.
+ @param[in] Length The length of the memory region to set the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ )
+{
+ if (MmuIsInit ()) {
+ Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
+ LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check to see if mmu successfully initializes and saves the result.
+
+ @param VOID.
+
+ @retval EFI_SUCCESS Initialization succeeded.
+**/
+EFI_STATUS
+MmuInitialize (VOID)
+{
+ if (PcdGet64 (PcdSwapPageDir) != 0) {
+ mMmuInited = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
new file mode 100644
index 0000000000..e9f294b356
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
@@ -0,0 +1,39 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Dir - Directory
+**/
+#ifndef MMU_LIB_CORE_H_
+#define MMU_LIB_CORE_H_
+/**
+ Iterates through the page directory to initialize it.
+
+ @param Dst A pointer to the directory of the page to initialize.
+ @param Num The number of page directories to initialize.
+ @param Src A pointer to the data used to initialize the page directory.
+
+ @retval VOID.
+**/
+VOID
+PageDirInit (
+ IN VOID *dest,
+ IN UINTN Count,
+ IN VOID *src
+ );
+/**
+ Page tables are established from memory-mapped tables.
+
+ @param MemoryRegion A pointer to a memory-mapped table entry.
+
+ @retval EFI_SUCCESS The page table was created successfully.
+ @retval EFI_OUT_OF_RESOURCES Page table establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+FillTranslationTable (
+ IN MEMORY_REGION_DESCRIPTOR *MemoryRegion
+ );
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
new file mode 100644
index 0000000000..84269e86fb
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
@@ -0,0 +1,237 @@
+/** @file
+ Platform PEI driver
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - FwCfg - Firmeware Config
+ - Tlb - Translation Lookaside Buffer
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "pte.h"
+#include "page.h"
+#include "mmu.h"
+#include <Library/Bpi.h>
+#include <Library/QemuFwCfgLib.h>
+#include "MmuLibCore.h"
+
+
+/**
+ Return the Virtual Memory Map of your platform
+
+ This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
+ on your platform.
+
+ @param[out] VirtualMemoryMap Array of MEMORY_REGION_DESCRIPTOR
+ describing a Physical-to-Virtual Memory
+ mapping. This array must be ended by a
+ zero-filled entry. The allocated memory
+ will not be freed.
+
+**/
+VOID
+GetMemoryMapFromFwCfg (
+ OUT MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
+ )
+{
+
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ LOONGARCH_MEMMAP_ENTRY MemoryMapEntry;
+ LOONGARCH_MEMMAP_ENTRY *StartEntry;
+ LOONGARCH_MEMMAP_ENTRY *pEntry;
+ UINTN Processed;
+ MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;
+ UINTN Index = 0;
+ ASSERT (VirtualMemoryMap != NULL);
+
+ VirtualMemoryTable = AllocatePool (
+ sizeof (MEMORY_REGION_DESCRIPTOR) *
+ MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
+ );
+ VirtualMemoryTable[Index].PhysicalBase = 0x10000000;
+ VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
+ VirtualMemoryTable[Index].Length = 0x80000000;
+ VirtualMemoryTable[Index].Attributes = PAGE_VALID | PAGE_USER | CACHE_CC | PAGE_DIRTY;
+ ++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;
+ }
+
+ VirtualMemoryTable[Index].PhysicalBase = pEntry->BaseAddr;
+ VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
+ VirtualMemoryTable[Index].Length = pEntry->Length;
+ VirtualMemoryTable[Index].Attributes = PAGE_VALID | PAGE_USER | CACHE_CC | PAGE_DIRTY;
+ ++Index;
+ }
+
+ FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize));
+ // End of Table
+ ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
+ *VirtualMemoryMap = VirtualMemoryTable;
+ return ;
+}
+
+/**
+ Create a page table and initialize the MMU.
+
+ @param[] VOID
+
+ @retval VOID
+**/
+EFIAPI
+VOID
+ConfigureMmu (VOID)
+{
+ PGD *SwapperPageDir = NULL;
+ PGD *InvalidPgd = NULL;
+ PUD *InvalidPudTable = NULL;
+ PMD *InvalidPmdTable = NULL;
+ PTE *InvalidPteTable = NULL;
+ MEMORY_REGION_DESCRIPTOR *MemoryTable = NULL;
+ RETURN_STATUS PcdStatus;
+ UINTN PgdShift = PGD_SHIFT;
+ UINTN PgdWide = PGD_WIDE;
+ UINTN PudShift = PUD_SHIFT;
+ UINTN PudWide = PUD_WIDE;
+ UINTN PmdShift = PMD_SHIFT;
+ UINTN PmdWide = PMD_WIDE;
+ UINTN PteShift = PTE_SHIFT;
+ UINTN PteWide = PTE_WIDE;
+ UINTN PageEnable = 1 << 4;
+ VOID *TlbReEntry;
+ UINTN PageSize;
+
+ SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ InvalidPgd = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ InvalidPudTable = AllocatePages (EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
+ InvalidPmdTable = AllocatePages (EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
+ InvalidPteTable = AllocatePages (EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
+ ZeroMem (InvalidPteTable, PTE_TABLE_SIZE);
+
+ if ((!InvalidPgd) ||
+ (!InvalidPudTable) ||
+ (!InvalidPmdTable) ||
+ (!InvalidPteTable))
+ {
+ goto FreeTranslationTable;
+ }
+
+ /*pgd init*/
+ PageDirInit (SwapperPageDir , ENTRYS_PER_PGD, InvalidPudTable);
+ /*pgd init*/
+ PageDirInit (InvalidPgd, ENTRYS_PER_PGD, InvalidPudTable);
+ /*pud init*/
+ PageDirInit (InvalidPudTable, ENTRYS_PER_PUD, InvalidPmdTable);
+ /*pmd init*/
+ PageDirInit (InvalidPmdTable, ENTRYS_PER_PMD, InvalidPteTable);
+ GetMemoryMapFromFwCfg (&MemoryTable);
+
+ PcdStatus |= PcdSet64S (PcdSwapPageDir, (UINTN)SwapperPageDir);
+ PcdStatus |= PcdSet64S (PcdInvalidPgd, (UINTN)InvalidPgd);
+ PcdStatus |= PcdSet64S (PcdInvalidPud, (UINTN)InvalidPudTable);
+ PcdStatus |= PcdSet64S (PcdInvalidPmd, (UINTN)InvalidPmdTable);
+ PcdStatus |= PcdSet64S (PcdInvalidPte, (UINTN)InvalidPteTable);
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ while (MemoryTable->Length != 0) {
+ DEBUG ((DEBUG_VERBOSE, "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", __func__, __LINE__,
+ MemoryTable->VirtualBase,
+ (MemoryTable->Length + MemoryTable->VirtualBase),
+ MemoryTable->Attributes));
+
+ PcdStatus = FillTranslationTable (MemoryTable);
+ if (EFI_ERROR (PcdStatus)) {
+ goto FreeTranslationTable;
+ }
+ MemoryTable++;
+ }
+
+ /*set page size*/
+ WRITE_CSR_PAGE_SIZE (DEFAULT_PAGE_SIZE);
+ WRITE_CSR_STLB_PAGE_SIZE (DEFAULT_PAGE_SIZE);
+ WRITE_CSR_TLBREFILL_PAGE_SIZE (DEFAULT_PAGE_SIZE);
+ READ_CSR_PAGE_SIZE (PageSize);
+ if (PageSize != DEFAULT_PAGE_SIZE) {
+ goto FreeTranslationTable;
+ }
+
+ TlbReEntry = AllocatePages (1);
+ if (TlbReEntry == NULL) {
+ goto FreeTranslationTable;
+ }
+ CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - HandleTlbRefill));
+ SET_REFILL_TLBBASE ((UINTN)HandleTlbRefill);
+
+ DEBUG ((DEBUG_VERBOSE,
+ "%a %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudWide %d PgdShift %d PgdWide %d.\n",
+ __func__, __LINE__,
+ PteShift, PteWide, PmdShift, PmdWide,PudShift, PudWide, PgdShift, PgdWide));
+
+ LOONGARCH_CSR_WRITEQ (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25,
+ LOONGARCH_CSR_PWCTL0);
+ LOONGARCH_CSR_WRITEQ (PgdShift | PgdWide << 6, LOONGARCH_CSR_PWCTL1);
+ LOONGARCH_CSR_WRITEQ ((UINTN)SwapperPageDir, LOONGARCH_CSR_PGDL);
+ LOONGARCH_CSR_WRITEQ ((UINTN)InvalidPgd, LOONGARCH_CSR_PGDH);
+
+ DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
+ LOONGARCH_CSR_XCHGQ ( PageEnable, 1 << 4, LOONGARCH_CSR_CRMD);
+ DEBUG ((DEBUG_INFO, "%a %d Enable Mmu End.\n", __func__, __LINE__));
+
+ return ;
+
+FreeTranslationTable:
+ if (SwapperPageDir) {
+ FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ }
+
+ if (InvalidPgd) {
+ FreePages (InvalidPgd, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ }
+
+ if (InvalidPudTable) {
+ FreePages (InvalidPudTable, EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
+ }
+
+ if (InvalidPmdTable) {
+ FreePages (InvalidPmdTable, EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
+ }
+
+ if (InvalidPteTable) {
+ FreePages (InvalidPteTable, EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
+ }
+
+ PcdSet64S (PcdSwapPageDir, (UINTN)0);
+ PcdSet64S (PcdInvalidPgd, (UINTN)0);
+ PcdSet64S (PcdInvalidPud, (UINTN)0);
+ PcdSet64S (PcdInvalidPmd, (UINTN)0);
+ PcdSet64S (PcdInvalidPte, (UINTN)0);
+
+ return ;
+}
+
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
new file mode 100644
index 0000000000..cd11f45dd4
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
@@ -0,0 +1,101 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Tlb or TLB - Translation Lookaside Buffer
+ - CSR - Cpu State Register
+ - PGDL - Page Global Directory Low
+ - PGDH - Page Global Directory High
+ - TLBIDX - TLB Index
+ - TLBREHI - TLB Refill Entry High
+ - PWCTL - Page Walk Control
+ - STLB - Singular Page Size TLB
+ - PS - Page Size
+**/
+#ifndef MMU_H_
+#define MMU_H_
+/*page size 4k*/
+#define DEFAULT_PAGE_SIZE 0x0c
+#define LOONGARCH_CSR_PGDL 0x19 /* Page table base address when VA[47] = 0 */
+#define LOONGARCH_CSR_PGDH 0x1a /* Page table base address when VA[47] = 1 */
+#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP */
+#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */
+#define LOONGARCH_CSR_PWCTL0 0x1c /* PWCtl0 */
+#define LOONGARCH_CSR_PWCTL1 0x1d /* PWCtl1 */
+#define LOONGARCH_CSR_STLBPGSIZE 0x1e
+#define CSR_TLBIDX_SIZE_MASK 0x3f000000
+#define CSR_TLBIDX_PS_SHIFT 24
+#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT
+
+/*
+ Set Cpu Status Register STLB Page Size.
+
+ @param val Page Size.
+
+ @retval VOID
+ */
+#define WRITE_CSR_STLB_PAGE_SIZE(val) LOONGARCH_CSR_WRITEQ((val), LOONGARCH_CSR_STLBPGSIZE)
+/*
+ Set Cpu Status Register Page Size.
+
+ @param size Page Size.
+
+ @retval VOID
+ */
+#define WRITE_CSR_PAGE_SIZE(size) LOONGARCH_CSR_XCHGQ((size) << CSR_TLBIDX_SIZE, CSR_TLBIDX_SIZE_MASK, LOONGARCH_CSR_TLBIDX)
+/*
+ Set Cpu Status Register TLBREFILL Page Size.
+
+ @param size Page Size.
+
+ @retval VOID
+ */
+#define WRITE_CSR_TLBREFILL_PAGE_SIZE(size) LOONGARCH_CSR_XCHGQ((size) << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI)
+/*
+ Set Cpu Status Register TLBREFILL Base Address.
+
+ @param BaseAddress the code base address of TLB refills .
+
+ @retval VOID
+ */
+#define SET_REFILL_TLBBASE(BaseAddress) LOONGARCH_CSR_WRITEQ((BaseAddress), LOONGARCH_CSR_TLBREBASE);
+/*
+ Get Cpu Status Register Page Size.
+
+ @param val Gets the page size.
+
+ @retval VOID
+ */
+#define READ_CSR_PAGE_SIZE(val) \
+{ \
+ LOONGARCH_CSR_READQ ((val), LOONGARCH_CSR_TLBIDX); \
+ (val) = ((val) & CSR_TLBIDX_SIZE_MASK) >> CSR_TLBIDX_SIZE; \
+}
+
+
+#define CSR_TLBREHI_PS_SHIFT 0
+#define CSR_TLBREHI_PS ((UINTN)(0x3f) << CSR_TLBREHI_PS_SHIFT)
+
+#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \
+ EFI_MEMORY_WC | \
+ EFI_MEMORY_WT | \
+ EFI_MEMORY_WB | \
+ EFI_MEMORY_UCE \
+ )
+
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS PhysicalBase;
+ EFI_VIRTUAL_ADDRESS VirtualBase;
+ UINTN Length;
+ UINTN Attributes;
+} MEMORY_REGION_DESCRIPTOR;
+
+// The total number of descriptors, including the final "end-of-table" descriptor.
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)
+
+extern CHAR8 HandleTlbRefill[], HandleTlbRefillEnd[];
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
new file mode 100644
index 0000000000..3773ddcd09
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
@@ -0,0 +1,267 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Pgd or Pgd or PGD - Page Global Directory
+ - Pud or Pud or PUD - Page Upper Directory
+ - Pmd or Pmd or PMD - Page Middle Directory
+ - Pte or pte or PTE - Page Table Entry
+ - Val or VAL or val - Value
+ - Dir - Directory
+**/
+#ifndef PAGE_H_
+#define PAGE_H_
+
+#define MAX_VA_BITS 47
+#define PGD_WIDE (8)
+#define PUD_WIDE (9)
+#define PMD_WIDE (9)
+#define PTE_WIDE (9)
+
+#define ENTRYS_PER_PGD (1 << PGD_WIDE)
+#define ENTRYS_PER_PUD (1 << PUD_WIDE)
+#define ENTRYS_PER_PMD (1 << PMD_WIDE)
+#define ENTRYS_PER_PTE (1 << PTE_WIDE)
+
+#define PGD_SHIFT (PUD_SHIFT + PUD_WIDE)
+#define PUD_SHIFT (PMD_SHIFT + PMD_WIDE)
+#define PMD_SHIFT (EFI_PAGE_SHIFT + PTE_WIDE)
+#define PTE_SHIFT (EFI_PAGE_SHIFT)
+
+#define PGD_SIZE (1UL << PGD_SHIFT)
+#define PUD_SIZE (1UL << PUD_SHIFT)
+#define PMD_SIZE (1UL << PMD_SHIFT)
+
+#define PGD_MASK (~(PGD_SIZE-1))
+#define PUD_MASK (~(PUD_SIZE-1))
+#define PMD_MASK (~(PMD_SIZE-1))
+#define PAGE_MASK (~(EFI_PAGE_SIZE - 1)
+#define PFN_MASK (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \
+ (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
+
+typedef struct { UINTN PgdVal; } PGD;
+typedef struct { UINTN PudVal; } PUD;
+typedef struct { UINTN PmdVal; } PMD;
+typedef struct { UINTN PteVal; } PTE;
+/**
+ Gets the value of the page global directory table entry.
+
+ @param x Page global directory struct variables.
+
+ @retval the value of the page global directory table entry.
+ **/
+#define PGD_VAL(x) ((x).PgdVal)
+/**
+ Gets the value of the page upper directory table entry.
+
+ @param x Page upper directory struct variables.
+
+ @retval the value of the page upper directory table entry.
+ **/
+#define PUD_VAL(x) ((x).PudVal)
+/**
+ Gets the value of the page middle directory table entry.
+
+ @param x Page middle directory struct variables.
+
+ @retval the value of the page middle directory table entry.
+ **/
+#define PMD_VAL(x) ((x).PmdVal)
+/**
+ Gets the value of the page table entry.
+
+ @param x Page table entry struct variables.
+
+ @retval the value of the page table entry.
+ **/
+#define PTE_VAL(x) ((x).PteVal)
+
+
+#define PGD_TABLE_SIZE (ENTRYS_PER_PGD * sizeof(PGD))
+#define PUD_TABLE_SIZE (ENTRYS_PER_PUD * sizeof(PUD))
+#define PMD_TABLE_SIZE (ENTRYS_PER_PMD * sizeof(PMD))
+#define PTE_TABLE_SIZE (ENTRYS_PER_PTE * sizeof(PTE))
+/**
+ Gets the physical address of the record in the page table entry.
+
+ @param x Page table entry struct variables.
+
+ @retval the value of the physical address.
+ **/
+#define GET_PAGE_ATTRIBUTES(x) (UINTN) {(PTE_VAL(x) & ~PFN_MASK)}
+/**
+ Gets the virtual address of the next block of the specified virtual address
+ that is aligned with the size of the global page directory mapping.
+
+ @param Address Specifies the virtual address.
+ @param End The end address of the memory region.
+
+ @retval the specified virtual address of the next block.
+ **/
+#define PGD_ADDRESS_END(Address, End) \
+({ UINTN Boundary = ((Address) + PGD_SIZE) & PGD_MASK; \
+ (Boundary - 1 < (End) - 1)? Boundary: (End); \
+})
+/**
+ Gets the virtual address of the next block of the specified virtual address
+ that is aligned with the size of the page upper directory mapping.
+
+ @param Address Specifies the virtual address.
+ @param End The end address of the memory region.
+
+ @retval the specified virtual address of the next block.
+ **/
+#define PUD_ADDRESS_END(Address, End) \
+({ UINTN Boundary = ((Address) + PUD_SIZE) & PUD_MASK; \
+ (Boundary - 1 < (End) - 1)? Boundary: (End); \
+})
+/**
+ Gets the virtual address of the next block of the specified virtual address
+ that is aligned with the size of the page middle directory mapping.
+
+ @param Address Specifies the virtual address.
+ @param End The end address of the memory region.
+
+ @retval the specified virtual address of the next block.
+ **/
+#define PMD_ADDRESS_END(Address, End) \
+({ UINTN Boundary = ((Address) + PMD_SIZE) & PMD_MASK; \
+ (Boundary - 1 < (End) - 1)? Boundary: (End); \
+})
+/**
+ Get Specifies the virtual address corresponding to the index of the page global directory table entry.
+
+ @param Address Specifies the virtual address.
+
+ @retval the index of the page global directory table entry.
+ **/
+#define PGD_INDEX(Address) (((Address) >> PGD_SHIFT) & (ENTRYS_PER_PGD-1))
+/**
+ Get Specifies the virtual address corresponding to the index of the page upper directory table entry.
+
+ @param Address Specifies the virtual address.
+ @param End The end address of the memory region.
+
+ @retval the index of the page upper directory table entry.
+ **/
+#define PUD_INDEX(Address) (((Address) >> PUD_SHIFT) & (ENTRYS_PER_PUD - 1))
+/**
+ Get Specifies the virtual address corresponding to the index of the page middle directory table entry.
+
+ @param Address Specifies the virtual address.
+
+ @retval the index of the page middle directory table entry.
+ **/
+#define PMD_INDEX(Address) (((Address) >> PMD_SHIFT) & (ENTRYS_PER_PMD - 1))
+/**
+ Get Specifies the virtual address corresponding to the index of the page table entry.
+
+ @param Address Specifies the virtual address.
+
+ @retval the index of the page table entry.
+ **/
+#define PTE_INDEX(Address) (((Address) >> EFI_PAGE_SHIFT) & (ENTRYS_PER_PTE - 1))
+
+/**
+ Calculates the value of the page table entry based on the specified virtual address and properties.
+
+ @param Address Specifies the virtual address.
+ @param Attributes Specifies the Attributes.
+
+ @retval the value of the page table entry.
+ **/
+#define MAKE_PTE(Address, Attributes) (PTE){((((Address) >> EFI_PAGE_SHIFT) << 12) | (Attributes))}
+/**
+ Calculates the value of the Huge page table entry based on the specified virtual address and properties.
+
+ @param Address Specifies the virtual address.
+ @param Attributes Specifies the Attributes.
+
+ @retval the value of the HUGE page table entry.
+ **/
+#define MAKE_HUGE_PTE(Address, Attributes) (((((Address) >> PMD_SHIFT) << PMD_SHIFT) | ((Attributes) | PAGE_HUGE)))
+ /**
+ Check whether the large page table entry is.
+
+ @param Val The value of the page table entry.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+#define IS_HUGE_PAGE(Val) (((Val) & PAGE_HUGE) == PAGE_HUGE)
+#define HUGE_PAGE_SIZE (PMD_SIZE)
+
+ /**
+ Check that the global page directory table entry is empty.
+
+ @param pgd the global page directory struct variables.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pgd_none (
+ IN PGD pgd
+ )
+{
+ return (PGD_VAL(pgd) == (UINTN)PcdGet64(PcdInvalidPud));
+}
+
+ /**
+ Check that the page upper directory table entry is empty.
+
+ @param pud Page upper directory struct variables.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pud_none (
+ IN PUD pud
+ )
+{
+ return (PUD_VAL(pud) == (UINTN)PcdGet64 (PcdInvalidPmd));
+}
+
+ /**
+ Check that the page middle directory table entry is empty.
+
+ @param pmd Page middle directory struct variables.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pmd_none (
+ IN PMD pmd
+ )
+{
+ return (PMD_VAL(pmd) == (UINTN)PcdGet64(PcdInvalidPte));
+}
+ /**
+ Check that the page table entry is empty.
+
+ @param pmd Page table entry struct variables.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pte_none (
+ IN PTE pte
+ )
+{
+ return (!(PTE_VAL(pte) & (~PAGE_GLOBAL)));
+}
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
new file mode 100644
index 0000000000..d4eabdaed3
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
@@ -0,0 +1,57 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Tlb or TLB - Translation Lookaside Buffer
+ - HGLOBAL - Huge Global
+ - PFN - Page Frame number
+ - EXEC - Execute
+ - PLV - Privilege Level
+ - RPLV - Restricted Privilege Level
+ - SUC - Strong-ordered UnCached
+ - CC - Coherent Cached
+ - WUC - Weak-ordered UnCached
+**/
+#ifndef PTE_H_
+#define PTE_H_
+/*Page table property definitions */
+#define PAGE_VALID_SHIFT 0
+#define PAGE_DIRTY_SHIFT 1
+#define PAGE_PLV_SHIFT 2 /* 2~3, two bits */
+#define CACHE_SHIFT 4 /* 4~5, two bits */
+#define PAGE_GLOBAL_SHIFT 6
+#define PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */
+
+#define PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */
+#define PAGE_PFN_SHIFT 12
+#define PAGE_PFN_END_SHIFT 48
+#define PAGE_NO_READ_SHIFT 61
+#define PAGE_NO_EXEC_SHIFT 62
+#define PAGE_RPLV_SHIFT 63
+
+/* Used by TLB hardware (placed in EntryLo*) */
+#define PAGE_VALID ((UINTN)(1) << PAGE_VALID_SHIFT)
+#define PAGE_DIRTY ((UINTN)(1) << PAGE_DIRTY_SHIFT)
+#define PAGE_PLV ((UINTN)(3) << PAGE_PLV_SHIFT)
+#define PAGE_GLOBAL ((UINTN)(1) << PAGE_GLOBAL_SHIFT)
+#define PAGE_HUGE ((UINTN)(1) << PAGE_HUGE_SHIFT)
+#define PAGE_HGLOBAL ((UINTN)(1) << PAGE_HGLOBAL_SHIFT)
+#define PAGE_NO_READ ((UINTN)(1) << PAGE_NO_READ_SHIFT)
+#define PAGE_NO_EXEC ((UINTN)(1) << PAGE_NO_EXEC_SHIFT)
+#define PAGE_RPLV ((UINTN)(1) << PAGE_RPLV_SHIFT)
+#define CACHE_MASK ((UINTN)(3) << CACHE_SHIFT)
+#define PFN_SHIFT (EFI_PAGE_SHIFT - 12 + PAGE_PFN_SHIFT)
+
+#define PLV_KERNEL 0
+#define PLV_USER 3
+
+#define PAGE_USER (PLV_USER << PAGE_PLV_SHIFT)
+#define PAGE_KERNEL (PLV_KERN << PAGE_PLV_SHIFT)
+
+#define CACHE_SUC (0 << CACHE_SHIFT) /* Strong-ordered UnCached */
+#define CACHE_CC (1 << CACHE_SHIFT) /* Coherent Cached */
+#define CACHE_WUC (2 << CACHE_SHIFT) /* Weak-ordered UnCached */
+#endif
--
2.27.0
next prev parent reply other threads:[~2022-03-02 8:45 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 01/15] Platform/Loongson: Add Serial Port library xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 02/15] Platform/Loongson: Support SEC And Add Readme.md xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 03/15] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 04/15] Platform/Loongson: Add QemuFwCfgLib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 05/15] Platform/Loongson: Add BpiLib xianglai
2022-03-02 8:44 ` xianglai [this message]
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 07/15] Platform/Loongson: Add StableTimerLib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 08/15] Platform/Loongson: Support PEI phase xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 09/15] Platform/Loongson: Add CPU DXE driver xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 10/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 11/15] Platform/Loongson: Add timer Dxe driver xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 12/15] Platform/Loongson: Add RealTime Clock lib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 13/15] Platform/Loongson: Add Platform Boot Manager Lib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 14/15] Platform/Loongson: Add Reset System Lib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 15/15] Platform/Loongson: Support Dxe 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=20220302084447.2991355-7-lixianglai@loongson.cn \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox