From ace279c036fc15a0317a94dade9ee17f685ec592 Mon Sep 17 00:00:00 2001 From: Chao Li Date: Fri, 14 Jun 2024 17:02:59 +0800 Subject: OvmfPkg/LoongArchVirt: Add CpuMmuInit library Added a new library for LoongArch, it use for initialization the CPU MMU, it consumed the CpuMmuLib. Cc: Ard Biesheuvel Cc: Jiewen Yao 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 --- OvmfPkg/Include/Library/CpuMmuInitLib.h | 26 +++ .../Library/CpuMmuInitLib/CpuMmuInit.c | 200 +++++++++++++++++++++ .../Library/CpuMmuInitLib/CpuMmuInitLib.inf | 35 ++++ .../Library/CpuMmuInitLib/CpuMmuInitLib.uni | 14 ++ OvmfPkg/OvmfPkg.dec | 4 + 5 files changed, 279 insertions(+) create mode 100644 OvmfPkg/Include/Library/CpuMmuInitLib.h create mode 100644 OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInit.c create mode 100644 OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInitLib.inf create mode 100644 OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInitLib.uni diff --git a/OvmfPkg/Include/Library/CpuMmuInitLib.h b/OvmfPkg/Include/Library/CpuMmuInitLib.h new file mode 100644 index 0000000..44b5664 --- /dev/null +++ b/OvmfPkg/Include/Library/CpuMmuInitLib.h @@ -0,0 +1,26 @@ +/** @file + CPU Memory Map Unit Initialization library header. + + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +/** + Create a page table and initialize the memory management unit(MMU). + + @param[in] MemoryTable A pointer to a memory ragion table. + + @retval EFI_SUCCESS Configure MMU successfully. + EFI_INVALID_PARAMETER MemoryTable is NULL. + EFI_UNSUPPORTED MemoryRegionMap failed or out of memory space or size not aligned + or MaxLivel out of bound. +**/ +EFI_STATUS +EFIAPI +ConfigureMemoryManagementUnit ( + IN EFI_MEMORY_DESCRIPTOR *MemoryTable + ); diff --git a/OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInit.c b/OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInit.c new file mode 100644 index 0000000..be2d98c --- /dev/null +++ b/OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInit.c @@ -0,0 +1,200 @@ +/** @file + CPU Memory Map Unit Initialization library instance. + + Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include + +// +// 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 DEFAULT_BIT_WIDTH_PER_LEVEL (EFI_PAGE_SHIFT - 3) + +/** + Decided page walker width, level. + + @param[in, out] PageWalkCfg Page walker value instance. + @param[in] BitWidt The bit width what you want, 0 is means use the default bit width. + + @retval PageTableLevelNum The max page table level. +**/ +STATIC +UINT8 +DecidePageWalkConfiguration ( + IN OUT UINT64 *PageWalkCfg OPTIONAL, + IN UINT8 BitWidth + ) +{ + CPUCFG_REG1_INFO_DATA CpucfgReg1Data; + UINT8 CpuVirtMemAddressWidth; + UINT8 PageTableLevelNum; + UINT8 CurrentPageTableLevel; + UINT32 Pwcl0Value; + UINT32 Pwcl1Value; + + // + // If BitWidth is 0, use the default bit width. + // + if (BitWidth == 0) { + BitWidth = DEFAULT_BIT_WIDTH_PER_LEVEL; + } + + // + // 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) % BitWidth) > 0) { + PageTableLevelNum++; + } + + PageTableLevelNum += (CpuVirtMemAddressWidth - EFI_PAGE_SHIFT) / BitWidth; + + // + // 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 |= ((BitWidth * CurrentPageTableLevel + EFI_PAGE_SHIFT) << 10 * CurrentPageTableLevel) | + BitWidth << (10 * CurrentPageTableLevel + 5); + } else { + // Lager then level 3 + Pwcl1Value |= ((BitWidth * CurrentPageTableLevel + EFI_PAGE_SHIFT) << 12 * (CurrentPageTableLevel - 3)) | + BitWidth << (12 * (CurrentPageTableLevel - 3) + 6); + } + + DEBUG (( + DEBUG_INFO, + "%a %d Level %d DIR shift %d.\n", + __func__, + __LINE__, + (CurrentPageTableLevel + 1), + (BitWidth * CurrentPageTableLevel + EFI_PAGE_SHIFT) + )); + } + + *PageWalkCfg = ((UINT64)Pwcl1Value << 32) | Pwcl0Value; + + return PageTableLevelNum; +} + +/** + Create a page table and initialize the memory management unit(MMU). + + @param[in] MemoryTable A pointer to a memory ragion table. + + @retval EFI_SUCCESS Configure MMU successfully. + EFI_INVALID_PARAMETER MemoryTable is NULL. + EFI_UNSUPPORTED MemoryRegionMap failed or out of memory space or size not aligned + or MaxLivel out of bound. +**/ +EFI_STATUS +EFIAPI +ConfigureMemoryManagementUnit ( + IN EFI_MEMORY_DESCRIPTOR *MemoryTable + ) +{ + EFI_STATUS Status; + UINTN PageTable; + UINT64 PageWalkCfg; + UINT8 MaxLevel; + + if (MemoryTable == NULL) { + ASSERT (MemoryTable != NULL); + return EFI_INVALID_PARAMETER; + } + + // + // Automatically obtain the current appropriate page walker configuration. + // + MaxLevel = DecidePageWalkConfiguration (&PageWalkCfg, 0); + + if ((MaxLevel < 0) || (MaxLevel > 5)) { + return EFI_UNSUPPORTED; + } + + PageTable = 0; + 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 = MemoryRegionMap ( + &PageTable, + PageWalkCfg, + MemoryTable->VirtualStart, + EFI_PAGES_TO_SIZE (MemoryTable->NumberOfPages), + MemoryTable->Attribute, + 0x0 + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + MemoryTable++; + } + + // + // Configure page walker. + // + CsrWrite (LOONGARCH_CSR_PWCTL0, (UINT32)PageWalkCfg); + if ((PageWalkCfg >> 32) != 0x0) { + CsrWrite (LOONGARCH_CSR_PWCTL1, (UINT32)(PageWalkCfg >> 32)); + } + + // + // 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); + + // + // Enable MMU + // + CsrWrite (LOONGARCH_CSR_PGDL, PageTable); + + // + // Enable Paging + // + CsrXChg (LOONGARCH_CSR_CRMD, BIT4, BIT4|BIT3); + + DEBUG ((DEBUG_INFO, "%a %d Enable MMU Start PageBassAddress %p.\n", __func__, __LINE__, PageTable)); + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInitLib.inf b/OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInitLib.inf new file mode 100644 index 0000000..64bd3ce --- /dev/null +++ b/OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInitLib.inf @@ -0,0 +1,35 @@ +## @file +# CPU Memory Map Unit Initialization library instance. +# +# Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
+# +# 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] + CpuMmuInit.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + CacheMaintenanceLib + CpuMmuLib + DebugLib diff --git a/OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInitLib.uni b/OvmfPkg/LoongArchVirt/Library/CpuMmuInitLib/CpuMmuInitLib.uni new file mode 100644 index 0000000..907f024 --- /dev/null +++ b/OvmfPkg/LoongArchVirt/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.
+// +// 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/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index 51be9a5..ad7c196 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -148,6 +148,10 @@ # HardwareInfoLib|Include/Library/HardwareInfoLib.h + ## @libraryclass CPU MMU Initialization library. + # + CpuMmuInitLib|Include/Library/CpuMmuInitLib.h + [Guids] gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}} gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}} -- cgit v1.1