Hi Ray, Can you please help to review this patch again? Thanks, Chao On 2024/1/26 14:29, Chao Li wrote: > Add a new library named CpuMmuLib and add a LoongArch64 instance with in > the library. > It provides two-stage MMU libraryinstances, PEI and DXE. > > BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584 > > Cc: Eric Dong > Cc: Ray Ni > Cc: Laszlo Ersek > Cc: Rahul Kumar > Cc: Gerd Hoffmann > Signed-off-by: Chao Li > Co-authored-by: Baoqi Zhang > Co-authored-by: Dongyan Qian > Co-authored-by: Xianglai Li > Co-authored-by: Bibo Mao > --- > UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.inf | 36 + > UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.uni | 14 + > .../CpuMmuLib/LoongArch64/CommonMmuLib.c | 988 ++++++++++++++++++ > .../CpuMmuLib/LoongArch64/CommonMmuLib.h | 43 + > .../Library/CpuMmuLib/LoongArch64/Page.h | 279 +++++ > .../CpuMmuLib/LoongArch64/PeiCpuMmuLib.c | 178 ++++ > .../Library/CpuMmuLib/LoongArch64/Tlb.h | 48 + > .../CpuMmuLib/LoongArch64/TlbOperation.S | 44 + > UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.inf | 44 + > UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.uni | 14 + > UefiCpuPkg/UefiCpuPkg.dsc | 4 + > 11 files changed, 1692 insertions(+) > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.inf > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.uni > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.c > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.h > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/PeiCpuMmuLib.c > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Tlb.h > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbOperation.S > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.inf > create mode 100644 UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.uni > > diff --git a/UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.inf b/UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.inf > new file mode 100644 > index 0000000000..bfce3ce96d > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.inf > @@ -0,0 +1,36 @@ > +## @file > +# CPU Memory Map Unit DXE phase driver. > +# > +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 1.29 > + BASE_NAME = DxeCpuMmuLib > + MODULE_UNI_FILE = DxeCpuMmuLib.uni > + FILE_GUID = DA8F0232-FB14-42F0-922C-63104D2C70BE > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = CpuMmuLib | DXE_DRIVER > + CONSTRUCTOR = MmuInitialize > + > +# > +# VALID_ARCHITECTURES = LOONGARCH64 > +# > + > +[Sources.LoongArch64] > + LoongArch64/TlbOperation.S | GCC > + LoongArch64/CommonMmuLib.c > + LoongArch64/Page.h > + LoongArch64/Tlb.h > + > +[Packages] > + MdePkg/MdePkg.dec > + UefiCpuPkg/UefiCpuPkg.dec > + > +[LibraryClasses] > + DebugLib > + MemoryAllocationLib > diff --git a/UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.uni b/UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.uni > new file mode 100644 > index 0000000000..7342249516 > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.uni > @@ -0,0 +1,14 @@ > +// /** @file > +// CPU Memory Manager Unit library instance for DXE modules. > +// > +// CPU Memory Manager Unit library instance for DXE modules. > +// > +// Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
> +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for DXE modules." > + > +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for DXE modules." > diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.c b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.c > new file mode 100644 > index 0000000000..2e852c3371 > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.c > @@ -0,0 +1,988 @@ > +/** @file > + > + CPU Memory Map Unit Handler Library common functions. > + > + Copyright (c) 2024 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 > +#include > +#include "Tlb.h" > +#include "Page.h" > + > +#define SWAP_PAGE_DIR CsrRead(LOONGARCH_CSR_PGDL) > +#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \ > + EFI_MEMORY_WC | \ > + EFI_MEMORY_WT | \ > + EFI_MEMORY_WB | \ > + EFI_MEMORY_UCE \ > + ) > + > +BOOLEAN mMmuInited = FALSE; > + > +/** > + Check to see if mmu successfully initializes. > + > + @param VOID. > + > + @retval TRUE Initialization has been completed. > + FALSE Initialization did not complete. > +**/ > +STATIC > +BOOLEAN > +MmuIsInit ( > + VOID > + ) > +{ > + if (mMmuInited || (SWAP_PAGE_DIR != 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. > + > + @return VOID. > +**/ > +STATIC > +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. > +**/ > +STATIC > +PGD * > +PgdOffset ( > + IN UINTN Address > + ) > +{ > + return (PGD *)(SWAP_PAGE_DIR) + 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. > +**/ > +STATIC > +PUD * > +PudOffset ( > + IN PGD *Pgd, > + IN UINTN Address > + ) > +{ > + UINTN PgdVal; > + > + 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. > +**/ > +STATIC > +PMD * > +PmdOffset ( > + IN PUD *Pud, > + IN UINTN Address > + ) > +{ > + UINTN PudVal; > + > + 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. > +**/ > +STATIC > +PTE * > +PteOffset ( > + IN PMD *Pmd, > + IN UINTN Address > + ) > +{ > + UINTN PmdVal; > + > + 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. > + > +**/ > +STATIC > +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. > + > +**/ > +STATIC > +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. > + > +**/ > +STATIC > +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. > + > +**/ > +STATIC > +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. > + > +**/ > +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. > + > +**/ > +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. > + > +**/ > +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. > +**/ > +STATIC > +EFI_STATUS > +PudAlloc ( > + IN PGD *Pgd > + ) > +{ > + PUD *Pud; > + > + Pud = (PUD *)AllocatePages (1); > + if (Pud == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)INVALID_PAGE); > + > + SetPgd (Pgd, 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. > +**/ > +STATIC > +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 *)INVALID_PAGE); > + > + SetPud (Pud, 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. > +**/ > +STATIC > +EFI_STATUS > +PteAlloc ( > + IN PMD *Pmd > + ) > +{ > + PTE *Pte; > + > + Pte = (PTE *)AllocatePages (1); > + if (!Pte) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Pte = ZeroMem (Pte, EFI_PAGE_SIZE); > + > + SetPmd (Pmd, 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. > + @param Address The corresponding virtual address of the page table entry. > + > + @retval A pointer to the page upper directory entry. Return NULL, if > + allocate the memory buffer is fail. > +**/ > +STATIC > +PUD * > +PudAllocGet ( > + IN PGD *Pgd, > + IN UINTN Address > + ) > +{ > + EFI_STATUS Status; > + > + if (PGD_IS_EMPTY (*Pgd)) { > + Status = PudAlloc (Pgd); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return NULL; > + } > + } > + > + return 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. > + @param Address The corresponding virtual address of the page table entry. > + > + @retval A pointer to the page middle directory entry. Return NULL, if > + allocate the memory buffer is fail. > +**/ > +STATIC > +PMD * > +PmdAllocGet ( > + IN PUD *Pud, > + IN UINTN Address > + ) > +{ > + EFI_STATUS Status; > + > + if (PUD_IS_EMPTY (*Pud)) { > + Status = PmdAlloc (Pud); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return NULL; > + } > + } > + > + return PmdOffset (Pud, Address); > +} > + > +/** > + 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. > + @param Address The corresponding virtual address of the page table entry. > + > + @retval A pointer to the page table entry. Return NULL, if allocate > + the memory buffer is fail. > +**/ > +STATIC > +PTE * > +PteAllocGet ( > + IN PMD *Pmd, > + IN UINTN Address > + ) > +{ > + EFI_STATUS Status; > + > + if (PMD_IS_EMPTY (*Pmd)) { > + Status = PteAlloc (Pmd); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return NULL; > + } > + } > + > + return PteOffset (Pmd, Address); > +} > + > +/** > + Gets the physical address of the page table entry corresponding to the specified virtual address. > + > + @param Address The corresponding virtual address of the page table entry. > + > + @retval A pointer to the page table entry. > + @retval NULL > +**/ > +STATIC > +PTE * > +GetPteAddress ( > + IN UINTN Address > + ) > +{ > + PGD *Pgd; > + PUD *Pud; > + PMD *Pmd; > + > + Pgd = PgdOffset (Address); > + > + if (PGD_IS_EMPTY (*Pgd)) { > + return NULL; > + } > + > + Pud = PudOffset (Pgd, Address); > + > + if (PUD_IS_EMPTY (*Pud)) { > + return NULL; > + } > + > + Pmd = PmdOffset (Pud, Address); > + if (PMD_IS_EMPTY (*Pmd)) { > + return NULL; > + } > + > + if (IS_HUGE_PAGE (Pmd->PmdVal)) { > + return ((PTE *)Pmd); > + } > + > + return PteOffset (Pmd, Address); > +} > + > +/** > + Gets the Attributes of Huge Page. > + > + @param Pmd A pointer to the page middle directory. > + > + @retval Value of Attributes. > +**/ > +STATIC > +UINTN > +GetHugePageAttributes ( > + IN PMD *Pmd > + ) > +{ > + UINTN Attributes; > + UINTN GlobalFlag; > + UINTN HugeVal; > + > + HugeVal = PMD_VAL (*Pmd); > + Attributes = HugeVal & (~HUGEP_PAGE_MASK); > + GlobalFlag = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT; > + Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT); > + Attributes |= GlobalFlag; > + return Attributes; > +} > + > +/** > + 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. > +**/ > +STATIC > +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; > + } > + > + DEBUG (( > + DEBUG_INFO, > + "%a %d Address %p End %p Attributes %llx\n", > + __func__, > + __LINE__, > + Address, > + End, > + Attributes > + )); > + > + do { > + UpDate = FALSE; > + PteVal = MAKE_PTE (Address, Attributes); > + > + if ((!PTE_IS_EMPTY (*Pte)) && > + (PTE_VAL (*Pte) != PTE_VAL (PteVal))) > + { > + UpDate = TRUE; > + } > + > + SetPte (Pte, PteVal); > + if (UpDate) { > + InvalidTlb (Address); > + } > + } while (Pte++, Address += EFI_PAGE_SIZE, Address != End); > + > + return EFI_SUCCESS; > +} > + > +/** > + Convert Huge Page to Page. > + > + @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. > +**/ > +STATIC > +EFI_STATUS > +ConvertHugePageToPage ( > + IN PMD *Pmd, > + IN UINTN Address, > + IN UINTN End, > + IN UINTN Attributes > + ) > +{ > + UINTN OldAttributes; > + UINTN HugePageEnd; > + UINTN HugePageStart; > + EFI_STATUS Status; > + > + Status = EFI_SUCCESS; > + > + if ((PMD_IS_EMPTY (*Pmd)) || > + (!IS_HUGE_PAGE (Pmd->PmdVal))) > + { > + Status |= MemoryMapPteRange (Pmd, Address, End, Attributes); > + } else { > + OldAttributes = GetHugePageAttributes (Pmd); > + if (Attributes == OldAttributes) { > + return Status; > + } > + > + SetPmd (Pmd, (PTE *)(INVALID_PAGE)); > + HugePageStart = Address & PMD_MASK; > + HugePageEnd = HugePageStart + HUGE_PAGE_SIZE; > + ASSERT (HugePageEnd >= End); > + > + if (Address > HugePageStart) { > + Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes); > + } > + > + Status |= MemoryMapPteRange (Pmd, Address, End, Attributes); > + > + if (End < HugePageEnd) { > + Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes); > + } > + } > + > + return Status; > +} > + > +/** > + 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. > +**/ > +STATIC > +EFI_STATUS > +MemoryMapPmdRange ( > + IN PUD *Pud, > + IN UINTN Address, > + IN UINTN End, > + IN UINTN Attributes > + ) > +{ > + PMD *Pmd; > + UINTN Next; > + PTE PteVal; > + BOOLEAN UpDate; > + > + Pmd = PmdAllocGet (Pud, Address); > + if (Pmd == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + do { > + Next = PMD_ADDRESS_END (Address, End); > + if (((Address & (~PMD_MASK)) == 0) && > + ((Next & (~PMD_MASK)) == 0) && > + (PMD_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal))) > + { > + UpDate = FALSE; > + PteVal = MAKE_HUGE_PTE (Address, Attributes); > + > + if ((!PMD_IS_EMPTY (*Pmd)) && > + (PMD_VAL (*Pmd) != PTE_VAL (PteVal))) > + { > + UpDate = TRUE; > + } > + > + SetPmd (Pmd, (PTE *)PteVal.PteVal); > + if (UpDate) { > + InvalidTlb (Address); > + } > + } else { > + ConvertHugePageToPage (Pmd, Address, Next, Attributes); > + } > + } while (Pmd++, Address = Next, Address != End); > + > + return EFI_SUCCESS; > +} > + > +/** > + 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. > +**/ > +STATIC > +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 == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + do { > + Next = PUD_ADDRESS_END (Address, End); > + if (EFI_ERROR (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. > +**/ > +STATIC > +EFI_STATUS > +MemoryMapPageRange ( > + IN UINTN Start, > + IN UINTN End, > + IN UINTN Attributes > + ) > +{ > + PGD *Pgd; > + UINTN Next; > + UINTN Address; > + EFI_STATUS Err; > + > + Address = Start; > + > + /* Get PGD(PTE PMD PUD PGD) in PageTables */ > + Pgd = PgdOffset (Address); > + do { > + Next = PGD_ADDRESS_END (Address, End); > + /* Get Next Align Page to Map */ > + 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 > + ); > +} > + > +/** > + Convert EFI Attributes to Loongarch Attributes. > + > + @param[in] EfiAttributes Efi Attributes. > + > + @retval Corresponding architecture attributes. > +**/ > +UINTN > +EFIAPI > +EfiAttributeConverse ( > + IN UINTN EfiAttributes > + ) > +{ > + UINTN LoongArchAttributes; > + > + LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | PAGE_GLOBAL; > + > + switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) { > + case EFI_MEMORY_UC: > + LoongArchAttributes |= CACHE_SUC; > + break; > + case EFI_MEMORY_WC: > + LoongArchAttributes |= CACHE_WUC; > + break; > + 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) || > + ((EfiAttributes & EFI_MEMORY_WP) != 0)) > + { > + LoongArchAttributes &= ~PAGE_DIRTY; > + } > + > + if ((EfiAttributes & EFI_MEMORY_RP) != 0) { > + LoongArchAttributes |= PAGE_NO_READ; > + } > + > + // eXecute protection attribute > + if ((EfiAttributes & EFI_MEMORY_XP) != 0) { > + LoongArchAttributes |= PAGE_NO_EXEC; > + } > + > + return LoongArchAttributes; > +} > + > +/** > + Finds the first of 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, out] RegionLength Pointer holding: > + - At entry, the length of the memory region > + expected to be found. > + - At exit, 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_OUT_OF_RESOURCES Base address or expected memory region exceeds the maximum > + address. > +**/ > +EFI_STATUS > +EFIAPI > +GetMemoryRegionAttributes ( > + IN UINTN BaseAddress, > + IN OUT UINTN *RegionLength, > + OUT UINTN *RegionAttributes > + ) > +{ > + PTE *Pte; > + UINTN Attributes; > + UINTN AttributesTmp; > + UINTN MaxAddress; > + UINTN EndAddress; > + UINTN AddSize; > + > + if (!MmuIsInit ()) { > + return EFI_UNSUPPORTED; > + } > + > + EndAddress = BaseAddress + *RegionLength; > + MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1; > + > + // Clean the value to prepare output to find region size. > + *RegionLength = 0x0; > + > + if ((BaseAddress >= MaxAddress) || (EndAddress >= MaxAddress)) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Pte = GetPteAddress (BaseAddress); > + > + if (Pte == NULL) { > + return EFI_NOT_FOUND; > + } > + > + Attributes = GET_PAGE_ATTRIBUTES (*Pte); > + if (IS_HUGE_PAGE (Pte->PteVal)) { > + *RegionAttributes = Attributes & (~(PAGE_HUGE)); > + } else { > + *RegionAttributes = Attributes; > + } > + > + do { > + Pte = GetPteAddress (BaseAddress); > + if (Pte == NULL) { > + return EFI_SUCCESS; > + } > + > + AttributesTmp = GET_PAGE_ATTRIBUTES (*Pte); > + if (AttributesTmp == Attributes) { > + if (IS_HUGE_PAGE (Pte->PteVal)) { > + AddSize = HUGE_PAGE_SIZE; > + } else { > + AddSize = EFI_PAGE_SIZE; > + } > + > + *RegionLength += AddSize; > + BaseAddress += AddSize; > + } else { > + return EFI_SUCCESS; > + } > + } while (BaseAddress <= EndAddress); > + > + 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. > + @param[in] AttributeMask Mask of memory attributes to take into account. > + > + @retval EFI_SUCCESS The Attributes was set successfully > +**/ > +EFI_STATUS > +EFIAPI > +SetMemoryRegionAttributes ( > + IN EFI_PHYSICAL_ADDRESS BaseAddress, > + IN UINTN Length, > + IN UINTN Attributes, > + IN UINT64 AttributeMask > + ) > +{ > + EFI_STATUS Status; > + > + if (!MmuIsInit ()) { > + return EFI_UNSUPPORTED; > + } > + > + Attributes = EfiAttributeConverse (Attributes); > + Status = MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > + > +/** > + Check to see if mmu successfully initializes and saves the result. > + > + @param[in] ImageHandle The firmware allocated handle for the EFI image. > + @param[in] SystemTable A pointer to the EFI System Table. > + > + @retval RETURN_SUCCESS Initialization succeeded. > +**/ > +RETURN_STATUS > +MmuInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + if (SWAP_PAGE_DIR != 0) { > + mMmuInited = TRUE; > + } > + > + return RETURN_SUCCESS; > +} > diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.h b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.h > new file mode 100644 > index 0000000000..d8c922c8fa > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.h > @@ -0,0 +1,43 @@ > +/** @file > + > + Copyright (c) 2024 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 // MMU_LIB_CORE_H_ > diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h > new file mode 100644 > index 0000000000..bac4f52327 > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h > @@ -0,0 +1,279 @@ > +/** @file > + > + Copyright (c) 2024 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_ > + > +#include > + > +#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)) > + > +#define HUGEP_PAGE_MASK (~(((UINTN)(1) << (PMD_SHIFT)) - 1) & \ > + (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1)) > + > +#define INVALID_PAGE 0 > + > +typedef struct { > + UINTN PgdVal; > +} PGD; > +typedef struct { > + UINTN PudVal; > +} PUD; > +typedef struct { > + UINTN PmdVal; > +} PMD; > +typedef struct { > + UINTN PteVal; > +} PTE; > + > +/** > + Gets the value of the page global directory table entry. > + > + @param x Page global directory struct variables. > + > + @retval the value of the page global directory table entry. > + **/ > +#define PGD_VAL(x) ((x).PgdVal) > + > +/** > + Gets the value of the page upper directory table entry. > + > + @param x Page upper directory struct variables. > + > + @retval the value of the page upper directory table entry. > + **/ > +#define PUD_VAL(x) ((x).PudVal) > + > +/** > + Gets the value of the page middle directory table entry. > + > + @param x Page middle directory struct variables. > + > + @retval the value of the page middle directory table entry. > + **/ > +#define PMD_VAL(x) ((x).PmdVal) > + > +/** > + Gets the value of the page table entry. > + > + @param x Page table entry struct variables. > + > + @retval the value of the page table entry. > + **/ > +#define PTE_VAL(x) ((x).PteVal) > + > +#define PGD_TABLE_SIZE (ENTRYS_PER_PGD * sizeof(PGD)) > +#define PUD_TABLE_SIZE (ENTRYS_PER_PUD * sizeof(PUD)) > +#define PMD_TABLE_SIZE (ENTRYS_PER_PMD * sizeof(PMD)) > +#define PTE_TABLE_SIZE (ENTRYS_PER_PTE * sizeof(PTE)) > + > +/** > + Gets the physical address of the record in the page table entry. > + > + @param x Page table entry struct variables. > + > + @retval the value of the physical address. > + **/ > +#define GET_PAGE_ATTRIBUTES(x) (UINTN) {(PTE_VAL(x) & ~PFN_MASK)} > + > +/** > + Gets the virtual address of the next block of the specified virtual address > + that is aligned with the size of the global page directory mapping. > + > + @param Address Specifies the virtual address. > + @param End The end address of the memory region. > + > + @retval the specified virtual address of the next block. > + **/ > +#define PGD_ADDRESS_END(Address, End) \ > +({ \ > + UINTN Boundary = ((Address) + PGD_SIZE) & PGD_MASK; \ > + (Boundary - 1 < (End) - 1)? Boundary: (End); \ > +}) > + > +/** > + Gets the virtual address of the next block of the specified virtual address > + that is aligned with the size of the page upper directory mapping. > + > + @param Address Specifies the virtual address. > + @param End The end address of the memory region. > + > + @retval the specified virtual address of the next block. > + **/ > +#define PUD_ADDRESS_END(Address, End) \ > +({ \ > + UINTN Boundary = ((Address) + PUD_SIZE) & PUD_MASK; \ > + (Boundary - 1 < (End) - 1)? Boundary: (End); \ > +}) > + > +/** > + Gets the virtual address of the next block of the specified virtual address > + that is aligned with the size of the page middle directory mapping. > + > + @param Address Specifies the virtual address. > + @param End The end address of the memory region. > + > + @retval the specified virtual address of the next block. > + **/ > +#define PMD_ADDRESS_END(Address, End) \ > +({ \ > + UINTN Boundary = ((Address) + PMD_SIZE) & PMD_MASK; \ > + (Boundary - 1 < (End) - 1)? Boundary: (End); \ > +}) > + > +/** > + Get Specifies the virtual address corresponding to the index of the page global directory table entry. > + > + @param Address Specifies the virtual address. > + > + @retval the index of the page global directory table entry. > + **/ > +#define PGD_INDEX(Address) (((Address) >> PGD_SHIFT) & (ENTRYS_PER_PGD-1)) > + > +/** > + Get Specifies the virtual address corresponding to the index of the page upper directory table entry. > + > + @param Address Specifies the virtual address. > + @param End The end address of the memory region. > + > + @retval the index of the page upper directory table entry. > + **/ > +#define PUD_INDEX(Address) (((Address) >> PUD_SHIFT) & (ENTRYS_PER_PUD - 1)) > + > +/** > + Get Specifies the virtual address corresponding to the index of the page middle directory table entry. > + > + @param Address Specifies the virtual address. > + > + @retval the index of the page middle directory table entry. > + **/ > +#define PMD_INDEX(Address) (((Address) >> PMD_SHIFT) & (ENTRYS_PER_PMD - 1)) > + > +/** > + Get Specifies the virtual address corresponding to the index of the page table entry. > + > + @param Address Specifies the virtual address. > + > + @retval the index of the page table entry. > + **/ > +#define PTE_INDEX(Address) (((Address) >> EFI_PAGE_SHIFT) & (ENTRYS_PER_PTE - 1)) > + > +/** > + Calculates the value of the page table entry based on the specified virtual address and properties. > + > + @param Address Specifies the virtual address. > + @param Attributes Specifies the Attributes. > + > + @retval the value of the page table entry. > + **/ > +#define MAKE_PTE(Address, Attributes) (PTE){((((Address) >> EFI_PAGE_SHIFT) << 12) | (Attributes))} > + > +/** > + Get Global bit from Attributes > + > + @param Attributes Specifies the Attributes. > + * */ > +#define GET_GLOBALBIT(Attributes) ((Attributes & PAGE_GLOBAL) >> PAGE_GLOBAL_SHIFT) > + > +/** > + Calculates the value of the Huge page table entry based on the specified virtual address and properties. > + > + @param Address Specifies the virtual address. > + @param Attributes Specifies the Attributes. > + > + @retval the value of the HUGE page table entry. > + **/ > +#define MAKE_HUGE_PTE(Address, Attributes) (PTE){(((((Address) >> PMD_SHIFT) << PMD_SHIFT) | \ > + ((Attributes) | (GET_GLOBALBIT(Attributes) << PAGE_HGLOBAL_SHIFT) | \ > + PAGE_HUGE)))} > + > +/** > + Check whether the large page table entry is. > + > + @param Val The value of the page table entry. > + > + @retval 1 Is huge page table entry. > + @retval 0 Isn't huge page table entry. > +**/ > +#define IS_HUGE_PAGE(Val) ((((Val) & PAGE_HUGE) == PAGE_HUGE) && \ > + (((Val) & PAGE_HGLOBAL) == PAGE_HGLOBAL)) > + > +#define HUGE_PAGE_SIZE (PMD_SIZE) > + > +/** > + Check that the global page directory table entry is empty. > + > + @param pgd the global page directory struct variables. > + > + @retval 1 The page table is invalid. > + @retval 0 The page table is valid. > +**/ > +#define PGD_IS_EMPTY(Val) (PGD_VAL(Val) == INVALID_PAGE) > + > +/** > + Check that the page upper directory table entry is empty. > + > + @param pud Page upper directory struct variables. > + > + @retval 1 The page table is invalid. > + @retval 0 The page table is valid. > +**/ > +#define PUD_IS_EMPTY(Val) (PUD_VAL(Val) == INVALID_PAGE) > + > +/** > + Check that the page middle directory table entry is empty. > + > + @param pmd Page middle directory struct variables. > + > + @retval 1 The page table is invalid. > + @retval 0 The page table is valid. > +**/ > +#define PMD_IS_EMPTY(Val) (PMD_VAL(Val) == INVALID_PAGE) > + > +/** > + Check that the page the page table entry is empty. > + > + @param pte Page table entry struct variables. > + > + @retval 1 The page table is invalid. > + @retval 0 The page table is valid. > +**/ > +#define PTE_IS_EMPTY(Val) (!(PTE_VAL(Val) & (~PAGE_VALID))) > +#endif // PAGE_H_ > diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/PeiCpuMmuLib.c b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/PeiCpuMmuLib.c > new file mode 100644 > index 0000000000..c214e8d847 > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/PeiCpuMmuLib.c > @@ -0,0 +1,178 @@ > +/** @file > + CPU Memory Map Unit PEI phase driver. > + > + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Glossary: > + - Tlb - Translation Lookaside Buffer > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "Page.h" > +#include "Tlb.h" > +#include "CommonMmuLib.h" > + > +// > +// For coding convenience, define the maximum valid > +// LoongArch exception. > +// Since UEFI V2.11, it will be present in DebugSupport.h. > +// > +#define MAX_LOONGARCH_EXCEPTION 64 > + > +/** > + Create a page table and initialize the memory management unit(MMU). > + > + @param[in] MemoryTable A pointer to a memory ragion table. > + @param[out] TranslationTableBase A pointer to a translation table base address. > + @param[out] TranslationTableSize A pointer to a translation table base size. > + > + @retval EFI_SUCCESS Configure MMU successfully. > + EFI_INVALID_PARAMETER MemoryTable is NULL. > + EFI_UNSUPPORTED Out of memory space or size not aligned. > +**/ > +EFI_STATUS > +EFIAPI > +ConfigureMemoryManagementUnit ( > + IN MEMORY_REGION_DESCRIPTOR *MemoryTable, > + OUT VOID **TranslationTableBase OPTIONAL, > + OUT UINTN *TranslationTableSize OPTIONAL > + ) > +{ > + PGD *SwapperPageDir; > + UINTN PgdShift; > + UINTN PgdWide; > + UINTN PudShift; > + UINTN PudWide; > + UINTN PmdShift; > + UINTN PmdWide; > + UINTN PteShift; > + UINTN PteWide; > + UINTN Length; > + UINTN TlbReEntry; > + UINTN TlbReEntryOffset; > + UINTN Remaining; > + RETURN_STATUS Status; > + > + SwapperPageDir = NULL; > + PgdShift = PGD_SHIFT; > + PgdWide = PGD_WIDE; > + PudShift = PUD_SHIFT; > + PudWide = PUD_WIDE; > + PmdShift = PMD_SHIFT; > + PmdWide = PMD_WIDE; > + PteShift = PTE_SHIFT; > + PteWide = PTE_WIDE; > + > + if (MemoryTable == NULL) { > + ASSERT (MemoryTable != NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE)); > + ZeroMem (SwapperPageDir, PGD_TABLE_SIZE); > + > + if (SwapperPageDir == NULL) { > + goto FreeTranslationTable; > + } > + > + CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir); > + > + while (MemoryTable->Length != 0) { > + DEBUG (( > + DEBUG_INFO, > + "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", > + __func__, > + __LINE__, > + MemoryTable->VirtualBase, > + (MemoryTable->Length + MemoryTable->VirtualBase), > + MemoryTable->Attributes > + )); > + > + Status = FillTranslationTable (MemoryTable); > + if (EFI_ERROR (Status)) { > + goto FreeTranslationTable; > + } > + > + MemoryTable++; > + } > + > + // > + // TLB Re-entry address at the end of exception vector, a vector is up to 512 bytes, > + // so the starting address is: total exception vector size + total interrupt vector size + base. > + // The total size of TLB handler and exception vector size and interrupt vector size should not > + // be lager than 64KB. > + // > + Length = (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart; > + TlbReEntryOffset = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512; > + Remaining = TlbReEntryOffset % SIZE_4KB; > + if (Remaining != 0x0) { > + TlbReEntryOffset += (SIZE_4KB - Remaining); > + } > + > + TlbReEntry = PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryOffset; > + if ((TlbReEntryOffset + Length) > SIZE_64KB) { > + goto FreeTranslationTable; > + } > + > + // > + // Ensure that TLB refill exception base address alignment is equals to 4KB and is valid. > + // > + if (TlbReEntry & (SIZE_4KB - 1)) { > + goto FreeTranslationTable; > + } > + > + CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length); > + InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length); > + > + DEBUG (( > + DEBUG_INFO, > + "%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 > + )); > + > + // > + // Set the address of TLB refill exception handler > + // > + SetTlbRebaseAddress ((UINTN)TlbReEntry); > + > + // > + // Set page size > + // > + CsrXChg (LOONGARCH_CSR_TLBIDX, (DEFAULT_PAGE_SIZE << CSR_TLBIDX_SIZE), CSR_TLBIDX_SIZE_MASK); > + CsrWrite (LOONGARCH_CSR_STLBPGSIZE, DEFAULT_PAGE_SIZE); > + CsrXChg (LOONGARCH_CSR_TLBREHI, (DEFAULT_PAGE_SIZE << CSR_TLBREHI_PS_SHIFT), CSR_TLBREHI_PS); > + > + CsrWrite (LOONGARCH_CSR_PWCTL0, (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25)); > + CsrWrite (LOONGARCH_CSR_PWCTL1, (PgdShift | PgdWide << 6)); > + > + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir)); > + > + return EFI_SUCCESS; > + > +FreeTranslationTable: > + if (SwapperPageDir != NULL) { > + FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE)); > + } > + > + return EFI_UNSUPPORTED; > +} > diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Tlb.h b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Tlb.h > new file mode 100644 > index 0000000000..9a681ce8e1 > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Tlb.h > @@ -0,0 +1,48 @@ > +/** @file > + > + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef TLB_H_ > +#define TLB_H_ > + > +/** > + Invalid corresponding TLB entries are based on the address given > + > + @param Address The address corresponding to the invalid page table entry > + > + @retval none > +**/ > +VOID > +InvalidTlb ( > + UINTN Address > + ); > + > +/** > + TLB refill handler start. > + > + @param none > + > + @retval none > +**/ > +VOID > +HandleTlbRefillStart ( > + VOID > + ); > + > +/** > + TLB refill handler end. > + > + @param none > + > + @retval none > +**/ > +VOID > +HandleTlbRefillEnd ( > + VOID > + ); > + > +#endif // TLB_H_ > diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbOperation.S b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbOperation.S > new file mode 100644 > index 0000000000..c9a8c16336 > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbOperation.S > @@ -0,0 +1,44 @@ > +#------------------------------------------------------------------------------ > +# > +# TLB operation functions > +# > +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +#----------------------------------------------------------------------------- > + > +#include > + > +ASM_GLOBAL ASM_PFX(HandleTlbRefillStart) > +ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd) > +ASM_GLOBAL ASM_PFX(InvalidTlb) > + > +# > +# Refill the page table. > +# @param VOID > +# @retval VOID > +# > +ASM_PFX(HandleTlbRefillStart): > + 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 // refill hi,lo0,lo1 > + csrrd $t0, LOONGARCH_CSR_TLBRSAVE > + ertn > +ASM_PFX(HandleTlbRefillEnd): > + > +# > +# Invalid corresponding TLB entries are based on the address given > +# @param a0 The address corresponding to the invalid page table entry > +# @retval none > +# > +ASM_PFX(InvalidTlb): > + invtlb INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0 > + jirl $zero, $ra, 0 > + > + .end > diff --git a/UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.inf b/UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.inf > new file mode 100644 > index 0000000000..45b15db4c9 > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.inf > @@ -0,0 +1,44 @@ > +## @file > +# CPU Memory Map Unit PEI phase driver. > +# > +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 1.29 > + BASE_NAME = PeiCpuMmuLib > + MODULE_UNI_FILE = PeiCpuMmuLib.uni > + FILE_GUID = F67EB983-AC2A-7550-AB69-3BC51A1C895B > + MODULE_TYPE = PEIM > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = CpuMmuLib | SEC PEIM > + > +# > +# VALID_ARCHITECTURES = LOONGARCH64 > +# > + > +[Sources.LoongArch64] > + LoongArch64/TlbOperation.S | GCC > + LoongArch64/CommonMmuLib.c > + LoongArch64/PeiCpuMmuLib.c > + LoongArch64/CommonMmuLib.h > + LoongArch64/Tlb.h > + LoongArch64/Page.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + UefiCpuPkg/UefiCpuPkg.dec > + > +[PCD] > + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask > + gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress > + > +[LibraryClasses] > + CacheMaintenanceLib > + DebugLib > + MemoryAllocationLib > + PcdLib > diff --git a/UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.uni b/UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.uni > new file mode 100644 > index 0000000000..3e21334f3e > --- /dev/null > +++ b/UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.uni > @@ -0,0 +1,14 @@ > +// /** @file > +// CPU Memory Manager Unit library instance for PEI modules. > +// > +// CPU Memory Manager Unit library instance for PEI modules. > +// > +// Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
> +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for PEI modules." > + > +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for PEI modules." > diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc > index 28eed85bce..178dc3c0f9 100644 > --- a/UefiCpuPkg/UefiCpuPkg.dsc > +++ b/UefiCpuPkg/UefiCpuPkg.dsc > @@ -207,5 +207,9 @@ > UefiCpuPkg/CpuTimerDxeRiscV64/CpuTimerDxeRiscV64.inf > UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf > > +[Components.LOONGARCH64] > + UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.inf > + UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.inf > + > [BuildOptions] > *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114850): https://edk2.groups.io/g/devel/message/114850 Mute This Topic: https://groups.io/mt/104068947/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-