public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chao Li" <lichao@loongson.cn>
To: devel@edk2.groups.io
Cc: Ray Ni <ray.ni@intel.com>, Rahul Kumar <rahul1.kumar@intel.com>,
	Gerd Hoffmann <kraxel@redhat.com>,
	Baoqi Zhang <zhangbaoqi@loongson.cn>,
	Dongyan Qian <qiandongyan@loongson.cn>,
	Xianglai Li <lixianglai@loongson.cn>,
	Bibo Mao <maobibo@loongson.cn>
Subject: [edk2-devel] [PATCH v2 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg
Date: Wed, 20 Mar 2024 16:43:31 +0800	[thread overview]
Message-ID: <20240320084331.276727-1-lichao@loongson.cn> (raw)
In-Reply-To: <20240320084152.268323-1-lichao@loongson.cn>

Add a new base library named CpuMmuLib and add a LoongArch64 instance
with in the library.

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4734

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
Co-authored-by: Dongyan Qian <qiandongyan@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf    |  35 +
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni    |  14 +
 .../Library/CpuMmuLib/LoongArch64/CpuMmu.c    | 638 ++++++++++++++++++
 .../Library/CpuMmuLib/LoongArch64/Page.h      |  24 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.S        |  24 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.h        |  24 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |   3 +
 7 files changed, 762 insertions(+)
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h

diff --git a/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
new file mode 100644
index 0000000000..890a614da2
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
@@ -0,0 +1,35 @@
+## @file
+#  CPU Memory Manager Unit 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                      = CpuMmuLib
+  MODULE_UNI_FILE                = CpuMmuLib.uni
+  FILE_GUID                      = DA8F0232-FB14-42F0-922C-63104D2C70BE
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = CpuMmuLib
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources.LoongArch64]
+  LoongArch64/TlbInvalid.S   | GCC
+  LoongArch64/CpuMmu.c
+  LoongArch64/Page.h
+  LoongArch64/TlbInvalid.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  MemoryAllocationLib
diff --git a/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni
new file mode 100644
index 0000000000..2408f2f90b
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CPU Memory Manager Unit library instance.
+//
+// CPU Memory Manager Unit 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."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "CPU Memory Manager Unit library instance."
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c
new file mode 100644
index 0000000000..9f57499d3f
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c
@@ -0,0 +1,638 @@
+/** @file
+
+  CPU Memory Map Unit Handler Library common functions.
+
+  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
+  Copyright (c) 2016, Linaro Limited. All rights reserved.
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2023, Ventana Micro Systems Inc. All Rights Reserved.<BR>
+  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/CpuMmuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include "TlbInvalid.h"
+#include "Page.h"
+
+/**
+  Check to see if mmu successfully initializes.
+
+  @param  VOID.
+
+  @retval  TRUE  Initialization has been completed.
+           FALSE Initialization did not complete.
+**/
+STATIC
+BOOLEAN
+MmuIsInit (
+  VOID
+  )
+{
+  if (CsrRead (LOONGARCH_CSR_PGDL) != 0) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Check to see if mmu is enabled.
+
+  @param  VOID.
+
+  @retval  TRUE  MMU has been enabled.
+           FALSE MMU did not enabled.
+**/
+STATIC
+BOOLEAN
+MmuIsEnabled (
+  VOID
+  )
+{
+  if ((CsrRead (LOONGARCH_CSR_CRMD) & BIT4) != 0) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Determine if an entry is valid pte.
+
+  @param    Entry   The entry value.
+
+  @retval   TRUE    The entry is a valid pte.
+  @retval   FALSE   The entry is not a valid pte.
+
+**/
+STATIC
+BOOLEAN
+IsValidPte (
+  IN  UINTN  Entry
+  )
+{
+  if (Entry != INVALID_PAGE) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Determine if an entry is huge page.
+
+  @param    Entry   The entry value.
+
+  @retval   TRUE    The entry is a huge page.
+  @retval   FALSE   The entry is not a valid huge page.
+
+**/
+STATIC
+BOOLEAN
+IsValidHugePage (
+  IN  UINTN  Entry
+  )
+{
+  if ((Entry & (PAGE_HGLOBAL | PAGE_HUGE)) == (PAGE_HGLOBAL | PAGE_HUGE)) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Set an entry to be a valid pte.
+
+  @param  Entry   The entry value.
+
+  @return         The entry value.
+
+**/
+STATIC
+UINTN
+SetValidPte (
+  IN  UINTN  Entry
+  )
+{
+  /* Set Valid and Global mapping bits */
+  return Entry | PAGE_GLOBAL | PAGE_VALID;
+}
+
+/**
+  Get current max page table level.
+
+  @param  VOID.
+
+  @return         5   MAX page level is 5
+                  4   MAX page level is 4
+                  3   MAX page level is 3
+                  0   Invalid
+
+**/
+STATIC
+UINTN
+GetCurrentMaxPageTableLevel (
+  VOID
+  )
+{
+  if (((CsrRead (LOONGARCH_CSR_PWCTL1) >> 18) & 0x3F) != 0x0) {
+    return LEVEL5;
+  } else if (((CsrRead (LOONGARCH_CSR_PWCTL1) >> 6) & 0x3F) != 0x0) {
+    return LEVEL4;
+  } else if (((CsrRead (LOONGARCH_CSR_PWCTL0) >> 25) & 0x3F) != 0x0) {
+    return LEVEL3;
+  }
+
+  return 0;
+}
+
+/**
+  Get current page table bit width.
+
+  @param  VOID.
+
+  @return         page table bit width
+
+**/
+STATIC
+UINTN
+GetCurrentPageTableBitWidth (
+  VOID
+  )
+{
+  //
+  // PTwidth
+  //
+  return ((CsrRead (LOONGARCH_CSR_PWCTL0) >> 5) & 0x1F);
+}
+
+/**
+  Determine if an entry is a HUGE PTE or 4K PTE.
+
+  @param    Entry   The entry value.
+  @param    Level   The current page table level.
+
+  @retval   TRUE    The entry is a block pte.
+  @retval   FALSE   The entry is not a block pte.
+
+**/
+STATIC
+BOOLEAN
+IsBlockEntry (
+  IN  UINTN  Entry,
+  IN  UINTN  Level
+  )
+{
+  if (Level == (GetCurrentMaxPageTableLevel () - 1)) {
+    return ((Entry & PAGE_VALID) == PAGE_VALID);
+  }
+
+  return IsValidHugePage (Entry);
+}
+
+/**
+  Determine if an entry is a table pte.
+
+  @param    Entry   The entry value.
+  @param    Level   The current page table level.
+
+  @retval   TRUE    The entry is a table pte.
+  @retval   FALSE   The entry is not a table pte.
+
+**/
+STATIC
+BOOLEAN
+IsTableEntry (
+  IN  UINTN  Entry,
+  IN  UINTN  Level
+  )
+{
+  if (Level == (GetCurrentMaxPageTableLevel () - 1)) {
+    //
+    // The last level is PAGE rather than Table.
+    //
+    return FALSE;
+  }
+
+  //
+  // Is DIR4 or DIR3 or DIR2 a Huge Page ?
+  //
+  return (!IsValidHugePage (Entry)) && (IsValidPte (Entry));
+}
+
+/**
+  Replace an existing entry with new value.
+
+  @param  Entry               The entry pointer.
+  @param  Value               The new entry value.
+  @param  RegionStart         The start of region that new value affects.
+  @param  IsLiveBlockMapping  TRUE if this is live update, FALSE otherwise.
+
+**/
+STATIC
+VOID
+ReplaceTableEntry (
+  IN  UINTN    *Entry,
+  IN  UINTN    Value,
+  IN  UINTN    RegionStart,
+  IN  BOOLEAN  IsLiveBlockMapping
+  )
+{
+  *Entry = Value;
+
+  if (IsLiveBlockMapping && MmuIsInit ()) {
+    InvalidTlb (RegionStart);
+  }
+}
+
+/**
+  Get an ppn value from an entry.
+
+  @param  Entry   The entry value.
+
+  @return         The ppn value.
+
+**/
+STATIC
+UINTN
+GetPpnfromPte (
+  IN UINTN  Entry
+  )
+{
+  return ((Entry & PTE_PPN_MASK) >> PTE_PPN_SHIFT);
+}
+
+/**
+  Set an ppn value to a entry.
+
+  @param  Entry   The entry value.
+  @param  Address The address.
+
+  @return The new entry value.
+
+**/
+STATIC
+UINTN
+SetPpnToPte (
+  UINTN  Entry,
+  UINTN  Address
+  )
+{
+  UINTN  Ppn;
+
+  Ppn = ((Address >> LOONGARCH_MMU_PAGE_SHIFT) << PTE_PPN_SHIFT);
+  ASSERT (~(Ppn & ~PTE_PPN_MASK));
+  Entry &= ~PTE_PPN_MASK;
+  return Entry | Ppn;
+}
+
+/**
+  Free resources of translation table recursively.
+
+  @param  TranslationTable  The pointer of table.
+  @param  Level             The current level.
+
+**/
+STATIC
+VOID
+FreePageTablesRecursive (
+  IN  UINTN  *TranslationTable,
+  IN  UINTN  Level
+  )
+{
+  UINTN  Index;
+  UINTN  TableEntryNum;
+
+  TableEntryNum = (1 << GetCurrentPageTableBitWidth ());
+
+  if (Level < (GetCurrentMaxPageTableLevel () - 1)) {
+    for (Index = 0; Index < TableEntryNum; Index++) {
+      if (IsTableEntry (TranslationTable[Index], Level)) {
+        FreePageTablesRecursive (
+          (UINTN *)(GetPpnfromPte ((TranslationTable[Index])) <<
+                    LOONGARCH_MMU_PAGE_SHIFT),
+          Level + 1
+          );
+      }
+    }
+  }
+
+  FreePages (TranslationTable, 1);
+}
+
+/**
+  Update region mapping recursively.
+
+  @param  RegionStart           The start address of the region.
+  @param  RegionEnd             The end address of the region.
+  @param  AttributeSetMask      The attribute mask to be set.
+  @param  AttributeClearMask    The attribute mask to be clear.
+  @param  PageTable             The pointer of current page table.
+  @param  Level                 The current level.
+  @param  TableIsLive           TRUE if this is live update, FALSE otherwise.
+
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource.
+  @retval EFI_SUCCESS           The operation succesfully.
+
+**/
+STATIC
+EFI_STATUS
+UpdateRegionMappingRecursive (
+  IN  UINTN    RegionStart,
+  IN  UINTN    RegionEnd,
+  IN  UINTN    AttributeSetMask,
+  IN  UINTN    AttributeClearMask,
+  IN  UINTN    *PageTable,
+  IN  UINTN    Level,
+  IN  BOOLEAN  TableIsLive
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BlockShift;
+  UINTN       BlockMask;
+  UINTN       BlockEnd;
+  UINTN       *Entry;
+  UINTN       EntryValue;
+  UINTN       *TranslationTable;
+  UINTN       TableEntryNum;
+  UINTN       TableBitWidth;
+  BOOLEAN     NextTableIsLive;
+
+  ASSERT (Level < GetCurrentMaxPageTableLevel ());
+  ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) == 0);
+
+  TableBitWidth = GetCurrentPageTableBitWidth ();
+  BlockShift    = (GetCurrentMaxPageTableLevel () - Level - 1) * TableBitWidth + LOONGARCH_MMU_PAGE_SHIFT;
+  BlockMask     = MAX_ADDRESS >> (64 - BlockShift);
+
+  DEBUG (
+    (
+     DEBUG_VERBOSE,
+     "%a(%d): %llx - %llx set %lx clr %lx\n",
+     __func__,
+     Level,
+     RegionStart,
+     RegionEnd,
+     AttributeSetMask,
+     AttributeClearMask
+    )
+    );
+
+  TableEntryNum = (1 << TableBitWidth);
+  for ( ; RegionStart < RegionEnd; RegionStart = BlockEnd) {
+    BlockEnd = MIN (RegionEnd, (RegionStart | BlockMask) + 1);
+    Entry    = &PageTable[(RegionStart >> BlockShift) & (TableEntryNum - 1)];
+
+    //
+    // If RegionStart or BlockEnd is not aligned to the block size at this
+    // level, we will have to create a table mapping in order to map less
+    // than a block, and recurse to create the block or page entries at
+    // the next level. No block mappings are allowed at all at level 2,
+    // so in that case, we have to recurse unconditionally.
+    //
+    if ((Level < 2) ||
+        (((RegionStart | BlockEnd) & BlockMask) != 0) || IsTableEntry (*Entry, Level))
+    {
+      ASSERT (Level < (GetCurrentMaxPageTableLevel () - 1));
+      if (!IsTableEntry (*Entry, Level)) {
+        //
+        // No table entry exists yet, so we need to allocate a page table
+        // for the next level.
+        //
+        TranslationTable = AllocatePages (1);
+        if (TranslationTable == NULL) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        ZeroMem (TranslationTable, EFI_PAGE_SIZE);
+
+        if (IsBlockEntry (*Entry, Level)) {
+          //
+          // We are splitting an existing block entry, so we have to populate
+          // the new table with the attributes of the block entry it replaces.
+          //
+          Status = UpdateRegionMappingRecursive (
+                     RegionStart & ~BlockMask,
+                     (RegionStart | BlockMask) + 1,
+                     *Entry & PTE_ATTRIBUTES_MASK,
+                     PTE_ATTRIBUTES_MASK,
+                     TranslationTable,
+                     Level + 1,
+                     FALSE
+                     );
+          if (EFI_ERROR (Status)) {
+            //
+            // The range we passed to UpdateRegionMappingRecursive () is block
+            // aligned, so it is guaranteed that no further pages were allocated
+            // by it, and so we only have to free the page we allocated here.
+            //
+            FreePages (TranslationTable, 1);
+            return Status;
+          }
+        }
+
+        NextTableIsLive = FALSE;
+      } else {
+        TranslationTable = (UINTN *)(GetPpnfromPte (*Entry) << LOONGARCH_MMU_PAGE_SHIFT);
+        NextTableIsLive  = TableIsLive;
+      }
+
+      //
+      // Recurse to the next level
+      //
+      Status = UpdateRegionMappingRecursive (
+                 RegionStart,
+                 BlockEnd,
+                 AttributeSetMask,
+                 AttributeClearMask,
+                 TranslationTable,
+                 Level + 1,
+                 NextTableIsLive
+                 );
+      if (EFI_ERROR (Status)) {
+        if (!IsTableEntry (*Entry, Level)) {
+          //
+          // We are creating a new table entry, so on failure, we can free all
+          // allocations we made recursively, given that the whole subhierarchy
+          // has not been wired into the live page tables yet. (This is not
+          // possible for existing table entries, since we cannot revert the
+          // modifications we made to the subhierarchy it represents.)
+          //
+          FreePageTablesRecursive (TranslationTable, Level + 1);
+        }
+
+        return Status;
+      }
+
+      if (!IsTableEntry (*Entry, Level)) {
+        EntryValue = SetPpnToPte (0, (UINTN)TranslationTable);
+        ReplaceTableEntry (
+          Entry,
+          EntryValue,
+          RegionStart,
+          TableIsLive
+          );
+      }
+    } else {
+      EntryValue = (*Entry & ~AttributeClearMask) | AttributeSetMask;
+
+      EntryValue = SetPpnToPte (EntryValue, RegionStart);
+      EntryValue = SetValidPte (EntryValue);
+
+      if (Level < (GetCurrentMaxPageTableLevel () - 1)) {
+        EntryValue |= (PAGE_HGLOBAL | PAGE_HUGE | PAGE_VALID);
+      } else {
+        EntryValue |= PAGE_GLOBAL | PAGE_VALID;
+      }
+
+      ReplaceTableEntry (Entry, EntryValue, RegionStart, TableIsLive);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update region mapping at root table.
+
+  @param  RegionStart           The start address of the region.
+  @param  RegionLength          The length of the region.
+  @param  AttributeSetMask      The attribute mask to be set.
+  @param  AttributeClearMask    The attribute mask to be clear.
+  @param  RootTable             The pointer of root table.
+  @param  TableIsLive           TRUE if this is live update, FALSE otherwise.
+
+  @retval EFI_INVALID_PARAMETER The RegionStart or RegionLength was not valid.
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource.
+  @retval EFI_SUCCESS           The operation succesfully.
+
+**/
+EFI_STATUS
+UpdateRegionMapping (
+  IN  UINTN    RegionStart,
+  IN  UINTN    RegionLength,
+  IN  UINTN    AttributeSetMask,
+  IN  UINTN    AttributeClearMask,
+  IN  UINTN    *RootTable,
+  IN  BOOLEAN  TableIsLive
+  )
+{
+  if (((RegionStart | RegionLength) & EFI_PAGE_MASK) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return UpdateRegionMappingRecursive (
+           RegionStart,
+           RegionStart + RegionLength,
+           AttributeSetMask,
+           AttributeClearMask,
+           RootTable,
+           0,
+           TableIsLive
+           );
+}
+
+/**
+  Convert EFI Attributes to Loongarch Attributes.
+
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  Corresponding architecture attributes.
+**/
+UINTN
+EFIAPI
+EfiAttributeConverse (
+  IN UINTN  EfiAttributes
+  )
+{
+  UINTN  LoongArchAttributes;
+
+  LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | PAGE_GLOBAL;
+
+  switch (EfiAttributes & EFI_CACHE_ATTRIBUTE_MASK) {
+    case EFI_MEMORY_UC:
+      LoongArchAttributes |= CACHE_SUC;
+      break;
+    case EFI_MEMORY_WC:
+      LoongArchAttributes |= CACHE_WUC;
+      break;
+    case EFI_MEMORY_WT:
+    case EFI_MEMORY_WB:
+      LoongArchAttributes |= CACHE_CC;
+      break;
+    case EFI_MEMORY_WP:
+      LoongArchAttributes &= ~PAGE_DIRTY;
+      break;
+    default:
+      break;
+  }
+
+  // Write protection attributes
+  switch (EfiAttributes & EFI_MEMORY_ACCESS_MASK) {
+    case EFI_MEMORY_RP:
+      LoongArchAttributes |= PAGE_NO_READ;
+      break;
+    case EFI_MEMORY_XP:
+      LoongArchAttributes |= PAGE_NO_EXEC;
+      break;
+    case EFI_MEMORY_RO:
+      LoongArchAttributes &= ~PAGE_DIRTY;
+      break;
+    default:
+      break;
+  }
+
+  return LoongArchAttributes;
+}
+
+/**
+  Sets the Attributes  of the specified memory region
+
+  @param[in]  BaseAddress    The base address of the memory region to set the Attributes.
+  @param[in]  Length         The length of the memory region to set the Attributes.
+  @param[in]  Attributes     The Attributes to be set.
+  @param[in]  AttributeMask  Mask of memory attributes to take into account.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+EFIAPI
+SetMemoryRegionAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN                 Length,
+  IN UINTN                 Attributes,
+  IN UINT64                AttributeMask
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       LoongArchAttributes;
+
+  if (!MmuIsInit ()) {
+    return EFI_UNSUPPORTED;
+  }
+
+  LoongArchAttributes = EfiAttributeConverse (Attributes);
+
+  //
+  // If MMU is enabled, then page tables must be active.
+  //
+  Status = UpdateRegionMapping (
+             BaseAddress,
+             Length,
+             LoongArchAttributes,
+             PTE_ATTRIBUTES_MASK,
+             (UINTN *)CsrRead (LOONGARCH_CSR_PGDL),
+             MmuIsEnabled ()
+             );
+
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h
new file mode 100644
index 0000000000..bd568db967
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h
@@ -0,0 +1,24 @@
+/** @file
+
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PAGE_H_
+#define PAGE_H_
+
+#define INVALID_PAGE  0
+
+#define LEVEL5  5
+#define LEVEL4  4
+#define LEVEL3  3
+
+#define PTE_ATTRIBUTES_MASK  0x600000000000007EULL
+
+#define PTE_PPN_MASK              0xFFFFFFFFF000ULL
+#define PTE_PPN_SHIFT             EFI_PAGE_SHIFT
+#define LOONGARCH_MMU_PAGE_SHIFT  EFI_PAGE_SHIFT
+
+#endif // PAGE_H_
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S
new file mode 100644
index 0000000000..676aada240
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S
@@ -0,0 +1,24 @@
+#------------------------------------------------------------------------------
+#
+# Invalid TLB operation function
+#
+# 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(InvalidTlb)
+
+#
+# Invalid corresponding TLB entries are based on the address given
+# @param a0 The address corresponding to the invalid page table entry
+# @retval  none
+#
+ASM_PFX(InvalidTlb):
+    invtlb  INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0
+    jirl    $zero, $ra, 0
+
+    .end
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h
new file mode 100644
index 0000000000..5063e6662b
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h
@@ -0,0 +1,24 @@
+/** @file
+
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef INVALID_TLB_H_
+#define INVALID_TLB_H_
+
+/**
+  Invalid corresponding TLB entries are based on the address given
+
+  @param Address The address corresponding to the invalid page table entry
+
+  @retval  none
+**/
+VOID
+InvalidTlb (
+  UINTN  Address
+  );
+
+#endif // INVALID_TLB_H_
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 2eebd45125..e92ceb6466 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -211,5 +211,8 @@ [Components.RISCV64]
   UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
   UefiCpuPkg/CpuMmio2Dxe/CpuMmio2Dxe.inf
 
+[Components.LOONGARCH64]
+  UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.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 (#116926): https://edk2.groups.io/g/devel/message/116926
Mute This Topic: https://groups.io/mt/105041098/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  parent reply	other threads:[~2024-03-20  8:43 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-20  8:41 [edk2-devel] [PATCH v2 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
2024-03-20  8:42 ` [edk2-devel] [PATCH v2 01/13] UefiCpuPkg/CpuTimerLib: Reorder the INF file alphabetically Chao Li
2024-03-22  1:15   ` Ni, Ray
2024-03-20  8:42 ` [edk2-devel] [PATCH v2 02/13] UefiCpuPkg/CpuExceptionHandlerLib: Reorder the INF files alphabetically Chao Li
2024-03-22  1:21   ` Ni, Ray
2024-03-20  8:42 ` [edk2-devel] [PATCH v2 03/13] UefiCpuPkg/MpInitLib: " Chao Li
2024-03-20  8:42 ` [edk2-devel] [PATCH v2 04/13] UefiCpuPkg/CpuDxe: Reorder the INF file alphabetically Chao Li
2024-03-20  8:43 ` [edk2-devel] [PATCH v2 05/13] UefiCpuPkg: Add LoongArch64 CPU Timer instance Chao Li
2024-03-20  8:43 ` [edk2-devel] [PATCH v2 06/13] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
2024-03-20  8:43 ` [edk2-devel] [PATCH v2 07/13] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
2024-03-25  2:29   ` Ni, Ray
2024-03-25  2:31   ` Ni, Ray
2024-03-25  2:52     ` Chao Li
2024-03-20  8:43 ` [edk2-devel] [PATCH v2 08/13] UefiCpuPkg: Added a new PCD named PcdCpuExceptionVectorBaseAddress Chao Li
2024-03-20  8:43 ` Chao Li [this message]
2024-03-20  8:43 ` [edk2-devel] [PATCH v2 10/13] UefiCpuPkg: Add CpuMmuInitLib.h to UefiCpuPkg Chao Li
2024-03-20  8:43 ` [edk2-devel] [PATCH v2 11/13] UefiCpuPkg: Add CpuMmuInitLib " Chao Li
2024-03-20  8:43 ` [edk2-devel] [PATCH v2 12/13] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
2024-03-20  8:43 ` [edk2-devel] [PATCH v2 13/13] UefiCpuPkg: Add CpuDxe driver " Chao Li
2024-03-25  2:35   ` Ni, Ray
2024-03-22 12:39 ` [edk2-devel] [PATCH v2 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Gerd Hoffmann
2024-03-25  2:46   ` Ni, Ray
2024-03-25  3:10     ` Chao Li
     [not found]     ` <17BFE34457098413.21233@groups.io>
2024-03-26  1:32       ` Chao Li
     [not found]       ` <17C02C7EE39BF604.20354@groups.io>
2024-03-29  1:28         ` Chao Li
2024-04-09  2:06           ` Ni, Ray
2024-04-09  4:29             ` Chao Li
2024-04-09  5:27               ` Ni, Ray
2024-04-09  6:21                 ` Chao Li
     [not found]         ` <17C1180424B48FA9.19344@groups.io>
2024-04-03  1:21           ` Chao Li

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240320084331.276727-1-lichao@loongson.cn \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox