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=4734

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   |  41 ++++
 .../Library/CpuMmuInitLib/CpuMmuInitLib.uni   |  14 ++
 .../CpuMmuInitLib/LoongArch64/CpuMmuInit.c    | 232 ++++++++++++++++++
 .../LoongArch64/TlbExceptionHandle.S          |  51 ++++
 .../LoongArch64/TlbExceptionHandle.h          |  36 +++
 UefiCpuPkg/UefiCpuPkg.dsc                     |   1 +
 6 files changed, 375 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..673d2a8eab
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuInitLib/CpuMmuInitLib.inf
@@ -0,0 +1,41 @@
+## @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
+
+[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..5c74bdc264
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuInitLib/LoongArch64/CpuMmuInit.c
@@ -0,0 +1,232 @@
+/** @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;
+  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);
+
+  //
+  // 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.
+  //
+  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 (#116927): https://edk2.groups.io/g/devel/message/116927
Mute This Topic: https://groups.io/mt/105041101/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to