From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from loongson.cn (loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web08.1101.1667025929131862231 for ; Fri, 28 Oct 2022 23:45:30 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: loongson.cn, ip: 114.242.206.163, mailfrom: maobibo@loongson.cn) Received: from loongson.cn (unknown [10.20.42.170]) by gateway (Coremail) with SMTP id _____8DxC7YGzFxjojsDAA--.385S3; Sat, 29 Oct 2022 14:45:26 +0800 (CST) Received: from [10.20.42.170] (unknown [10.20.42.170]) by localhost.localdomain (Coremail) with SMTP id AQAAf8DxNlcDzFxjDCsHAA--.5866S3; Sat, 29 Oct 2022 14:45:23 +0800 (CST) Message-ID: Date: Sat, 29 Oct 2022 14:45:23 +0800 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.13.0 Subject: Re: [edk2-platforms][PATCH V4 05/14] Platform/Loongson: Add MmuLib. To: xianglai li , devel@edk2.groups.io Cc: quic_llindhol@quicinc.com, michael.d.kinney@intel.com, ardb@kernel.org References: <1d54b72b110ab8a6aa5c0f3f029fd4cc43b85c0c.1666335216.git.lixianglai@loongson.cn> From: "maobibo" In-Reply-To: <1d54b72b110ab8a6aa5c0f3f029fd4cc43b85c0c.1666335216.git.lixianglai@loongson.cn> X-CM-TRANSID: AQAAf8DxNlcDzFxjDCsHAA--.5866S3 X-CM-SenderInfo: xpdruxter6z05rqj20fqof0/ X-Coremail-Antispam: 1Uk129KBjvAXoWDGry8GrWDZw45ZrWkJF4fKrg_yoW7Cw4UJo WYvFs3Cw48Jw1rArW8G3s7Wa17tF4Fy393XFZ5tFWUXFsavFs0kayrJayUG3s3Cw1Fvrn8 GrykXaykAFZaqr1rn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7ZEXasCq-sGcSsGvf J3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnRJU UUv2b4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2IYs7xG6rWj6s 0DM7CIcVAFz4kK6r1j6r18M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l84 ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AKxVW8Jr0_Cr1U M2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6xACxx1l5I8CrVACY4 xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1j6r18McIj6I8E87Iv67AKxVWUJVW8 JwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IY64vIr41lc7I2V7IY0VAS07AlzVAYIcxG8w CF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j 6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_JF0_Jw1lIxkGc2Ij64 vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Jr0_ Gr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0x vEx4A2jsIEc7CjxVAFwI0_Jr0_GrUvcSsGvfC2KfnxnUUI43ZEXa7IU1CPfJUUUUU== Content-Language: en-US Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 2022/10/21 15:11, xianglai li 写道: > Read the memory map information through the QemuFwCfg interface, > then build the page table through the memory map information, > and finally enable Mmu. > > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054 > > Signed-off-by: xianglai li > --- > .../LoongArchQemuPkg/Include/Library/MmuLib.h | 85 ++ > .../LoongArchQemuPkg/Library/MmuLib/Mmu.S | 35 + > .../Library/MmuLib/MmuBaseLib.inf | 35 + > .../Library/MmuLib/MmuBaseLibPei.inf | 42 + > .../Library/MmuLib/MmuLibCore.c | 908 ++++++++++++++++++ > .../Library/MmuLib/MmuLibCore.h | 39 + > .../Library/MmuLib/MmuLibCorePei.c | 236 +++++ > .../LoongArchQemuPkg/Library/MmuLib/mmu.h | 104 ++ > .../LoongArchQemuPkg/Library/MmuLib/page.h | 267 +++++ > .../LoongArchQemuPkg/Library/MmuLib/pte.h | 57 ++ > 10 files changed, 1808 insertions(+) > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h > create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h > > diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h > new file mode 100644 > index 0000000000..6c501eca07 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h > @@ -0,0 +1,85 @@ > +/** @file > + > + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.
> + > + 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.
> +# > +# 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.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = MmuBaseLib > + FILE_GUID = da8f0232-fb14-42f0-922c-63104d2c70be > + MODULE_TYPE = BASE > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = MmuLib > + > + CONSTRUCTOR = MmuInitialize > +[Sources.common] > + MmuLibCore.c > + > +[Packages] > + MdePkg/MdePkg.dec > + Platform/Loongson/LoongArchQemuPkg/Loongson.dec > + > +[PCD] > + gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir > + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd > + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud > + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd > + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte > + > +[LibraryClasses] > + MemoryAllocationLib > + PcdLib > + DebugLib > diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf > new file mode 100644 > index 0000000000..f6a3cab45f > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf > @@ -0,0 +1,42 @@ > +## @file > +# > +# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = MmuPeiLib > + FILE_GUID = da8f0232-fb14-42f0-922c-63104d2c70bd > + MODULE_TYPE = BASE > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = MmuLib | SEC PEIM > + > +[Sources.common] > + MmuLibCorePei.c > + Mmu.S > + MmuLibCore.h > + MmuLibCore.c > + > +[Packages] > + MdePkg/MdePkg.dec > + Platform/Loongson/LoongArchQemuPkg/Loongson.dec > + OvmfPkg/OvmfPkg.dec > + > +[PCD] > + gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir > + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd > + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud > + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd > + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte > + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize > + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase > + gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize > + > +[LibraryClasses] > + MemoryAllocationLib > + PcdLib > + DebugLib > + QemuFwCfgLib > diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c > new file mode 100644 > index 0000000000..d737759ad2 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c > @@ -0,0 +1,908 @@ > +/** @file > + > + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.
> + > + 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 > +#include > +#include > +#include > +#include > +#include "Library/Cpu.h" > +#include "pte.h" > +#include "page.h" > +#include "mmu.h" > + > +BOOLEAN mMmuInited = FALSE; > +/** > + Check to see if mmu successfully initializes. > + > + @param VOID. > + > + @retval TRUE Initialization has been completed. > + FALSE Initialization did not complete. > +**/ > +BOOLEAN > +MmuIsInit (VOID) { > + if ((mMmuInited == TRUE) || > + (PcdGet64 (PcdSwapPageDir) != 0)) { > + return TRUE; > + } > + return FALSE; > +} > + > +/** > + Iterates through the page directory to initialize it. > + > + @param Dst A pointer to the directory of the page to initialize. > + @param Num The number of page directories to initialize. > + @param Src A pointer to the data used to initialize the page directory. > + > + @retval VOID. > +**/ > +VOID > +PageDirInit ( > + IN VOID *Dst, > + IN UINTN Num, > + IN VOID *Src > + ) > +{ > + UINTN *Ptr; > + UINTN *End; > + UINTN Entry; > + > + Entry = (UINTN)Src; > + Ptr = (UINTN *)Dst; > + End = Ptr + Num; > + > + for ( ;Ptr < End; Ptr++) { > + *Ptr = Entry; > + } > + > + return ; > +} > +/** > + Gets the virtual address corresponding to the page global directory table entry. > + > + @param Address the virtual address for the table entry. > + > + @retval PGD A pointer to get the table item. > +**/ > +PGD * > +PgdOffset ( > + IN UINTN Address > + ) > +{ > + return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address); > +} > +/** > + Gets the virtual address corresponding to the page upper directory table entry. > + > + @param Pgd A pointer to a page global directory table entry. > + @param Address the virtual address for the table entry. > + > + @retval PUD A pointer to get the table item. > +**/ > +PUD * > +PudOffset ( > + IN PGD *Pgd, > + IN UINTN Address > + ) > +{ > + UINTN PgdVal = (UINTN)PGD_VAL (*Pgd); > + return (PUD *)PgdVal + PUD_INDEX (Address); > +} > +/** > + Gets the virtual address corresponding to the page middle directory table entry. > + > + @param Pud A pointer to a page upper directory table entry. > + @param Address the virtual address for the table entry. > + > + @retval PMD A pointer to get the table item. > +**/ > +PMD * > +PmdOffset ( > + IN PUD *Pud, > + IN UINTN Address > + ) > +{ > + UINTN PudVal = PUD_VAL (*Pud); > + return (PMD *)PudVal + PMD_INDEX (Address); > +} > +/** > + Gets the virtual address corresponding to the page table entry. > + > + @param Pmd A pointer to a page middle directory table entry. > + @param Address the virtual address for the table entry. > + > + @retval PTE A pointer to get the table item. > +**/ > +PTE * > +PteOffset ( > + IN PMD *Pmd, > + IN UINTN Address > + ) > +{ > + UINTN PmdVal = (UINTN)PMD_VAL (*Pmd); > + return (PTE *)PmdVal + PTE_INDEX (Address); > +} > + > +/** > + Sets the value of the page table entry. > + > + @param Pte A pointer to a page table entry. > + @param PteVal The value of the page table entry to set. > + > + @retval VOID > +**/ > +VOID > +SetPte ( > + IN PTE *Pte, > + IN PTE PteVal > + ) > +{ > + *Pte = PteVal; > +} > +/** > + Sets the value of the page global directory. > + > + @param Pgd A pointer to a page global directory. > + @param Pud The value of the page global directory to set. > + > + @retval VOID > +**/ > +VOID > +SetPgd ( > + IN PGD *Pgd, > + IN PUD *Pud > + ) > +{ > + *Pgd = (PGD) {((UINTN)Pud)}; > +} > + > +/** > + Sets the value of the page upper directory. > + > + @param Pud A pointer to a page upper directory. > + @param Pmd The value of the page upper directory to set. > + > + @retval VOID > +**/ > +VOID > +SetPud ( > + IN PUD *Pud, > + IN PMD *Pmd > + ) > +{ > + *Pud = (PUD) {((UINTN)Pmd)}; > +} > + > +/** > + Sets the value of the page middle directory. > + > + @param Pmd A pointer to a page middle directory. > + @param Pte The value of the page middle directory to set. > + > + @retval VOID > +**/ > +VOID > +SetPmd ( > + IN PMD *Pmd, > + IN PTE *Pte > + ) > +{ > + *Pmd = (PMD) {((UINTN)Pte)}; > +} > +/** > + Free up memory space occupied by page tables. > + > + @param Pte A pointer to the page table. > + > + @retval VOID > +**/ > +VOID > +PteFree ( > + IN PTE *Pte > + ) > +{ > + FreePages ((VOID *)Pte, 1); > +} > +/** > + Free up memory space occupied by page middle directory. > + > + @param Pmd A pointer to the page middle directory. > + > + @retval VOID > +**/ > +VOID > +PmdFree ( > + IN PMD *Pmd > + ) > +{ > + FreePages ((VOID *)Pmd, 1); > +} > +/** > + Free up memory space occupied by page upper directory. > + > + @param Pud A pointer to the page upper directory. > + > + @retval VOID > +**/ > +VOID > +PudFree ( > + IN PUD *Pud > + ) > +{ > + FreePages ((VOID *)Pud, 1); > +} > +/** > + Requests the memory space required for the page upper directory, > + initializes it, and places it in the specified page global directory > + > + @param Pgd A pointer to the page global directory. > + > + @retval EFI_SUCCESS Memory request successful. > + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory. > +**/ > +INTN > +PudAlloc ( > + IN PGD *Pgd > + ) > +{ > + PUD *Pud = (PUD *) AllocatePages (1); > + if (!Pud) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPmd)); > + > + if (pgd_none (*Pgd)) { > + SetPgd (Pgd, Pud); > + } else { /* Another has populated it */ > + PudFree (Pud); > + } > + > + return EFI_SUCCESS; > +} > +/** > + Requests the memory space required for the page middle directory, > + initializes it, and places it in the specified page upper directory > + > + @param Pud A pointer to the page upper directory. > + > + @retval EFI_SUCCESS Memory request successful. > + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory. > +**/ > +EFI_STATUS > +PmdAlloc ( > + IN PUD *Pud > + ) > +{ > + PMD *Pmd; > + > + Pmd = (PMD *) AllocatePages (1); > + if (!Pmd) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPte)); > + > + if (pud_none (*Pud)) { > + SetPud (Pud, Pmd); > + } else {/* Another has populated it */ > + PmdFree (Pmd); > + } > + > + return EFI_SUCCESS; > +} > +/** > + Requests the memory space required for the page table, > + initializes it, and places it in the specified page middle directory > + > + @param Pmd A pointer to the page middle directory. > + > + @retval EFI_SUCCESS Memory request successful. > + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory. > +**/ > +INTN > +PteAlloc ( > + IN PMD *Pmd > + ) > +{ > + PTE *Pte; > + > + Pte = (PTE *) AllocatePages (1); > + if (!Pte) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Pte = ZeroMem (Pte, EFI_PAGE_SIZE); > + > + if (pmd_none (*Pmd)) { > + SetPmd (Pmd, Pte); > + } else { /* Another has populated it */ > + PteFree (Pte); > + } > + > + return EFI_SUCCESS; > +} > +/** > + Requests the memory space required for the page upper directory, > + initializes it, and places it in the specified page global directory, > + and get the page upper directory entry corresponding to the virtual address > + > + @param Pgd A pointer to the page global directory. > + > + @retval Gets the page upper directory entry > +**/ > +PUD * > +PudAllocGet ( > + IN PGD *Pgd, > + IN UINTN Address > + ) > +{ > + return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ? > + NULL : PudOffset (Pgd, Address)); > +} > +/** > + Requests the memory space required for the page middle directory, > + initializes it, and places it in the specified page upper directory, > + and get the page middle directory entry corresponding to the virtual address > + > + @param Pud A pointer to the page upper directory. > + > + @retval Gets the page middle directory entry > +**/ > +PMD * > +PmdAllocGet ( > + IN PUD *Pud, > + IN UINTN Address > + ) > +{ > + PMD * ret = (pud_none (*Pud) && PmdAlloc (Pud))? > + NULL: PmdOffset (Pud, Address); > + DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", __func__, __LINE__, > + Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) )); > + > + return ret; > +} > +/** > + Requests the memory space required for the page table, > + initializes it, and places it in the specified page middle directory, > + and get the page table entry corresponding to the virtual address > + > + @param Pmd A pointer to the page upper directory. > + > + @retval Gets the page table entry > +**/ > +PTE * > +PteAllocGet ( > + IN PMD *Pmd, > + IN UINTN Address > + ) > +{ > + return (pmd_none (*Pmd) && PteAlloc (Pmd))? > + NULL: PteOffset (Pmd, Address); > +} > + /** > + Convert page middle directory table entry to tlb entry. > + > + @param PmdVal page middle directory table entry value. > + > + @retval tlb entry value. > + **/ > +UINTN > +PmdToTlbEntry ( > + UINTN PmdVal > + ) > +{ > + UINTN Value; > + > + Value = PmdVal ^ PAGE_HUGE; > + Value |= ((Value & PAGE_HGLOBAL) >> > + (PAGE_HGLOBAL_SHIFT - PAGE_GLOBAL_SHIFT)); > + > + return Value; > +} > + > + /** > + Update huge tlb. > + > + @param address The address corresponding to tlb. > + @param Pte A pointer to the page table entry. > + > + @retval VOID. > + **/ > +VOID > +UpdateHugeTlb ( > + IN UINTN address, > + PTE *Pte) > +{ > + INTN Idx; > + UINTN TlbEntry; > + address &= (PAGE_MASK << 1); > + LOONGARCH_CSR_WRITEQ (address, LOONGARCH_CSR_TLBEHI); > + LOONGARCH_TLB_SRCH(); > + LOONGARCH_CSR_READQ (Idx, LOONGARCH_CSR_TLBIDX); > + > + if (Idx < 0) { > + return ; > + } > + WRITE_CSR_PAGE_SIZE (HUGE_PAGE_SIZE); > + TlbEntry = PmdToTlbEntry(PTE_VAL (*Pte)); > + LOONGARCH_CSR_WRITEQ(TlbEntry, LOONGARCH_CSR_TLBELO0); > + LOONGARCH_CSR_WRITEQ(TlbEntry + (HUGE_PAGE_SIZE >> 1), LOONGARCH_CSR_TLBELO1); > + LOONGARCH_TLB_WR (); > + > + WRITE_CSR_PAGE_SIZE (DEFAULT_PAGE_SIZE); > + > + return ; > +} > + /** > + Update tlb. > + > + @param address The address corresponding to tlb. > + @param Pte A pointer to the page table entry. > + > + @retval VOID. > + **/ > +VOID > +UpdateTlb ( > + IN UINTN address, > + PTE *Pte) > +{ > + INTN Idx; > + if (IS_HUGE_PAGE (Pte->PteVal)) { > + return UpdateHugeTlb(address, Pte); > + } > + > + address &= (PAGE_MASK << 1); > + LOONGARCH_CSR_WRITEQ (address, LOONGARCH_CSR_TLBEHI); > + LOONGARCH_TLB_SRCH(); > + LOONGARCH_CSR_READQ (Idx, LOONGARCH_CSR_TLBIDX); > + > + if (Idx < 0) { > + return ; > + } > + > + if ((UINTN)Pte & sizeof(PTE)) { > + Pte--; > + } > + > + WRITE_CSR_PAGE_SIZE (DEFAULT_PAGE_SIZE); > + LOONGARCH_CSR_WRITEQ(PTE_VAL (*Pte), LOONGARCH_CSR_TLBELO0); > + Pte++; > + LOONGARCH_CSR_WRITEQ(PTE_VAL (*Pte), LOONGARCH_CSR_TLBELO1); > + LOONGARCH_TLB_WR (); > + > + return ; > +} > + > +/** > + Gets the physical address of the page table entry corresponding to the specified virtual address. > + > + @param Address the corresponding virtual address of the page table entry. > + > + @retval A pointer to the page table entry. > + @retval NULL > +**/ > +PTE * > +GetPteAddress ( > + IN UINTN Address > + ) > +{ > + PGD *Pgd; > + PUD *Pud; > + PMD *Pmd; > + > + Pgd = PgdOffset (Address); > + > + if (pgd_none (*Pgd)) { > + return NULL; > + } > + > + Pud = PudOffset (Pgd, Address); > + > + if (pud_none (*Pud)) { > + return NULL; > + } > + > + Pmd = PmdOffset (Pud, Address); > + if (pmd_none (*Pmd)) { > + return NULL; > + } > + > + if (IS_HUGE_PAGE (Pmd->PmdVal)) { > + return ((PTE *)Pmd); > + } > + > + return PteOffset (Pmd, Address); > +} > +/** > + Establishes a page table entry based on the specified memory region. > + > + @param Pmd A pointer to the page middle directory. > + @param Address The memory space start address. > + @param End The end address of the memory space. > + @param Attributes Memory space Attributes. > + > + @retval EFI_SUCCESS The page table entry was created successfully. > + @retval EFI_OUT_OF_RESOURCES Page table entry establishment failed due to resource exhaustion. > +**/ > +EFI_STATUS > +MemoryMapPteRange ( > + IN PMD *Pmd, > + IN UINTN Address, > + IN UINTN End, > + IN UINTN Attributes > + ) > +{ > + PTE *Pte; > + PTE PteVal; > + BOOLEAN UpDate; > + > + Pte = PteAllocGet (Pmd, Address); > + if (!Pte) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + do { > + UpDate = FALSE; > + PteVal = MAKE_PTE (Address, Attributes); > + DEBUG ((DEBUG_VERBOSE, > + "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p PTE_INDEX %p MAKE_PTE %p\n", > + __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address), > + PTE_INDEX (Address), PteVal)); > + > + if ((!pte_none (*Pte)) && > + (PTE_VAL(*Pte) != PTE_VAL(PteVal))) > + { > + UpDate = TRUE; > + } > + > + SetPte (Pte, PteVal); > + if (UpDate) { > + UpdateTlb (Address, Pte); > + } > + } while (Pte++, Address += EFI_PAGE_SIZE, Address != End); > + > + return EFI_SUCCESS; > +} > +/** > + Establishes a page middle directory based on the specified memory region. > + > + @param Pud A pointer to the page upper directory. > + @param Address The memory space start address. > + @param End The end address of the memory space. > + @param Attributes Memory space Attributes. > + > + @retval EFI_SUCCESS The page middle directory was created successfully. > + @retval EFI_OUT_OF_RESOURCES Page middle directory establishment failed due to resource exhaustion. > +**/ > +EFI_STATUS > +MemoryMapPmdRange ( > + IN PUD *Pud, > + IN UINTN Address, > + IN UINTN End, > + IN UINTN Attributes > + ) > +{ > + PMD *Pmd; > + PTE *Pte; > + UINTN Next; > + UINTN AddressStart_HugePage; > + UINTN AddressEnd_HugePage; > + > + Pmd = PmdAllocGet (Pud, Address); > + if (!Pmd) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + do { > + Next = PMD_ADDRESS_END (Address, End); > + if (((Address & (~PMD_MASK)) == 0) && > + ((Next & (~PMD_MASK)) == 0) && > + (pmd_none (*Pmd))) > + { > + DEBUG ((DEBUG_VERBOSE, > + "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p MAKE_HUGE_PTE %p\n", > + __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address), > + MAKE_HUGE_PTE (Address, Attributes))); > + > + SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes)); > + } else { > + if ((pmd_none (*Pmd)) || > + ((!pmd_none (*Pmd)) && > + (!IS_HUGE_PAGE (Pmd->PmdVal)))) > + { > + if (MemoryMapPteRange (Pmd, Address, Next, Attributes)) { > + return EFI_OUT_OF_RESOURCES; > + } > + } else { > + SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte)); > + AddressStart_HugePage = Address & PMD_MASK; > + AddressEnd_HugePage = AddressStart_HugePage + HUGE_PAGE_SIZE; > + if (MemoryMapPteRange (Pmd, AddressStart_HugePage, AddressEnd_HugePage, Attributes)) { > + return EFI_OUT_OF_RESOURCES; > + } > + Pte = GetPteAddress (AddressStart_HugePage); > + if (Pte == NULL) { > + continue ; > + } > + UpdateTlb (AddressStart_HugePage, Pte); > + if (AddressEnd_HugePage > End) { > + Next = End; > + } > + } > + } > + } while (Pmd++, Address = Next, Address != End); > + > + return 0; > +} > +/** > + Establishes a page upper directory based on the specified memory region. > + > + @param Pgd A pointer to the page global directory. > + @param Address The memory space start address. > + @param End The end address of the memory space. > + @param Attributes Memory space Attributes. > + > + @retval EFI_SUCCESS The page upper directory was created successfully. > + @retval EFI_OUT_OF_RESOURCES Page upper directory establishment failed due to resource exhaustion. > +**/ > +EFI_STATUS > +MemoryMapPudRange ( > + IN PGD *Pgd, > + IN UINTN Address, > + IN UINTN End, > + IN UINTN Attributes > + ) > +{ > + PUD *Pud; > + UINTN Next; > + > + Pud = PudAllocGet (Pgd, Address); > + if (!Pud) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + do { > + Next = PUD_ADDRESS_END (Address, End); > + if (MemoryMapPmdRange (Pud, Address, Next, Attributes)) { > + return EFI_OUT_OF_RESOURCES; > + } > + } while (Pud++, Address = Next, Address != End); > + return EFI_SUCCESS; > +} > +/** > + Establishes a page global directory based on the specified memory region. > + > + @param Start The memory space start address. > + @param End The end address of the memory space. > + @param Attributes Memory space Attributes. > + > + @retval EFI_SUCCESS The page global directory was created successfully. > + @retval EFI_OUT_OF_RESOURCES Page global directory establishment failed due to resource exhaustion. > +**/ > +EFI_STATUS > +MemoryMapPageRange ( > + IN UINTN Start, > + IN UINTN End, > + IN UINTN Attributes > + ) > +{ > + PGD *Pgd; > + UINTN Next; > + UINTN Address = Start; > + EFI_STATUS Err; > + > + Pgd = PgdOffset (Address); > + do { > + Next = PGD_ADDRESS_END (Address, End); > + Err = MemoryMapPudRange (Pgd, Address, Next, Attributes); > + if (Err) { > + return Err; > + } > + } while (Pgd++, Address = Next, Address != End); > + > + return EFI_SUCCESS; > +} > + > +/** > + Page tables are established from memory-mapped tables. > + > + @param MemoryRegion A pointer to a memory-mapped table entry. > + > + @retval EFI_SUCCESS The page table was created successfully. > + @retval EFI_OUT_OF_RESOURCES Page table establishment failed due to resource exhaustion. > +**/ > +EFI_STATUS > +FillTranslationTable ( > + IN MEMORY_REGION_DESCRIPTOR *MemoryRegion > + ) > +{ > + return MemoryMapPageRange (MemoryRegion->VirtualBase, > + (MemoryRegion->Length + MemoryRegion->VirtualBase), > + MemoryRegion->Attributes); > +} > + > +/** > + write operation is performed Count times from the first element of Buffer. > +Convert EFI Attributes to Loongarch Attributes. > + @param[in] EfiAttributes Efi Attributes. > + > + @retval LoongArch Attributes. > +**/ > +UINTN > +EfiAttributeToLoongArchAttribute ( > + IN UINTN EfiAttributes > + ) > +{ > + UINTN LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | CACHE_CC | PAGE_USER; I just think that PAGE_KERNEL need be used here rather than PAGE_USER, it can only be accessed with kernel priviledge. > + switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) { > + case EFI_MEMORY_UC: > + LoongArchAttributes |= CACHE_SUC; > + break; > + case EFI_MEMORY_WC: > + case EFI_MEMORY_WT: > + case EFI_MEMORY_WB: > + LoongArchAttributes |= CACHE_CC; > + break; > + default : > + LoongArchAttributes |= CACHE_CC; > + break; > + } > + > + // Write protection attributes > + if ((EfiAttributes & EFI_MEMORY_RO) != 0) { > + LoongArchAttributes &= ~PAGE_DIRTY; > + } > + > + //eXecute protection attribute > + if ((EfiAttributes & EFI_MEMORY_XP) != 0) { > + LoongArchAttributes |= PAGE_NO_EXEC; > + } > + > + return LoongArchAttributes; > +} > + > +/** > + Finds the length and memory properties of the memory region corresponding to the specified base address. > + > + @param[in] BaseAddress To find the base address of the memory region. > + @param[in] EndAddress To find the end address of the memory region. > + @param[out] RegionLength The length of the memory region found. > + @param[out] RegionAttributes Properties of the memory region found. > + > + @retval EFI_SUCCESS The corresponding memory area was successfully found > + EFI_NOT_FOUND No memory area found > +**/ > +EFI_STATUS > +GetLoongArchMemoryRegion ( > + IN UINTN BaseAddress, > + IN UINTN EndAddress, > + OUT UINTN *RegionLength, > + OUT UINTN *RegionAttributes > + ) > +{ > + PTE *Pte; > + UINTN Attributes; > + UINTN AttributesTmp; > + UINTN MaxAddress; > + MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1; > + Pte = GetPteAddress (BaseAddress); > + > + if (!MmuIsInit ()) { > + return EFI_SUCCESS; > + } > + if (Pte == NULL) { > + return EFI_NOT_FOUND; > + } > + Attributes = GET_PAGE_ATTRIBUTES (*Pte); > + if (IS_HUGE_PAGE (Pte->PteVal)) { > + *RegionAttributes = Attributes & (~(PAGE_HUGE)); > + *RegionLength += HUGE_PAGE_SIZE; > + } else { > + *RegionLength += EFI_PAGE_SIZE; > + *RegionAttributes = Attributes; > + } > + > + while (BaseAddress <= MaxAddress) { > + Pte = GetPteAddress (BaseAddress); > + if (Pte == NULL) { > + return EFI_SUCCESS; > + } > + AttributesTmp = GET_PAGE_ATTRIBUTES (*Pte); > + if (IS_HUGE_PAGE (Pte->PteVal)) { > + if (AttributesTmp == Attributes) { > + *RegionLength += HUGE_PAGE_SIZE; > + } > + BaseAddress += HUGE_PAGE_SIZE; > + } else { > + if (AttributesTmp == Attributes) { > + *RegionLength += EFI_PAGE_SIZE; > + } > + BaseAddress += EFI_PAGE_SIZE; > + } > + > + if (BaseAddress > EndAddress) { > + break; > + } > + } > + return EFI_SUCCESS; > +} > + > +/** > + Sets the Attributes of the specified memory region > + > + @param[in] BaseAddress The base address of the memory region to set the Attributes. > + @param[in] Length The length of the memory region to set the Attributes. > + @param[in] Attributes The Attributes to be set. > + > + @retval EFI_SUCCESS The Attributes was set successfully > + > +**/ > +EFI_STATUS > +LoongArchSetMemoryAttributes ( > + IN EFI_PHYSICAL_ADDRESS BaseAddress, > + IN UINTN Length, > + IN UINTN Attributes > + ) > +{ > + > + if (!MmuIsInit ()) { > + return EFI_SUCCESS; > + } > + Attributes = EfiAttributeToLoongArchAttribute (Attributes); > + DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes)); > + MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes); > + > + return EFI_SUCCESS; > +} > + > +/** > + Sets the non-executable Attributes for the specified memory region > + > + @param[in] BaseAddress The base address of the memory region to set the Attributes. > + @param[in] Length The length of the memory region to set the Attributes. > + > + @retval EFI_SUCCESS The Attributes was set successfully > +**/ > +EFI_STATUS > +LoongArchSetMemoryRegionNoExec ( > + IN EFI_PHYSICAL_ADDRESS BaseAddress, > + IN UINTN Length > + ) > +{ > + if (MmuIsInit ()) { > + Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length)); > + LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP); > + } > + return EFI_SUCCESS; > +} > + > +/** > + Check to see if mmu successfully initializes and saves the result. > + > + @param VOID. > + > + @retval EFI_SUCCESS Initialization succeeded. > +**/ > +EFI_STATUS > +MmuInitialize (VOID) > +{ > + if (PcdGet64 (PcdSwapPageDir) != 0) { > + mMmuInited = TRUE; > + } > + > + return EFI_SUCCESS; > +} > diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h > new file mode 100644 > index 0000000000..e9f294b356 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h > @@ -0,0 +1,39 @@ > +/** @file > + > + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Glossary: > + - Dir - Directory > +**/ > +#ifndef MMU_LIB_CORE_H_ > +#define MMU_LIB_CORE_H_ > +/** > + Iterates through the page directory to initialize it. > + > + @param Dst A pointer to the directory of the page to initialize. > + @param Num The number of page directories to initialize. > + @param Src A pointer to the data used to initialize the page directory. > + > + @retval VOID. > +**/ > +VOID > +PageDirInit ( > + IN VOID *dest, > + IN UINTN Count, > + IN VOID *src > + ); > +/** > + Page tables are established from memory-mapped tables. > + > + @param MemoryRegion A pointer to a memory-mapped table entry. > + > + @retval EFI_SUCCESS The page table was created successfully. > + @retval EFI_OUT_OF_RESOURCES Page table establishment failed due to resource exhaustion. > +**/ > +EFI_STATUS > +FillTranslationTable ( > + IN MEMORY_REGION_DESCRIPTOR *MemoryRegion > + ); > +#endif > diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c > new file mode 100644 > index 0000000000..899f40fd94 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c > @@ -0,0 +1,236 @@ > +/** @file > + Platform PEI driver > + > + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Glossary: > + - FwCfg - Firmeware Config > + - Tlb - Translation Lookaside Buffer > +**/ > +#include > +#include > +#include > +#include > +#include > +#include "Library/Cpu.h" > +#include "pte.h" > +#include "page.h" > +#include "mmu.h" > +#include > +#include "MmuLibCore.h" > + > +/** > + Return the Virtual Memory Map of your platform > + > + This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU > + on your platform. > + > + @param[out] VirtualMemoryMap Array of MEMORY_REGION_DESCRIPTOR > + describing a Physical-to-Virtual Memory > + mapping. This array must be ended by a > + zero-filled entry. The allocated memory > + will not be freed. > + > +**/ > +VOID > +GetMemoryMapFromFwCfg ( > + OUT MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap > + ) > +{ > + > + EFI_STATUS Status; > + FIRMWARE_CONFIG_ITEM FwCfgItem; > + UINTN FwCfgSize; > + LOONGARCH_MEMMAP_ENTRY MemoryMapEntry; > + LOONGARCH_MEMMAP_ENTRY *StartEntry; > + LOONGARCH_MEMMAP_ENTRY *pEntry; > + UINTN Processed; > + MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable; > + UINTN Index = 0; > + ASSERT (VirtualMemoryMap != NULL); > + > + VirtualMemoryTable = AllocatePool ( > + sizeof (MEMORY_REGION_DESCRIPTOR) * > + MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS > + ); > + VirtualMemoryTable[Index].PhysicalBase = 0x10000000; > + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; > + VirtualMemoryTable[Index].Length = 0x80000000; > + VirtualMemoryTable[Index].Attributes = PAGE_VALID | PAGE_USER | CACHE_CC | PAGE_DIRTY; PAGE_KERNEL need be used here rather than PAGE_USER. And the memory space from 0x10000000 -- 0x80000000 is mmio space, it should be uncachable. CACHE_SUC should be used here. > + ++Index; > + > + Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status)); > + ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR)); > + *VirtualMemoryMap = VirtualMemoryTable; > + return ; > + } > + if (FwCfgSize % sizeof MemoryMapEntry != 0) { > + DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize)); > + } > + > + QemuFwCfgSelectItem (FwCfgItem); > + StartEntry = AllocatePages (EFI_SIZE_TO_PAGES (FwCfgSize)); > + QemuFwCfgReadBytes (FwCfgSize, StartEntry); > + for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) { > + pEntry = StartEntry + Processed; > + if (pEntry->Length == 0) { > + continue; > + } > + > + DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type)); > + VirtualMemoryTable[Index].PhysicalBase = pEntry->BaseAddr; > + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; > + VirtualMemoryTable[Index].Length = pEntry->Length; > + VirtualMemoryTable[Index].Attributes = PAGE_VALID | PAGE_USER | CACHE_CC | PAGE_DIRTY; > + ++Index; > + } > + > + FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize)); > + // End of Table > + ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR)); > + *VirtualMemoryMap = VirtualMemoryTable; > + return ; > +} > + > +/** > + Create a page table and initialize the MMU. > + > + @param[] VOID > + > + @retval VOID > +**/ > +EFIAPI > +VOID > +ConfigureMmu (VOID) > +{ > + PGD *SwapperPageDir = NULL; > + PGD *InvalidPgd = NULL; > + PUD *InvalidPudTable = NULL; > + PMD *InvalidPmdTable = NULL; > + PTE *InvalidPteTable = NULL; > + MEMORY_REGION_DESCRIPTOR *MemoryTable = NULL; > + RETURN_STATUS PcdStatus; > + UINTN PgdShift = PGD_SHIFT; > + UINTN PgdWide = PGD_WIDE; > + UINTN PudShift = PUD_SHIFT; > + UINTN PudWide = PUD_WIDE; > + UINTN PmdShift = PMD_SHIFT; > + UINTN PmdWide = PMD_WIDE; > + UINTN PteShift = PTE_SHIFT; > + UINTN PteWide = PTE_WIDE; > + UINTN PageEnable = 1 << 4; > + VOID *TlbReEntry; > + UINTN PageSize; > + > + SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE)); > + InvalidPgd = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE)); > + InvalidPudTable = AllocatePages (EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE)); > + InvalidPmdTable = AllocatePages (EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE)); > + InvalidPteTable = AllocatePages (EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE)); > + ZeroMem (InvalidPteTable, PTE_TABLE_SIZE); > + > + if ((!InvalidPgd) || > + (!InvalidPudTable) || > + (!InvalidPmdTable) || > + (!InvalidPteTable)) > + { > + goto FreeTranslationTable; > + } > + > + /*pgd init*/ > + PageDirInit (SwapperPageDir , ENTRYS_PER_PGD, InvalidPudTable); > + /*pgd init*/ > + PageDirInit (InvalidPgd, ENTRYS_PER_PGD, InvalidPudTable); > + /*pud init*/ > + PageDirInit (InvalidPudTable, ENTRYS_PER_PUD, InvalidPmdTable); > + /*pmd init*/ > + PageDirInit (InvalidPmdTable, ENTRYS_PER_PMD, InvalidPteTable); > + GetMemoryMapFromFwCfg (&MemoryTable); > + > + PcdStatus |= PcdSet64S (PcdSwapPageDir, (UINTN)SwapperPageDir); > + PcdStatus |= PcdSet64S (PcdInvalidPgd, (UINTN)InvalidPgd); > + PcdStatus |= PcdSet64S (PcdInvalidPud, (UINTN)InvalidPudTable); > + PcdStatus |= PcdSet64S (PcdInvalidPmd, (UINTN)InvalidPmdTable); > + PcdStatus |= PcdSet64S (PcdInvalidPte, (UINTN)InvalidPteTable); > + ASSERT_RETURN_ERROR (PcdStatus); > + > + while (MemoryTable->Length != 0) { > + DEBUG ((DEBUG_VERBOSE, "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", __func__, __LINE__, > + MemoryTable->VirtualBase, > + (MemoryTable->Length + MemoryTable->VirtualBase), > + MemoryTable->Attributes)); > + > + PcdStatus = FillTranslationTable (MemoryTable); > + if (EFI_ERROR (PcdStatus)) { > + goto FreeTranslationTable; > + } > + MemoryTable++; > + } > + > + /*set page size*/ > + WRITE_CSR_PAGE_SIZE (DEFAULT_PAGE_SIZE); > + WRITE_CSR_STLB_PAGE_SIZE (DEFAULT_PAGE_SIZE); > + WRITE_CSR_TLBREFILL_PAGE_SIZE (DEFAULT_PAGE_SIZE); > + READ_CSR_PAGE_SIZE (PageSize); > + if (PageSize != DEFAULT_PAGE_SIZE) { > + goto FreeTranslationTable; > + } > + > + TlbReEntry = AllocatePages (1); > + if (TlbReEntry == NULL) { > + goto FreeTranslationTable; > + } > + CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - HandleTlbRefill)); > + SET_REFILL_TLBBASE ((UINTN)HandleTlbRefill); > + > + DEBUG ((DEBUG_VERBOSE, > + "%a %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudWide %d PgdShift %d PgdWide %d.\n", > + __func__, __LINE__, > + PteShift, PteWide, PmdShift, PmdWide,PudShift, PudWide, PgdShift, PgdWide)); > + > + LOONGARCH_CSR_WRITEQ (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25, > + LOONGARCH_CSR_PWCTL0); > + LOONGARCH_CSR_WRITEQ (PgdShift | PgdWide << 6, LOONGARCH_CSR_PWCTL1); > + LOONGARCH_CSR_WRITEQ ((UINTN)SwapperPageDir, LOONGARCH_CSR_PGDL); > + LOONGARCH_CSR_WRITEQ ((UINTN)InvalidPgd, LOONGARCH_CSR_PGDH); > + > + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir)); > + LOONGARCH_CSR_XCHGQ ( PageEnable, 1 << 4, LOONGARCH_CSR_CRMD); > + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu End.\n", __func__, __LINE__)); > + > + return ; > + > +FreeTranslationTable: > + if (SwapperPageDir) { > + FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE)); > + } > + > + if (InvalidPgd) { > + FreePages (InvalidPgd, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE)); > + } > + > + if (InvalidPudTable) { > + FreePages (InvalidPudTable, EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE)); > + } > + > + if (InvalidPmdTable) { > + FreePages (InvalidPmdTable, EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE)); > + } > + > + if (InvalidPteTable) { > + FreePages (InvalidPteTable, EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE)); > + } > + > + PcdSet64S (PcdSwapPageDir, (UINTN)0); > + PcdSet64S (PcdInvalidPgd, (UINTN)0); > + PcdSet64S (PcdInvalidPud, (UINTN)0); > + PcdSet64S (PcdInvalidPmd, (UINTN)0); > + PcdSet64S (PcdInvalidPte, (UINTN)0); > + > + return ; > +} > + > diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h > new file mode 100644 > index 0000000000..50b785bb6e > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h > @@ -0,0 +1,104 @@ > +/** @file > + > + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Glossary: > + - Tlb or TLB - Translation Lookaside Buffer > + - CSR - Cpu State Register > + - PGDL - Page Global Directory Low > + - PGDH - Page Global Directory High > + - TLBIDX - TLB Index > + - TLBREHI - TLB Refill Entry High > + - PWCTL - Page Walk Control > + - STLB - Singular Page Size TLB > + - PS - Page Size > +**/ > +#ifndef MMU_H_ > +#define MMU_H_ > +/*page size 4k*/ > +#define DEFAULT_PAGE_SIZE 0x0c > +#define LOONGARCH_CSR_PGDL 0x19 /* Page table base address when VA[47] = 0 */ > +#define LOONGARCH_CSR_PGDH 0x1a /* Page table base address when VA[47] = 1 */ > +#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP */ > +#define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi */ > +#define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */ > +#define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */ > +#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */ > +#define LOONGARCH_CSR_PWCTL0 0x1c /* PWCtl0 */ > +#define LOONGARCH_CSR_PWCTL1 0x1d /* PWCtl1 */ > +#define LOONGARCH_CSR_STLBPGSIZE 0x1e > +#define CSR_TLBIDX_SIZE_MASK 0x3f000000 > +#define CSR_TLBIDX_PS_SHIFT 24 > +#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT > + > +/* > + Set Cpu Status Register STLB Page Size. > + > + @param val Page Size. > + > + @retval VOID > + */ > +#define WRITE_CSR_STLB_PAGE_SIZE(val) LOONGARCH_CSR_WRITEQ((val), LOONGARCH_CSR_STLBPGSIZE) > +/* > + Set Cpu Status Register Page Size. > + > + @param size Page Size. > + > + @retval VOID > + */ > +#define WRITE_CSR_PAGE_SIZE(size) LOONGARCH_CSR_XCHGQ((size) << CSR_TLBIDX_SIZE, CSR_TLBIDX_SIZE_MASK, LOONGARCH_CSR_TLBIDX) > +/* > + Set Cpu Status Register TLBREFILL Page Size. > + > + @param size Page Size. > + > + @retval VOID > + */ > +#define WRITE_CSR_TLBREFILL_PAGE_SIZE(size) LOONGARCH_CSR_XCHGQ((size) << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI) > +/* > + Set Cpu Status Register TLBREFILL Base Address. > + > + @param BaseAddress the code base address of TLB refills . > + > + @retval VOID > + */ > +#define SET_REFILL_TLBBASE(BaseAddress) LOONGARCH_CSR_WRITEQ((BaseAddress), LOONGARCH_CSR_TLBREBASE); > +/* > + Get Cpu Status Register Page Size. > + > + @param val Gets the page size. > + > + @retval VOID > + */ > +#define READ_CSR_PAGE_SIZE(val) \ > +{ \ > + LOONGARCH_CSR_READQ ((val), LOONGARCH_CSR_TLBIDX); \ > + (val) = ((val) & CSR_TLBIDX_SIZE_MASK) >> CSR_TLBIDX_SIZE; \ > +} > + > + > +#define CSR_TLBREHI_PS_SHIFT 0 > +#define CSR_TLBREHI_PS ((UINTN)(0x3f) << CSR_TLBREHI_PS_SHIFT) > + > +#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \ > + EFI_MEMORY_WC | \ > + EFI_MEMORY_WT | \ > + EFI_MEMORY_WB | \ > + EFI_MEMORY_UCE \ > + ) > + > + > +typedef struct { > + EFI_PHYSICAL_ADDRESS PhysicalBase; > + EFI_VIRTUAL_ADDRESS VirtualBase; > + UINTN Length; > + UINTN Attributes; > +} MEMORY_REGION_DESCRIPTOR; > + > +// The total number of descriptors, including the final "end-of-table" descriptor. > +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128) > + > +extern CHAR8 HandleTlbRefill[], HandleTlbRefillEnd[]; > +#endif > diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h > new file mode 100644 > index 0000000000..3b3b0b72c3 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h > @@ -0,0 +1,267 @@ > +/** @file > + > + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Glossary: > + - Pgd or Pgd or PGD - Page Global Directory > + - Pud or Pud or PUD - Page Upper Directory > + - Pmd or Pmd or PMD - Page Middle Directory > + - Pte or pte or PTE - Page Table Entry > + - Val or VAL or val - Value > + - Dir - Directory > +**/ > +#ifndef PAGE_H_ > +#define PAGE_H_ > + > +#define MAX_VA_BITS 47 > +#define PGD_WIDE (8) > +#define PUD_WIDE (9) > +#define PMD_WIDE (9) > +#define PTE_WIDE (9) > + > +#define ENTRYS_PER_PGD (1 << PGD_WIDE) > +#define ENTRYS_PER_PUD (1 << PUD_WIDE) > +#define ENTRYS_PER_PMD (1 << PMD_WIDE) > +#define ENTRYS_PER_PTE (1 << PTE_WIDE) > + > +#define PGD_SHIFT (PUD_SHIFT + PUD_WIDE) > +#define PUD_SHIFT (PMD_SHIFT + PMD_WIDE) > +#define PMD_SHIFT (EFI_PAGE_SHIFT + PTE_WIDE) > +#define PTE_SHIFT (EFI_PAGE_SHIFT) > + > +#define PGD_SIZE (1UL << PGD_SHIFT) > +#define PUD_SIZE (1UL << PUD_SHIFT) > +#define PMD_SIZE (1UL << PMD_SHIFT) > + > +#define PGD_MASK (~(PGD_SIZE-1)) > +#define PUD_MASK (~(PUD_SIZE-1)) > +#define PMD_MASK (~(PMD_SIZE-1)) > +#define PAGE_MASK (~(EFI_PAGE_SIZE - 1)) > +#define PFN_MASK (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \ > + (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1)) > + > +typedef struct { UINTN PgdVal; } PGD; > +typedef struct { UINTN PudVal; } PUD; > +typedef struct { UINTN PmdVal; } PMD; > +typedef struct { UINTN PteVal; } PTE; > +/** > + Gets the value of the page global directory table entry. > + > + @param x Page global directory struct variables. > + > + @retval the value of the page global directory table entry. > + **/ > +#define PGD_VAL(x) ((x).PgdVal) > +/** > + Gets the value of the page upper directory table entry. > + > + @param x Page upper directory struct variables. > + > + @retval the value of the page upper directory table entry. > + **/ > +#define PUD_VAL(x) ((x).PudVal) > +/** > + Gets the value of the page middle directory table entry. > + > + @param x Page middle directory struct variables. > + > + @retval the value of the page middle directory table entry. > + **/ > +#define PMD_VAL(x) ((x).PmdVal) > +/** > + Gets the value of the page table entry. > + > + @param x Page table entry struct variables. > + > + @retval the value of the page table entry. > + **/ > +#define PTE_VAL(x) ((x).PteVal) > + > + > +#define PGD_TABLE_SIZE (ENTRYS_PER_PGD * sizeof(PGD)) > +#define PUD_TABLE_SIZE (ENTRYS_PER_PUD * sizeof(PUD)) > +#define PMD_TABLE_SIZE (ENTRYS_PER_PMD * sizeof(PMD)) > +#define PTE_TABLE_SIZE (ENTRYS_PER_PTE * sizeof(PTE)) > +/** > + Gets the physical address of the record in the page table entry. > + > + @param x Page table entry struct variables. > + > + @retval the value of the physical address. > + **/ > +#define GET_PAGE_ATTRIBUTES(x) (UINTN) {(PTE_VAL(x) & ~PFN_MASK)} > +/** > + Gets the virtual address of the next block of the specified virtual address > + that is aligned with the size of the global page directory mapping. > + > + @param Address Specifies the virtual address. > + @param End The end address of the memory region. > + > + @retval the specified virtual address of the next block. > + **/ > +#define PGD_ADDRESS_END(Address, End) \ > +({ UINTN Boundary = ((Address) + PGD_SIZE) & PGD_MASK; \ > + (Boundary - 1 < (End) - 1)? Boundary: (End); \ > +}) > +/** > + Gets the virtual address of the next block of the specified virtual address > + that is aligned with the size of the page upper directory mapping. > + > + @param Address Specifies the virtual address. > + @param End The end address of the memory region. > + > + @retval the specified virtual address of the next block. > + **/ > +#define PUD_ADDRESS_END(Address, End) \ > +({ UINTN Boundary = ((Address) + PUD_SIZE) & PUD_MASK; \ > + (Boundary - 1 < (End) - 1)? Boundary: (End); \ > +}) > +/** > + Gets the virtual address of the next block of the specified virtual address > + that is aligned with the size of the page middle directory mapping. > + > + @param Address Specifies the virtual address. > + @param End The end address of the memory region. > + > + @retval the specified virtual address of the next block. > + **/ > +#define PMD_ADDRESS_END(Address, End) \ > +({ UINTN Boundary = ((Address) + PMD_SIZE) & PMD_MASK; \ > + (Boundary - 1 < (End) - 1)? Boundary: (End); \ > +}) > +/** > + Get Specifies the virtual address corresponding to the index of the page global directory table entry. > + > + @param Address Specifies the virtual address. > + > + @retval the index of the page global directory table entry. > + **/ > +#define PGD_INDEX(Address) (((Address) >> PGD_SHIFT) & (ENTRYS_PER_PGD-1)) > +/** > + Get Specifies the virtual address corresponding to the index of the page upper directory table entry. > + > + @param Address Specifies the virtual address. > + @param End The end address of the memory region. > + > + @retval the index of the page upper directory table entry. > + **/ > +#define PUD_INDEX(Address) (((Address) >> PUD_SHIFT) & (ENTRYS_PER_PUD - 1)) > +/** > + Get Specifies the virtual address corresponding to the index of the page middle directory table entry. > + > + @param Address Specifies the virtual address. > + > + @retval the index of the page middle directory table entry. > + **/ > +#define PMD_INDEX(Address) (((Address) >> PMD_SHIFT) & (ENTRYS_PER_PMD - 1)) > +/** > + Get Specifies the virtual address corresponding to the index of the page table entry. > + > + @param Address Specifies the virtual address. > + > + @retval the index of the page table entry. > + **/ > +#define PTE_INDEX(Address) (((Address) >> EFI_PAGE_SHIFT) & (ENTRYS_PER_PTE - 1)) > + > +/** > + Calculates the value of the page table entry based on the specified virtual address and properties. > + > + @param Address Specifies the virtual address. > + @param Attributes Specifies the Attributes. > + > + @retval the value of the page table entry. > + **/ > +#define MAKE_PTE(Address, Attributes) (PTE){((((Address) >> EFI_PAGE_SHIFT) << 12) | (Attributes))} > +/** > + Calculates the value of the Huge page table entry based on the specified virtual address and properties. > + > + @param Address Specifies the virtual address. > + @param Attributes Specifies the Attributes. > + > + @retval the value of the HUGE page table entry. > + **/ > +#define MAKE_HUGE_PTE(Address, Attributes) (((((Address) >> PMD_SHIFT) << PMD_SHIFT) | ((Attributes) | PAGE_HUGE))) > + /** > + Check whether the large page table entry is. > + > + @param Val The value of the page table entry. > + > + @retval 1 Is huge page table entry. > + @retval 0 Isn't huge page table entry. > + **/ > +#define IS_HUGE_PAGE(Val) (((Val) & PAGE_HUGE) == PAGE_HUGE) > +#define HUGE_PAGE_SIZE (PMD_SIZE) > + > + /** > + Check that the global page directory table entry is empty. > + > + @param pgd the global page directory struct variables. > + > + @retval 1 Is huge page table entry. > + @retval 0 Isn't huge page table entry. > + **/ > +STATIC > +inline > +UINTN > +pgd_none ( > + IN PGD pgd > + ) > +{ > + return (PGD_VAL(pgd) == (UINTN)PcdGet64(PcdInvalidPud)); > +} > + > + /** > + Check that the page upper directory table entry is empty. > + > + @param pud Page upper directory struct variables. > + > + @retval 1 Is huge page table entry. > + @retval 0 Isn't huge page table entry. > + **/ > +STATIC > +inline > +UINTN > +pud_none ( > + IN PUD pud > + ) > +{ > + return (PUD_VAL(pud) == (UINTN)PcdGet64 (PcdInvalidPmd)); > +} > + > + /** > + Check that the page middle directory table entry is empty. > + > + @param pmd Page middle directory struct variables. > + > + @retval 1 Is huge page table entry. > + @retval 0 Isn't huge page table entry. > + **/ > +STATIC > +inline > +UINTN > +pmd_none ( > + IN PMD pmd > + ) > +{ > + return (PMD_VAL(pmd) == (UINTN)PcdGet64(PcdInvalidPte)); > +} > + /** > + Check that the page table entry is empty. > + > + @param pmd Page table entry struct variables. > + > + @retval 1 Is huge page table entry. > + @retval 0 Isn't huge page table entry. > + **/ > +STATIC > +inline > +UINTN > +pte_none ( > + IN PTE pte > + ) > +{ > + return (!(PTE_VAL(pte) & (~PAGE_GLOBAL))); PAGE_VALID represents the tlb is valid, PAGE_GLOBAL represents tlb entry is valid for all asid processes. how about using PAGE_VALID bit rather than PAGE_GLOBAL: return (!(PTE_VAL(pte) & PAGE_VALID)); > +} > +#endif > diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h > new file mode 100644 > index 0000000000..d6ac74f9c9 > --- /dev/null > +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h > @@ -0,0 +1,57 @@ > +/** @file > + > + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.
> + > + 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