From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 1E845AC0C05 for ; Wed, 31 Jan 2024 05:32:49 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=XJb8ZRBCE/aaBERq8QD6SzatKVfgHNpp76y1Nc4owIQ=; c=relaxed/simple; d=groups.io; h=Message-ID:Date:MIME-Version:User-Agent:Subject:From:To:Cc:Reply-To:References:In-Reply-To:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type; s=20140610; t=1706679168; v=1; b=DhreGRzI63pKBw4mCwgrlXi/AKh5f9zA2r+ETQWBPgIMuzkLwHIWsXLvqrUSHCCYnH/l3NHp MYmO4A0DtqJxjDU148CqAy2tllV3wHOLDWHnpaF9Q+sfnckac3vQuvXhn6MNbHTDy1u/pq3hHTI PBJQnjxgotEDob6jAn+nexro= X-Received: by 127.0.0.2 with SMTP id XamEYY7687511xkVJpON9zfw; Tue, 30 Jan 2024 21:32:48 -0800 X-Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web11.8228.1706679166407668887 for ; Tue, 30 Jan 2024 21:32:47 -0800 X-Received: from loongson.cn (unknown [10.40.24.149]) by gateway (Coremail) with SMTP id _____8Axjut827llXskIAA--.26237S3; Wed, 31 Jan 2024 13:32:44 +0800 (CST) X-Received: from [10.40.24.149] (unknown [10.40.24.149]) by localhost.localdomain (Coremail) with SMTP id AQAAf8AxRMx627llW5gpAA--.21721S3; Wed, 31 Jan 2024 13:32:42 +0800 (CST) Message-ID: <5b482e81-ec5c-481c-b708-b1faa4ad3100@loongson.cn> Date: Wed, 31 Jan 2024 13:32:42 +0800 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [edk2-devel] [PATCH v8 14/37] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg From: "Chao Li" To: devel@edk2.groups.io, Ray Ni , Laszlo Ersek Cc: Eric Dong , Rahul Kumar , Gerd Hoffmann , Baoqi Zhang , Dongyan Qian , Xianglai Li , Bibo Mao Reply-To: devel@edk2.groups.io,lichao@loongson.cn References: <20240126062715.3099433-1-lichao@loongson.cn> <17ADD1D9CA04F352.11113@groups.io> <17AF511188DE2475.15701@groups.io> In-Reply-To: <17AF511188DE2475.15701@groups.io> X-CM-TRANSID: AQAAf8AxRMx627llW5gpAA--.21721S3 X-CM-SenderInfo: xolfxt3r6o00pqjv00gofq/1tbiAQANCGW4s2EJfwAFs4 X-Coremail-Antispam: 1Uk129KBj9fXoWDJFy7Zw4kZF1DJw45Kr48GrX_yoWruw48Jo WYvF4rCw4UJw4fAr4xC3s7Way7GFsYgrZ3Xr4Fva1jga1qvrs0kFW7ta15A34fA34jvr1D Gr97Xw1vyFWfXr1rl-sFpf9Il3svdjkaLaAFLSUrUUUUUb8apTn2vfkv8UJUUUU8wcxFpf 9Il3svdxBIdaVrn8Aqx4xG62kEwI0EY4vaYxAvb48xYxn0WfASr-VFAUDa7-sFnT9fnUUI cSsGvfJTRUUUbxxYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20x vaj40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxS w2x7M28EF7xvwVC0I7IYx2IY67AKxVWUCVW8JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxV W8JVWxJwA2z4x0Y4vEx4A2jsIE14v26F4j6r4UJwA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_ Gr1j6F4UJwAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07AIYIkI8VC2zVCFFI0UMc 02F40En4AKxVAvwIkv4cxYr24lYx0E2Ix0cI8IcVAFwI0_JF0_Jw1lYx0Ex4A2jsIE14v2 6r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG0xvEwIxGrwCjr7xvwVCIw2I0I7xG6c 02F41l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AK xVWUGVWUWwC20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrx kI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_JFI_Gr1lIxAIcVC0I7IYx2IY6xkF7I0E14v2 6r4j6F4UMIIF0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJw CI42IY6I8E87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjxU7iihUUUU U Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: pj0aSLkV9NXAeZ44x6fKYQgqx7686176AA= Content-Type: multipart/alternative; boundary="------------BsSXLlpJMnV6ViNm3TG4MLau" X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=DhreGRzI; dmarc=none; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io --------------BsSXLlpJMnV6ViNm3TG4MLau Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable Hi Ray and Laszlo, I would very much like to be merged into stable202302, the soft feature=20 deadline is 2024-02-05, so could you please hlep to review this patch as=20 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=3D4584 >> >> 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/CommonMmuL= ib.c >> create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuL= ib.h >> create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h >> create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/PeiCpuMmuL= ib.c >> create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Tlb.h >> create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbOperati= on.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 righ= ts reserved.
>> +# >> +# SPDX-License-Identifier: BSD-2-Clause-Patent >> +# >> +## >> + >> +[Defines] >> + INF_VERSION =3D 1.29 >> + BASE_NAME =3D DxeCpuMmuLib >> + MODULE_UNI_FILE =3D DxeCpuMmuLib.uni >> + FILE_GUID =3D DA8F0232-FB14-42F0-922C-63104D2C70= BE >> + MODULE_TYPE =3D DXE_DRIVER >> + VERSION_STRING =3D 1.0 >> + LIBRARY_CLASS =3D CpuMmuLib | DXE_DRIVER >> + CONSTRUCTOR =3D MmuInitialize >> + >> +# >> +# VALID_ARCHITECTURES =3D 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 rig= hts reserved.
>> +// >> +// SPDX-License-Identifier: BSD-2-Clause-Patent >> +// >> +// **/ >> + >> +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Man= ager Unit library instance for DXE modules." >> + >> +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Man= ager Unit library instance for DXE modules." >> diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.c b/U= efiCpuPkg/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 right= s 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 =3D 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 !=3D 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 direct= ory. >> + >> + @return VOID. >> +**/ >> +STATIC >> +VOID >> +PageDirInit ( >> + IN VOID *Dst, >> + IN UINTN Num, >> + IN VOID *Src >> + ) >> +{ >> + UINTN *Ptr; >> + UINTN *End; >> + UINTN Entry; >> + >> + Entry =3D (UINTN)Src; >> + Ptr =3D (UINTN *)Dst; >> + End =3D Ptr + Num; >> + >> + for ( ; Ptr < End; Ptr++) { >> + *Ptr =3D Entry; >> + } >> + >> + return; >> +} >> + >> +/** >> + Gets the virtual address corresponding to the page global directory t= able 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 ta= ble 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 =3D (UINTN)PGD_VAL (*Pgd); >> + >> + return (PUD *)PgdVal + PUD_INDEX (Address); >> +} >> + >> +/** >> + Gets the virtual address corresponding to the page middle directory t= able 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 =3D 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 =3D (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 =3D 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 =3D (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 =3D (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 =3D (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 requeste= d to memory. >> +**/ >> +STATIC >> +EFI_STATUS >> +PudAlloc ( >> + IN PGD *Pgd >> + ) >> +{ >> + PUD *Pud; >> + >> + Pud =3D (PUD *)AllocatePages (1); >> + if (Pud =3D=3D 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 requeste= d to memory. >> +**/ >> +STATIC >> +EFI_STATUS >> +PmdAlloc ( >> + IN PUD *Pud >> + ) >> +{ >> + PMD *Pmd; >> + >> + Pmd =3D (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 requeste= d to memory. >> +**/ >> +STATIC >> +EFI_STATUS >> +PteAlloc ( >> + IN PMD *Pmd >> + ) >> +{ >> + PTE *Pte; >> + >> + Pte =3D (PTE *)AllocatePages (1); >> + if (!Pte) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + Pte =3D 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 a= ddress. >> + >> + @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 =3D 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 =3D 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 a= llocate >> + the memory buffer is fail. >> +**/ >> +STATIC >> +PTE * >> +PteAllocGet ( >> + IN PMD *Pmd, >> + IN UINTN Address >> + ) >> +{ >> + EFI_STATUS Status; >> + >> + if (PMD_IS_EMPTY (*Pmd)) { >> + Status =3D 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 th= e 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 =3D PgdOffset (Address); >> + >> + if (PGD_IS_EMPTY (*Pgd)) { >> + return NULL; >> + } >> + >> + Pud =3D PudOffset (Pgd, Address); >> + >> + if (PUD_IS_EMPTY (*Pud)) { >> + return NULL; >> + } >> + >> + Pmd =3D 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 =3D PMD_VAL (*Pmd); >> + Attributes =3D HugeVal & (~HUGEP_PAGE_MASK); >> + GlobalFlag =3D ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGL= OBAL_SHIFT) << PAGE_GLOBAL_SHIFT; >> + Attributes &=3D ~(1 << PAGE_HGLOBAL_SHIFT); >> + Attributes |=3D 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 successful= ly. >> + @retval EFI_OUT_OF_RESOURCES Page table entry establishment fail= ed 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 =3D 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 =3D FALSE; >> + PteVal =3D MAKE_PTE (Address, Attributes); >> + >> + if ((!PTE_IS_EMPTY (*Pte)) && >> + (PTE_VAL (*Pte) !=3D PTE_VAL (PteVal))) >> + { >> + UpDate =3D TRUE; >> + } >> + >> + SetPte (Pte, PteVal); >> + if (UpDate) { >> + InvalidTlb (Address); >> + } >> + } while (Pte++, Address +=3D EFI_PAGE_SIZE, Address !=3D 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 =3D EFI_SUCCESS; >> + >> + if ((PMD_IS_EMPTY (*Pmd)) || >> + (!IS_HUGE_PAGE (Pmd->PmdVal))) >> + { >> + Status |=3D MemoryMapPteRange (Pmd, Address, End, Attributes); >> + } else { >> + OldAttributes =3D GetHugePageAttributes (Pmd); >> + if (Attributes =3D=3D OldAttributes) { >> + return Status; >> + } >> + >> + SetPmd (Pmd, (PTE *)(INVALID_PAGE)); >> + HugePageStart =3D Address & PMD_MASK; >> + HugePageEnd =3D HugePageStart + HUGE_PAGE_SIZE; >> + ASSERT (HugePageEnd >=3D End); >> + >> + if (Address > HugePageStart) { >> + Status |=3D MemoryMapPteRange (Pmd, HugePageStart, Address, OldAt= tributes); >> + } >> + >> + Status |=3D MemoryMapPteRange (Pmd, Address, End, Attributes); >> + >> + if (End < HugePageEnd) { >> + Status |=3D MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttribut= es); >> + } >> + } >> + >> + return Status; >> +} >> + >> +/** >> + Establishes a page middle directory based on the specified memory reg= ion. >> + >> + @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 succe= ssfully. >> + @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 =3D PmdAllocGet (Pud, Address); >> + if (Pmd =3D=3D NULL) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + do { >> + Next =3D PMD_ADDRESS_END (Address, End); >> + if (((Address & (~PMD_MASK)) =3D=3D 0) && >> + ((Next & (~PMD_MASK)) =3D=3D 0) && >> + (PMD_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal))) >> + { >> + UpDate =3D FALSE; >> + PteVal =3D MAKE_HUGE_PTE (Address, Attributes); >> + >> + if ((!PMD_IS_EMPTY (*Pmd)) && >> + (PMD_VAL (*Pmd) !=3D PTE_VAL (PteVal))) >> + { >> + UpDate =3D TRUE; >> + } >> + >> + SetPmd (Pmd, (PTE *)PteVal.PteVal); >> + if (UpDate) { >> + InvalidTlb (Address); >> + } >> + } else { >> + ConvertHugePageToPage (Pmd, Address, Next, Attributes); >> + } >> + } while (Pmd++, Address =3D Next, Address !=3D End); >> + >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + Establishes a page upper directory based on the specified memory regi= on. >> + >> + @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 succes= sfully. >> + @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 =3D PudAllocGet (Pgd, Address); >> + if (Pud =3D=3D NULL) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + do { >> + Next =3D PUD_ADDRESS_END (Address, End); >> + if (EFI_ERROR (MemoryMapPmdRange (Pud, Address, Next, Attributes)))= { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + } while (Pud++, Address =3D Next, Address !=3D End); >> + >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + Establishes a page global directory based on the specified memory reg= ion. >> + >> + @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 succe= ssfully. >> + @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 =3D Start; >> + >> + /* Get PGD(PTE PMD PUD PGD) in PageTables */ >> + Pgd =3D PgdOffset (Address); >> + do { >> + Next =3D PGD_ADDRESS_END (Address, End); >> + /* Get Next Align Page to Map */ >> + Err =3D MemoryMapPudRange (Pgd, Address, Next, Attributes); >> + if (Err) { >> + return Err; >> + } >> + } while (Pgd++, Address =3D Next, Address !=3D 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 du= e 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 =3D PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | PAGE_G= LOBAL; >> + >> + switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) { >> + case EFI_MEMORY_UC: >> + LoongArchAttributes |=3D CACHE_SUC; >> + break; >> + case EFI_MEMORY_WC: >> + LoongArchAttributes |=3D CACHE_WUC; >> + break; >> + case EFI_MEMORY_WT: >> + case EFI_MEMORY_WB: >> + LoongArchAttributes |=3D CACHE_CC; >> + break; >> + default: >> + LoongArchAttributes |=3D CACHE_CC; >> + break; >> + } >> + >> + // Write protection attributes >> + if (((EfiAttributes & EFI_MEMORY_RO) !=3D 0) || >> + ((EfiAttributes & EFI_MEMORY_WP) !=3D 0)) >> + { >> + LoongArchAttributes &=3D ~PAGE_DIRTY; >> + } >> + >> + if ((EfiAttributes & EFI_MEMORY_RP) !=3D 0) { >> + LoongArchAttributes |=3D PAGE_NO_READ; >> + } >> + >> + // eXecute protection attribute >> + if ((EfiAttributes & EFI_MEMORY_XP) !=3D 0) { >> + LoongArchAttributes |=3D PAGE_NO_EXEC; >> + } >> + >> + return LoongArchAttributes; >> +} >> + >> +/** >> + Finds the first of the length and memory properties of the memory reg= ion corresponding >> + to the specified base address. >> + >> + @param[in] BaseAddress To find the base address of the me= mory region. >> + @param[in, out] RegionLength Pointer holding: >> + - At entry, the length of the mem= ory region >> + expected to be found. >> + - At exit, the length of the memo= ry region found. >> + @param[out] RegionAttributes Properties of the memory region fo= und. >> + >> + @retval EFI_SUCCESS The corresponding memory area was succ= essfully 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 =3D BaseAddress + *RegionLength; >> + MaxAddress =3D LShiftU64 (1ULL, MAX_VA_BITS) - 1; >> + >> + // Clean the value to prepare output to find region size. >> + *RegionLength =3D 0x0; >> + >> + if ((BaseAddress >=3D MaxAddress) || (EndAddress >=3D MaxAddress)) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + Pte =3D GetPteAddress (BaseAddress); >> + >> + if (Pte =3D=3D NULL) { >> + return EFI_NOT_FOUND; >> + } >> + >> + Attributes =3D GET_PAGE_ATTRIBUTES (*Pte); >> + if (IS_HUGE_PAGE (Pte->PteVal)) { >> + *RegionAttributes =3D Attributes & (~(PAGE_HUGE)); >> + } else { >> + *RegionAttributes =3D Attributes; >> + } >> + >> + do { >> + Pte =3D GetPteAddress (BaseAddress); >> + if (Pte =3D=3D NULL) { >> + return EFI_SUCCESS; >> + } >> + >> + AttributesTmp =3D GET_PAGE_ATTRIBUTES (*Pte); >> + if (AttributesTmp =3D=3D Attributes) { >> + if (IS_HUGE_PAGE (Pte->PteVal)) { >> + AddSize =3D HUGE_PAGE_SIZE; >> + } else { >> + AddSize =3D EFI_PAGE_SIZE; >> + } >> + >> + *RegionLength +=3D AddSize; >> + BaseAddress +=3D AddSize; >> + } else { >> + return EFI_SUCCESS; >> + } >> + } while (BaseAddress <=3D EndAddress); >> + >> + return EFI_SUCCESS; >> +} >> + >> +/** >> + Sets the Attributes of the specified memory region >> + >> + @param[in] BaseAddress The base address of the memory region to s= et 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 acc= ount. >> + >> + @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 =3D EfiAttributeConverse (Attributes); >> + Status =3D 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 im= age. >> + @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 !=3D 0) { >> + mMmuInited =3D TRUE; >> + } >> + >> + return RETURN_SUCCESS; >> +} >> diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.h b/U= efiCpuPkg/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 right= s 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 direct= ory. >> + >> + @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 du= e 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/UefiCpuPk= g/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 right= s 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 a= ddress >> + 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 =3D ((Address) + PGD_SIZE) & PGD_MASK; \ >> + (Boundary - 1 < (End) - 1)? Boundary: (End); \ >> +}) >> + >> +/** >> + Gets the virtual address of the next block of the specified virtual a= ddress >> + 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 =3D ((Address) + PUD_SIZE) & PUD_MASK; \ >> + (Boundary - 1 < (End) - 1)? Boundary: (End); \ >> +}) >> + >> +/** >> + Gets the virtual address of the next block of the specified virtual a= ddress >> + 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 =3D ((Address) + PMD_SIZE) & PMD_MASK; \ >> + (Boundary - 1 < (End) - 1)? Boundary: (End); \ >> +}) >> + >> +/** >> + Get Specifies the virtual address corresponding to the index of the p= age 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 p= age 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 p= age 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 p= age 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_PE= R_PTE - 1)) >> + >> +/** >> + Calculates the value of the page table entry based on the specified v= irtual 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_S= HIFT) << 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 specif= ied 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_GLOBA= LBIT(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) =3D=3D PAGE_HUGE) && \ >> + (((Val) & PAGE_HGLOBAL) =3D=3D 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) =3D=3D 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) =3D=3D 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) =3D=3D 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/U= efiCpuPkg/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 right= s 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 b= ase address. >> + @param[out] TranslationTableSize A pointer to a translation table b= ase size. >> + >> + @retval EFI_SUCCESS Configure MMU successfully. >> + EFI_INVALID_PARAMETER MemoryTable is NULL. >> + EFI_UNSUPPORTED Out of memory space or size not a= ligned. >> +**/ >> +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 =3D NULL; >> + PgdShift =3D PGD_SHIFT; >> + PgdWide =3D PGD_WIDE; >> + PudShift =3D PUD_SHIFT; >> + PudWide =3D PUD_WIDE; >> + PmdShift =3D PMD_SHIFT; >> + PmdWide =3D PMD_WIDE; >> + PteShift =3D PTE_SHIFT; >> + PteWide =3D PTE_WIDE; >> + >> + if (MemoryTable =3D=3D NULL) { >> + ASSERT (MemoryTable !=3D NULL); >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + SwapperPageDir =3D AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE))= ; >> + ZeroMem (SwapperPageDir, PGD_TABLE_SIZE); >> + >> + if (SwapperPageDir =3D=3D NULL) { >> + goto FreeTranslationTable; >> + } >> + >> + CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir); >> + >> + while (MemoryTable->Length !=3D 0) { >> + DEBUG (( >> + DEBUG_INFO, >> + "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", >> + __func__, >> + __LINE__, >> + MemoryTable->VirtualBase, >> + (MemoryTable->Length + MemoryTable->VirtualBase), >> + MemoryTable->Attributes >> + )); >> + >> + Status =3D FillTranslationTable (MemoryTable); >> + if (EFI_ERROR (Status)) { >> + goto FreeTranslationTable; >> + } >> + >> + MemoryTable++; >> + } >> + >> + // >> + // TLB Re-entry address at the end of exception vector, a vector is u= p to 512 bytes, >> + // so the starting address is: total exception vector size + total in= terrupt vector size + base. >> + // The total size of TLB handler and exception vector size and interr= upt vector size should not >> + // be lager than 64KB. >> + // >> + Length =3D (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefi= llStart; >> + TlbReEntryOffset =3D (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRU= PT) * 512; >> + Remaining =3D TlbReEntryOffset % SIZE_4KB; >> + if (Remaining !=3D 0x0) { >> + TlbReEntryOffset +=3D (SIZE_4KB - Remaining); >> + } >> + >> + TlbReEntry =3D PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEnt= ryOffset; >> + 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 P= udWide %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 !=3D 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 right= s 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 en= try >> + >> + @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/U= efiCpuPkg/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 right= s 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 righ= ts reserved.
>> +# >> +# SPDX-License-Identifier: BSD-2-Clause-Patent >> +# >> +## >> + >> +[Defines] >> + INF_VERSION =3D 1.29 >> + BASE_NAME =3D PeiCpuMmuLib >> + MODULE_UNI_FILE =3D PeiCpuMmuLib.uni >> + FILE_GUID =3D F67EB983-AC2A-7550-AB69-3BC51A1C89= 5B >> + MODULE_TYPE =3D PEIM >> + VERSION_STRING =3D 1.0 >> + LIBRARY_CLASS =3D CpuMmuLib | SEC PEIM >> + >> +# >> +# VALID_ARCHITECTURES =3D 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 rig= hts reserved.
>> +// >> +// SPDX-License-Identifier: BSD-2-Clause-Patent >> +// >> +// **/ >> + >> +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Man= ager Unit library instance for PEI modules." >> + >> +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Man= ager 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 >> =20 >> +[Components.LOONGARCH64] >> + UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.inf >> + UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.inf >> + >> [BuildOptions] >> *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES >=20 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- 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] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- --------------BsSXLlpJMnV6ViNm3TG4MLau Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable

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 CpuM=
muLib 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.cg=
i?id=3D4584

Cc: Eric Dong <er=
ic.dong@intel.com>
Cc: Ray Ni <ray.n=
i@intel.com>
Cc: Laszlo Ersek <lers=
ek@redhat.com>
Cc: Rahul Kumar <=
;rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <krax=
el@redhat.com>
Signed-off-by: Chao Li <lic=
hao@loongson.cn>
Co-authored-by: Baoqi Zhang <=
;zhangbaoqi@loongson.cn>
Co-authored-by: Dongyan Qian &l=
t;qiandongyan@loongson.cn>
Co-authored-by: Xianglai Li <=
;lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <ma=
obibo@loongson.cn>
---
 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/Lib=
rary/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.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    =3D 1.29
+  BASE_NAME                      =3D DxeCpuMmuLib
+  MODULE_UNI_FILE                =3D DxeCpuMmuLib.uni
+  FILE_GUID                      =3D DA8F0232-FB14-42F0-922C-63104D2C70BE
+  MODULE_TYPE                    =3D DXE_DRIVER
+  VERSION_STRING                 =3D 1.0
+  LIBRARY_CLASS                  =3D CpuMmuLib | DXE_DRIVER
+  CONSTRUCTOR                    =3D MmuInitialize
+
+#
+#  VALID_ARCHITECTURES           =3D 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/Lib=
rary/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.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "CPU Memory Manage=
r Unit library instance for DXE modules."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "CPU Memory Manage=
r Unit library instance for DXE modules."
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.c b/Uefi=
CpuPkg/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 r=
eserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Pgd or Pgd or PGD    - Page Global Directory
+    - Pud or Pud or PUD    - Page Upper Directory
+    - Pmd or Pmd or PMD    - Page Middle Directory
+    - Pte or pte or PTE    - Page Table Entry
+    - Val or VAL or val    - Value
+    - Dir    - Directory
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Register/LoongArch64/Csr.h>
+#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 =3D 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 !=3D 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 =3D (UINTN)Src;
+  Ptr   =3D (UINTN *)Dst;
+  End   =3D Ptr + Num;
+
+  for ( ; Ptr < End; Ptr++) {
+    *Ptr =3D Entry;
+  }
+
+  return;
+}
+
+/**
+  Gets the virtual address corresponding to the page global directory tabl=
e 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 =3D (UINTN)PGD_VAL (*Pgd);
+
+  return (PUD *)PgdVal + PUD_INDEX (Address);
+}
+
+/**
+  Gets the virtual address corresponding to the page middle directory tabl=
e 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 =3D 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 =3D (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 =3D 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 =3D (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 =3D (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 =3D (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 t=
o memory.
+**/
+STATIC
+EFI_STATUS
+PudAlloc (
+  IN PGD  *Pgd
+  )
+{
+  PUD  *Pud;
+
+  Pud =3D (PUD *)AllocatePages (1);
+  if (Pud =3D=3D 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 t=
o memory.
+**/
+STATIC
+EFI_STATUS
+PmdAlloc (
+  IN PUD  *Pud
+  )
+{
+  PMD  *Pmd;
+
+  Pmd =3D (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 t=
o memory.
+**/
+STATIC
+EFI_STATUS
+PteAlloc (
+  IN PMD  *Pmd
+  )
+{
+  PTE  *Pte;
+
+  Pte =3D (PTE *)AllocatePages (1);
+  if (!Pte) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Pte =3D 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 addr=
ess.
+
+  @param  Pgd      A pointer to the page global directory.
+  @param  Address  The corresponding virtual address of the page table ent=
ry.
+
+  @retval          A pointer to the page upper directory entry. Return NUL=
L, 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 =3D 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 add=
ress.
+
+  @param  Pud      A pointer to the page upper directory.
+  @param  Address  The corresponding virtual address of the page table ent=
ry.
+
+  @retval          A pointer to the page middle directory entry. Return NU=
LL, 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 =3D 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 ent=
ry.
+
+  @retval          A pointer to the page table entry. Return NULL, if allo=
cate
+                   the memory buffer is fail.
+**/
+STATIC
+PTE *
+PteAllocGet (
+  IN PMD    *Pmd,
+  IN UINTN  Address
+  )
+{
+  EFI_STATUS  Status;
+
+  if (PMD_IS_EMPTY (*Pmd)) {
+    Status =3D 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 s=
pecified virtual address.
+
+  @param  Address  The corresponding virtual address of the page table ent=
ry.
+
+  @retval  A pointer to the page table entry.
+  @retval  NULL
+**/
+STATIC
+PTE *
+GetPteAddress (
+  IN UINTN  Address
+  )
+{
+  PGD  *Pgd;
+  PUD  *Pud;
+  PMD  *Pmd;
+
+  Pgd =3D PgdOffset (Address);
+
+  if (PGD_IS_EMPTY (*Pgd)) {
+    return NULL;
+  }
+
+  Pud =3D PudOffset (Pgd, Address);
+
+  if (PUD_IS_EMPTY (*Pud)) {
+    return NULL;
+  }
+
+  Pmd =3D 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     =3D PMD_VAL (*Pmd);
+  Attributes  =3D HugeVal & (~HUGEP_PAGE_MASK);
+  GlobalFlag  =3D ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >=
> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT;
+  Attributes &=3D ~(1 << PAGE_HGLOBAL_SHIFT);
+  Attributes |=3D 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 =3D 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 =3D FALSE;
+    PteVal =3D MAKE_PTE (Address, Attributes);
+
+    if ((!PTE_IS_EMPTY (*Pte)) &&
+        (PTE_VAL (*Pte) !=3D PTE_VAL (PteVal)))
+    {
+      UpDate =3D TRUE;
+    }
+
+    SetPte (Pte, PteVal);
+    if (UpDate) {
+      InvalidTlb (Address);
+    }
+  } while (Pte++, Address +=3D EFI_PAGE_SIZE, Address !=3D 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 =3D EFI_SUCCESS;
+
+  if ((PMD_IS_EMPTY (*Pmd)) ||
+      (!IS_HUGE_PAGE (Pmd->PmdVal)))
+  {
+    Status |=3D MemoryMapPteRange (Pmd, Address, End, Attributes);
+  } else {
+    OldAttributes =3D GetHugePageAttributes (Pmd);
+    if (Attributes =3D=3D OldAttributes) {
+      return Status;
+    }
+
+    SetPmd (Pmd, (PTE *)(INVALID_PAGE));
+    HugePageStart =3D Address & PMD_MASK;
+    HugePageEnd   =3D HugePageStart + HUGE_PAGE_SIZE;
+    ASSERT (HugePageEnd >=3D End);
+
+    if (Address > HugePageStart) {
+      Status |=3D MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttri=
butes);
+    }
+
+    Status |=3D MemoryMapPteRange (Pmd, Address, End, Attributes);
+
+    if (End < HugePageEnd) {
+      Status |=3D 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 successf=
ully.
+  @retval     EFI_OUT_OF_RESOURCES  Page middle directory establishment fa=
iled 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 =3D PmdAllocGet (Pud, Address);
+  if (Pmd =3D=3D NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    Next =3D PMD_ADDRESS_END (Address, End);
+    if (((Address & (~PMD_MASK)) =3D=3D 0) &&
+        ((Next &  (~PMD_MASK)) =3D=3D 0) &&
+        (PMD_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal)))
+    {
+      UpDate =3D FALSE;
+      PteVal =3D MAKE_HUGE_PTE (Address, Attributes);
+
+      if ((!PMD_IS_EMPTY (*Pmd)) &&
+          (PMD_VAL (*Pmd) !=3D PTE_VAL (PteVal)))
+      {
+        UpDate =3D TRUE;
+      }
+
+      SetPmd (Pmd, (PTE *)PteVal.PteVal);
+      if (UpDate) {
+        InvalidTlb (Address);
+      }
+    } else {
+      ConvertHugePageToPage (Pmd, Address, Next, Attributes);
+    }
+  } while (Pmd++, Address =3D Next, Address !=3D 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 successfu=
lly.
+  @retval     EFI_OUT_OF_RESOURCES  Page upper directory establishment fai=
led 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 =3D PudAllocGet (Pgd, Address);
+  if (Pud =3D=3D NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    Next =3D PUD_ADDRESS_END (Address, End);
+    if (EFI_ERROR (MemoryMapPmdRange (Pud, Address, Next, Attributes))) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } while (Pud++, Address =3D Next, Address !=3D 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 successf=
ully.
+  @retval     EFI_OUT_OF_RESOURCES  Page global directory establishment fa=
iled 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 =3D Start;
+
+  /* Get PGD(PTE PMD PUD PGD) in PageTables */
+  Pgd =3D PgdOffset (Address);
+  do {
+    Next =3D PGD_ADDRESS_END (Address, End);
+    /* Get Next Align Page to Map */
+    Err =3D MemoryMapPudRange (Pgd, Address, Next, Attributes);
+    if (Err) {
+      return Err;
+    }
+  } while (Pgd++, Address =3D Next, Address !=3D 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 t=
o 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 =3D PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | PAGE_GLOB=
AL;
+
+  switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
+    case EFI_MEMORY_UC:
+      LoongArchAttributes |=3D CACHE_SUC;
+      break;
+    case EFI_MEMORY_WC:
+      LoongArchAttributes |=3D CACHE_WUC;
+      break;
+    case EFI_MEMORY_WT:
+    case EFI_MEMORY_WB:
+      LoongArchAttributes |=3D CACHE_CC;
+      break;
+    default:
+      LoongArchAttributes |=3D CACHE_CC;
+      break;
+  }
+
+  // Write protection attributes
+  if (((EfiAttributes & EFI_MEMORY_RO) !=3D 0) ||
+      ((EfiAttributes & EFI_MEMORY_WP) !=3D 0))
+  {
+    LoongArchAttributes &=3D ~PAGE_DIRTY;
+  }
+
+  if ((EfiAttributes & EFI_MEMORY_RP) !=3D 0) {
+    LoongArchAttributes |=3D PAGE_NO_READ;
+  }
+
+  // eXecute protection attribute
+  if ((EfiAttributes & EFI_MEMORY_XP) !=3D 0) {
+    LoongArchAttributes |=3D 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 memor=
y 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 success=
fully found
+           EFI_NOT_FOUND         No memory area found
+           EFI_OUT_OF_RESOURCES  Base address or expected memory region ex=
ceeds 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 =3D BaseAddress + *RegionLength;
+  MaxAddress =3D LShiftU64 (1ULL, MAX_VA_BITS) - 1;
+
+  // Clean the value to prepare output to find region size.
+  *RegionLength =3D 0x0;
+
+  if ((BaseAddress >=3D MaxAddress) || (EndAddress >=3D MaxAddress))=
 {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Pte =3D GetPteAddress (BaseAddress);
+
+  if (Pte =3D=3D NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  Attributes =3D GET_PAGE_ATTRIBUTES (*Pte);
+  if (IS_HUGE_PAGE (Pte->PteVal)) {
+    *RegionAttributes =3D Attributes & (~(PAGE_HUGE));
+  } else {
+    *RegionAttributes =3D Attributes;
+  }
+
+  do {
+    Pte =3D GetPteAddress (BaseAddress);
+    if (Pte =3D=3D NULL) {
+      return EFI_SUCCESS;
+    }
+
+    AttributesTmp =3D GET_PAGE_ATTRIBUTES (*Pte);
+    if (AttributesTmp =3D=3D Attributes) {
+      if (IS_HUGE_PAGE (Pte->PteVal)) {
+        AddSize =3D HUGE_PAGE_SIZE;
+      } else {
+        AddSize =3D EFI_PAGE_SIZE;
+      }
+
+      *RegionLength +=3D AddSize;
+      BaseAddress   +=3D AddSize;
+    } else {
+      return EFI_SUCCESS;
+    }
+  } while (BaseAddress <=3D 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 At=
tributes.
+  @param[in]  Attributes     The Attributes to be set.
+  @param[in]  AttributeMask  Mask of memory attributes to take into accoun=
t.
+
+  @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 =3D EfiAttributeConverse (Attributes);
+  Status     =3D MemoryMapPageRange (BaseAddress, BaseAddress + Length, At=
tributes);
+  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 !=3D 0) {
+    mMmuInited =3D TRUE;
+  }
+
+  return RETURN_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CommonMmuLib.h b/Uefi=
CpuPkg/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 r=
eserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Dir    - Directory
+**/
+
+#ifndef  MMU_LIB_CORE_H_
+#define  MMU_LIB_CORE_H_
+
+/**
+  Iterates through the page directory to initialize it.
+
+  @param  Dst  A pointer to the directory of the page to initialize.
+  @param  Num  The number of page directories to initialize.
+  @param  Src  A pointer to the data used to initialize the page directory=
.
+
+  @retval VOID.
+**/
+VOID
+PageDirInit (
+  IN VOID   *dest,
+  IN UINTN  Count,
+  IN VOID   *src
+  );
+
+/**
+  Page tables are established from memory-mapped tables.
+
+  @param  MemoryRegion   A pointer to a memory-mapped table entry.
+
+  @retval     EFI_SUCCESS   The page table was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page table  establishment failed due t=
o 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/L=
ibrary/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 r=
eserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Pgd or Pgd or PGD    - Page Global Directory
+    - Pud or Pud or PUD    - Page Upper Directory
+    - Pmd or Pmd or PMD    - Page Middle Directory
+    - Pte or pte or PTE    - Page Table Entry
+    - Val or VAL or val    - Value
+    - Dir    - Directory
+**/
+
+#ifndef PAGE_H_
+#define PAGE_H_
+
+#include <Library/CpuMmuLib.h>
+
+#define MAX_VA_BITS  47
+#define PGD_WIDE     (8)
+#define PUD_WIDE     (9)
+#define PMD_WIDE     (9)
+#define PTE_WIDE     (9)
+
+#define ENTRYS_PER_PGD  (1 << PGD_WIDE)
+#define ENTRYS_PER_PUD  (1 << PUD_WIDE)
+#define ENTRYS_PER_PMD  (1 << PMD_WIDE)
+#define ENTRYS_PER_PTE  (1 << PTE_WIDE)
+
+#define PGD_SHIFT  (PUD_SHIFT + PUD_WIDE)
+#define PUD_SHIFT  (PMD_SHIFT + PMD_WIDE)
+#define PMD_SHIFT  (EFI_PAGE_SHIFT + PTE_WIDE)
+#define PTE_SHIFT  (EFI_PAGE_SHIFT)
+
+#define PGD_SIZE  (1UL << PGD_SHIFT)
+#define PUD_SIZE  (1UL << PUD_SHIFT)
+#define PMD_SIZE  (1UL << PMD_SHIFT)
+
+#define PGD_MASK   (~(PGD_SIZE-1))
+#define PUD_MASK   (~(PUD_SIZE-1))
+#define PMD_MASK   (~(PMD_SIZE-1))
+#define PAGE_MASK  (~(EFI_PAGE_SIZE - 1))
+#define PFN_MASK   (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \
+                   (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
+
+#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 addr=
ess
+  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 =3D ((Address) + PGD_SIZE) & PGD_MASK;  \
+  (Boundary - 1 < (End) - 1)? Boundary: (End);         \
+})
+
+/**
+  Gets the virtual address of the next block of the specified virtual addr=
ess
+  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 =3D ((Address) + PUD_SIZE) & PUD_MASK;  \
+  (Boundary - 1 < (End) - 1)? Boundary: (End);         \
+})
+
+/**
+  Gets the virtual address of the next block of the specified virtual addr=
ess
+  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 =3D ((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) & (EN=
TRYS_PER_PTE - 1))
+
+/**
+  Calculates the value of the page table entry based on the specified virt=
ual 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_PAG=
E_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) >> P=
MD_SHIFT) << PMD_SHIFT) | \
+                                             ((Attributes) | (GET_GLOBALBI=
T(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) =3D=3D PAGE_HUGE) &am=
p;& \
+                            (((Val) & PAGE_HGLOBAL) =3D=3D PAGE_HGLOBA=
L))
+
+#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) =3D=3D 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) =3D=3D 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) =3D=3D 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/Uefi=
CpuPkg/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 r=
eserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Tlb      - Translation Lookaside Buffer
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#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 alig=
ned.
+**/
+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 =3D NULL;
+  PgdShift       =3D PGD_SHIFT;
+  PgdWide        =3D PGD_WIDE;
+  PudShift       =3D PUD_SHIFT;
+  PudWide        =3D PUD_WIDE;
+  PmdShift       =3D PMD_SHIFT;
+  PmdWide        =3D PMD_WIDE;
+  PteShift       =3D PTE_SHIFT;
+  PteWide        =3D PTE_WIDE;
+
+  if (MemoryTable =3D=3D NULL) {
+    ASSERT (MemoryTable !=3D NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SwapperPageDir =3D AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  ZeroMem (SwapperPageDir, PGD_TABLE_SIZE);
+
+  if (SwapperPageDir =3D=3D NULL) {
+    goto FreeTranslationTable;
+  }
+
+  CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir);
+
+  while (MemoryTable->Length !=3D 0) {
+    DEBUG ((
+      DEBUG_INFO,
+      "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n",
+      __func__,
+      __LINE__,
+      MemoryTable->VirtualBase,
+      (MemoryTable->Length + MemoryTable->VirtualBase),
+      MemoryTable->Attributes
+      ));
+
+    Status =3D FillTranslationTable (MemoryTable);
+    if (EFI_ERROR (Status)) {
+      goto FreeTranslationTable;
+    }
+
+    MemoryTable++;
+  }
+
+  //
+  // TLB Re-entry address at the end of exception vector, a vector is up t=
o 512 bytes,
+  // so the starting address is: total exception vector size + total inter=
rupt vector size + base.
+  // The total size of TLB handler and exception vector size and interrupt=
 vector size should not
+  // be lager than 64KB.
+  //
+  Length           =3D (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillS=
tart;
+  TlbReEntryOffset =3D (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT)=
 * 512;
+  Remaining        =3D TlbReEntryOffset % SIZE_4KB;
+  if (Remaining !=3D 0x0) {
+    TlbReEntryOffset +=3D (SIZE_4KB - Remaining);
+  }
+
+  TlbReEntry =3D PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryO=
ffset;
+  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, Le=
ngth);
+
+  DEBUG ((
+    DEBUG_INFO,
+    "%a  %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudW=
ide %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_SI=
ZE), 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 | PmdShif=
t << 10 | PmdWide << 15 | PudShift << 20 | PudWide <&l=
t; 25));
+  CsrWrite (LOONGARCH_CSR_PWCTL1, (PgdShift | PgdWide << 6));
+
+  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __fu=
nc__, __LINE__, SwapperPageDir));
+
+  return EFI_SUCCESS;
+
+FreeTranslationTable:
+  if (SwapperPageDir !=3D NULL) {
+    FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  }
+
+  return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Tlb.h b/UefiCpuPkg/Li=
brary/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 r=
eserved.<BR>
+
+  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/Uefi=
CpuPkg/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 r=
eserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-------------------------------------------------------------------------=
----
+
+#include <Register/LoongArch64/Csr.h>
+
+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/Lib=
rary/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.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    =3D 1.29
+  BASE_NAME                      =3D PeiCpuMmuLib
+  MODULE_UNI_FILE                =3D PeiCpuMmuLib.uni
+  FILE_GUID                      =3D F67EB983-AC2A-7550-AB69-3BC51A1C895B
+  MODULE_TYPE                    =3D PEIM
+  VERSION_STRING                 =3D 1.0
+  LIBRARY_CLASS                  =3D CpuMmuLib | SEC PEIM
+
+#
+#  VALID_ARCHITECTURES           =3D 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/Lib=
rary/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.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "CPU Memory Manage=
r Unit library instance for PEI modules."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "CPU Memory Manage=
r 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
=20
+[Components.LOONGARCH64]
+  UefiCpuPkg/Library/CpuMmuLib/DxeCpuMmuLib.inf
+  UefiCpuPkg/Library/CpuMmuLib/PeiCpuMmuLib.inf
+
 [BuildOptions]
   *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES
=20
_._,_._,_

Groups.io Links:

=20 You receive all messages sent to this group. =20 =20

View/Reply Online (#114861) | =20 | Mute= This Topic | New Topic
Your Subscriptio= n | Contact Group Owner | Unsubscribe [rebecca@openfw.io]

_._,_._,_
--------------BsSXLlpJMnV6ViNm3TG4MLau--