From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from loongson.cn (loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web08.3549.1668157959834733276 for ; Fri, 11 Nov 2022 01:12:41 -0800 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: loongson.cn, ip: 114.242.206.163, mailfrom: lixianglai@loongson.cn) Received: from loongson.cn (unknown [10.2.5.185]) by gateway (Coremail) with SMTP id _____8BxXbcGEm5jghMGAA--.9766S3; Fri, 11 Nov 2022 17:12:38 +0800 (CST) Received: from localhost.localdomain (unknown [10.2.5.185]) by localhost.localdomain (Coremail) with SMTP id AQAAf8BxFlcAEm5jXc0QAA--.27651S7; Fri, 11 Nov 2022 17:12:37 +0800 (CST) From: "xianglai" To: devel@edk2.groups.io Cc: Bibo Mao , Chao Li , Leif Lindholm , Liming Gao , Michael D Kinney Subject: [edk2-platforms][PATCH V5 05/15] Platform/Loongson: Add MmuLib. Date: Fri, 11 Nov 2022 17:12:20 +0800 Message-Id: <40c87e6da8780f77f841e5b531c866596ff26048.1668157715.git.lixianglai@loongson.cn> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: AQAAf8BxFlcAEm5jXc0QAA--.27651S7 X-CM-SenderInfo: 5ol0xt5qjotxo6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBjvAXoWDWF1kWw1kZF1fJw15Jr17Awb_yoW7CrW3uo WY9F4ruw4UJw4rZr4rCwn2gayxtFsYq39xXr1FvF4jqFsYvrs0kFWUtay5J34fZ34Svrnr GrykXaykJFWS9r1rn29KB7ZKAUJUUUU7529EdanIXcx71UUUUU7KY7ZEXasCq-sGcSsGvf J3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnRJU UUyS1xkIjI8I6I8E6xAIw20EY4v20xvaj40_Wr0E3s1l8cAvFVAK0II2c7xJM28CjxkF64 kEwVA0rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY 1x0267AKxVW8JVWxJwA2z4x0Y4vEx4A2jsIE14v26F4UJVW0owA2z4x0Y4vEx4A2jsIEc7 CjxVAFwI0_Cr1j6rxdM2kKe7AKxVWUXVWUAwAS0I0E0xvYzxvE52x082IY62kv0487Mc80 4VCY07AIYIkI8VC2zVCFFI0UMc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VCjz48v1sIEY2 0_WwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41l42xK82IYc2Ij64vIr41l 42xK82IY6x8ErcxFaVAv8VWrMxC20s026xCaFVCjc4AY6r1j6r4UMxCIbckI1I0E14v26r 1Y6r17MI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CE b7AF67AKxVWUAVWUtwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26ryj6F1UMIIF0x vE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAI cVC2z280aVAFwI0_Cr0_Gr1UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxh VjvjDU0xZFpf9x0zRByIUUUUUU= Content-Transfer-Encoding: quoted-printable Read the memory map information through the QemuFwCfg interface,=0D then build the page table through the memory map information,=0D and finally enable Mmu.=0D =0D REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4054=0D =0D Cc: Bibo Mao =0D Cc: Chao Li =0D Cc: Leif Lindholm =0D Cc: Liming Gao =0D Cc: Michael D Kinney =0D Signed-off-by: xianglai li =0D ---=0D .../LoongArchQemuPkg/Include/Library/MmuLib.h | 85 ++=0D .../LoongArchQemuPkg/Library/MmuLib/Mmu.S | 155 ++++=0D .../Library/MmuLib/MmuBaseLib.inf | 40 +=0D .../Library/MmuLib/MmuBaseLibPei.inf | 47 +=0D .../Library/MmuLib/MmuLibCore.c | 831 ++++++++++++++++++=0D .../Library/MmuLib/MmuLibCore.h | 40 +=0D .../Library/MmuLib/MmuLibCorePei.c | 231 +++++=0D .../LoongArchQemuPkg/Library/MmuLib/mmu.h | 190 ++++=0D .../LoongArchQemuPkg/Library/MmuLib/page.h | 280 ++++++=0D .../LoongArchQemuPkg/Library/MmuLib/pte.h | 57 ++=0D 10 files changed, 1956 insertions(+)=0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuL= ib.h=0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S= =0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBa= seLib.inf=0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBa= seLibPei.inf=0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLi= bCore.c=0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLi= bCore.h=0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLi= bCorePei.c=0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h= =0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.= h=0D create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h= =0D =0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h b/= Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h=0D new file mode 100644=0D index 0000000000..9880fc385c=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h=0D @@ -0,0 +1,85 @@=0D +/** @file=0D +=0D + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - EXC - execute=0D +**/=0D +#ifndef MMU_LIB_H_=0D +#define MMU_LIB_H_=0D +/**=0D + write operation is performed Count times from the first element of Buffe= r.=0D + Convert EFI Attributes to Loongarch Attributes.=0D + @param[in] EfiAttributes Efi Attributes.=0D +=0D + @retval LoongArch Attributes.=0D +**/=0D +UINTN=0D +EfiAttributeToLoongArchAttribute (=0D + IN UINTN EfiAttributes=0D + );=0D +=0D +/**=0D + Finds the length and memory properties of the memory region correspondin= g to the specified base address.=0D +=0D + @param[in] BaseAddress To find the base address of the memory region= .=0D + @param[in] EndAddress To find the end address of the memory region.= =0D + @param[out] RegionLength The length of the memory region found.=0D + @param[out] RegionAttributes Properties of the memory region found.= =0D +=0D + @retval EFI_SUCCESS The corresponding memory area was successfully f= ound=0D + EFI_NOT_FOUND No memory area found=0D +**/=0D +EFI_STATUS=0D +GetLoongArchMemoryRegion (=0D + IN UINTN BaseAddress,=0D + IN UINTN EndAddress,=0D + OUT UINTN *RegionLength,=0D + OUT UINTN *RegionAttributes=0D + );=0D +=0D +/**=0D + Sets the Attributes of the specified memory region=0D +=0D + @param[in] BaseAddress The base address of the memory region to set th= e Attributes.=0D + @param[in] Length The length of the memory region to set the Attr= ibutes.=0D + @param[in] Attributes The Attributes to be set.=0D +=0D + @retval EFI_SUCCESS The Attributes was set successfully=0D +**/=0D +EFI_STATUS=0D +LoongArchSetMemoryAttributes (=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN UINTN Length,=0D + IN UINTN Attributes=0D + );=0D +=0D +/**=0D + Sets the non-executable Attributes for the specified memory region=0D +=0D + @param[in] BaseAddress The base address of the memory region to set th= e Attributes.=0D + @param[in] Length The length of the memory region to set the Attr= ibutes.=0D +=0D + @retval EFI_SUCCESS The Attributes was set successfully=0D +**/=0D +EFI_STATUS=0D +LoongArchSetMemoryRegionNoExec (=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN UINTN Length=0D + );=0D +=0D +/**=0D + Create a page table and initialize the MMU.=0D +=0D + @param[] VOID=0D +=0D + @retval VOID=0D +**/=0D +VOID=0D +EFIAPI=0D +ConfigureMmu (=0D + VOID=0D + );=0D +#endif // MMU_LIB_H_=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S b/Plat= form/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S=0D new file mode 100644=0D index 0000000000..d5863de072=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S=0D @@ -0,0 +1,155 @@=0D +#-------------------------------------------------------------------------= -----=0D +#=0D +# LoongArch for LoongArch=0D +#=0D +# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +#-------------------------------------------------------------------------= ----=0D +=0D +#ifndef __ASSEMBLY__=0D +#define __ASSEMBLY__=0D +#endif=0D +=0D +#include "Library/Cpu.h"=0D +#include "mmu.h"=0D +=0D +ASM_GLOBAL ASM_PFX(HandleTlbRefill)=0D +ASM_GLOBAL HandleTlbRefillEnd=0D +ASM_GLOBAL ASM_PFX(LoongarchInvalidTlb)=0D +ASM_GLOBAL ASM_PFX(SetTlbRefillFuncBase)=0D +ASM_GLOBAL ASM_PFX(WriteCsrPageSize)=0D +ASM_GLOBAL ASM_PFX(WriteCsrTlbRefillPageSize)=0D +ASM_GLOBAL ASM_PFX(WriteCsrStlbPageSize)=0D +ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPwctl0)=0D +ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPwctl1)=0D +ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPgdl)=0D +ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPgdh)=0D +ASM_GLOBAL ASM_PFX(LoongArchXchgCsrCrmd)=0D +=0D +#=0D +# Refill the page table.=0D +# @param VOID=0D +# @retval VOID=0D +#=0D +=0D +ASM_PFX(HandleTlbRefill):=0D + csrwr T0, LOONGARCH_CSR_TLBRSAVE=0D + csrrd T0, LOONGARCH_CSR_PGD=0D + lddir T0, T0, 3 #Put pud BaseAddress into T0=0D + lddir T0, T0, 2 #Put pmd BaseAddress into T0=0D + lddir T0, T0, 1 #Put pte BaseAddress into T0=0D + ldpte T0, 0=0D + ldpte T0, 1=0D + tlbfill=0D + csrrd T0, LOONGARCH_CSR_TLBRSAVE=0D + ertn=0D +HandleTlbRefillEnd:=0D +=0D +#=0D +# Invalid corresponding TLB entries are based on the address given=0D +# @param A0 The address corresponding to the invalid page table entry=0D +# @retval none=0D +#=0D +=0D +ASM_PFX(LoongarchInvalidTlb):=0D + invtlb INVTLB_ADDR_GTRUE_OR_ASID, ZERO, A0=0D + jirl ZERO, RA, 0=0D +=0D +#=0D +# Set Tlb Refill function to hardware=0D +# @param A0 The address of tlb refill function=0D +# @retval none=0D +#=0D +=0D +ASM_PFX(SetTlbRefillFuncBase):=0D + csrwr A0, LOONGARCH_CSR_TLBREBASE=0D + jirl ZERO, RA,0=0D +=0D +#=0D +# Set Cpu Status Register Page Size.=0D +# @param A0 Page Size.=0D +# @retval none=0D +#=0D +=0D +ASM_PFX(WriteCsrPageSize):=0D + li.d T0, CSR_TLBIDX_SIZE=0D + sll.d A0, A0, T0=0D + li.d T0, CSR_TLBIDX_SIZE_MASK=0D + csrxchg A0, T0, LOONGARCH_CSR_TLBIDX=0D + jirl ZERO, RA,0=0D +=0D +#=0D +# Set Cpu Status Register TLBREFILL Page Size.=0D +# @param A0 Page Size.=0D +# @retval none=0D +#=0D +=0D +ASM_PFX(WriteCsrTlbRefillPageSize):=0D + li.d T0, CSR_TLBREHI_PS_SHIFT=0D + sll.d A0, A0, T0=0D + li.d T0, CSR_TLBREHI_PS=0D + csrxchg A0, T0, LOONGARCH_CSR_TLBREHI=0D + jirl ZERO, RA,0=0D +=0D +#=0D +# Set Cpu Status Register STLB Page Size.=0D +# @param val Page Size.=0D +# @retval VOID=0D +#=0D +=0D +ASM_PFX(WriteCsrStlbPageSize):=0D + csrwr A0, LOONGARCH_CSR_STLBPGSIZE=0D + jirl ZERO, RA,0=0D +=0D +#=0D +# Write Csr PWCTL0 register.=0D +# @param A0 The value used to write to the PWCTL0 register=0D +# @retval none=0D +#=0D +=0D +ASM_PFX(LoongArchWriteqCsrPwctl0):=0D + csrwr A0, LOONGARCH_CSR_PWCTL0=0D + jirl ZERO, RA,0=0D +=0D +#=0D +# Write Csr PWCTL1 register.=0D +# @param A0 The value used to write to the PWCTL1 register=0D +# @retval none=0D +#=0D +=0D +ASM_PFX(LoongArchWriteqCsrPwctl1):=0D + csrwr A0, LOONGARCH_CSR_PWCTL1=0D + jirl ZERO, RA,0=0D +=0D +#=0D +# Write Csr PGDL register.=0D +# @param A0 The value used to write to the PGDL register=0D +# @retval none=0D +#=0D +=0D +ASM_PFX(LoongArchWriteqCsrPgdl):=0D + csrwr A0, LOONGARCH_CSR_PGDL=0D + jirl ZERO, RA,0=0D +=0D +#=0D +# Write Csr PGDH register.=0D +# @param A0 The value used to write to the PGDH register=0D +# @retval none=0D +#=0D +=0D +ASM_PFX(LoongArchWriteqCsrPgdh):=0D + csrwr A0, LOONGARCH_CSR_PGDH=0D + jirl ZERO, RA,0=0D +=0D +#=0D +# Exchange specified bit data with the Csr CRMD register.=0D +# @param[IN] A0 The value Exchanged with the CSR CRMD register.=0D +# @param[IN] A1 Specifies the mask for swapping bits=0D +# @retval VOID=0D +#=0D +=0D +ASM_PFX(LoongArchXchgCsrCrmd):=0D + csrxchg A0, A1, LOONGARCH_CSR_CRMD=0D + jirl ZERO, RA,0=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.i= nf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf=0D new file mode 100644=0D index 0000000000..abd864a324=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf=0D @@ -0,0 +1,40 @@=0D +## @file=0D +#=0D +# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights = reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D MmuBaseLib=0D + FILE_GUID =3D da8f0232-fb14-42f0-922c-63104d2c70be= =0D + MODULE_TYPE =3D BASE=0D + VERSION_STRING =3D 1.0=0D + LIBRARY_CLASS =3D MmuLib=0D + CONSTRUCTOR =3D MmuInitialize=0D +=0D +#=0D +# VALID_ARCHITECTURES =3D LOONGARCH64=0D +#=0D +=0D +[Sources]=0D + MmuLibCore.c=0D + Mmu.S=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + Platform/Loongson/LoongArchQemuPkg/Loongson.dec=0D +=0D +[PCD]=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte=0D +=0D +[LibraryClasses]=0D + MemoryAllocationLib=0D + PcdLib=0D + DebugLib=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPe= i.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf= =0D new file mode 100644=0D index 0000000000..12848eecfe=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf=0D @@ -0,0 +1,47 @@=0D +## @file=0D +#=0D +# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights = reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D MmuPeiLib=0D + FILE_GUID =3D da8f0232-fb14-42f0-922c-63104d2c70bd= =0D + MODULE_TYPE =3D BASE=0D + VERSION_STRING =3D 1.0=0D + LIBRARY_CLASS =3D MmuLib | SEC PEIM=0D +=0D +#=0D +# VALID_ARCHITECTURES =3D LOONGARCH64=0D +#=0D +=0D +[Sources]=0D + MmuLibCorePei.c=0D + Mmu.S=0D + MmuLibCore.h=0D + MmuLibCore.c=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + Platform/Loongson/LoongArchQemuPkg/Loongson.dec=0D + OvmfPkg/OvmfPkg.dec=0D +=0D +[PCD]=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize=0D +=0D +[LibraryClasses]=0D + MemoryAllocationLib=0D + CacheMaintenanceLib=0D + PcdLib=0D + DebugLib=0D + QemuFwCfgLib=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c= b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c=0D new file mode 100644=0D index 0000000000..b932e3d568=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c=0D @@ -0,0 +1,831 @@=0D +/** @file=0D +=0D + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - Pgd or Pgd or PGD - Page Global Directory=0D + - Pud or Pud or PUD - Page Upper Directory=0D + - Pmd or Pmd or PMD - Page Middle Directory=0D + - Pte or pte or PTE - Page Table Entry=0D + - Val or VAL or val - Value=0D + - Dir - Directory=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "Library/Cpu.h"=0D +#include "pte.h"=0D +#include "page.h"=0D +#include "mmu.h"=0D +=0D +BOOLEAN mMmuInited =3D FALSE;=0D +/**=0D + Check to see if mmu successfully initializes.=0D +=0D + @param VOID.=0D +=0D + @retval TRUE Initialization has been completed.=0D + FALSE Initialization did not complete.=0D +**/=0D +BOOLEAN=0D +MmuIsInit (VOID) {=0D + if ((mMmuInited =3D=3D TRUE) ||=0D + (PcdGet64 (PcdSwapPageDir) !=3D 0)) {=0D + return TRUE;=0D + }=0D + return FALSE;=0D +}=0D +=0D +/**=0D + Iterates through the page directory to initialize it.=0D +=0D + @param Dst A pointer to the directory of the page to initialize.=0D + @param Num The number of page directories to initialize.=0D + @param Src A pointer to the data used to initialize the page directory= .=0D +=0D + @retval VOID.=0D +**/=0D +VOID=0D +PageDirInit (=0D + IN VOID *Dst,=0D + IN UINTN Num,=0D + IN VOID *Src=0D + )=0D +{=0D + UINTN *Ptr;=0D + UINTN *End;=0D + UINTN Entry;=0D +=0D + Entry =3D (UINTN)Src;=0D + Ptr =3D (UINTN *)Dst;=0D + End =3D Ptr + Num;=0D +=0D + for ( ;Ptr < End; Ptr++) {=0D + *Ptr =3D Entry;=0D + }=0D +=0D + return ;=0D +}=0D +=0D +/**=0D + Gets the virtual address corresponding to the page global directory tabl= e entry.=0D +=0D + @param Address the virtual address for the table entry.=0D +=0D + @retval PGD A pointer to get the table item.=0D +**/=0D +PGD *=0D +PgdOffset (=0D + IN UINTN Address=0D + )=0D +{=0D + return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address);=0D +}=0D +=0D +/**=0D + Gets the virtual address corresponding to the page upper directory table= entry.=0D +=0D + @param Pgd A pointer to a page global directory table entry.=0D + @param Address the virtual address for the table entry.=0D +=0D + @retval PUD A pointer to get the table item.=0D +**/=0D +PUD *=0D +PudOffset (=0D + IN PGD *Pgd,=0D + IN UINTN Address=0D + )=0D +{=0D + UINTN PgdVal =3D (UINTN)PGD_VAL (*Pgd);=0D + return (PUD *)PgdVal + PUD_INDEX (Address);=0D +}=0D +=0D +/**=0D + Gets the virtual address corresponding to the page middle directory tabl= e entry.=0D +=0D + @param Pud A pointer to a page upper directory table entry.=0D + @param Address the virtual address for the table entry.=0D +=0D + @retval PMD A pointer to get the table item.=0D +**/=0D +PMD *=0D +PmdOffset (=0D + IN PUD *Pud,=0D + IN UINTN Address=0D + )=0D +{=0D + UINTN PudVal =3D PUD_VAL (*Pud);=0D + return (PMD *)PudVal + PMD_INDEX (Address);=0D +}=0D +=0D +/**=0D + Gets the virtual address corresponding to the page table entry.=0D +=0D + @param Pmd A pointer to a page middle directory table entry.=0D + @param Address the virtual address for the table entry.=0D +=0D + @retval PTE A pointer to get the table item.=0D +**/=0D +PTE *=0D +PteOffset (=0D + IN PMD *Pmd,=0D + IN UINTN Address=0D + )=0D +{=0D + UINTN PmdVal =3D (UINTN)PMD_VAL (*Pmd);=0D + return (PTE *)PmdVal + PTE_INDEX (Address);=0D +}=0D +=0D +/**=0D + Sets the value of the page table entry.=0D +=0D + @param Pte A pointer to a page table entry.=0D + @param PteVal The value of the page table entry to set.=0D +=0D + @retval VOID=0D +**/=0D +VOID=0D +SetPte (=0D + IN PTE *Pte,=0D + IN PTE PteVal=0D + )=0D +{=0D + *Pte =3D PteVal;=0D +}=0D +=0D +/**=0D + Sets the value of the page global directory.=0D +=0D + @param Pgd A pointer to a page global directory.=0D + @param Pud The value of the page global directory to set.=0D +=0D + @retval VOID=0D +**/=0D +VOID=0D +SetPgd (=0D + IN PGD *Pgd,=0D + IN PUD *Pud=0D + )=0D +{=0D + *Pgd =3D (PGD) {((UINTN)Pud)};=0D +}=0D +=0D +/**=0D + Sets the value of the page upper directory.=0D +=0D + @param Pud A pointer to a page upper directory.=0D + @param Pmd The value of the page upper directory to set.=0D +=0D + @retval VOID=0D +**/=0D +VOID=0D +SetPud (=0D + IN PUD *Pud,=0D + IN PMD *Pmd=0D + )=0D +{=0D + *Pud =3D (PUD) {((UINTN)Pmd)};=0D +}=0D +=0D +/**=0D + Sets the value of the page middle directory.=0D +=0D + @param Pmd A pointer to a page middle directory.=0D + @param Pte The value of the page middle directory to set.=0D +=0D + @retval VOID=0D +**/=0D +VOID=0D +SetPmd (=0D + IN PMD *Pmd,=0D + IN PTE *Pte=0D + )=0D +{=0D + *Pmd =3D (PMD) {((UINTN)Pte)};=0D +}=0D +=0D +/**=0D + Free up memory space occupied by page tables.=0D +=0D + @param Pte A pointer to the page table.=0D +=0D + @retval VOID=0D +**/=0D +VOID=0D +PteFree (=0D + IN PTE *Pte=0D + )=0D +{=0D + FreePages ((VOID *)Pte, 1);=0D +}=0D +=0D +/**=0D + Free up memory space occupied by page middle directory.=0D +=0D + @param Pmd A pointer to the page middle directory.=0D +=0D + @retval VOID=0D +**/=0D +VOID=0D +PmdFree (=0D + IN PMD *Pmd=0D + )=0D +{=0D + FreePages ((VOID *)Pmd, 1);=0D +}=0D +=0D +/**=0D + Free up memory space occupied by page upper directory.=0D +=0D + @param Pud A pointer to the page upper directory.=0D +=0D + @retval VOID=0D +**/=0D +VOID=0D +PudFree (=0D + IN PUD *Pud=0D + )=0D +{=0D + FreePages ((VOID *)Pud, 1);=0D +}=0D +=0D +/**=0D + Requests the memory space required for the page upper directory,=0D + initializes it, and places it in the specified page global directory=0D +=0D + @param Pgd A pointer to the page global directory.=0D +=0D + @retval EFI_SUCCESS Memory request successful.=0D + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested t= o memory.=0D +**/=0D +INTN=0D +PudAlloc (=0D + IN PGD *Pgd=0D + )=0D +{=0D + PUD *Pud =3D (PUD *) AllocatePages (1);=0D + if (!Pud) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPm= d));=0D +=0D + if (pgd_none (*Pgd)) {=0D + SetPgd (Pgd, Pud);=0D + } else { /* Another has populated it */=0D + PudFree (Pud);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Requests the memory space required for the page middle directory,=0D + initializes it, and places it in the specified page upper directory=0D +=0D + @param Pud A pointer to the page upper directory.=0D +=0D + @retval EFI_SUCCESS Memory request successful.=0D + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested t= o memory.=0D +**/=0D +EFI_STATUS=0D +PmdAlloc (=0D + IN PUD *Pud=0D + )=0D +{=0D + PMD *Pmd;=0D +=0D + Pmd =3D (PMD *) AllocatePages (1);=0D + if (!Pmd) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPt= e));=0D +=0D + if (pud_none (*Pud)) {=0D + SetPud (Pud, Pmd);=0D + } else {/* Another has populated it */=0D + PmdFree (Pmd);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Requests the memory space required for the page table,=0D + initializes it, and places it in the specified page middle directory=0D +=0D + @param Pmd A pointer to the page middle directory.=0D +=0D + @retval EFI_SUCCESS Memory request successful.=0D + @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested t= o memory.=0D +**/=0D +INTN=0D +PteAlloc (=0D + IN PMD *Pmd=0D + )=0D +{=0D + PTE *Pte;=0D +=0D + Pte =3D (PTE *) AllocatePages (1);=0D + if (!Pte) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + Pte =3D ZeroMem (Pte, EFI_PAGE_SIZE);=0D +=0D + if (pmd_none (*Pmd)) {=0D + SetPmd (Pmd, Pte);=0D + } else { /* Another has populated it */=0D + PteFree (Pte);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Requests the memory space required for the page upper directory,=0D + initializes it, and places it in the specified page global directory,=0D + and get the page upper directory entry corresponding to the virtual addr= ess=0D +=0D + @param Pgd A pointer to the page global directory.=0D +=0D + @retval Gets the page upper directory entry=0D +**/=0D +PUD *=0D +PudAllocGet (=0D + IN PGD *Pgd,=0D + IN UINTN Address=0D + )=0D +{=0D + return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ?=0D + NULL : PudOffset (Pgd, Address));=0D +}=0D +=0D +/**=0D + Requests the memory space required for the page middle directory,=0D + initializes it, and places it in the specified page upper directory,=0D + and get the page middle directory entry corresponding to the virtual add= ress=0D +=0D + @param Pud A pointer to the page upper directory.=0D +=0D + @retval Gets the page middle directory entry=0D +**/=0D +PMD *=0D +PmdAllocGet (=0D + IN PUD *Pud,=0D + IN UINTN Address=0D + )=0D +{=0D + PMD * ret =3D (pud_none (*Pud) && PmdAlloc (Pud))?=0D + NULL: PmdOffset (Pud, Address);=0D + DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", = __func__, __LINE__,=0D + Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) ));=0D +=0D + return ret;=0D +}=0D +=0D +/**=0D + Requests the memory space required for the page table,=0D + initializes it, and places it in the specified page middle directory,=0D + and get the page table entry corresponding to the virtual address=0D +=0D + @param Pmd A pointer to the page upper directory.=0D +=0D + @retval Gets the page table entry=0D +**/=0D +PTE *=0D +PteAllocGet (=0D + IN PMD *Pmd,=0D + IN UINTN Address=0D + )=0D +{=0D + return (pmd_none (*Pmd) && PteAlloc (Pmd))?=0D + NULL: PteOffset (Pmd, Address);=0D +}=0D +=0D +/**=0D + Gets the physical address of the page table entry corresponding to the s= pecified virtual address.=0D +=0D + @param Address the corresponding virtual address of the page table ent= ry.=0D +=0D + @retval A pointer to the page table entry.=0D + @retval NULL=0D +**/=0D +PTE *=0D +GetPteAddress (=0D + IN UINTN Address=0D + )=0D +{=0D + PGD *Pgd;=0D + PUD *Pud;=0D + PMD *Pmd;=0D +=0D + Pgd =3D PgdOffset (Address);=0D +=0D + if (pgd_none (*Pgd)) {=0D + return NULL;=0D + }=0D +=0D + Pud =3D PudOffset (Pgd, Address);=0D +=0D + if (pud_none (*Pud)) {=0D + return NULL;=0D + }=0D +=0D + Pmd =3D PmdOffset (Pud, Address);=0D + if (pmd_none (*Pmd)) {=0D + return NULL;=0D + }=0D +=0D + if (IS_HUGE_PAGE (Pmd->PmdVal)) {=0D + return ((PTE *)Pmd);=0D + }=0D +=0D + return PteOffset (Pmd, Address);=0D +}=0D +=0D +/**=0D + Establishes a page table entry based on the specified memory region.=0D +=0D + @param Pmd A pointer to the page middle directory.=0D + @param Address The memory space start address.=0D + @param End The end address of the memory space.=0D + @param Attributes Memory space Attributes.=0D +=0D + @retval EFI_SUCCESS The page table entry was created successfully.= =0D + @retval EFI_OUT_OF_RESOURCES Page table entry establishment failed = due to resource exhaustion.=0D +**/=0D +EFI_STATUS=0D +MemoryMapPteRange (=0D + IN PMD *Pmd,=0D + IN UINTN Address,=0D + IN UINTN End,=0D + IN UINTN Attributes=0D + )=0D +{=0D + PTE *Pte;=0D + PTE PteVal;=0D + BOOLEAN UpDate;=0D +=0D + Pte =3D PteAllocGet (Pmd, Address);=0D + if (!Pte) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + do {=0D + UpDate =3D FALSE;=0D + PteVal =3D MAKE_PTE (Address, Attributes);=0D + DEBUG ((DEBUG_VERBOSE,=0D + "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p PTE_IND= EX %p MAKE_PTE %p\n",=0D + __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Addres= s), PMD_INDEX (Address),=0D + PTE_INDEX (Address), PteVal));=0D +=0D + if ((!pte_none (*Pte)) &&=0D + (PTE_VAL(*Pte) !=3D PTE_VAL(PteVal)))=0D + {=0D + UpDate =3D TRUE;=0D + }=0D +=0D + SetPte (Pte, PteVal);=0D + if (UpDate) {=0D + LoongarchInvalidTlb(Address);=0D + }=0D + } while (Pte++, Address +=3D EFI_PAGE_SIZE, Address !=3D End);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Establishes a page middle directory based on the specified memory region= .=0D +=0D + @param Pud A pointer to the page upper directory.=0D + @param Address The memory space start address.=0D + @param End The end address of the memory space.=0D + @param Attributes Memory space Attributes.=0D +=0D + @retval EFI_SUCCESS The page middle directory was created successf= ully.=0D + @retval EFI_OUT_OF_RESOURCES Page middle directory establishment fa= iled due to resource exhaustion.=0D +**/=0D +EFI_STATUS=0D +MemoryMapPmdRange (=0D + IN PUD *Pud,=0D + IN UINTN Address,=0D + IN UINTN End,=0D + IN UINTN Attributes=0D + )=0D +{=0D + PMD *Pmd;=0D + PTE *Pte;=0D + UINTN Next;=0D + UINTN AddressStart_HugePage;=0D + UINTN AddressEnd_HugePage;=0D +=0D + Pmd =3D PmdAllocGet (Pud, Address);=0D + if (!Pmd) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + do {=0D + Next =3D PMD_ADDRESS_END (Address, End);=0D + if (((Address & (~PMD_MASK)) =3D=3D 0) &&=0D + ((Next & (~PMD_MASK)) =3D=3D 0) &&=0D + (pmd_none (*Pmd)))=0D + {=0D + DEBUG ((DEBUG_VERBOSE,=0D + "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p MAKE_= HUGE_PTE %p\n",=0D + __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Addr= ess), PMD_INDEX (Address),=0D + MAKE_HUGE_PTE (Address, Attributes)));=0D +=0D + SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes));=0D + } else {=0D + if ((pmd_none (*Pmd)) ||=0D + ((!pmd_none (*Pmd)) &&=0D + (!IS_HUGE_PAGE (Pmd->PmdVal))))=0D + {=0D + if (MemoryMapPteRange (Pmd, Address, Next, Attributes)) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + } else {=0D + SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte));=0D + AddressStart_HugePage =3D Address & PMD_MASK;=0D + AddressEnd_HugePage =3D AddressStart_HugePage + HUGE_PAGE_SIZE;=0D + if (MemoryMapPteRange (Pmd, AddressStart_HugePage, AddressEnd_Hug= ePage, Attributes)) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + Pte =3D GetPteAddress (AddressStart_HugePage);=0D + if (Pte =3D=3D NULL) {=0D + continue ;=0D + }=0D + if (AddressEnd_HugePage > End) {=0D + Next =3D End;=0D + }=0D + }=0D + }=0D + } while (Pmd++, Address =3D Next, Address !=3D End);=0D +=0D + return 0;=0D +}=0D +=0D +/**=0D + Establishes a page upper directory based on the specified memory region.= =0D +=0D + @param Pgd A pointer to the page global directory.=0D + @param Address The memory space start address.=0D + @param End The end address of the memory space.=0D + @param Attributes Memory space Attributes.=0D +=0D + @retval EFI_SUCCESS The page upper directory was created successfu= lly.=0D + @retval EFI_OUT_OF_RESOURCES Page upper directory establishment fai= led due to resource exhaustion.=0D +**/=0D +EFI_STATUS=0D +MemoryMapPudRange (=0D + IN PGD *Pgd,=0D + IN UINTN Address,=0D + IN UINTN End,=0D + IN UINTN Attributes=0D + )=0D +{=0D + PUD *Pud;=0D + UINTN Next;=0D +=0D + Pud =3D PudAllocGet (Pgd, Address);=0D + if (!Pud) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + do {=0D + Next =3D PUD_ADDRESS_END (Address, End);=0D + if (MemoryMapPmdRange (Pud, Address, Next, Attributes)) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + } while (Pud++, Address =3D Next, Address !=3D End);=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Establishes a page global directory based on the specified memory region= .=0D +=0D + @param Start The memory space start address.=0D + @param End The end address of the memory space.=0D + @param Attributes Memory space Attributes.=0D +=0D + @retval EFI_SUCCESS The page global directory was created successf= ully.=0D + @retval EFI_OUT_OF_RESOURCES Page global directory establishment fa= iled due to resource exhaustion.=0D +**/=0D +EFI_STATUS=0D +MemoryMapPageRange (=0D + IN UINTN Start,=0D + IN UINTN End,=0D + IN UINTN Attributes=0D + )=0D +{=0D + PGD *Pgd;=0D + UINTN Next;=0D + UINTN Address =3D Start;=0D + EFI_STATUS Err;=0D +=0D + Pgd =3D PgdOffset (Address);=0D + do {=0D + Next =3D PGD_ADDRESS_END (Address, End);=0D + Err =3D MemoryMapPudRange (Pgd, Address, Next, Attributes);=0D + if (Err) {=0D + return Err;=0D + }=0D + } while (Pgd++, Address =3D Next, Address !=3D End);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Page tables are established from memory-mapped tables.=0D +=0D + @param MemoryRegion A pointer to a memory-mapped table entry.=0D +=0D + @retval EFI_SUCCESS The page table was created successfully.=0D + @retval EFI_OUT_OF_RESOURCES Page table establishment failed due t= o resource exhaustion.=0D +**/=0D +EFI_STATUS=0D +FillTranslationTable (=0D + IN MEMORY_REGION_DESCRIPTOR *MemoryRegion=0D + )=0D +{=0D + return MemoryMapPageRange (MemoryRegion->VirtualBase,=0D + (MemoryRegion->Length + MemoryRegion->VirtualBase),=0D + MemoryRegion->Attributes);=0D +}=0D +=0D +/**=0D + write operation is performed Count times from the first element of Buffe= r.=0D + Convert EFI Attributes to Loongarch Attributes.=0D + @param[in] EfiAttributes Efi Attributes.=0D +=0D + @retval LoongArch Attributes.=0D +**/=0D +UINTN=0D +EfiAttributeToLoongArchAttribute (=0D + IN UINTN EfiAttributes=0D + )=0D +{=0D + UINTN LoongArchAttributes =3D PAGE_VALID | PAGE_DIRTY | CACHE_CC | PAGE= _USER | PAGE_GLOBAL;=0D + switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {=0D + case EFI_MEMORY_UC:=0D + LoongArchAttributes |=3D CACHE_SUC;=0D + break;=0D + case EFI_MEMORY_WC:=0D + case EFI_MEMORY_WT:=0D + case EFI_MEMORY_WB:=0D + LoongArchAttributes |=3D CACHE_CC;=0D + break;=0D + default :=0D + LoongArchAttributes |=3D CACHE_CC;=0D + break;=0D + }=0D +=0D + // Write protection attributes=0D + if ((EfiAttributes & EFI_MEMORY_RO) !=3D 0) {=0D + LoongArchAttributes &=3D ~PAGE_DIRTY;=0D + }=0D +=0D + //eXecute protection attribute=0D + if ((EfiAttributes & EFI_MEMORY_XP) !=3D 0) {=0D + LoongArchAttributes |=3D PAGE_NO_EXEC;=0D + }=0D +=0D + return LoongArchAttributes;=0D +}=0D +=0D +/**=0D + Finds the length and memory properties of the memory region correspondin= g to the specified base address.=0D +=0D + @param[in] BaseAddress To find the base address of the memory region= .=0D + @param[in] EndAddress To find the end address of the memory region.= =0D + @param[out] RegionLength The length of the memory region found.=0D + @param[out] RegionAttributes Properties of the memory region found.= =0D +=0D + @retval EFI_SUCCESS The corresponding memory area was successfully f= ound=0D + EFI_NOT_FOUND No memory area found=0D +**/=0D +EFI_STATUS=0D +GetLoongArchMemoryRegion (=0D + IN UINTN BaseAddress,=0D + IN UINTN EndAddress,=0D + OUT UINTN *RegionLength,=0D + OUT UINTN *RegionAttributes=0D + )=0D +{=0D + PTE *Pte;=0D + UINTN Attributes;=0D + UINTN AttributesTmp;=0D + UINTN MaxAddress;=0D + MaxAddress =3D LShiftU64 (1ULL, MAX_VA_BITS) - 1;=0D + Pte =3D GetPteAddress (BaseAddress);=0D +=0D + if (!MmuIsInit ()) {=0D + return EFI_SUCCESS;=0D + }=0D + if (Pte =3D=3D NULL) {=0D + return EFI_NOT_FOUND;=0D + }=0D + Attributes =3D GET_PAGE_ATTRIBUTES (*Pte);=0D + if (IS_HUGE_PAGE (Pte->PteVal)) {=0D + *RegionAttributes =3D Attributes & (~(PAGE_HUGE));=0D + *RegionLength +=3D HUGE_PAGE_SIZE;=0D + } else {=0D + *RegionLength +=3D EFI_PAGE_SIZE;=0D + *RegionAttributes =3D Attributes;=0D + }=0D +=0D + while (BaseAddress <=3D MaxAddress) {=0D + Pte =3D GetPteAddress (BaseAddress);=0D + if (Pte =3D=3D NULL) {=0D + return EFI_SUCCESS;=0D + }=0D + AttributesTmp =3D GET_PAGE_ATTRIBUTES (*Pte);=0D + if (IS_HUGE_PAGE (Pte->PteVal)) {=0D + if (AttributesTmp =3D=3D Attributes) {=0D + *RegionLength +=3D HUGE_PAGE_SIZE;=0D + }=0D + BaseAddress +=3D HUGE_PAGE_SIZE;=0D + } else {=0D + if (AttributesTmp =3D=3D Attributes) {=0D + *RegionLength +=3D EFI_PAGE_SIZE;=0D + }=0D + BaseAddress +=3D EFI_PAGE_SIZE;=0D + }=0D +=0D + if (BaseAddress > EndAddress) {=0D + break;=0D + }=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Sets the Attributes of the specified memory region=0D +=0D + @param[in] BaseAddress The base address of the memory region to set th= e Attributes.=0D + @param[in] Length The length of the memory region to set the Attr= ibutes.=0D + @param[in] Attributes The Attributes to be set.=0D +=0D + @retval EFI_SUCCESS The Attributes was set successfully=0D +**/=0D +EFI_STATUS=0D +LoongArchSetMemoryAttributes (=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN UINTN Length,=0D + IN UINTN Attributes=0D + )=0D +{=0D +=0D + if (!MmuIsInit ()) {=0D + return EFI_SUCCESS;=0D + }=0D + Attributes =3D EfiAttributeToLoongArchAttribute (Attributes);=0D + DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddr= ess , Length, Attributes));=0D + MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Sets the non-executable Attributes for the specified memory region=0D +=0D + @param[in] BaseAddress The base address of the memory region to set th= e Attributes.=0D + @param[in] Length The length of the memory region to set the Attr= ibutes.=0D +=0D + @retval EFI_SUCCESS The Attributes was set successfully=0D +**/=0D +EFI_STATUS=0D +LoongArchSetMemoryRegionNoExec (=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN UINTN Length=0D + )=0D +{=0D + if (MmuIsInit ()) {=0D + Length =3D EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));=0D + LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP);=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Check to see if mmu successfully initializes and saves the result.=0D +=0D + @param VOID.=0D +=0D + @retval EFI_SUCCESS Initialization succeeded.=0D +**/=0D +EFI_STATUS=0D +MmuInitialize (VOID)=0D +{=0D + if (PcdGet64 (PcdSwapPageDir) !=3D 0) {=0D + mMmuInited =3D TRUE;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h= b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h=0D new file mode 100644=0D index 0000000000..7a5e8ea0dd=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h=0D @@ -0,0 +1,40 @@=0D +/** @file=0D +=0D + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - Dir - Directory=0D +**/=0D +#ifndef MMU_LIB_CORE_H_=0D +#define MMU_LIB_CORE_H_=0D +/**=0D + Iterates through the page directory to initialize it.=0D +=0D + @param Dst A pointer to the directory of the page to initialize.=0D + @param Num The number of page directories to initialize.=0D + @param Src A pointer to the data used to initialize the page directory= .=0D +=0D + @retval VOID.=0D +**/=0D +VOID=0D +PageDirInit (=0D + IN VOID *dest,=0D + IN UINTN Count,=0D + IN VOID *src=0D + );=0D +=0D +/**=0D + Page tables are established from memory-mapped tables.=0D +=0D + @param MemoryRegion A pointer to a memory-mapped table entry.=0D +=0D + @retval EFI_SUCCESS The page table was created successfully.=0D + @retval EFI_OUT_OF_RESOURCES Page table establishment failed due t= o resource exhaustion.=0D +**/=0D +EFI_STATUS=0D +FillTranslationTable (=0D + IN MEMORY_REGION_DESCRIPTOR *MemoryRegion=0D + );=0D +#endif // MMU_LIB_CORE_H_=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePe= i.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c=0D new file mode 100644=0D index 0000000000..32a7fc0beb=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c=0D @@ -0,0 +1,231 @@=0D +/** @file=0D + Platform PEI driver=0D +=0D + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - FwCfg - Firmeware Config=0D + - Tlb - Translation Lookaside Buffer=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "Library/Cpu.h"=0D +#include "pte.h"=0D +#include "page.h"=0D +#include "mmu.h"=0D +#include =0D +#include "MmuLibCore.h"=0D +#include =0D +=0D +/**=0D + Return the Virtual Memory Map of your platform=0D +=0D + This Virtual Memory Map is used by MemoryInitPei Module to initialize th= e MMU=0D + on your platform.=0D +=0D + @param[out] VirtualMemoryMap Array of MEMORY_REGION_DESCRIPTOR=0D + describing a Physical-to-Virtual Memor= y=0D + mapping. This array must be ended by a= =0D + zero-filled entry. The allocated memor= y=0D + will not be freed.=0D +**/=0D +VOID=0D +GetMemoryMapFromFwCfg (=0D + OUT MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap=0D + )=0D +{=0D +=0D + EFI_STATUS Status;=0D + FIRMWARE_CONFIG_ITEM FwCfgItem;=0D + UINTN FwCfgSize;=0D + LOONGARCH_MEMMAP_ENTRY MemoryMapEntry;=0D + LOONGARCH_MEMMAP_ENTRY *StartEntry;=0D + LOONGARCH_MEMMAP_ENTRY *pEntry;=0D + UINTN Processed;=0D + MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;=0D + UINTN Index =3D 0;=0D + ASSERT (VirtualMemoryMap !=3D NULL);=0D +=0D + VirtualMemoryTable =3D AllocatePool (=0D + sizeof (MEMORY_REGION_DESCRIPTOR) *=0D + MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS=0D + );=0D + VirtualMemoryTable[Index].PhysicalBase =3D 0x10000000;=0D + VirtualMemoryTable[Index].VirtualBase =3D VirtualMemoryTable[Index].Phy= sicalBase;=0D + VirtualMemoryTable[Index].Length =3D 0x10000000;=0D + VirtualMemoryTable[Index].Attributes =3D PAGE_VALID | PLV_KERNEL | CA= CHE_SUC | PAGE_DIRTY | PAGE_GLOBAL;=0D + ++Index;=0D +=0D + Status =3D QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __fun= c__, __LINE__, Status));=0D + ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR)= );=0D + *VirtualMemoryMap =3D VirtualMemoryTable;=0D + return ;=0D + }=0D + if (FwCfgSize % sizeof MemoryMapEntry !=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize));= =0D + }=0D +=0D + QemuFwCfgSelectItem (FwCfgItem);=0D + StartEntry =3D AllocatePages (EFI_SIZE_TO_PAGES (FwCfgSize));=0D + QemuFwCfgReadBytes (FwCfgSize, StartEntry);=0D + for (Processed =3D 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); P= rocessed++) {=0D + pEntry =3D StartEntry + Processed;=0D + if (pEntry->Length =3D=3D 0) {=0D + continue;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p type %d\n", pEntry= ->BaseAddr, pEntry->Length, pEntry->Type));=0D + VirtualMemoryTable[Index].PhysicalBase =3D pEntry->BaseAddr;=0D + VirtualMemoryTable[Index].VirtualBase =3D VirtualMemoryTable[Index].P= hysicalBase;=0D + VirtualMemoryTable[Index].Length =3D pEntry->Length;=0D + VirtualMemoryTable[Index].Attributes =3D PAGE_VALID | PLV_KERNEL | = CACHE_CC | PAGE_DIRTY | PAGE_GLOBAL;=0D + ++Index;=0D + }=0D +=0D + FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize));=0D + // End of Table=0D + ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));= =0D + *VirtualMemoryMap =3D VirtualMemoryTable;=0D + return ;=0D +}=0D +=0D +/**=0D + Create a page table and initialize the MMU.=0D +=0D + @param[] VOID=0D +=0D + @retval VOID=0D +**/=0D +EFIAPI=0D +VOID=0D +ConfigureMmu (VOID)=0D +{=0D + PGD *SwapperPageDir =3D NULL;=0D + PGD *InvalidPgd =3D NULL;=0D + PUD *InvalidPudTable =3D NULL;=0D + PMD *InvalidPmdTable =3D NULL;=0D + PTE *InvalidPteTable =3D NULL;=0D + MEMORY_REGION_DESCRIPTOR *MemoryTable =3D NULL;=0D + RETURN_STATUS PcdStatus;=0D + UINTN PgdShift =3D PGD_SHIFT;=0D + UINTN PgdWide =3D PGD_WIDE;=0D + UINTN PudShift =3D PUD_SHIFT;=0D + UINTN PudWide =3D PUD_WIDE;=0D + UINTN PmdShift =3D PMD_SHIFT;=0D + UINTN PmdWide =3D PMD_WIDE;=0D + UINTN PteShift =3D PTE_SHIFT;=0D + UINTN PteWide =3D PTE_WIDE;=0D + UINTN PageEnable =3D 1 << 4;=0D + VOID *TlbReEntry;=0D +=0D + SwapperPageDir =3D AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));=0D + InvalidPgd =3D AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));=0D + InvalidPudTable =3D AllocatePages (EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));= =0D + InvalidPmdTable =3D AllocatePages (EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));= =0D + InvalidPteTable =3D AllocatePages (EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));= =0D + ZeroMem (InvalidPteTable, PTE_TABLE_SIZE);=0D +=0D + if ((!InvalidPgd) ||=0D + (!InvalidPudTable) ||=0D + (!InvalidPmdTable) ||=0D + (!InvalidPteTable))=0D + {=0D + goto FreeTranslationTable;=0D + }=0D +=0D + /*pgd init*/=0D + PageDirInit (SwapperPageDir , ENTRYS_PER_PGD, InvalidPudTable);=0D + /*pgd init*/=0D + PageDirInit (InvalidPgd, ENTRYS_PER_PGD, InvalidPudTable);=0D + /*pud init*/=0D + PageDirInit (InvalidPudTable, ENTRYS_PER_PUD, InvalidPmdTable);=0D + /*pmd init*/=0D + PageDirInit (InvalidPmdTable, ENTRYS_PER_PMD, InvalidPteTable);=0D + GetMemoryMapFromFwCfg (&MemoryTable);=0D +=0D + PcdStatus |=3D PcdSet64S (PcdSwapPageDir, (UINTN)SwapperPageDir);=0D + PcdStatus |=3D PcdSet64S (PcdInvalidPgd, (UINTN)InvalidPgd);=0D + PcdStatus |=3D PcdSet64S (PcdInvalidPud, (UINTN)InvalidPudTable);=0D + PcdStatus |=3D PcdSet64S (PcdInvalidPmd, (UINTN)InvalidPmdTable);=0D + PcdStatus |=3D PcdSet64S (PcdInvalidPte, (UINTN)InvalidPteTable);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +=0D + while (MemoryTable->Length !=3D 0) {=0D + DEBUG ((DEBUG_VERBOSE, "%a %d VirtualBase %p VirtualEnd %p Attributes = %p .\n", __func__, __LINE__,=0D + MemoryTable->VirtualBase,=0D + (MemoryTable->Length + MemoryTable->VirtualBase),=0D + MemoryTable->Attributes));=0D +=0D + PcdStatus =3D FillTranslationTable (MemoryTable);=0D + if (EFI_ERROR (PcdStatus)) {=0D + goto FreeTranslationTable;=0D + }=0D + MemoryTable++;=0D + }=0D +=0D + TlbReEntry =3D AllocatePages (1);=0D + if (TlbReEntry =3D=3D NULL) {=0D + goto FreeTranslationTable;=0D + }=0D + CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - Hand= leTlbRefill));=0D + InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefill, (UINTN)= (HandleTlbRefillEnd - HandleTlbRefill));=0D +=0D + DEBUG ((DEBUG_VERBOSE,=0D + "%a %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudW= ide %d PgdShift %d PgdWide %d.\n",=0D + __func__, __LINE__,=0D + PteShift, PteWide, PmdShift, PmdWide,PudShift, PudWide, PgdShift, PgdW= ide));=0D +=0D + SetTlbRefillFuncBase ((UINTN)TlbReEntry);=0D + /*set page size*/=0D + WriteCsrPageSize (DEFAULT_PAGE_SIZE);=0D + WriteCsrStlbPageSize (DEFAULT_PAGE_SIZE);=0D + WriteCsrTlbRefillPageSize (DEFAULT_PAGE_SIZE);=0D +=0D + LoongArchWriteqCsrPwctl0 ((PteShift | PteWide << 5 | PmdShift << 10 | Pm= dWide << 15 | PudShift << 20 | PudWide << 25=0D + ));=0D + LoongArchWriteqCsrPwctl1 (PgdShift | PgdWide << 6);=0D + LoongArchWriteqCsrPgdl ((UINTN)SwapperPageDir);=0D + LoongArchWriteqCsrPgdh ((UINTN)InvalidPgd);=0D +=0D + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __fu= nc__, __LINE__, SwapperPageDir));=0D + LoongArchXchgCsrCrmd ( PageEnable, 1 << 4);=0D + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu End.\n", __func__, __LINE__));=0D +=0D + return ;=0D +=0D +FreeTranslationTable:=0D + if (SwapperPageDir) {=0D + FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));=0D + }=0D +=0D + if (InvalidPgd) {=0D + FreePages (InvalidPgd, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));=0D + }=0D +=0D + if (InvalidPudTable) {=0D + FreePages (InvalidPudTable, EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));=0D + }=0D +=0D + if (InvalidPmdTable) {=0D + FreePages (InvalidPmdTable, EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));=0D + }=0D +=0D + if (InvalidPteTable) {=0D + FreePages (InvalidPteTable, EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));=0D + }=0D +=0D + PcdSet64S (PcdSwapPageDir, (UINTN)0);=0D + PcdSet64S (PcdInvalidPgd, (UINTN)0);=0D + PcdSet64S (PcdInvalidPud, (UINTN)0);=0D + PcdSet64S (PcdInvalidPmd, (UINTN)0);=0D + PcdSet64S (PcdInvalidPte, (UINTN)0);=0D +=0D + return ;=0D +}=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h b/Plat= form/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h=0D new file mode 100644=0D index 0000000000..8e284a2ecd=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h=0D @@ -0,0 +1,190 @@=0D +/** @file=0D +=0D + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - Tlb or TLB - Translation Lookaside Buffer=0D + - CSR - Cpu State Register=0D + - PGDL - Page Global Directory Low=0D + - PGDH - Page Global Directory High=0D + - TLBIDX - TLB Index=0D + - TLBREHI - TLB Refill Entry High=0D + - PWCTL - Page Walk Control=0D + - STLB - Singular Page Size TLB=0D + - PS - Page Size=0D +**/=0D +#ifndef MMU_H_=0D +#define MMU_H_=0D +/*page size 4k*/=0D +#define DEFAULT_PAGE_SIZE 0x0c=0D +#define LOONGARCH_CSR_PGDL 0x19 /* Page table base address when VA[= 47] =3D 0 */=0D +#define LOONGARCH_CSR_PGDH 0x1a /* Page table base address when VA[= 47] =3D 1 */=0D +#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP *= /=0D +#define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi */=0D +#define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */=0D +#define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */=0D +#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */=0D +#define LOONGARCH_CSR_PWCTL0 0x1c /* PWCtl0 */=0D +#define LOONGARCH_CSR_PWCTL1 0x1d /* PWCtl1 */=0D +#define LOONGARCH_CSR_STLBPGSIZE 0x1e=0D +#define CSR_TLBIDX_SIZE_MASK 0x3f000000=0D +#define CSR_TLBIDX_PS_SHIFT 24=0D +#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT=0D +=0D +#define CSR_TLBREHI_PS_SHIFT 0=0D +#define CSR_TLBREHI_PS 0x3f=0D +=0D +#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \=0D + EFI_MEMORY_WC | \=0D + EFI_MEMORY_WT | \=0D + EFI_MEMORY_WB | \=0D + EFI_MEMORY_UCE \=0D + )=0D +=0D +typedef struct {=0D + EFI_PHYSICAL_ADDRESS PhysicalBase;=0D + EFI_VIRTUAL_ADDRESS VirtualBase;=0D + UINTN Length;=0D + UINTN Attributes;=0D +} MEMORY_REGION_DESCRIPTOR;=0D +=0D +// The total number of descriptors, including the final "end-of-table" des= criptor.=0D +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)=0D +=0D +extern CHAR8 HandleTlbRefill[], HandleTlbRefillEnd[];=0D +=0D +/*=0D + Invalid corresponding TLB entries are based on the address given=0D +=0D + @param Address The address corresponding to the invalid page table entry= =0D +=0D + @retval none=0D +*/=0D +extern=0D +VOID=0D +LoongarchInvalidTlb (=0D + UINTN Address=0D + );=0D +=0D +/*=0D + Set Tlb Refill function to hardware=0D +=0D + @param A0 The address of tlb refill function=0D +=0D + @retval none=0D +*/=0D +extern=0D +VOID=0D +SetTlbRefillFuncBase (=0D + UINTN Address=0D + );=0D +=0D +/*=0D + Set Cpu Status Register Page Size.=0D +=0D + @param PageSize Page Size.=0D +=0D + @retval none=0D +*/=0D +extern=0D +VOID=0D +WriteCsrPageSize (=0D + UINTN PageSize=0D + );=0D +=0D +/*=0D + Set Cpu Status Register TLBREFILL Page Size.=0D +=0D + @param PageSize Page Size.=0D +=0D + @retval none=0D +*/=0D +extern=0D +VOID=0D +WriteCsrTlbRefillPageSize (=0D + UINTN PageSize=0D + );=0D +=0D +/*=0D + Set Cpu Status Register STLB Page Size.=0D +=0D + @param PageSize Page Size.=0D +=0D + @retval VOID=0D +*/=0D +extern=0D +VOID=0D +WriteCsrStlbPageSize (=0D + UINTN PageSize=0D +);=0D +=0D +/*=0D + Write Csr PWCTL0 register.=0D +=0D + @param Val The value used to write to the PWCTL0 register=0D +=0D + @retval none=0D +*/=0D +extern=0D +VOID=0D +LoongArchWriteqCsrPwctl0 (=0D + UINTN Val=0D + );=0D +=0D +/*=0D + Write Csr PWCTL1 register.=0D +=0D + @param Val The value used to write to the PWCTL1 register=0D +=0D + @retval none=0D +*/=0D +extern=0D +VOID=0D +LoongArchWriteqCsrPwctl1 (=0D + UINTN Val=0D + );=0D +=0D +/*=0D + Write Csr PGDL register.=0D +=0D + @param Val The value used to write to the PGDL register=0D +=0D + @retval none=0D +*/=0D +extern=0D +VOID=0D +LoongArchWriteqCsrPgdl (=0D + UINTN Val=0D + );=0D +=0D +/*=0D + Write Csr PGDH register.=0D +=0D + @param Val The value used to write to the PGDH register=0D +=0D + @retval none=0D +*/=0D +extern=0D +VOID=0D +LoongArchWriteqCsrPgdh (=0D + UINTN Val=0D + );=0D +=0D +/*=0D + Exchange specified bit data with the Csr CRMD register.=0D +=0D + @param[IN] Val The value Exchanged with the CSR CRMD register.=0D + @param[IN] Mask Specifies the mask for swapping bits=0D +=0D + @retval VOID=0D +*/=0D +extern=0D +VOID=0D +LoongArchXchgCsrCrmd (=0D + UINTN Val,=0D + UINTN Mask=0D + );=0D +=0D +#endif // MMU_H_=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Pla= tform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h=0D new file mode 100644=0D index 0000000000..6ab07e7900=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h=0D @@ -0,0 +1,280 @@=0D +/** @file=0D +=0D + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - Pgd or Pgd or PGD - Page Global Directory=0D + - Pud or Pud or PUD - Page Upper Directory=0D + - Pmd or Pmd or PMD - Page Middle Directory=0D + - Pte or pte or PTE - Page Table Entry=0D + - Val or VAL or val - Value=0D + - Dir - Directory=0D +**/=0D +#ifndef PAGE_H_=0D +#define PAGE_H_=0D +=0D +#define MAX_VA_BITS 47=0D +#define PGD_WIDE (8)=0D +#define PUD_WIDE (9)=0D +#define PMD_WIDE (9)=0D +#define PTE_WIDE (9)=0D +=0D +#define ENTRYS_PER_PGD (1 << PGD_WIDE)=0D +#define ENTRYS_PER_PUD (1 << PUD_WIDE)=0D +#define ENTRYS_PER_PMD (1 << PMD_WIDE)=0D +#define ENTRYS_PER_PTE (1 << PTE_WIDE)=0D +=0D +#define PGD_SHIFT (PUD_SHIFT + PUD_WIDE)=0D +#define PUD_SHIFT (PMD_SHIFT + PMD_WIDE)=0D +#define PMD_SHIFT (EFI_PAGE_SHIFT + PTE_WIDE)=0D +#define PTE_SHIFT (EFI_PAGE_SHIFT)=0D +=0D +#define PGD_SIZE (1UL << PGD_SHIFT)=0D +#define PUD_SIZE (1UL << PUD_SHIFT)=0D +#define PMD_SIZE (1UL << PMD_SHIFT)=0D +=0D +#define PGD_MASK (~(PGD_SIZE-1))=0D +#define PUD_MASK (~(PUD_SIZE-1))=0D +#define PMD_MASK (~(PMD_SIZE-1))=0D +#define PAGE_MASK (~(EFI_PAGE_SIZE - 1))=0D +#define PFN_MASK (~(((UINTN)(1) << (EFI_PAGE_SH= IFT)) - 1) & \=0D + (((UINTN)(1) << (PAGE_PFN_END= _SHIFT)) - 1))=0D +=0D +typedef struct { UINTN PgdVal; } PGD;=0D +typedef struct { UINTN PudVal; } PUD;=0D +typedef struct { UINTN PmdVal; } PMD;=0D +typedef struct { UINTN PteVal; } PTE;=0D +/**=0D + Gets the value of the page global directory table entry.=0D +=0D + @param x Page global directory struct variables.=0D +=0D + @retval the value of the page global directory table entry.=0D + **/=0D +#define PGD_VAL(x) ((x).PgdVal)=0D +/**=0D + Gets the value of the page upper directory table entry.=0D +=0D + @param x Page upper directory struct variables.=0D +=0D + @retval the value of the page upper directory table entry.=0D + **/=0D +#define PUD_VAL(x) ((x).PudVal)=0D +/**=0D + Gets the value of the page middle directory table entry.=0D +=0D + @param x Page middle directory struct variables.=0D +=0D + @retval the value of the page middle directory table entry.=0D + **/=0D +#define PMD_VAL(x) ((x).PmdVal)=0D +/**=0D + Gets the value of the page table entry.=0D +=0D + @param x Page table entry struct variables.=0D +=0D + @retval the value of the page table entry.=0D + **/=0D +#define PTE_VAL(x) ((x).PteVal)=0D +=0D +#define PGD_TABLE_SIZE (ENTRYS_PER_PGD * sizeof(PGD))= =0D +#define PUD_TABLE_SIZE (ENTRYS_PER_PUD * sizeof(PUD))= =0D +#define PMD_TABLE_SIZE (ENTRYS_PER_PMD * sizeof(PMD))= =0D +#define PTE_TABLE_SIZE (ENTRYS_PER_PTE * sizeof(PTE))= =0D +/**=0D + Gets the physical address of the record in the page table entry.=0D +=0D + @param x Page table entry struct variables.=0D +=0D + @retval the value of the physical address.=0D + **/=0D +#define GET_PAGE_ATTRIBUTES(x) (UINTN) {(PTE_VAL(x) & ~PFN_MA= SK)}=0D +/**=0D + Gets the virtual address of the next block of the specified virtual addr= ess=0D + that is aligned with the size of the global page directory mapping.=0D +=0D + @param Address Specifies the virtual address.=0D + @param End The end address of the memory region.=0D +=0D + @retval the specified virtual address of the next block.=0D + **/=0D +#define PGD_ADDRESS_END(Address, End) \=0D +({ \=0D + UINTN Boundary =3D ((Address) + PGD_SIZE) & PGD_MASK; \=0D + (Boundary - 1 < (End) - 1)? Boundary: (End); \=0D +})=0D +/**=0D + Gets the virtual address of the next block of the specified virtual addr= ess=0D + that is aligned with the size of the page upper directory mapping.=0D +=0D + @param Address Specifies the virtual address.=0D + @param End The end address of the memory region.=0D +=0D + @retval the specified virtual address of the next block.=0D + **/=0D +#define PUD_ADDRESS_END(Address, End) \=0D +({ \=0D + UINTN Boundary =3D ((Address) + PUD_SIZE) & PUD_MASK; \=0D + (Boundary - 1 < (End) - 1)? Boundary: (End); \=0D +})=0D +/**=0D + Gets the virtual address of the next block of the specified virtual addr= ess=0D + that is aligned with the size of the page middle directory mapping.=0D +=0D + @param Address Specifies the virtual address.=0D + @param End The end address of the memory region.=0D +=0D + @retval the specified virtual address of the next block.=0D + **/=0D +#define PMD_ADDRESS_END(Address, End) \=0D +({ \=0D + UINTN Boundary =3D ((Address) + PMD_SIZE) & PMD_MASK; \=0D + (Boundary - 1 < (End) - 1)? Boundary: (End); \=0D +})=0D +/**=0D + Get Specifies the virtual address corresponding to the index of the page= global directory table entry.=0D +=0D + @param Address Specifies the virtual address.=0D +=0D + @retval the index of the page global directory table entry.=0D + **/=0D +#define PGD_INDEX(Address) (((Address) >> PGD_SHIFT) & (E= NTRYS_PER_PGD-1))=0D +/**=0D + Get Specifies the virtual address corresponding to the index of the page= upper directory table entry.=0D +=0D + @param Address Specifies the virtual address.=0D + @param End The end address of the memory region.=0D +=0D + @retval the index of the page upper directory table entry.=0D + **/=0D +#define PUD_INDEX(Address) (((Address) >> PUD_SHIFT) & (E= NTRYS_PER_PUD - 1))=0D +/**=0D + Get Specifies the virtual address corresponding to the index of the page= middle directory table entry.=0D +=0D + @param Address Specifies the virtual address.=0D +=0D + @retval the index of the page middle directory table entry.=0D + **/=0D +#define PMD_INDEX(Address) (((Address) >> PMD_SHIFT) & (E= NTRYS_PER_PMD - 1))=0D +/**=0D + Get Specifies the virtual address corresponding to the index of the page= table entry.=0D +=0D + @param Address Specifies the virtual address.=0D +=0D + @retval the index of the page table entry.=0D + **/=0D +#define PTE_INDEX(Address) (((Address) >> EFI_PAGE_SHIFT)= & (ENTRYS_PER_PTE - 1))=0D +=0D +/**=0D + Calculates the value of the page table entry based on the specified virt= ual address and properties.=0D +=0D + @param Address Specifies the virtual address.=0D + @param Attributes Specifies the Attributes.=0D +=0D + @retval the value of the page table entry.=0D + **/=0D +#define MAKE_PTE(Address, Attributes) (PTE){((((Address) >> EFI_PAGE= _SHIFT) << 12) | (Attributes))}=0D +/**=0D + Get Global bit from Attributes=0D +=0D + @param Attributes Specifies the Attributes.=0D + * */=0D +#define GET_GLOBALBIT(Attributes) ((Attributes & PAGE_GLOBAL) >>= PAGE_GLOBAL_SHIFT)=0D +/**=0D + Calculates the value of the Huge page table entry based on the specified= virtual address and properties.=0D +=0D + @param Address Specifies the virtual address.=0D + @param Attributes Specifies the Attributes.=0D +=0D + @retval the value of the HUGE page table entry.=0D + **/=0D +#define MAKE_HUGE_PTE(Address, Attributes) (((((Address) >> PMD_SHIFT) <<= PMD_SHIFT) | \=0D + ((Attributes) | (GET_GLOBALBI= T(Attributes) << PAGE_HGLOBAL_SHIFT) | \=0D + PAGE_HUGE)))=0D +=0D + /**=0D + Check whether the large page table entry is.=0D +=0D + @param Val The value of the page table entry.=0D +=0D + @retval 1 Is huge page table entry.=0D + @retval 0 Isn't huge page table entry.=0D + **/=0D +#define IS_HUGE_PAGE(Val) ((((Val) & PAGE_HUGE) =3D=3D P= AGE_HUGE) && \=0D + (((Val) & PAGE_HGLOBAL) =3D= =3D PAGE_HGLOBAL))=0D +=0D +#define HUGE_PAGE_SIZE (PMD_SIZE)=0D +=0D + /**=0D + Check that the global page directory table entry is empty.=0D +=0D + @param pgd the global page directory struct variables.=0D +=0D + @retval 1 Is huge page table entry.=0D + @retval 0 Isn't huge page table entry.=0D + **/=0D +STATIC=0D +inline=0D +UINTN=0D +pgd_none (=0D + IN PGD pgd=0D + )=0D +{=0D + return (PGD_VAL(pgd) =3D=3D (UINTN)PcdGet64(PcdInvalidPud));=0D +}=0D +=0D + /**=0D + Check that the page upper directory table entry is empty.=0D +=0D + @param pud Page upper directory struct variables.=0D +=0D + @retval 1 Is huge page table entry.=0D + @retval 0 Isn't huge page table entry.=0D + **/=0D +STATIC=0D +inline=0D +UINTN=0D +pud_none (=0D + IN PUD pud=0D + )=0D +{=0D + return (PUD_VAL(pud) =3D=3D (UINTN)PcdGet64 (PcdInvalidPmd));=0D +}=0D +=0D + /**=0D + Check that the page middle directory table entry is empty.=0D +=0D + @param pmd Page middle directory struct variables.=0D +=0D + @retval 1 Is huge page table entry.=0D + @retval 0 Isn't huge page table entry.=0D + **/=0D +STATIC=0D +inline=0D +UINTN=0D +pmd_none (=0D + IN PMD pmd=0D + )=0D +{=0D + return (PMD_VAL(pmd) =3D=3D (UINTN)PcdGet64(PcdInvalidPte));=0D +}=0D + /**=0D + Check that the page table entry is empty.=0D +=0D + @param pmd Page table entry struct variables.=0D +=0D + @retval 1 Is huge page table entry.=0D + @retval 0 Isn't huge page table entry.=0D + **/=0D +STATIC=0D +inline=0D +UINTN=0D +pte_none (=0D + IN PTE pte=0D + )=0D +{=0D + return (!(PTE_VAL(pte) & (~PAGE_GLOBAL)));=0D +}=0D +#endif // PAGE_H_=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h b/Plat= form/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h=0D new file mode 100644=0D index 0000000000..aacbf81744=0D --- /dev/null=0D +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h=0D @@ -0,0 +1,57 @@=0D +/** @file=0D +=0D + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - Tlb or TLB - Translation Lookaside Buffer=0D + - HGLOBAL - Huge Global=0D + - PFN - Page Frame number=0D + - EXEC - Execute=0D + - PLV - Privilege Level=0D + - RPLV - Restricted Privilege Level=0D + - SUC - Strong-ordered UnCached=0D + - CC - Coherent Cached=0D + - WUC - Weak-ordered UnCached=0D +**/=0D +#ifndef PTE_H_=0D +#define PTE_H_=0D +/*Page table property definitions */=0D +#define PAGE_VALID_SHIFT 0=0D +#define PAGE_DIRTY_SHIFT 1=0D +#define PAGE_PLV_SHIFT 2 /* 2~3, two bits */=0D +#define CACHE_SHIFT 4 /* 4~5, two bits */=0D +#define PAGE_GLOBAL_SHIFT 6=0D +#define PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */=0D +=0D +#define PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */=0D +#define PAGE_PFN_SHIFT 12=0D +#define PAGE_PFN_END_SHIFT 48=0D +#define PAGE_NO_READ_SHIFT 61=0D +#define PAGE_NO_EXEC_SHIFT 62=0D +#define PAGE_RPLV_SHIFT 63=0D +=0D +/* Used by TLB hardware (placed in EntryLo*) */=0D +#define PAGE_VALID ((UINTN)(1) << PAGE_VALID_SHIFT)=0D +#define PAGE_DIRTY ((UINTN)(1) << PAGE_DIRTY_SHIFT)=0D +#define PAGE_PLV ((UINTN)(3) << PAGE_PLV_SHIFT)=0D +#define PAGE_GLOBAL ((UINTN)(1) << PAGE_GLOBAL_SHIFT)=0D +#define PAGE_HUGE ((UINTN)(1) << PAGE_HUGE_SHIFT)=0D +#define PAGE_HGLOBAL ((UINTN)(1) << PAGE_HGLOBAL_SHIFT)=0D +#define PAGE_NO_READ ((UINTN)(1) << PAGE_NO_READ_SHIFT)=0D +#define PAGE_NO_EXEC ((UINTN)(1) << PAGE_NO_EXEC_SHIFT)=0D +#define PAGE_RPLV ((UINTN)(1) << PAGE_RPLV_SHIFT)=0D +#define CACHE_MASK ((UINTN)(3) << CACHE_SHIFT)=0D +#define PFN_SHIFT (EFI_PAGE_SHIFT - 12 + PAGE_PFN_SHIFT)=0D +=0D +#define PLV_KERNEL 0=0D +#define PLV_USER 3=0D +=0D +#define PAGE_USER (PLV_USER << PAGE_PLV_SHIFT)=0D +#define PAGE_KERNEL (PLV_KERN << PAGE_PLV_SHIFT)=0D +=0D +#define CACHE_SUC (0 << CACHE_SHIFT) /* Strong-ordered UnCached= */=0D +#define CACHE_CC (1 << CACHE_SHIFT) /* Coherent Cached */=0D +#define CACHE_WUC (2 << CACHE_SHIFT) /* Weak-ordered UnCached *= /=0D +#endif // PTE_H_=0D -- =0D 2.31.1=0D =0D