Hi Ray and Laszlo, I would very much like to be merged into stable202302, the soft feature deadline is 2024-02-05, so could you please hlep to review this patch as soon as passable? Please... Thanks, Chao On 2024/1/31 11:31, Chao Li wrote: > > Hi Ray, > > Can you please help to review this patch again? > > 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 (#114861): https://edk2.groups.io/g/devel/message/114861 Mute This Topic: https://groups.io/mt/104070179/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-