Add a new base library named CpuMmuInitLib and add a LoongArch64 instance with in the library. It is the consumer of the CpuMmuLib.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584 Cc: Ray Ni <ray...@intel.com> Cc: Rahul Kumar <rahul1.ku...@intel.com> Cc: Gerd Hoffmann <kra...@redhat.com> Signed-off-by: Chao Li <lic...@loongson.cn> Co-authored-by: Baoqi Zhang <zhangba...@loongson.cn> Co-authored-by: Dongyan Qian <qiandong...@loongson.cn> Co-authored-by: Xianglai Li <lixiang...@loongson.cn> Co-authored-by: Bibo Mao <maob...@loongson.cn> --- .../Library/CpuMmuInitLib/CpuMmuInitLib.inf | 42 +++ .../Library/CpuMmuInitLib/CpuMmuInitLib.uni | 14 + .../CpuMmuInitLib/LoongArch64/CpuMmuInit.c | 242 ++++++++++++++++++ .../LoongArch64/TlbExceptionHandle.S | 51 ++++ .../LoongArch64/TlbExceptionHandle.h | 36 +++ UefiCpuPkg/UefiCpuPkg.dsc | 1 + 6 files changed, 386 insertions(+) create mode 100644 UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.inf create mode 100644 UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.uni create mode 100644 UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/CpuMmuInit.c create mode 100644 UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/TlbExceptionHandle.S create mode 100644 UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/TlbExceptionHandle.h diff --git a/UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.inf b/UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.inf new file mode 100644 index 0000000000..a1326346fb --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.inf @@ -0,0 +1,42 @@ +## @file +# CPU Memory Map Unit Initialization library instance. +# +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = CpuMmuInitLib + MODULE_UNI_FILE = CpuMmuInitLib.uni + FILE_GUID = F67EB983-AC2A-7550-AB69-3BC51A1C895B + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CpuMmuInitLib + +# +# VALID_ARCHITECTURES = LOONGARCH64 +# + +[Sources.LoongArch64] + LoongArch64/TlbExceptionHandle.S | GCC + LoongArch64/CpuMmuInit.c + LoongArch64/TlbExceptionHandle.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress + gUefiCpuPkgTokenSpaceGuid.PcdCpuMmuIsEnabled ## CONSUMES + +[LibraryClasses] + CacheMaintenanceLib + CpuMmuLib + DebugLib + MemoryAllocationLib + PcdLib diff --git a/UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.uni b/UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.uni new file mode 100644 index 0000000000..907f024302 --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.uni @@ -0,0 +1,14 @@ +// /** @file +// CPU Memory Map Unit Initialization library instance. +// +// CPU Memory Map Unit Initialization library instance. +// +// 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 Manager Unit library instance for PEI modules." + +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for PEI modules." diff --git a/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/CpuMmuInit.c b/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/CpuMmuInit.c new file mode 100644 index 0000000000..41e9328fd0 --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/CpuMmuInit.c @@ -0,0 +1,242 @@ +/** @file + CPU Memory Map Unit Initialization library instance. + + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/CacheMaintenanceLib.h> +#include <Library/CpuMmuLib.h> +#include <Library/CpuMmuInitLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Protocol/DebugSupport.h> +#include <Register/LoongArch64/Csr.h> +#include <Register/LoongArch64/Cpucfg.h> +#include "TlbExceptionHandle.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 + +// +// Because the page size in edk2 is 4KB, the lowest level +// page table is align to 12 bits, and the page table width +// of other levels is set to 9 bits by default, which will +// be 3 or 4 or 5 level page tables, and continuous. +// +// Correspondence between max virtual memory address width +// and page table level: +// 39 bit >= VA > 31 bit, 3 level page tables +// 48 bit >= VA > 40 bit, 4 level page tables +// 57 bit >= VA > 49 bit, 5 level page tables +// +#define BIT_WIDTH_PER_LEVEL 9 +#define MAX_SIZE_OF_PGD ((1 << BIT_WIDTH_PER_LEVEL) * 8) // 512 items, 8 Byte each. + +/** + Create a page table and initialize the memory management unit(MMU). + + @param[in] MemoryTable A pointer to a memory ragion table. + @param[out] TranslationTableBase A pointer to a translation table base address. + @param[out] TranslationTableSize A pointer to a translation table base size. + + @retval EFI_SUCCESS Configure MMU successfully. + EFI_INVALID_PARAMETER MemoryTable is NULL. + EFI_UNSUPPORTED Out of memory space or size not aligned. +**/ +EFI_STATUS +EFIAPI +ConfigureMemoryManagementUnit ( + IN EFI_MEMORY_DESCRIPTOR *MemoryTable, + OUT VOID **TranslationTableBase OPTIONAL, + OUT UINTN *TranslationTableSize OPTIONAL + ) +{ + VOID *TranslationTable; + UINTN Length; + UINTN TlbReEntry; + UINTN TlbReEntryOffset; + UINTN Remaining; + EFI_STATUS Status; + RETURN_STATUS PcdStatus; + CPUCFG_REG1_INFO_DATA CpucfgReg1Data; + UINT8 CpuVirtMemAddressWidth; + UINT8 PageTableLevelNum; + UINT8 CurrentPageTableLevel; + UINT32 Pwcl0Value; + UINT32 Pwcl1Value; + + if (MemoryTable == NULL) { + ASSERT (MemoryTable != NULL); + return EFI_INVALID_PARAMETER; + } + + // + // Get the the CPU virtual memory address width. + // + AsmCpucfg (CPUCFG_REG1_INFO, &CpucfgReg1Data.Uint32); + + CpuVirtMemAddressWidth = (UINT8)(CpucfgReg1Data.Bits.VALEN + 1); + + // + // Statisitics the maximum page table level + // + PageTableLevelNum = 0x0; + if (((CpuVirtMemAddressWidth - EFI_PAGE_SHIFT) % BIT_WIDTH_PER_LEVEL) > 0) { + PageTableLevelNum++; + } + + PageTableLevelNum += (CpuVirtMemAddressWidth - EFI_PAGE_SHIFT) / BIT_WIDTH_PER_LEVEL; + + // + // Set page table level + // + Pwcl0Value = 0x0; + Pwcl1Value = 0x0; + for (CurrentPageTableLevel = 0x0; CurrentPageTableLevel < PageTableLevelNum; CurrentPageTableLevel++) { + if (CurrentPageTableLevel < 0x3) { + // Less then or equal to level 3 + Pwcl0Value |= ((BIT_WIDTH_PER_LEVEL * CurrentPageTableLevel + EFI_PAGE_SHIFT) << 10 * CurrentPageTableLevel) | + BIT_WIDTH_PER_LEVEL << (10 * CurrentPageTableLevel + 5); + } else { + // Lager then level 3 + Pwcl1Value |= ((BIT_WIDTH_PER_LEVEL * CurrentPageTableLevel + EFI_PAGE_SHIFT) << 12 * (CurrentPageTableLevel - 3)) | + BIT_WIDTH_PER_LEVEL << (12 * (CurrentPageTableLevel - 3) + 6); + } + + DEBUG (( + DEBUG_INFO, + "%a %d Level %d DIR shift %d.\n", + __func__, + __LINE__, + (CurrentPageTableLevel + 1), + (BIT_WIDTH_PER_LEVEL * CurrentPageTableLevel + EFI_PAGE_SHIFT) + )); + } + + CsrWrite (LOONGARCH_CSR_PWCTL0, Pwcl0Value); + if (Pwcl1Value != 0x0) { + CsrWrite (LOONGARCH_CSR_PWCTL1, Pwcl1Value); + } + + // + // 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); + + // + // Create PGD and set the PGD address to PGDL + // + TranslationTable = AllocatePages (EFI_SIZE_TO_PAGES (MAX_SIZE_OF_PGD)); + ZeroMem (TranslationTable, MAX_SIZE_OF_PGD); + + if (TranslationTable == NULL) { + goto FreeTranslationTable; + } + + CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)TranslationTable); + + // + // Ensures MMU flag is disabled. + // + PcdStatus = PcdSetBoolS (PcdCpuMmuIsEnabled, FALSE); + ASSERT_RETURN_ERROR (PcdStatus); + + // + // Fill page tables + // + while (MemoryTable->NumberOfPages != 0) { + DEBUG (( + DEBUG_INFO, + "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", + __func__, + __LINE__, + MemoryTable->VirtualStart, + (EFI_PAGES_TO_SIZE (MemoryTable->NumberOfPages) + MemoryTable->VirtualStart), + MemoryTable->Attribute + )); + + Status = SetMemoryRegionAttributes ( + MemoryTable->VirtualStart, + EFI_PAGES_TO_SIZE (MemoryTable->NumberOfPages), + MemoryTable->Attribute, + 0x0 + ); + + if (EFI_ERROR (Status)) { + goto FreeTranslationTable; + } + + MemoryTable++; + } + + // + // Set TLB exception handler + // + /// + /// TLB Re-entry address at the end of exception vector, a vector is up to 512 bytes, + /// so the starting address is: total exception vector size + total interrupt vector size + base. + /// The total size of TLB handler and exception vector size and interrupt vector size should not + /// be lager than 64KB. + /// + Length = (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart; + TlbReEntryOffset = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512; + Remaining = TlbReEntryOffset % SIZE_4KB; + if (Remaining != 0x0) { + TlbReEntryOffset += (SIZE_4KB - Remaining); + } + + TlbReEntry = PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryOffset; + if ((TlbReEntryOffset + Length) > SIZE_64KB) { + goto FreeTranslationTable; + } + + // + // Ensure that TLB refill exception base address alignment is equals to 4KB and is valid. + // + if (TlbReEntry & (SIZE_4KB - 1)) { + goto FreeTranslationTable; + } + + CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length); + InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length); + + // + // Set the address of TLB refill exception handler + // + SetTlbRebaseAddress ((UINTN)TlbReEntry); + + // + // Enable MMU + // + CsrXChg (LOONGARCH_CSR_CRMD, BIT4, BIT4|BIT3); + + DEBUG ((DEBUG_INFO, "%a %d Enable MMU Start PageBassAddress %p.\n", __func__, __LINE__, TranslationTable)); + + // + // Set MMU enable flag. + // + PcdStatus = PcdSetBoolS (PcdCpuMmuIsEnabled, TRUE); + ASSERT_RETURN_ERROR (PcdStatus); + + return EFI_SUCCESS; + +FreeTranslationTable: + if (TranslationTable != NULL) { + FreePages (TranslationTable, EFI_SIZE_TO_PAGES (MAX_SIZE_OF_PGD)); + } + + return EFI_UNSUPPORTED; +} diff --git a/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/TlbExceptionHandle.S b/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/TlbExceptionHandle.S new file mode 100644 index 0000000000..4395b574f5 --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/TlbExceptionHandle.S @@ -0,0 +1,51 @@ +#------------------------------------------------------------------------------ +# +# TLB refill exception handler +# +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#----------------------------------------------------------------------------- + +#include <Register/LoongArch64/Csr.h> + +ASM_GLOBAL ASM_PFX(HandleTlbRefillStart) +ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd) + +# +# Refill the page table. +# @param VOID +# @retval VOID +# +ASM_PFX(HandleTlbRefillStart): + csrwr $t0, LOONGARCH_CSR_TLBRSAVE + csrrd $t0, LOONGARCH_CSR_PWCTL1 + srli.d $t0, $t0, 18 + andi $t0, $t0, 0x3F + bnez $t0, Level5 + csrrd $t0, LOONGARCH_CSR_PWCTL1 + srli.d $t0, $t0, 6 + andi $t0, $t0, 0x3F + bnez $t0, Level4 + csrrd $t0, LOONGARCH_CSR_PGD + b Level3 +Level5: + csrrd $t0, LOONGARCH_CSR_PGD + lddir $t0, $t0, 4 #Put pud BaseAddress into T0 + lddir $t0, $t0, 3 #Put pud BaseAddress into T0 + b Level3 +Level4: + csrrd $t0, LOONGARCH_CSR_PGD + lddir $t0, $t0, 3 #Put pud BaseAddress into T0 +Level3: + 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): + + .end diff --git a/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/TlbExceptionHandle.h b/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/TlbExceptionHandle.h new file mode 100644 index 0000000000..c164db567d --- /dev/null +++ b/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/TlbExceptionHandle.h @@ -0,0 +1,36 @@ +/** @file + + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef TLB_EXCEPTION_HANDLE_H_ +#define TLB_EXCEPTION_HANDLE_H_ + +/** + TLB refill handler start. + + @param none + + @retval none +**/ +VOID +HandleTlbRefillStart ( + VOID + ); + +/** + TLB refill handler end. + + @param none + + @retval none +**/ +VOID +HandleTlbRefillEnd ( + VOID + ); + +#endif // TLB_EXCEPTION_HANDLE_H_ diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index e92ceb6466..a9787f9d70 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -213,6 +213,7 @@ [Components.RISCV64] [Components.LOONGARCH64] UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf + UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.inf [BuildOptions] *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES -- 2.27.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#116595): https://edk2.groups.io/g/devel/message/116595 Mute This Topic: https://groups.io/mt/104859884/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-