public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg
@ 2024-04-12  7:32 Chao Li
  2024-04-12  7:33 ` [edk2-devel] [PATCH v3 01/13] UefiCpuPkg/CpuTimerLib: Reorder the INF file alphabetically Chao Li
                   ` (13 more replies)
  0 siblings, 14 replies; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:32 UTC (permalink / raw)
  To: devel
  Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann, Sami Mujawar, Sunil V L,
	Bibo Mao, Dongyan Qian

This patch set adjusted some order in UefiCpuPig alphabetically, added
LoongArch libraries and drivers into UefiCpuPkg, it is a continuation of
the first patch series v8 submitted at
https://edk2.groups.io/g/devel/message/114526.

And also separated from https://edk2.groups.io/g/devel/message/116583.

This series only contents the changes for UefiCpuPkg.

Patch1-Patch4: Reorder some INF files located in UefiCpuPkg
alphabetically.

Patch5-Patch13: Added Timer, CpuMmuLib, CpuMmuInitLib, MpInitLib, CpuDxe
for LoongArch, and added some PCD and header files requested by the
above libraries and drivers.

Modfied modules: UefiCpuPkg

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

PR: https://github.com/tianocore/edk2/pull/5483

V1 -> V2:
1. Removed PcdCpuMmuIsEnabled.
2. Removed API GetMemoryRegionAttributes API as it is no longer needed.
3. Patch3, added two empty line in DXE and PEI INF files.
4. Patch5, added the Status check in GetTimeInnanoSecond function.
5. Separated into two series, this is series one, and the second one is
OvmfPkg.

V2 -> V3:
1. Remove CpuMmuInitLib.
2. Added a new GUID HOB named PROCESSOR_RESOURCE_HOG_GUID.
3. Following Ray suggest, adjust CpuMmuLib API, rename the API name.
4. Rename the PcdCpuExceptionVectorBaseAddress to
PcdLoongArch64ExceptionVectorBaseAddress.
5. Enable CpuMmio2Dxe in LoongArch.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Dongyan Qian <qiandongyan@loongson.cn>

Chao Li (13):
  UefiCpuPkg/CpuTimerLib: Reorder the INF file alphabetically
  UefiCpuPkg/CpuExceptionHandlerLib: Reorder the INF files
    alphabetically
  UefiCpuPkg/MpInitLib: Reorder the INF files alphabetically
  UefiCpuPkg/CpuDxe: Reorder the INF file alphabetically
  UefiCpuPkg: Add LoongArch64 CPU Timer instance
  UefiCpuPkg: Add CPU exception library for LoongArch
  UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
  UefiCpuPkg: Added a new PCD named
    PcdLoongArchExceptionVectorBaseAddress
  UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg
  UefiCpuPkg: Add a new GUID to store the processors resource
  UefiCpuPkg: Add multiprocessor library for LoongArch64
  UefiCpuPkg: Add CpuDxe driver for LoongArch64
  UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field

 UefiCpuPkg/CpuDxe/CpuDxe.inf                  |   39 +-
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c        |  439 +++++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h        |  288 +++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c         |  544 ++++++
 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c     |  159 ++
 .../Include/Guid/ProcessorResourceHob.h       |   29 +
 UefiCpuPkg/Include/Library/CpuMmuLib.h        |   41 +
 .../DxeCpuExceptionHandlerLib.inf             |   37 +-
 .../LoongArch/DxeExceptionLib.c               |  198 ++
 .../LoongArch/ExceptionCommon.c               |  171 ++
 .../LoongArch/ExceptionCommon.h               |  131 ++
 .../LoongArch64/ArchExceptionHandler.c        |  268 +++
 .../LoongArch64/ExceptionHandlerAsm.S         |  366 ++++
 .../LoongArch/SecPeiExceptionLib.c            |  102 ++
 .../PeiCpuExceptionHandlerLib.inf             |   16 +-
 .../SecPeiCpuExceptionHandlerLib.inf          |   31 +-
 .../SmmCpuExceptionHandlerLib.inf             |   16 +-
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf    |   39 +
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni    |   14 +
 .../Library/CpuMmuLib/LoongArch64/CpuMmu.c    |  785 ++++++++
 .../Library/CpuMmuLib/LoongArch64/Page.h      |   33 +
 .../LoongArch64/TlbExceptionHandle.S          |   51 +
 .../LoongArch64/TlbExceptionHandle.h          |   36 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.S        |   24 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.h        |   24 +
 .../Library/CpuTimerLib/BaseCpuTimerLib.inf   |   17 +-
 .../CpuTimerLib/LoongArch64/CpuTimerLib.c     |  250 +++
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   42 +-
 .../Library/MpInitLib/LoongArch64/DxeMpLib.c  |  480 +++++
 .../Library/MpInitLib/LoongArch64/MpLib.c     | 1626 +++++++++++++++++
 .../Library/MpInitLib/LoongArch64/MpLib.h     |  350 ++++
 .../Library/MpInitLib/LoongArch64/PeiMpLib.c  |  381 ++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   40 +-
 UefiCpuPkg/UefiCpuPkg.dec                     |   13 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |    7 +
 35 files changed, 7008 insertions(+), 79 deletions(-)
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c
 create mode 100644 UefiCpuPkg/Include/Guid/ProcessorResourceHob.h
 create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c
 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/TlbExceptionHandle.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h
 create mode 100644 UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c

-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117647): https://edk2.groups.io/g/devel/message/117647
Mute This Topic: https://groups.io/mt/105478478/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 01/13] UefiCpuPkg/CpuTimerLib: Reorder the INF file alphabetically
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
@ 2024-04-12  7:33 ` Chao Li
  2024-04-12  7:33 ` [edk2-devel] [PATCH v3 02/13] UefiCpuPkg/CpuExceptionHandlerLib: Reorder the INF files alphabetically Chao Li
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:33 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

Some of the order is not in alphabetical, reorder.

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

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
index de0648de91..f0f4ae902a 100644
--- a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -28,8 +28,8 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
-  PcdLib
   DebugLib
+  PcdLib
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency  ## CONSUMES
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117648): https://edk2.groups.io/g/devel/message/117648
Mute This Topic: https://groups.io/mt/105478487/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 02/13] UefiCpuPkg/CpuExceptionHandlerLib: Reorder the INF files alphabetically
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
  2024-04-12  7:33 ` [edk2-devel] [PATCH v3 01/13] UefiCpuPkg/CpuTimerLib: Reorder the INF file alphabetically Chao Li
@ 2024-04-12  7:33 ` Chao Li
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 03/13] UefiCpuPkg/MpInitLib: " Chao Li
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:33 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

Some of the order is not in alphabetical, reorder.

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

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 .../DxeCpuExceptionHandlerLib.inf             | 20 +++++++++----------
 .../PeiCpuExceptionHandlerLib.inf             | 16 +++++++--------
 .../SecPeiCpuExceptionHandlerLib.inf          | 12 +++++------
 .../SmmCpuExceptionHandlerLib.inf             | 16 +++++++--------
 4 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index fdbebadab9..aabcabff0f 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -22,21 +22,21 @@ [Defines]
 #
 
 [Sources.Ia32]
-  Ia32/ExceptionHandlerAsm.nasm
-  Ia32/ExceptionTssEntryAsm.nasm
   Ia32/ArchExceptionHandler.c
   Ia32/ArchInterruptDefs.h
+  Ia32/ExceptionHandlerAsm.nasm
+  Ia32/ExceptionTssEntryAsm.nasm
 
 [Sources.X64]
-  X64/ExceptionHandlerAsm.nasm
   X64/ArchExceptionHandler.c
   X64/ArchInterruptDefs.h
+  X64/ExceptionHandlerAsm.nasm
 
 [Sources.common]
   CpuExceptionCommon.h
   CpuExceptionCommon.c
-  PeiDxeSmmCpuException.c
   DxeException.c
+  PeiDxeSmmCpuException.c
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
@@ -53,14 +53,14 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
-  SerialPortLib
-  PrintLib
-  SynchronizationLib
+  CcExitLib
+  DebugLib
   LocalApicLib
-  PeCoffGetEntryPointLib
   MemoryAllocationLib
-  DebugLib
-  CcExitLib
+  PeCoffGetEntryPointLib
+  PrintLib
+  SerialPortLib
+  SynchronizationLib
 
 [BuildOptions]
   XCODE:*_*_X64_NASM_FLAGS = -D NO_ABSOLUTE_RELOCS_IN_TEXT
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index 3bcaff5c5f..3a11516e32 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -22,15 +22,15 @@ [Defines]
 #
 
 [Sources.Ia32]
-  Ia32/ExceptionHandlerAsm.nasm
-  Ia32/ExceptionTssEntryAsm.nasm
   Ia32/ArchExceptionHandler.c
   Ia32/ArchInterruptDefs.h
+  Ia32/ExceptionHandlerAsm.nasm
+  Ia32/ExceptionTssEntryAsm.nasm
 
 [Sources.X64]
-  X64/SecPeiExceptionHandlerAsm.nasm
   X64/ArchExceptionHandler.c
   X64/ArchInterruptDefs.h
+  X64/SecPeiExceptionHandlerAsm.nasm
 
 [Sources.common]
   CpuExceptionCommon.h
@@ -45,14 +45,14 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
-  SerialPortLib
-  PrintLib
-  LocalApicLib
-  PeCoffGetEntryPointLib
+  CcExitLib
   HobLib
+  LocalApicLib
   MemoryAllocationLib
+  PeCoffGetEntryPointLib
+  PrintLib
+  SerialPortLib
   SynchronizationLib
-  CcExitLib
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard    # CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index e7b1144f69..f8e597d86d 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -22,15 +22,15 @@ [Defines]
 #
 
 [Sources.Ia32]
-  Ia32/ExceptionHandlerAsm.nasm
-  Ia32/ExceptionTssEntryAsm.nasm
   Ia32/ArchExceptionHandler.c
   Ia32/ArchInterruptDefs.h
+  Ia32/ExceptionHandlerAsm.nasm
+  Ia32/ExceptionTssEntryAsm.nasm
 
 [Sources.X64]
-  X64/SecPeiExceptionHandlerAsm.nasm
   X64/ArchExceptionHandler.c
   X64/ArchInterruptDefs.h
+  X64/SecPeiExceptionHandlerAsm.nasm
 
 [Sources.common]
   CpuExceptionCommon.h
@@ -44,11 +44,11 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
-  SerialPortLib
-  PrintLib
+  CcExitLib
   LocalApicLib
   PeCoffGetEntryPointLib
-  CcExitLib
+  PrintLib
+  SerialPortLib
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
index 27f0b96fa9..cc280a6ee7 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
@@ -22,15 +22,15 @@ [Defines]
 #
 
 [Sources.Ia32]
-  Ia32/ExceptionHandlerAsm.nasm
-  Ia32/ExceptionTssEntryAsm.nasm
   Ia32/ArchExceptionHandler.c
   Ia32/ArchInterruptDefs.h
+  Ia32/ExceptionHandlerAsm.nasm
+  Ia32/ExceptionTssEntryAsm.nasm
 
 [Sources.X64]
-  X64/ExceptionHandlerAsm.nasm
   X64/ArchExceptionHandler.c
   X64/ArchInterruptDefs.h
+  X64/ExceptionHandlerAsm.nasm
 
 [Sources.common]
   CpuExceptionCommon.h
@@ -45,13 +45,13 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
-  SerialPortLib
-  PrintLib
-  SynchronizationLib
+  CcExitLib
+  DebugLib
   LocalApicLib
   PeCoffGetEntryPointLib
-  DebugLib
-  CcExitLib
+  PrintLib
+  SerialPortLib
+  SynchronizationLib
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117649): https://edk2.groups.io/g/devel/message/117649
Mute This Topic: https://groups.io/mt/105478489/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 03/13] UefiCpuPkg/MpInitLib: Reorder the INF files alphabetically
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
  2024-04-12  7:33 ` [edk2-devel] [PATCH v3 01/13] UefiCpuPkg/CpuTimerLib: Reorder the INF file alphabetically Chao Li
  2024-04-12  7:33 ` [edk2-devel] [PATCH v3 02/13] UefiCpuPkg/CpuExceptionHandlerLib: Reorder the INF files alphabetically Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 04/13] UefiCpuPkg/CpuDxe: Reorder the INF file alphabetically Chao Li
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

Some of the order is not in alphabetical, reorder.

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

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 29 ++++++++++---------
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 25 ++++++++--------
 2 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 55e46d4a1f..7ef4c0d4db 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -23,21 +23,21 @@ [Defines]
 
 [Sources.IA32]
   Ia32/AmdSev.c
-  Ia32/MpFuncs.nasm
   Ia32/CreatePageTable.c
+  Ia32/MpFuncs.nasm
 
 [Sources.X64]
   X64/AmdSev.c
-  X64/MpFuncs.nasm
   X64/CreatePageTable.c
+  X64/MpFuncs.nasm
 
 [Sources.common]
   AmdSev.c
-  MpEqu.inc
   DxeMpLib.c
+  Microcode.c
+  MpEqu.inc
   MpLib.c
   MpLib.h
-  Microcode.c
   MpHandOff.h
 
 [Packages]
@@ -47,17 +47,18 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
+  CcExitLib
+  CpuLib
+  DebugAgentLib
+  HobLib
   LocalApicLib
   MemoryAllocationLib
-  HobLib
+  MicrocodeLib
   MtrrLib
-  CpuLib
-  UefiBootServicesTableLib
-  DebugAgentLib
-  SynchronizationLib
   PcdLib
-  CcExitLib
-  MicrocodeLib
+  SynchronizationLib
+  UefiBootServicesTableLib
+
 [LibraryClasses.X64]
   CpuPageTableLib
 
@@ -70,6 +71,9 @@ [Guids]
   gEdkiiMicrocodePatchHobGuid                   ## SOMETIMES_CONSUMES  ## HOB
 
 [Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES
+  gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr           ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber            ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber           ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds          ## SOMETIMES_CONSUMES
@@ -82,6 +86,3 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures                  ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                       ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdFirstTimeWakeUpAPsBySipi                ## CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES
-  gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr           ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index bc3d716aa9..599ca36bc2 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -31,31 +31,34 @@ [Sources.X64]
 
 [Sources.common]
   AmdSev.c
+  Microcode.c
   MpEqu.inc
-  PeiMpLib.c
   MpLib.c
   MpLib.h
-  Microcode.c
   MpHandOff.h
+  PeiMpLib.c
+
 [Packages]
   MdePkg/MdePkg.dec
-  UefiCpuPkg/UefiCpuPkg.dec
   MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   BaseLib
+  CcExitLib
+  CpuLib
+  HobLib
   LocalApicLib
   MemoryAllocationLib
-  HobLib
+  MicrocodeLib
   MtrrLib
-  CpuLib
-  SynchronizationLib
-  PeiServicesLib
   PcdLib
-  CcExitLib
-  MicrocodeLib
+  PeiServicesLib
+  SynchronizationLib
 
 [Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
+  gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber        ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber       ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds      ## SOMETIMES_CONSUMES
@@ -66,9 +69,7 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate                   ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                   ## SOMETIMES_CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures              ## CONSUMES
-  gUefiCpuPkgTokenSpaceGuid.PcdFirstTimeWakeUpAPsBySipi             ## CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
-  gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr       ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdFirstTimeWakeUpAPsBySipi            ## CONSUMES
 
 [Ppis]
   gEdkiiPeiShadowMicrocodePpiGuid        ## SOMETIMES_CONSUMES
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117650): https://edk2.groups.io/g/devel/message/117650
Mute This Topic: https://groups.io/mt/105478490/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 04/13] UefiCpuPkg/CpuDxe: Reorder the INF file alphabetically
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (2 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 03/13] UefiCpuPkg/MpInitLib: " Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 05/13] UefiCpuPkg: Add LoongArch64 CPU Timer instance Chao Li
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

Some of the order is not in alphabetical, reorder.

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

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 UefiCpuPkg/CpuDxe/CpuDxe.inf | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
index 1d3e9f8cdb..9e1c673283 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
@@ -25,21 +25,21 @@ [Packages]
 [LibraryClasses]
   BaseLib
   BaseMemoryLib
+  CpuExceptionHandlerLib
   CpuLib
   DebugLib
   DxeServicesTableLib
+  HobLib
+  LocalApicLib
   MemoryAllocationLib
   MtrrLib
+  MpInitLib
+  PeCoffGetEntryPointLib
+  ReportStatusCodeLib
+  TimerLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
-  LocalApicLib
   UefiLib
-  CpuExceptionHandlerLib
-  HobLib
-  ReportStatusCodeLib
-  MpInitLib
-  TimerLib
-  PeCoffGetEntryPointLib
 
 [Sources]
   CpuDxe.c
@@ -77,9 +77,9 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                       ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask               ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask                    ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList              ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize                    ## CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask                    ## CONSUMES
 
 [Depex]
   TRUE
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117651): https://edk2.groups.io/g/devel/message/117651
Mute This Topic: https://groups.io/mt/105478493/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 05/13] UefiCpuPkg: Add LoongArch64 CPU Timer instance
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (3 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 04/13] UefiCpuPkg/CpuDxe: Reorder the INF file alphabetically Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 06/13] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

Add the LoongArch64 CPU Timer instance to CpuTimerLib, using CPUCFG 0x4
and 0x5 for Stable Counter frequency.

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 .../Library/CpuTimerLib/BaseCpuTimerLib.inf   |  15 +-
 .../CpuTimerLib/LoongArch64/CpuTimerLib.c     | 250 ++++++++++++++++++
 UefiCpuPkg/UefiCpuPkg.dsc                     |   3 +
 3 files changed, 266 insertions(+), 2 deletions(-)
 create mode 100644 UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
index f0f4ae902a..4a1c7c0510 100644
--- a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -1,10 +1,15 @@
 ## @file
 #  Base CPU Timer Library
 #
-#  Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+#  Provides basic timer support.
+#
+#  In x86, using CPUID Leaf 0x15 XTAL frequency. The performance
 #  counter features are provided by the processors time stamp counter.
 #
+#  In LoongArch64, using CPUCFG 0x4 and 0x5 for Stable Counter frequency.
+#
 #  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -18,10 +23,13 @@ [Defines]
   LIBRARY_CLASS                  = TimerLib
   MODULE_UNI_FILE                = BaseCpuTimerLib.uni
 
-[Sources]
+[Sources.IA32, Sources.X64]
   CpuTimerLib.c
   BaseCpuTimerLib.c
 
+[Sources.LoongArch64]
+  LoongArch64/CpuTimerLib.c
+
 [Packages]
   MdePkg/MdePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
@@ -31,5 +39,8 @@ [LibraryClasses]
   DebugLib
   PcdLib
 
+[LibraryClasses.LoongArch64]
+  SafeIntLib
+
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency  ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c
new file mode 100644
index 0000000000..7ba7408498
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c
@@ -0,0 +1,250 @@
+/** @file
+  CPUCFG 0x4 and 0x5 for Stable Counter frequency instance of Timer Library.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SafeIntLib.h>
+#include <Library/TimerLib.h>
+#include <Register/LoongArch64/Cpucfg.h>
+
+/**
+  Calculate clock frequency using CPUCFG 0x4 and 0x5 registers.
+
+  @param  VOID.
+
+  @return The frequency in Hz.
+
+**/
+STATIC
+UINT64
+CalcConstFreq (
+  VOID
+  )
+{
+  UINT32                 BaseFreq;
+  UINT64                 ClockMultiplier;
+  UINT32                 ClockDivide;
+  CPUCFG_REG4_INFO_DATA  CcFreq;
+  CPUCFG_REG5_INFO_DATA  CpucfgReg5Data;
+  UINT64                 StableTimerFreq;
+
+  //
+  // Get the the crystal frequency corresponding to the constant
+  // frequency timer and the clock used by the timer.
+  //
+  AsmCpucfg (CPUCFG_REG4_INFO, &CcFreq.Uint32);
+
+  //
+  // Get the multiplication factor and frequency division factor
+  // corresponding to the constant frequency timer and the clock
+  // used by the timer.
+  //
+  AsmCpucfg (CPUCFG_REG5_INFO, &CpucfgReg5Data.Uint32);
+
+  BaseFreq        = CcFreq.Bits.CC_FREQ;
+  ClockMultiplier = CpucfgReg5Data.Bits.CC_MUL & 0xFFFF;
+  ClockDivide     = CpucfgReg5Data.Bits.CC_DIV & 0xFFFF;
+
+  if ((BaseFreq == 0x0) || (ClockMultiplier == 0x0) || (ClockDivide == 0x0)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "LoongArch Stable Timer is not available in the CPU, hence this library cannot be used.\n"
+      ));
+    ASSERT (FALSE);
+    CpuDeadLoop ();
+  }
+
+  StableTimerFreq = ((ClockMultiplier * BaseFreq) / ClockDivide);
+
+  ASSERT (StableTimerFreq != 0);
+
+  return StableTimerFreq;
+}
+
+/**
+  Stalls the CPU for at least the given number of microseconds.
+
+  Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+  @param  MicroSeconds  The minimum number of microseconds to delay.
+
+  @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+  IN UINTN  MicroSeconds
+  )
+{
+  UINT64         CurrentTicks, ExceptedTicks, Remaining;
+  RETURN_STATUS  Status;
+
+  Status = SafeUint64Mult (MicroSeconds, CalcConstFreq (), &Remaining);
+  ASSERT_RETURN_ERROR (Status);
+
+  ExceptedTicks  = DivU64x32 (Remaining, 1000000U);
+  CurrentTicks   = AsmReadStableCounter ();
+  ExceptedTicks += CurrentTicks;
+
+  do {
+    CurrentTicks = AsmReadStableCounter ();
+  } while (CurrentTicks < ExceptedTicks);
+
+  return MicroSeconds;
+}
+
+/**
+  Stalls the CPU for at least the given number of nanoseconds.
+
+  Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+  @param  NanoSeconds The minimum number of nanoseconds to delay.
+
+  @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+  IN UINTN  NanoSeconds
+  )
+{
+  UINTN  MicroSeconds;
+
+  // Round up to 1us Tick Number
+  MicroSeconds  = NanoSeconds / 1000;
+  MicroSeconds += ((NanoSeconds % 1000) == 0) ? 0 : 1;
+
+  MicroSecondDelay (MicroSeconds);
+
+  return NanoSeconds;
+}
+
+/**
+  Retrieves the current value of a 64-bit free running Stable Counter.
+
+  The LoongArch defines a constant frequency timer, whose main body is a
+  64-bit counter called StableCounter. StableCounter is set to 0 after
+  reset, and then increments by 1 every counting clock cycle. When the
+  count reaches all 1s, it automatically wraps around to 0 and continues
+  to increment.
+  The properties of the Stable Counter can be retrieved from
+  GetPerformanceCounterProperties().
+
+  @return The current value of the Stable Counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+  VOID
+  )
+{
+  //
+  // Just return the value of Stable Counter.
+  //
+  return AsmReadStableCounter ();
+}
+
+/**
+  Retrieves the 64-bit frequency in Hz and the range of Stable Counter
+  values.
+
+  If StartValue is not NULL, then the value that the stbale counter starts
+  with immediately after is it rolls over is returned in StartValue. If
+  EndValue is not NULL, then the value that the stable counter end with
+  immediately before it rolls over is returned in EndValue. The 64-bit
+  frequency of the system frequency in Hz is always returned.
+
+  @param  StartValue  The value the stable counter starts with when it
+                      rolls over.
+  @param  EndValue    The value that the stable counter ends with before
+                      it rolls over.
+
+  @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+  OUT UINT64  *StartValue   OPTIONAL,
+  OUT UINT64  *EndValue     OPTIONAL
+  )
+{
+  if (StartValue != NULL) {
+    *StartValue = 0;
+  }
+
+  if (EndValue != NULL) {
+    *EndValue = 0xFFFFFFFFFFFFFFFFULL;
+  }
+
+  return CalcConstFreq ();
+}
+
+/**
+  Converts elapsed ticks of performance counter to time in nanoseconds.
+
+  This function converts the elapsed ticks of running performance counter to
+  time value in unit of nanoseconds.
+
+  @param  Ticks     The number of elapsed ticks of running performance counter.
+
+  @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+  IN UINT64  Ticks
+  )
+{
+  UINT64         Frequency;
+  UINT64         NanoSeconds;
+  UINT64         Remainder;
+  INTN           Shift;
+  RETURN_STATUS  Status;
+
+  Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+  //
+  //          Ticks
+  // Time = --------- x 1,000,000,000
+  //        Frequency
+  //
+  Status = SafeUint64Mult (
+             DivU64x64Remainder (Ticks, Frequency, &Remainder),
+             1000000000u,
+             &NanoSeconds
+             );
+  ASSERT_RETURN_ERROR (Status);
+
+  //
+  // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+  // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+  // i.e. highest bit set in Remainder should <= 33.
+  //
+  Shift     = MAX (0, HighBitSet64 (Remainder) - 33);
+  Remainder = RShiftU64 (Remainder, (UINTN)Shift);
+  Frequency = RShiftU64 (Frequency, (UINTN)Shift);
+
+  Status = SafeUint64Add (
+             NanoSeconds,
+             DivU64x64Remainder (
+               MultU64x32 (Remainder, 1000000000u),
+               Frequency,
+               NULL
+               ),
+             &NanoSeconds
+             );
+  ASSERT_RETURN_ERROR (Status);
+
+  return NanoSeconds;
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 10b33594e5..2eebd45125 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -110,6 +110,9 @@ [LibraryClasses.common.UEFI_APPLICATION]
   UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
   MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
 
+[LibraryClasses.LoongArch64]
+  SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
+
 #
 # Drivers/Libraries within this package
 #
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117652): https://edk2.groups.io/g/devel/message/117652
Mute This Topic: https://groups.io/mt/105478494/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 06/13] UefiCpuPkg: Add CPU exception library for LoongArch
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (4 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 05/13] UefiCpuPkg: Add LoongArch64 CPU Timer instance Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 07/13] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann, Baoqi Zhang

Added LoongArch exception handler into CpuExceptionHandlerLib.

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 .../DxeCpuExceptionHandlerLib.inf             |  23 +-
 .../LoongArch/DxeExceptionLib.c               | 198 ++++++++++
 .../LoongArch/ExceptionCommon.c               | 171 ++++++++
 .../LoongArch/ExceptionCommon.h               | 131 +++++++
 .../LoongArch64/ArchExceptionHandler.c        | 268 +++++++++++++
 .../LoongArch64/ExceptionHandlerAsm.S         | 366 ++++++++++++++++++
 .../LoongArch/SecPeiExceptionLib.c            | 102 +++++
 .../SecPeiCpuExceptionHandlerLib.inf          |  23 +-
 8 files changed, 1273 insertions(+), 9 deletions(-)
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index aabcabff0f..9fcba009d6 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -2,6 +2,7 @@
 #  CPU Exception Handler library instance for DXE modules.
 #
 #  Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -18,7 +19,7 @@ [Defines]
 #
 # The following information is for reference only and not required by the build tools.
 #
-#  VALID_ARCHITECTURES           = IA32 X64
+#  VALID_ARCHITECTURES           = IA32 X64 LOONGARCH64
 #
 
 [Sources.Ia32]
@@ -32,12 +33,19 @@ [Sources.X64]
   X64/ArchInterruptDefs.h
   X64/ExceptionHandlerAsm.nasm
 
-[Sources.common]
+[Sources.Ia32, Sources.X64]
   CpuExceptionCommon.h
   CpuExceptionCommon.c
   DxeException.c
   PeiDxeSmmCpuException.c
 
+[Sources.LoongArch64]
+  LoongArch/DxeExceptionLib.c
+  LoongArch/ExceptionCommon.h
+  LoongArch/ExceptionCommon.c
+  LoongArch/LoongArch64/ArchExceptionHandler.c
+  LoongArch/LoongArch64/ExceptionHandlerAsm.S | GCC
+
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
   gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList
@@ -51,16 +59,21 @@ [Packages]
   MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
-[LibraryClasses]
+[LibraryClasses.common]
   BaseLib
-  CcExitLib
   DebugLib
-  LocalApicLib
   MemoryAllocationLib
   PeCoffGetEntryPointLib
   PrintLib
   SerialPortLib
   SynchronizationLib
 
+[LibraryClasses.Ia32, LibraryClasses.X64]
+  CcExitLib
+  LocalApicLib
+
+[LibraryClasses.LoongArch64]
+  CpuLib
+
 [BuildOptions]
   XCODE:*_*_X64_NASM_FLAGS = -D NO_ABSOLUTE_RELOCS_IN_TEXT
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c
new file mode 100644
index 0000000000..eed5644552
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c
@@ -0,0 +1,198 @@
+/** @file DxeExceptionLib.c
+
+  LoongArch exception library implemenation for DXE modules.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/CpuLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SerialPortLib.h>
+#include <Protocol/DebugSupport.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include "ExceptionCommon.h"
+
+EFI_EXCEPTION_CALLBACK  ExternalInterruptHandler[MAX_LOONGARCH_INTERRUPT + 1] = { 0 };
+EFI_EXCEPTION_CALLBACK  ExceptionHandler[MAX_LOONGARCH_EXCEPTION + 1]         = { 0 };
+
+/**
+  Registers a function to be called from the processor interrupt or exception handler.
+
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+                           when a processor interrupt occurs. If this parameter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterCpuInterruptHandler (
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  EFI_EXCEPTION_TYPE  ExceptionType;
+
+  ExceptionType = InterruptType & CSR_ESTAT_EXC;
+
+  if (ExceptionType != 0) {
+    //
+    // Exception >>= CSR_ESTAT_EXC_SHIFT, convert to ECODE
+    //
+    ExceptionType >>= CSR_ESTAT_EXC_SHIFT;
+
+    if (ExceptionType > EXCEPT_LOONGARCH_FPE) {
+      return EFI_UNSUPPORTED;
+    }
+
+    if ((InterruptHandler == NULL) && (ExceptionHandler[InterruptType] == NULL)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if ((InterruptHandler != NULL) && (ExceptionHandler[ExceptionType] != NULL)) {
+      return EFI_ALREADY_STARTED;
+    }
+
+    ExceptionHandler[ExceptionType] = InterruptHandler;
+  } else {
+    //
+    // Interrupt
+    //
+    if (InterruptType > MAX_LOONGARCH_INTERRUPT) {
+      return EFI_UNSUPPORTED;
+    }
+
+    if ((InterruptHandler == NULL) && (ExternalInterruptHandler[InterruptType] == NULL)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if ((InterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) {
+      return EFI_ALREADY_STARTED;
+    }
+
+    ExternalInterruptHandler[InterruptType] = InterruptHandler;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Common exception handler.
+
+  @param ExceptionType  Exception type.
+  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+  IN     EFI_EXCEPTION_TYPE  ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  EFI_EXCEPTION_TYPE  InterruptType;
+
+  if (ExceptionType == EXCEPT_LOONGARCH_INT) {
+    //
+    // Interrupt
+    //
+    InterruptType = GetInterruptType (SystemContext);
+    if (InterruptType == 0xFF) {
+      ExceptionType = InterruptType;
+    } else {
+      if ((ExternalInterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) {
+        ExternalInterruptHandler[InterruptType](InterruptType, SystemContext);
+        return;
+      }
+    }
+  } else if (ExceptionType == EXCEPT_LOONGARCH_FPD) {
+    EnableFloatingPointUnits ();
+    InitializeFloatingPointUnits ();
+    return;
+  } else {
+    //
+    // Exception
+    //
+    ExceptionType >>= CSR_ESTAT_EXC_SHIFT;
+    if ((ExceptionHandler != NULL) && (ExceptionHandler[ExceptionType] != NULL)) {
+      ExceptionHandler[ExceptionType](ExceptionType, SystemContext);
+      return;
+    }
+  }
+
+  //
+  // Only the TLB refill exception use the same entry point as normal exceptions.
+  //
+  if (CsrRead (LOONGARCH_CSR_TLBRERA) & 0x1) {
+    ExceptionType = mExceptionKnownNameNum - 1; // Use only to dump the exception context.
+  }
+
+  DefaultExceptionHandler (ExceptionType, SystemContext);
+}
+
+/**
+  Initializes all CPU exceptions entries and provides the default exception handlers.
+
+  Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+  persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+  If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+  If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+  @param[in]  VectorInfo    Pointer to reserved vector list.
+
+  @retval EFI_SUCCESS           CPU Exception Entries have been successfully initialized
+                                with default exception handlers.
+  @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+  IN EFI_VECTOR_HANDOFF_INFO  *VectorInfo OPTIONAL
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+  Setup separate stacks for certain exception handlers.
+  If the input Buffer and BufferSize are both NULL, use global variable if possible.
+
+  @param[in]       Buffer        Point to buffer used to separate exception stack.
+  @param[in, out]  BufferSize    On input, it indicates the byte size of Buffer.
+                                 If the size is not enough, the return status will
+                                 be EFI_BUFFER_TOO_SMALL, and output BufferSize
+                                 will be the size it needs.
+
+  @retval EFI_SUCCESS             The stacks are assigned successfully.
+  @retval EFI_UNSUPPORTED         This function is not supported.
+  @retval EFI_BUFFER_TOO_SMALL    This BufferSize is too small.
+**/
+EFI_STATUS
+EFIAPI
+InitializeSeparateExceptionStacks (
+  IN     VOID   *Buffer,
+  IN OUT UINTN  *BufferSize
+  )
+{
+  return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c
new file mode 100644
index 0000000000..801c8393e8
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c
@@ -0,0 +1,171 @@
+/** @file DxeExceptionLib.c
+
+  CPU Exception Handler Library common functions.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PrintLib.h>
+#include <Library/SerialPortLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include "ExceptionCommon.h"
+
+CONST CHAR8  mExceptionReservedStr[] = "Reserved";
+CONST CHAR8  *mExceptionNameStr[]    = {
+  "#INT - Interrupt(CSR.ECFG.VS=0)",
+  "#PIL - Page invalid exception for Load option",
+  "#PIS - Page invalid exception for Store operation",
+  "#PIF - Page invalid exception for Fetch operation",
+  "#PME - Page modification exception",
+  "#PNR - Page non-readable exception",
+  "#PNX - Page non-executable exception",
+  "#PPI - Page privilege level illegal exception",
+  "#ADE - Address error exception",
+  "#ALE - Address alignment fault exception",
+  "#BCE - Bound check exception",
+  "#SYS - System call exception",
+  "#BRK - Beeakpoint exception",
+  "#INE - Instruction non-defined exception",
+  "#IPE - Instruction privilege error exception",
+  "#FPD - Floating-point instruction disable exception",
+  "#SXD - 128-bit vector (SIMD instructions) expansion instruction disable exception",
+  "#ASXD - 256-bit vector (Advanced SIMD instructions) expansion instruction disable exception",
+  "#FPE - Floating-Point error exception",
+  "#WPE - WatchPoint Exception for Fetch watchpoint or Memory load/store watchpoint",
+  "#BTD - Binary Translation expansion instruction Disable exception",
+  "#BTE - Binary Translation related exceptions",
+  "#GSPR - Guest Sensitive Privileged Resource exception",
+  "#HVC - HyperVisor Call exception",
+  "#GCXC - Guest CSR Software/Hardware Change exception",
+  "#TBR - TLB refill exception" // !!! NOTICE: Because the TLB refill exception is not instructed in ECODE, so the TLB refill exception must be the last one!
+};
+
+INTN  mExceptionKnownNameNum = (sizeof (mExceptionNameStr) / sizeof (CHAR8 *));
+
+/**
+  Get ASCII format string exception name by exception type.
+
+  @param ExceptionType  Exception type.
+
+  @return  ASCII format string exception name.
+
+**/
+CONST CHAR8 *
+GetExceptionNameStr (
+  IN EFI_EXCEPTION_TYPE  ExceptionType
+  )
+{
+  if ((UINTN)ExceptionType < mExceptionKnownNameNum) {
+    return mExceptionNameStr[ExceptionType];
+  } else {
+    return mExceptionReservedStr;
+  }
+}
+
+/**
+  Prints a message to the serial port.
+
+  @param  Format      Format string for the message to print.
+  @param  ...         Variable argument list whose contents are accessed
+                      based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+InternalPrintMessage (
+  IN  CONST CHAR8  *Format,
+  ...
+  )
+{
+  CHAR8    Buffer[MAX_DEBUG_MESSAGE_LENGTH];
+  VA_LIST  Marker;
+
+  //
+  // Convert the message to an ASCII String
+  //
+  VA_START (Marker, Format);
+  AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+  VA_END (Marker);
+
+  //
+  // Send the print string to a Serial Port
+  //
+  SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
+}
+
+/**
+  Find and display image base address and return image base and its entry point.
+
+  @param CurrentEra      Current instruction pointer.
+
+**/
+VOID
+DumpModuleImageInfo (
+  IN  UINTN  CurrentEra
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Pe32Data;
+  VOID        *PdbPointer;
+  VOID        *EntryPoint;
+
+  Pe32Data = PeCoffSearchImageBase (CurrentEra);
+  if (Pe32Data == 0) {
+    InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
+  } else {
+    //
+    // Find Image Base entry point
+    //
+    Status = PeCoffLoaderGetEntryPoint ((VOID *)Pe32Data, &EntryPoint);
+    if (EFI_ERROR (Status)) {
+      EntryPoint = NULL;
+    }
+
+    InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentEra);
+    PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)Pe32Data);
+    if (PdbPointer != NULL) {
+      InternalPrintMessage ("%a", PdbPointer);
+    } else {
+      InternalPrintMessage ("(No PDB) ");
+    }
+
+    InternalPrintMessage (
+      " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
+      (VOID *)Pe32Data,
+      EntryPoint
+      );
+  }
+}
+
+/**
+  Default exception handler.
+
+  @param ExceptionType  Exception type.
+  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+DefaultExceptionHandler (
+  IN     EFI_EXCEPTION_TYPE  ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  //
+  // Initialize the serial port before dumping.
+  //
+  SerialPortInitialize ();
+  //
+  // Display ExceptionType, CPU information and Image information
+  //
+  DumpImageAndCpuContent (ExceptionType, SystemContext);
+
+  //
+  // Enter a dead loop.
+  //
+  CpuDeadLoop ();
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h
new file mode 100644
index 0000000000..e326b73e3f
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h
@@ -0,0 +1,131 @@
+/** @file DxeExceptionLib.h
+
+  Common header file for CPU Exception Handler Library.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef EXCEPTION_COMMON_H_
+#define EXCEPTION_COMMON_H_
+
+#define MAX_DEBUG_MESSAGE_LENGTH  0x100
+
+//
+// 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
+
+extern INTN  mExceptionKnownNameNum;
+
+/**
+  Get ASCII format string exception name by exception type.
+
+  @param[in] ExceptionType  Exception type.
+
+  @return    ASCII format string exception name.
+
+**/
+CONST CHAR8 *
+GetExceptionNameStr (
+  IN EFI_EXCEPTION_TYPE  ExceptionType
+  );
+
+/**
+  Prints a message to the serial port.
+
+  @param[in]  Format      Format string for the message to print.
+  @param[in]  ...         Variable argument list whose contents are accessed
+                      based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+InternalPrintMessage (
+  IN  CONST CHAR8  *Format,
+  ...
+  );
+
+/**
+  Find and display image base address and return image base and its entry point.
+
+  @param[in] CurrentEip      Current instruction pointer.
+
+**/
+VOID
+DumpModuleImageInfo (
+  IN UINTN  CurrentEip
+  );
+
+/**
+  IPI Interrupt Handler.
+
+  @param InterruptType    The type of interrupt that occurred
+  @param SystemContext    A pointer to the system context when the interrupt occurred
+**/
+VOID
+EFIAPI
+IpiInterruptHandler (
+  IN EFI_EXCEPTION_TYPE  InterruptType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+/**
+  Default exception handler.
+
+  @param[in] ExceptionType  Exception type.
+  @param[in] SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+DefaultExceptionHandler (
+  IN     EFI_EXCEPTION_TYPE  ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+/**
+  Display CPU information.
+
+  @param[in] ExceptionType  Exception type.
+  @param[in] SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+DumpImageAndCpuContent (
+  IN EFI_EXCEPTION_TYPE  ExceptionType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+/**
+  Get exception types
+
+  @param[in]  SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+  @return     Exception type.
+
+**/
+EFI_EXCEPTION_TYPE
+EFIAPI
+GetExceptionType (
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+/**
+  Get Common interrupt types
+
+  @param[in] SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+  @return    Interrupt type.
+
+**/
+EFI_EXCEPTION_TYPE
+EFIAPI
+GetInterruptType (
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+#endif
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c
new file mode 100644
index 0000000000..c0219deba5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c
@@ -0,0 +1,268 @@
+/** @file ArchExceptionHandler.c
+
+  LoongArch64 CPU Exception Handler.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include "ExceptionCommon.h"
+
+/**
+  Get Exception Type
+
+  @param[in] SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+  @return    LoongArch64 exception type.
+
+**/
+EFI_EXCEPTION_TYPE
+EFIAPI
+GetExceptionType (
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  EFI_EXCEPTION_TYPE  ExceptionType;
+
+  ExceptionType = (SystemContext.SystemContextLoongArch64->ESTAT & CSR_ESTAT_EXC);
+  return ExceptionType;
+}
+
+/**
+  Get Interrupt Type
+
+  @param[in] SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+  @return    LoongArch64 intrrupt type.
+
+**/
+EFI_EXCEPTION_TYPE
+EFIAPI
+GetInterruptType (
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  EFI_EXCEPTION_TYPE  InterruptType;
+
+  for (InterruptType = 0; InterruptType <= EXCEPT_LOONGARCH_INT_IPI; InterruptType++) {
+    if (SystemContext.SystemContextLoongArch64->ESTAT & (1 << InterruptType)) {
+      //
+      // 0  - EXCEPT_LOONGARCH_INT_SIP0
+      // 1  - EXCEPT_LOONGARCH_INT_SIP1
+      // 2  - EXCEPT_LOONGARCH_INT_IP0
+      // 3  - EXCEPT_LOONGARCH_INT_IP1
+      // 4  - EXCEPT_LOONGARCH_INT_IP2
+      // 5  - EXCEPT_LOONGARCH_INT_IP3
+      // 6  - EXCEPT_LOONGARCH_INT_IP4
+      // 7  - EXCEPT_LOONGARCH_INT_IP5
+      // 8  - EXCEPT_LOONGARCH_INT_IP6
+      // 9  - EXCEPT_LOONGARCH_INT_IP7
+      // 10 - EXCEPT_LOONGARCH_INT_PMC
+      // 11 - EXCEPT_LOONGARCH_INT_TIMER
+      // 12 - EXCEPT_LOONGARCH_INT_IPI
+      // Greater than EXCEPT_LOONGARCH_INI_IPI is currently invalid.
+      //
+      return InterruptType;
+    }
+  }
+
+  //
+  // Invalid IRQ
+  //
+  return 0xFF;
+}
+
+/**
+  Display CPU information.
+
+  @param ExceptionType  Exception type.
+  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+DumpCpuContext (
+  IN EFI_EXCEPTION_TYPE  ExceptionType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  InternalPrintMessage (
+    "\n!!!! LoongArch64 Exception Type - %02x(%a) !!!!\n",
+    ExceptionType,
+    GetExceptionNameStr (ExceptionType)
+    );
+
+  //
+  // Dump TLB refill ERA and BADV
+  //
+  if (ExceptionType == (mExceptionKnownNameNum - 1)) {
+    InternalPrintMessage ("TLB refill ERA  0x%llx\n", (CsrRead (LOONGARCH_CSR_TLBRERA) & (~0x3ULL)));
+    InternalPrintMessage ("TLB refill BADV  0x%llx\n", CsrRead (LOONGARCH_CSR_TLBRBADV));
+  }
+
+  //
+  // Dump the general registers
+  //
+  InternalPrintMessage (
+    "Zero  - 0x%016lx, RA  - 0x%016lx, TP - 0x%016lx, SP - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->R0,
+    SystemContext.SystemContextLoongArch64->R1,
+    SystemContext.SystemContextLoongArch64->R2,
+    SystemContext.SystemContextLoongArch64->R3
+    );
+  InternalPrintMessage (
+    "  A0  - 0x%016lx, A1  - 0x%016lx, A2 - 0x%016lx, A3 - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->R4,
+    SystemContext.SystemContextLoongArch64->R5,
+    SystemContext.SystemContextLoongArch64->R6,
+    SystemContext.SystemContextLoongArch64->R7
+    );
+  InternalPrintMessage (
+    "  A4  - 0x%016lx, A5  - 0x%016lx, A6 - 0x%016lx, A7 - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->R8,
+    SystemContext.SystemContextLoongArch64->R9,
+    SystemContext.SystemContextLoongArch64->R10,
+    SystemContext.SystemContextLoongArch64->R11
+    );
+  InternalPrintMessage (
+    "  T0  - 0x%016lx, T1  - 0x%016lx, T2 - 0x%016lx, T3 - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->R12,
+    SystemContext.SystemContextLoongArch64->R13,
+    SystemContext.SystemContextLoongArch64->R14,
+    SystemContext.SystemContextLoongArch64->R15
+    );
+  InternalPrintMessage (
+    "  T4  - 0x%016lx, T5  - 0x%016lx, T6 - 0x%016lx, T7 - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->R16,
+    SystemContext.SystemContextLoongArch64->R17,
+    SystemContext.SystemContextLoongArch64->R18,
+    SystemContext.SystemContextLoongArch64->R19
+    );
+  InternalPrintMessage (
+    "  T8  - 0x%016lx, R21 - 0x%016lx, FP - 0x%016lx, S0 - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->R20,
+    SystemContext.SystemContextLoongArch64->R21,
+    SystemContext.SystemContextLoongArch64->R22,
+    SystemContext.SystemContextLoongArch64->R23
+    );
+  InternalPrintMessage (
+    "  S1  - 0x%016lx, S2  - 0x%016lx, S3 - 0x%016lx, S4 - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->R24,
+    SystemContext.SystemContextLoongArch64->R25,
+    SystemContext.SystemContextLoongArch64->R26,
+    SystemContext.SystemContextLoongArch64->R27
+    );
+  InternalPrintMessage (
+    "  S5  - 0x%016lx, S6  - 0x%016lx, S7 - 0x%016lx, S8 - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->R28,
+    SystemContext.SystemContextLoongArch64->R29,
+    SystemContext.SystemContextLoongArch64->R30,
+    SystemContext.SystemContextLoongArch64->R31
+    );
+  InternalPrintMessage ("\n");
+
+  //
+  // Dump the CSR registers
+  //
+  InternalPrintMessage (
+    "CRMD  - 0x%016lx, PRMD  - 0x%016lx, EUEN - 0x%016lx, MISC - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->CRMD,
+    SystemContext.SystemContextLoongArch64->PRMD,
+    SystemContext.SystemContextLoongArch64->EUEN,
+    SystemContext.SystemContextLoongArch64->MISC
+    );
+  InternalPrintMessage (
+    "ECFG  - 0x%016lx, ESTAT - 0x%016lx, ERA  - 0x%016lx, BADV - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->ECFG,
+    SystemContext.SystemContextLoongArch64->ESTAT,
+    SystemContext.SystemContextLoongArch64->ERA,
+    SystemContext.SystemContextLoongArch64->BADV
+    );
+  InternalPrintMessage (
+    "BADI  - 0x%016lx\n",
+    SystemContext.SystemContextLoongArch64->BADI
+    );
+}
+
+/**
+  Display CPU information.
+
+  @param ExceptionType  Exception type.
+  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+DumpImageAndCpuContent (
+  IN EFI_EXCEPTION_TYPE  ExceptionType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  DumpCpuContext (ExceptionType, SystemContext);
+
+  if (ExceptionType == (mExceptionKnownNameNum - 1)) {
+    //
+    // Dump TLB refill image info
+    //
+    DumpModuleImageInfo ((CsrRead (LOONGARCH_CSR_TLBRERA) & (~0x3ULL)));
+  } else {
+    DumpModuleImageInfo (SystemContext.SystemContextLoongArch64->ERA);
+  }
+}
+
+/**
+  IPI Interrupt Handler.
+
+  @param InterruptType    The type of interrupt that occurred
+  @param SystemContext    A pointer to the system context when the interrupt occurred
+**/
+VOID
+EFIAPI
+IpiInterruptHandler (
+  IN EFI_EXCEPTION_TYPE  InterruptType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  UINTN  ResumeVector;
+  UINTN  Parameter;
+
+  //
+  // Clear interrupt.
+  //
+  IoCsrWrite32 (LOONGARCH_IOCSR_IPI_CLEAR, IoCsrRead32 (LOONGARCH_IOCSR_IPI_STATUS));
+
+  //
+  // Get the resume vector and parameter if populated.
+  //
+  ResumeVector = IoCsrRead64 (LOONGARCH_IOCSR_MBUF0);
+  Parameter    = IoCsrRead64 (LOONGARCH_IOCSR_MBUF3);
+
+  //
+  // Clean up current processor mailbox 0 and mailbox 3.
+  //
+  IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, 0x0);
+  IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, 0x0);
+
+  //
+  // If mailbox 0 is non-NULL, it means that the BSP or other cores called the IPI to wake
+  // up the current core and let it use the resume vector stored in mailbox 0.
+  //
+  // If both the resume vector and parameter are non-NULL, it means that the IPI was
+  // called in the BIOS.
+  //
+  // The situation where the resume vector is non-NULL and the parameter is NULL has been
+  // processed after the exception entry is pushed onto the stack.
+  //
+  if ((ResumeVector != 0) && (Parameter != 0)) {
+    SystemContext.SystemContextLoongArch64->ERA = ResumeVector;
+    //
+    // Set $a0 as APIC ID and $a1 as parameter value.
+    //
+    SystemContext.SystemContextLoongArch64->R4 = CsrRead (LOONGARCH_CSR_CPUNUM);
+    SystemContext.SystemContextLoongArch64->R5 = Parameter;
+  }
+
+  MemoryFence ();
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S
new file mode 100644
index 0000000000..7c692e01c1
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S
@@ -0,0 +1,366 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch64 ASM exception handler
+#
+# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#include <Library/BaseLib.h>
+#include <Library/CpuLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#define RSIZE                 8           // 64 bit mode register size
+#define GP_REG_CONTEXT_SIZE   32 * RSIZE  // General-purpose registers size
+#define FP_REG_CONTEXT_SIZE   34 * RSIZE  // Floating-point registers size
+#define CSR_REG_CONTEXT_SIZE  9  * RSIZE  // CSR registers size
+
+ASM_GLOBAL ASM_PFX(ExceptionEntry)
+ASM_GLOBAL ASM_PFX(ExceptionEntryStart)
+ASM_GLOBAL ASM_PFX(ExceptionEntryEnd)
+
+ASM_PFX(ExceptionEntry):
+  move    $s0, $a0
+  bl      GetExceptionType        // Exception type stored in register a0
+  move    $a1, $s0                // SystemContxt
+  bl      CommonExceptionHandler
+
+PopContext:
+  //
+  // Not sure if interrupts are turned on during the exception handler, anyway disable interrupts here.
+  // It will be turned on when the instruction 'ertn' is executed.
+  //
+  bl      DisableInterrupts
+
+  bl      GetExceptionType        // Get current exception type, and stored in register a0
+
+  // Check whether the FPE is changed during interrupt handler, if ture restore it.
+  ld.d    $t1, $sp, (LOONGARCH_CSR_EUEN * RSIZE + GP_REG_CONTEXT_SIZE)
+  csrrd   $t0, LOONGARCH_CSR_EUEN        // Current EUEN
+  andi    $t0, $t0, CSR_EUEN_FPEN
+  andi    $t1, $t1, CSR_EUEN_FPEN
+  li.d    $t2, EXCEPT_LOONGARCH_INT
+  bne     $a0, $t2, PopRegs
+  beq     $t0, $t1, PopRegs
+  beqz    $t1, CloseFP
+  bl      EnableFloatingPointUnits
+  b       PopRegs
+
+CloseFP:
+  bl      DisableFloatingPointUnits
+
+PopRegs:
+  //
+  // Pop CSR reigsters
+  //
+  addi.d  $sp, $sp, GP_REG_CONTEXT_SIZE
+
+  ld.d    $t0, $sp, LOONGARCH_CSR_CRMD * RSIZE
+  csrwr   $t0, LOONGARCH_CSR_CRMD
+  ld.d    $t0, $sp, LOONGARCH_CSR_PRMD * RSIZE
+  csrwr   $t0, LOONGARCH_CSR_PRMD
+  ld.d    $t0, $sp, LOONGARCH_CSR_ECFG * RSIZE
+  csrwr   $t0, LOONGARCH_CSR_ECFG
+  ld.d    $t0, $sp, LOONGARCH_CSR_ERA * RSIZE
+  csrwr   $t0, LOONGARCH_CSR_ERA
+
+  addi.d  $sp, $sp, CSR_REG_CONTEXT_SIZE  // Fource change the stack pointer befor pop the FP registers.
+
+  beqz    $t1, PopGP                      // If the FPE not set, only pop the GP registers.
+
+  //
+  // Pop FP registers
+  //
+  fld.d  $fa0, $sp, 0 * RSIZE
+  fld.d  $fa1, $sp, 1 * RSIZE
+  fld.d  $fa2, $sp, 2 * RSIZE
+  fld.d  $fa3, $sp, 3 * RSIZE
+  fld.d  $fa4, $sp, 4 * RSIZE
+  fld.d  $fa5, $sp, 5 * RSIZE
+  fld.d  $fa6, $sp, 6 * RSIZE
+  fld.d  $fa7, $sp, 7 * RSIZE
+  fld.d  $ft0, $sp, 8 * RSIZE
+  fld.d  $ft1, $sp, 9 * RSIZE
+  fld.d  $ft2, $sp, 10 * RSIZE
+  fld.d  $ft3, $sp, 11 * RSIZE
+  fld.d  $ft4, $sp, 12 * RSIZE
+  fld.d  $ft5, $sp, 13 * RSIZE
+  fld.d  $ft6, $sp, 14 * RSIZE
+  fld.d  $ft7, $sp, 15 * RSIZE
+  fld.d  $ft8, $sp, 16 * RSIZE
+  fld.d  $ft9, $sp, 17 * RSIZE
+  fld.d  $ft10, $sp, 18 * RSIZE
+  fld.d  $ft11, $sp, 19 * RSIZE
+  fld.d  $ft12, $sp, 20 * RSIZE
+  fld.d  $ft13, $sp, 21 * RSIZE
+  fld.d  $ft14, $sp, 22 * RSIZE
+  fld.d  $ft15, $sp, 23 * RSIZE
+  fld.d  $fs0, $sp, 24 * RSIZE
+  fld.d  $fs1, $sp, 25 * RSIZE
+  fld.d  $fs2, $sp, 26 * RSIZE
+  fld.d  $fs3, $sp, 27 * RSIZE
+  fld.d  $fs4, $sp, 28 * RSIZE
+  fld.d  $fs5, $sp, 29 * RSIZE
+  fld.d  $fs6, $sp, 30 * RSIZE
+  fld.d  $fs7, $sp, 31 * RSIZE
+
+  ld.d        $t0, $sp, 32 * RSIZE
+  movgr2fcsr  $r0, $t0             // Pop the fcsr0 register.
+
+  //
+  // Pop the fcc0-fcc7 registers.
+  //
+  ld.d        $t0, $sp, 33 * RSIZE
+  bstrpick.d  $t1, $t0, 7, 0
+  movgr2cf    $fcc0, $t1
+  bstrpick.d  $t1, $t0, 15, 8
+  movgr2cf    $fcc1, $t1
+  bstrpick.d  $t1, $t0, 23, 16
+  movgr2cf    $fcc2, $t1
+  bstrpick.d  $t1, $t0, 31, 24
+  movgr2cf    $fcc3, $t1
+  bstrpick.d  $t1, $t0, 39, 32
+  movgr2cf    $fcc4, $t1
+  bstrpick.d  $t1, $t0, 47, 40
+  movgr2cf    $fcc5, $t1
+  bstrpick.d  $t1, $t0, 55, 48
+  movgr2cf    $fcc6, $t1
+  bstrpick.d  $t1, $t0, 63, 56
+  movgr2cf    $fcc7, $t1
+
+PopGP:
+  //
+  // Pop GP registers
+  //
+  addi.d  $sp, $sp, -(GP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
+  ld.d    $ra, $sp, 1 * RSIZE
+  ld.d    $tp, $sp, 2 * RSIZE
+  ld.d    $a0, $sp, 4 * RSIZE
+  ld.d    $a1, $sp, 5 * RSIZE
+  ld.d    $a2, $sp, 6 * RSIZE
+  ld.d    $a3, $sp, 7 * RSIZE
+  ld.d    $a4, $sp, 8 * RSIZE
+  ld.d    $a5, $sp, 9 * RSIZE
+  ld.d    $a6, $sp, 10 * RSIZE
+  ld.d    $a7, $sp, 11 * RSIZE
+  ld.d    $t0, $sp, 12 * RSIZE
+  ld.d    $t1, $sp, 13 * RSIZE
+  ld.d    $t2, $sp, 14 * RSIZE
+  ld.d    $t3, $sp, 15 * RSIZE
+  ld.d    $t4, $sp, 16 * RSIZE
+  ld.d    $t5, $sp, 17 * RSIZE
+  ld.d    $t6, $sp, 18 * RSIZE
+  ld.d    $t7, $sp, 19 * RSIZE
+  ld.d    $t8, $sp, 20 * RSIZE
+  ld.d    $r21, $sp, 21 * RSIZE
+  ld.d    $fp, $sp, 22 * RSIZE
+  ld.d    $s0, $sp, 23 * RSIZE
+  ld.d    $s1, $sp, 24 * RSIZE
+  ld.d    $s2, $sp, 25 * RSIZE
+  ld.d    $s3, $sp, 26 * RSIZE
+  ld.d    $s4, $sp, 27 * RSIZE
+  ld.d    $s5, $sp, 28 * RSIZE
+  ld.d    $s6, $sp, 29 * RSIZE
+  ld.d    $s7, $sp, 30 * RSIZE
+  ld.d    $s8, $sp, 31 * RSIZE
+  ld.d    $sp, $sp, 3 * RSIZE
+
+  ertn // Returen from exception.
+//
+// End of ExceptionEntry
+//
+
+ASM_PFX(ExceptionEntryStart):
+  //
+  // Store the old stack pointer in preparation for pushing the exception context onto the new stack.
+  //
+  csrwr   $sp, LOONGARCH_CSR_KS0
+
+  csrrd   $sp, LOONGARCH_CSR_KS0
+
+  //
+  // Push GP registers
+  //
+  addi.d  $sp, $sp, -(GP_REG_CONTEXT_SIZE + FP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
+  st.d    $zero, $sp, 0 * RSIZE
+  st.d    $ra, $sp, 1 * RSIZE
+  st.d    $tp, $sp, 2 * RSIZE
+  st.d    $a0, $sp, 4 * RSIZE
+  st.d    $a1, $sp, 5 * RSIZE
+  st.d    $a2, $sp, 6 * RSIZE
+  st.d    $a3, $sp, 7 * RSIZE
+  st.d    $a4, $sp, 8 * RSIZE
+  st.d    $a5, $sp, 9 * RSIZE
+  st.d    $a6, $sp, 10 * RSIZE
+  st.d    $a7, $sp, 11 * RSIZE
+  st.d    $t0, $sp, 12 * RSIZE
+  st.d    $t1, $sp, 13 * RSIZE
+  st.d    $t2, $sp, 14 * RSIZE
+  st.d    $t3, $sp, 15 * RSIZE
+  st.d    $t4, $sp, 16 * RSIZE
+  st.d    $t5, $sp, 17 * RSIZE
+  st.d    $t6, $sp, 18 * RSIZE
+  st.d    $t7, $sp, 19 * RSIZE
+  st.d    $t8, $sp, 20 * RSIZE
+  st.d    $r21, $sp, 21 * RSIZE
+  st.d    $fp, $sp, 22 * RSIZE
+  st.d    $s0, $sp, 23 * RSIZE
+  st.d    $s1, $sp, 24 * RSIZE
+  st.d    $s2, $sp, 25 * RSIZE
+  st.d    $s3, $sp, 26 * RSIZE
+  st.d    $s4, $sp, 27 * RSIZE
+  st.d    $s5, $sp, 28 * RSIZE
+  st.d    $s6, $sp, 29 * RSIZE
+  st.d    $s7, $sp, 30 * RSIZE
+  st.d    $s8, $sp, 31 * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_KS0  // Read the old stack pointer.
+  st.d    $t0, $sp, 3 * RSIZE
+
+  //
+  // Push CSR registers
+  //
+  addi.d  $sp, $sp, GP_REG_CONTEXT_SIZE
+
+  csrrd   $t0, LOONGARCH_CSR_CRMD
+  st.d    $t0, $sp, LOONGARCH_CSR_CRMD * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_PRMD
+  st.d    $t0, $sp, LOONGARCH_CSR_PRMD * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_EUEN
+  st.d    $t0, $sp, LOONGARCH_CSR_EUEN * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_MISC
+  st.d    $t0, $sp, LOONGARCH_CSR_MISC * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_ECFG
+  st.d    $t0, $sp, LOONGARCH_CSR_ECFG * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_ESTAT
+  st.d    $t0, $sp, LOONGARCH_CSR_ESTAT * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_ERA
+  st.d    $t0, $sp, LOONGARCH_CSR_ERA * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_BADV
+  st.d    $t0, $sp, LOONGARCH_CSR_BADV * RSIZE
+  csrrd   $t0, LOONGARCH_CSR_BADI
+  st.d    $t0, $sp, LOONGARCH_CSR_BADI * RSIZE
+
+  //
+  // Push FP registers
+  //
+  addi.d  $sp, $sp, CSR_REG_CONTEXT_SIZE
+
+  csrrd   $t0, LOONGARCH_CSR_EUEN
+  andi    $t0, $t0, CSR_EUEN_FPEN
+  beqz    $t0, PushRegDone
+
+  fst.d  $fa0, $sp, 0 * RSIZE
+  fst.d  $fa1, $sp, 1 * RSIZE
+  fst.d  $fa2, $sp, 2 * RSIZE
+  fst.d  $fa3, $sp, 3 * RSIZE
+  fst.d  $fa4, $sp, 4 * RSIZE
+  fst.d  $fa5, $sp, 5 * RSIZE
+  fst.d  $fa6, $sp, 6 * RSIZE
+  fst.d  $fa7, $sp, 7 * RSIZE
+  fst.d  $ft0, $sp, 8 * RSIZE
+  fst.d  $ft1, $sp, 9 * RSIZE
+  fst.d  $ft2, $sp, 10 * RSIZE
+  fst.d  $ft3, $sp, 11 * RSIZE
+  fst.d  $ft4, $sp, 12 * RSIZE
+  fst.d  $ft5, $sp, 13 * RSIZE
+  fst.d  $ft6, $sp, 14 * RSIZE
+  fst.d  $ft7, $sp, 15 * RSIZE
+  fst.d  $ft8, $sp, 16 * RSIZE
+  fst.d  $ft9, $sp, 17 * RSIZE
+  fst.d  $ft10, $sp, 18 * RSIZE
+  fst.d  $ft11, $sp, 19 * RSIZE
+  fst.d  $ft12, $sp, 20 * RSIZE
+  fst.d  $ft13, $sp, 21 * RSIZE
+  fst.d  $ft14, $sp, 22 * RSIZE
+  fst.d  $ft15, $sp, 23 * RSIZE
+  fst.d  $fs0, $sp, 24 * RSIZE
+  fst.d  $fs1, $sp, 25 * RSIZE
+  fst.d  $fs2, $sp, 26 * RSIZE
+  fst.d  $fs3, $sp, 27 * RSIZE
+  fst.d  $fs4, $sp, 28 * RSIZE
+  fst.d  $fs5, $sp, 29 * RSIZE
+  fst.d  $fs6, $sp, 30 * RSIZE
+  fst.d  $fs7, $sp, 31 * RSIZE
+
+  movfcsr2gr  $t3, $r0
+  st.d        $t3, $sp, 32 * RSIZE  // Push the FCSR0 register.
+
+  //
+  // Push the fcc0-fcc7 registers.
+  //
+  movcf2gr    $t3, $fcc0
+  or          $t2, $t3, $zero
+  movcf2gr    $t3, $fcc1
+  bstrins.d   $t2, $t3, 0xf, 0x8
+  movcf2gr    $t3, $fcc2
+  bstrins.d   $t2, $t3, 0x17, 0x10
+  movcf2gr    $t3, $fcc3
+  bstrins.d   $t2, $t3, 0x1f, 0x18
+  movcf2gr    $t3, $fcc4
+  bstrins.d   $t2, $t3, 0x27, 0x20
+  movcf2gr    $t3, $fcc5
+  bstrins.d   $t2, $t3, 0x2f, 0x28
+  movcf2gr    $t3, $fcc6
+  bstrins.d   $t2, $t3, 0x37, 0x30
+  movcf2gr    $t3, $fcc7
+  bstrins.d   $t2, $t3, 0x3f, 0x38
+  st.d        $t2, $sp, 33 * RSIZE
+  //
+  // Push exception context down
+  //
+
+PushRegDone:
+  //
+  // Process IPI only when mailbox3 is NULL and mailbox0 is no-NULL.
+  //
+  li.d      $t0, LOONGARCH_IOCSR_MBUF0
+  iocsrrd.d $a0, $t0
+  beqz      $a0, EntryConmmonHanlder
+
+  li.d      $t0, LOONGARCH_IOCSR_MBUF3
+  iocsrrd.d $t1, $t0
+  bnez      $t1, EntryConmmonHanlder
+
+  csrrd     $t0, LOONGARCH_CSR_ESTAT
+  srli.d    $t0, $t0, 12
+  andi      $t0, $t0, 0x1
+  beqz      $t0, EntryConmmonHanlder
+
+  //
+  // Clean up current processor mailbox 0 and mailbox 3.
+  //
+  li.d      $t0, LOONGARCH_IOCSR_MBUF0
+  iocsrwr.d $zero, $t0
+  li.d      $t0, LOONGARCH_IOCSR_MBUF3
+  iocsrwr.d $zero, $t0
+
+  //
+  // Clear IPI interrupt.
+  //
+  li.d      $t0, LOONGARCH_IOCSR_IPI_STATUS
+  iocsrrd.w $t1, $t0
+  li.d      $t0, LOONGARCH_IOCSR_IPI_CLEAR
+  iocsrwr.w $t1, $t0
+
+  //
+  // Only kernel stage BSP calls IPI without parameters. Clean up the PIE and make sure
+  // global interrupts are turned off for the current processor when jumping to the kernel.
+  //
+  csrwr     $a0, LOONGARCH_CSR_ERA         // Update ERA
+  li.w      $t0, BIT2                      // IE
+  csrxchg   $zero, $t0, LOONGARCH_CSR_PRMD // Clean PIE
+
+  //
+  // Return this exception and jump to kernel using ERA.
+  //
+  ertn
+
+EntryConmmonHanlder:
+  addi.d  $sp, $sp, -(GP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
+  move    $a0, $sp
+  la.abs  $ra, ExceptionEntry
+  jirl    $zero, $ra, 0
+ASM_PFX(ExceptionEntryEnd):
+.end
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c
new file mode 100644
index 0000000000..7588d2050b
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c
@@ -0,0 +1,102 @@
+/** @file SecPeiExceptionLib.c
+
+  LoongArch exception library implemenation for PEI and SEC modules.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/CpuLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SerialPortLib.h>
+#include <Protocol/DebugSupport.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include "ExceptionCommon.h"
+
+/**
+  Registers a function to be called from the processor interrupt or exception handler.
+
+  Always return EFI_UNSUPPORTED in the SEC exception initialization module.
+
+  @param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+                           when a processor interrupt occurs. If this parameter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_UNSUPPORTED  The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterCpuInterruptHandler (
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Common exception handler.
+
+  @param ExceptionType  Exception type.
+  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+  IN     EFI_EXCEPTION_TYPE  ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  EFI_EXCEPTION_TYPE  InterruptType;
+
+  if (ExceptionType == EXCEPT_LOONGARCH_INT) {
+    //
+    // Interrupt
+    //
+    InterruptType = GetInterruptType (SystemContext);
+    if (InterruptType == EXCEPT_LOONGARCH_INT_IPI) {
+      //
+      // APs may wake up via IPI IRQ during the SEC or PEI phase, clear the IPI interrupt and
+      // perform the remaining work.
+      //
+      IpiInterruptHandler (InterruptType, SystemContext);
+      return;
+    } else {
+      ExceptionType = InterruptType;
+    }
+  } else {
+    //
+    // Exception
+    //
+    ExceptionType >>= CSR_ESTAT_EXC_SHIFT;
+  }
+
+  DefaultExceptionHandler (ExceptionType, SystemContext);
+}
+
+/**
+  Initializes all CPU exceptions entries and provides the default exception handlers.
+
+  Always return EFI_SUCCESS in the SEC exception initialization module.
+
+  @param[in]  VectorInfo    Pointer to reserved vector list.
+
+  @retval EFI_SUCCESS       CPU Exception Entries have been successfully initialized
+                            with default exception handlers.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+  IN EFI_VECTOR_HANDOFF_INFO  *VectorInfo OPTIONAL
+  )
+{
+  return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index f8e597d86d..64de252dcd 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -2,6 +2,7 @@
 #  CPU Exception Handler library instance for SEC/PEI modules.
 #
 #  Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -19,6 +20,7 @@ [Defines]
 # The following information is for reference only and not required by the build tools.
 #
 #  VALID_ARCHITECTURES           = IA32 X64
+#  VALID_ARCHITECTURES           = IA32 X64 LOONGARCH64
 #
 
 [Sources.Ia32]
@@ -32,24 +34,37 @@ [Sources.X64]
   X64/ArchInterruptDefs.h
   X64/SecPeiExceptionHandlerAsm.nasm
 
-[Sources.common]
+[Sources.Ia32, Sources.X64]
   CpuExceptionCommon.h
   CpuExceptionCommon.c
   SecPeiCpuException.c
 
+[Sources.LoongArch64]
+  LoongArch/ExceptionCommon.h
+  LoongArch/ExceptionCommon.c
+  LoongArch/SecPeiExceptionLib.c
+  LoongArch/LoongArch64/ArchExceptionHandler.c
+  LoongArch/LoongArch64/ExceptionHandlerAsm.S | GCC
+
+
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
-[LibraryClasses]
+[LibraryClasses.common]
   BaseLib
-  CcExitLib
-  LocalApicLib
   PeCoffGetEntryPointLib
   PrintLib
   SerialPortLib
 
+[LibraryClasses.Ia32, LibraryClasses.X64]
+  CcExitLib
+  LocalApicLib
+
+[LibraryClasses.LoongArch64]
+  CpuLib
+
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
   gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117653): https://edk2.groups.io/g/devel/message/117653
Mute This Topic: https://groups.io/mt/105478495/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 07/13] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (5 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 06/13] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-15  2:10   ` Ni, Ray
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 08/13] UefiCpuPkg: Added a new PCD named PcdLoongArchExceptionVectorBaseAddress Chao Li
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel
  Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann, Leif Lindholm, Ard Biesheuvel,
	Sami Mujawar, Sunil V L, Andrei Warkentin

Add a new header file CpuMmuLib.h, whitch is referenced from
ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
LoongArch64 is added, and more architectures can be accommodated in the
future.

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>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Andrei Warkentin <andrei.warkentin@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Include/Library/CpuMmuLib.h | 41 ++++++++++++++++++++++++++
 UefiCpuPkg/UefiCpuPkg.dec              |  4 +++
 2 files changed, 45 insertions(+)
 create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h

diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h b/UefiCpuPkg/Include/Library/CpuMmuLib.h
new file mode 100644
index 0000000000..e6cfbd5168
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
@@ -0,0 +1,41 @@
+/** @file
+
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_MMU_LIB_H_
+#define CPU_MMU_LIB_H_
+
+#include <Uefi/UefiBaseType.h>
+
+/**
+  Maps the memory region in the page table to the specified attributes.
+
+  @param[in, out] PageTable      The pointer to the page table to update, or pointer to NULL
+                                 if a new page table is to be created.
+  @param[in]      PageWalkCfg    The page walk controller configure.
+  @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 bitmask of attributes to set, which refer to UEFI SPEC
+                                 7.2.3(EFI_BOOT_SERVICES.GetMemoryMap()).
+  @param[in]      AttributeMask  Mask of memory attributes to take into account.
+
+  @retval EFI_SUCCESS            The Attributes was set successfully or Length is 0.
+  @retval EFI_INVALID_PARAMETER  PageTable is NULL.
+  @retval EFI_UNSUPPORTED        *PageTable is NULL.
+**/
+EFI_STATUS
+EFIAPI
+MemoryRegionMap (
+  IN OUT UINTN                 *PageTable  OPTIONAL,
+  IN     UINT64                PageWalkCfg,
+  IN     EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN     UINT64                Length,
+  IN     UINT64                Attributes,
+  IN     UINT64                AttributeMask
+  );
+
+#endif // CPU_MMU_LIB_H_
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 571b59b36f..ca744fab55 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -72,6 +72,10 @@ [LibraryClasses.RISCV64]
   ##
   RiscVMmuLib|Include/Library/BaseRiscVMmuLib.h
 
+[LibraryClasses.LoongArch64]
+  ##  @libraryclass  Provides functions for the memory management unit.
+  CpuMmuLib|Include/Library/CpuMmuLib.h
+
 [Guids]
   gUefiCpuPkgTokenSpaceGuid      = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }}
   gMsegSmramGuid                 = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }}
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117654): https://edk2.groups.io/g/devel/message/117654
Mute This Topic: https://groups.io/mt/105478496/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 08/13] UefiCpuPkg: Added a new PCD named PcdLoongArchExceptionVectorBaseAddress
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (6 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 07/13] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-15  2:10   ` Ni, Ray
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg Chao Li
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

Added PcdLoongArchExceptionVectorBaseAddress use for storing the CPU
exception vector base address. This PCD can be populated at build time
or changed at runtime, and is used only by LoongArch.

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/UefiCpuPkg.dec | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index ca744fab55..1b890e975c 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -3,6 +3,7 @@
 #
 # Copyright (c) 2007 - 2023, Intel Corporation. All rights reserved.<BR>
 # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -414,6 +415,11 @@ [PcdsFixedAtBuild.RISCV64]
   #  10 - 57bit mode.
   gUefiCpuPkgTokenSpaceGuid.PcdCpuRiscVMmuMaxSatpMode|10|UINT32|0x60000021
 
+[PcdsFixedAtBuild.LOONGARCH64, PcdsPatchableInModule.LOONGARCH64, PcdsDynamic.LOONGARCH64, PcdsDynamicEx.LOONGARCH64]
+  ## This PCD Contains the pointer to a CPU exception vector base address.
+  # @Prompt The pointer to a CPU exception vector base address.
+  gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress|0x0|UINT64|0x60000022
+
 [PcdsDynamic, PcdsDynamicEx]
   ## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA.
   # @Prompt The pointer to a CPU S3 data buffer.
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117655): https://edk2.groups.io/g/devel/message/117655
Mute This Topic: https://groups.io/mt/105478499/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (7 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 08/13] UefiCpuPkg: Added a new PCD named PcdLoongArchExceptionVectorBaseAddress Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-15  2:11   ` Ni, Ray
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 10/13] UefiCpuPkg: Add a new GUID to store the processors resource Chao Li
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel
  Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann, Baoqi Zhang, Dongyan Qian,
	Xianglai Li, Bibo Mao

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf    |  39 +
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni    |  14 +
 .../Library/CpuMmuLib/LoongArch64/CpuMmu.c    | 785 ++++++++++++++++++
 .../Library/CpuMmuLib/LoongArch64/Page.h      |  33 +
 .../LoongArch64/TlbExceptionHandle.S          |  51 ++
 .../LoongArch64/TlbExceptionHandle.h          |  36 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.S        |  24 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.h        |  24 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |   3 +
 9 files changed, 1009 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/TlbExceptionHandle.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.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..5eecfb4838
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
@@ -0,0 +1,39 @@
+## @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/TlbExceptionHandle.S | GCC
+  LoongArch64/CpuMmu.c
+  LoongArch64/Page.h
+  LoongArch64/TlbInvalid.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  MemoryAllocationLib
+
+[Pcd.LoongArch64]
+  gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress      ## CONSUMES
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..6d77a1221f
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c
@@ -0,0 +1,785 @@
+/** @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/CacheMaintenanceLib.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/DebugSupport.h>
+#include <Register/LoongArch64/Csr.h>
+#include "TlbInvalid.h"
+#include "TlbExceptionHandle.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;
+}
+
+/**
+  Parse max page table level.
+
+  @param[in]  PageWalkCfg  Page table configure value.
+
+  @return         5   MAX page level is 5
+                  4   MAX page level is 4
+                  3   MAX page level is 3
+                  0   Invalid
+**/
+STATIC
+UINTN
+ParseMaxPageTableLevel (
+  IN  UINT64  PageWalkCfg
+  )
+{
+  UINT32  Pwctl0;
+  UINT32  Pwctl1;
+
+  Pwctl0 = PageWalkCfg & MAX_UINT32;
+  Pwctl1 = (PageWalkCfg >> 32) & MAX_UINT32;
+
+  if (((Pwctl1 >> 18) & 0x3F) != 0x0) {
+    return LEVEL5;
+  } else if (((Pwctl1 >> 6) & 0x3F) != 0x0) {
+    return LEVEL4;
+  } else if (((Pwctl0 >> 25) & 0x3F) != 0x0) {
+    return LEVEL3;
+  }
+
+  return 0;
+}
+
+/**
+  Parse page table bit width.
+
+  Assume that the bit width of the page table that each level is the same to PTwidth.
+
+  @param[in]  PageWalkCfg  Page table configure value.
+
+  @return         page table bit width
+
+**/
+STATIC
+UINTN
+ParsePageTableBitWidth (
+  IN  UINT64  PageWalkCfg
+  )
+{
+  //
+  // PTwidth
+  //
+  return ((PageWalkCfg >> 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.
+  @param    PageWalkCfg  Page table configure value.
+
+  @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,
+  IN  UINT64  PageWalkCfg
+  )
+{
+  if (Level == (ParseMaxPageTableLevel (PageWalkCfg) - 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.
+  @param    PageWalkCfg  Page table configure value.
+
+  @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,
+  IN  UINT64  PageWalkCfg
+  )
+{
+  if (Level == (ParseMaxPageTableLevel (PageWalkCfg) - 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  PageWalkCfg       Page table configure value.
+  @param  Level             The current level.
+
+**/
+STATIC
+VOID
+FreePageTablesRecursive (
+  IN  UINTN   *TranslationTable,
+  IN  UINT64  PageWalkCfg,
+  IN  UINTN   Level
+  )
+{
+  UINTN  Index;
+  UINTN  TableEntryNum;
+
+  TableEntryNum = (1 << ParsePageTableBitWidth (PageWalkCfg));
+
+  if (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 1)) {
+    for (Index = 0; Index < TableEntryNum; Index++) {
+      if (IsTableEntry (TranslationTable[Index], Level, PageWalkCfg)) {
+        FreePageTablesRecursive (
+          (UINTN *)(GetPpnfromPte ((TranslationTable[Index])) <<
+                    LOONGARCH_MMU_PAGE_SHIFT),
+          PageWalkCfg,
+          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  PageWalkCfg           Page table configure value.
+  @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  UINT64   PageWalkCfg,
+  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 < ParseMaxPageTableLevel (PageWalkCfg));
+  ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) == 0);
+
+  TableBitWidth = ParsePageTableBitWidth (PageWalkCfg);
+  BlockShift    = (ParseMaxPageTableLevel (PageWalkCfg) - 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, PageWalkCfg))
+    {
+      ASSERT (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 1));
+      if (!IsTableEntry (*Entry, Level, PageWalkCfg)) {
+        //
+        // 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, PageWalkCfg)) {
+          //
+          // 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,
+                     PageWalkCfg,
+                     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,
+                 PageWalkCfg,
+                 NextTableIsLive
+                 );
+      if (EFI_ERROR (Status)) {
+        if (!IsTableEntry (*Entry, Level, PageWalkCfg)) {
+          //
+          // 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, PageWalkCfg, Level + 1);
+        }
+
+        return Status;
+      }
+
+      if (!IsTableEntry (*Entry, Level, PageWalkCfg)) {
+        EntryValue = SetPpnToPte (0, (UINTN)TranslationTable);
+        ReplaceTableEntry (
+          Entry,
+          EntryValue,
+          RegionStart,
+          TableIsLive
+          );
+      }
+    } else {
+      EntryValue = (*Entry & ~AttributeClearMask) | AttributeSetMask;
+
+      EntryValue = SetPpnToPte (EntryValue, RegionStart);
+      EntryValue = SetValidPte (EntryValue);
+
+      if (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 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  PageWalkCfg           Page table configure value.
+  @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  UINT64   PageWalkCfg,
+  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,
+           PageWalkCfg,
+           TableIsLive
+           );
+}
+
+/**
+  Convert EFI Attributes to Loongarch Attributes.
+
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  Corresponding architecture attributes.
+**/
+UINT64
+EFIAPI
+EfiAttributeConverse (
+  IN UINT64  EfiAttributes
+  )
+{
+  UINT64  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:
+      LoongArchAttributes |= CACHE_CC;
+      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;
+}
+
+/**
+  TLB refill handler configure.
+
+  @param  VOID.
+
+  @retval  EFI_SUCCESS      TLB refill handler configure successfully.
+           EFI_UNSUPPORTED  Size not aligned.
+**/
+EFI_STATUS
+TlbRefillHandlerConfigure (
+  VOID
+  )
+{
+  UINTN  Length;
+  UINTN  TlbReEntry;
+  UINTN  TlbReEntryOffset;
+  UINTN  Remaining;
+
+  //
+  // 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 (PcdLoongArchExceptionVectorBaseAddress) + TlbReEntryOffset;
+  if ((TlbReEntryOffset + Length) > SIZE_64KB) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Ensure that TLB refill exception base address alignment is equals to 4KB and is valid.
+  //
+  if (TlbReEntry & (SIZE_4KB - 1)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
+  InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length);
+
+  //
+  // Set the address of TLB refill exception handler
+  //
+  SetTlbRebaseAddress ((UINTN)TlbReEntry);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Maps the memory region in the page table to the specified attributes.
+
+  @param[in, out] PageTable      The pointer to the page table to update, or pointer to NULL
+                                 if a new page table is to be created.
+  @param[in]      PageWalkCfg    The page walk controller configure.
+  @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 bitmask of attributes to set, which refer to UEFI SPEC
+                                 7.2.3(EFI_BOOT_SERVICES.GetMemoryMap()).
+  @param[in]      AttributeMask  Mask of memory attributes to take into account.
+
+  @retval EFI_SUCCESS            The Attributes was set successfully or Length is 0.
+  @retval EFI_INVALID_PARAMETER  PageTable is NULL, PageWalkCfg is invalid.
+  @retval EFI_UNSUPPORTED        *PageTable is NULL.
+**/
+EFI_STATUS
+EFIAPI
+MemoryRegionMap (
+  IN OUT UINTN                 *PageTable  OPTIONAL,
+  IN     UINT64                PageWalkCfg,
+  IN     EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN     UINT64                Length,
+  IN     UINT64                Attributes,
+  IN     UINT64                AttributeMask
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      LoongArchAttributes;
+  BOOLEAN     Initialization;
+  BOOLEAN     CreateNew;
+  UINTN       PageTableBitWidth;
+  UINTN       MaxLevel;
+  UINTN       PgdSize;
+
+  if ((PageTable == NULL) || (PageWalkCfg == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PageTableBitWidth = ParsePageTableBitWidth (PageWalkCfg);
+  MaxLevel          = ParseMaxPageTableLevel (PageWalkCfg);
+
+  if ((!PageTableBitWidth && !MaxLevel) || (PageTableBitWidth > 0x1F) || (MaxLevel > LEVEL5)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Initialization = FALSE;
+  CreateNew      = FALSE;
+
+  //
+  // *PageTable is NULL, create a new and return.
+  //
+  if (*PageTable == 0) {
+    CreateNew = TRUE;
+    //
+    // If the MMU has not been configured yet, configure it later.
+    //
+    if (!MmuIsInit ()) {
+      Initialization = TRUE;
+    }
+  }
+
+  if (Length == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (Initialization == TRUE) {
+    Status = TlbRefillHandlerConfigure ();
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  if (CreateNew == TRUE) {
+    //
+    // Create a new page table.
+    //
+    PgdSize    =  (1 << PageTableBitWidth) * sizeof (UINTN);
+    *PageTable = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PgdSize));
+    ZeroMem ((VOID *)*PageTable, PgdSize);
+
+    if ((VOID *)*PageTable == NULL) {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  LoongArchAttributes = EfiAttributeConverse (Attributes);
+
+  //
+  // Update the page table attributes.
+  //
+  // If the MMU has been configured and *PageTable == CSR_PGDL, the page table in use will update.
+  //
+  // If *PageTable != CSR_PGDL, only the page table structure in memory is update, but some TLB
+  // region may be invalidated during the mapping process. So at this time the caller must ensure
+  // that the execution environment must be safe. It is recommended to use the DA mode!
+  //
+  Status = UpdateRegionMapping (
+             BaseAddress,
+             Length,
+             PageWalkCfg,
+             LoongArchAttributes,
+             PTE_ATTRIBUTES_MASK,
+             (UINTN *)(*PageTable),
+             (MmuIsEnabled () && !CreateNew)
+             );
+
+  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..b115245d68
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h
@@ -0,0 +1,33 @@
+/** @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 LEVEL2  2
+#define LEVEL1  1
+
+#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
+
+//
+// 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
+
+#endif // PAGE_H_
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S
new file mode 100644
index 0000000000..4395b574f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/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/CpuMmuLib/LoongArch64/TlbExceptionHandle.h b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h
new file mode 100644
index 0000000000..c164db567d
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/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/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 (#117656): https://edk2.groups.io/g/devel/message/117656
Mute This Topic: https://groups.io/mt/105478500/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 10/13] UefiCpuPkg: Add a new GUID to store the processors resource
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (8 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-15  2:10   ` Ni, Ray
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 11/13] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

On a multi-processor system, if the BSP dose not know how many APs are
online or cannot wake up the AP via broadcast, it can collect AP
resouces before wakeing up the AP and add a new HOB to save the
processor resouces.

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>
---
 .../Include/Guid/ProcessorResourceHob.h       | 29 +++++++++++++++++++
 UefiCpuPkg/UefiCpuPkg.dec                     |  3 ++
 2 files changed, 32 insertions(+)
 create mode 100644 UefiCpuPkg/Include/Guid/ProcessorResourceHob.h

diff --git a/UefiCpuPkg/Include/Guid/ProcessorResourceHob.h b/UefiCpuPkg/Include/Guid/ProcessorResourceHob.h
new file mode 100644
index 0000000000..da7f381d3b
--- /dev/null
+++ b/UefiCpuPkg/Include/Guid/ProcessorResourceHob.h
@@ -0,0 +1,29 @@
+/** @file
+  Processor resource HOB
+
+  If BSP does not known how many cores are online or the platform cannot
+  wake up AP via broadcast, this HOB can be used to store the processor
+  resource data that may come from ACPI or FDT, etc.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PROCESSOR_RESOURCE_HOB_H_
+#define PROCESSOR_RESOURCE_HOB_H_
+
+#define PROCESSOR_RESOURCE_HOB_GUID \
+  { \
+    0xb855c7fe, 0xa758, 0x701f, { 0xa7, 0x30, 0x87, 0xf3, 0x9c, 0x03, 0x46, 0x7e } \
+  }
+
+typedef struct {
+  UINT32    NumberOfProcessor;
+  UINTN     *ApicId;
+} PROCESSOR_RESOURCE_DATA;
+
+extern EFI_GUID  gProcessorResourceHobGuid;
+
+#endif
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 1b890e975c..8ca3b7a5a6 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -96,6 +96,9 @@ [Guids]
   ## Include/Guid/MpInformation2.h
   gMpInformation2HobGuid         = { 0x417a7f64, 0xf4e9, 0x4b32, {0x84, 0x6a, 0x5c, 0xc4, 0xd8, 0x62, 0x18, 0x79 }}
 
+  ## Include/Guid/ProcessorResourceHob.h
+  gProcessorResourceHobGuid      = { 0xb855c7fe, 0xa758, 0x701f, { 0xa7, 0x30, 0x87, 0xf3, 0x9c, 0x03, 0x46, 0x7e }}
+
 [Protocols]
   ## Include/Protocol/SmmCpuService.h
   gEfiSmmCpuServiceProtocolGuid   = { 0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 }}
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117657): https://edk2.groups.io/g/devel/message/117657
Mute This Topic: https://groups.io/mt/105478501/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 11/13] UefiCpuPkg: Add multiprocessor library for LoongArch64
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (9 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 10/13] UefiCpuPkg: Add a new GUID to store the processors resource Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 12/13] UefiCpuPkg: Add CpuDxe driver " Chao Li
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

Added LoongArch multiprocessor initialization instance into MpInitLib.

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   23 +-
 .../Library/MpInitLib/LoongArch64/DxeMpLib.c  |  480 +++++
 .../Library/MpInitLib/LoongArch64/MpLib.c     | 1626 +++++++++++++++++
 .../Library/MpInitLib/LoongArch64/MpLib.h     |  350 ++++
 .../Library/MpInitLib/LoongArch64/PeiMpLib.c  |  381 ++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   23 +-
 6 files changed, 2871 insertions(+), 12 deletions(-)
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index 7ef4c0d4db..407f4988b5 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -2,6 +2,7 @@
 #  MP Initialize Library instance for DXE driver.
 #
 #  Copyright (c) 2016 - 2023, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -18,7 +19,7 @@ [Defines]
 #
 # The following information is for reference only and not required by the build tools.
 #
-#  VALID_ARCHITECTURES           = IA32 X64
+#  VALID_ARCHITECTURES           = IA32 X64 LOONGARCH64
 #
 
 [Sources.IA32]
@@ -31,7 +32,7 @@ [Sources.X64]
   X64/CreatePageTable.c
   X64/MpFuncs.nasm
 
-[Sources.common]
+[Sources.IA32, Sources.X64]
   AmdSev.c
   DxeMpLib.c
   Microcode.c
@@ -40,6 +41,11 @@ [Sources.common]
   MpLib.h
   MpHandOff.h
 
+[Sources.LoongArch64]
+  LoongArch64/DxeMpLib.c
+  LoongArch64/MpLib.c
+  LoongArch64/MpLib.h
+
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
@@ -47,18 +53,20 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
-  CcExitLib
   CpuLib
   DebugAgentLib
   HobLib
-  LocalApicLib
   MemoryAllocationLib
-  MicrocodeLib
-  MtrrLib
   PcdLib
   SynchronizationLib
   UefiBootServicesTableLib
 
+[LibraryClasses.IA32, LibraryClasses.X64]
+  CcExitLib
+  LocalApicLib
+  MicrocodeLib
+  MtrrLib
+
 [LibraryClasses.X64]
   CpuPageTableLib
 
@@ -70,6 +78,9 @@ [Guids]
   gEfiEventLegacyBootGuid                       ## SOMETIMES_CONSUMES  ## Event
   gEdkiiMicrocodePatchHobGuid                   ## SOMETIMES_CONSUMES  ## HOB
 
+[Guids.LoongArch64]
+  gProcessorResourceHobGuid                     ## SOMETIMES_CONSUMES  ## HOB
+
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c
new file mode 100644
index 0000000000..739da77e32
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c
@@ -0,0 +1,480 @@
+/** @file
+  LoongArch64 MP initialize support functions for DXE phase.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+#include <Library/DebugAgentLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/Timer.h>
+
+CPU_MP_DATA       *mCpuMpData            = NULL;
+EFI_EVENT         mCheckAllApsEvent      = NULL;
+volatile BOOLEAN  mStopCheckAllApsStatus = TRUE;
+
+/**
+  Enable Debug Agent to support source debugging on AP function.
+
+**/
+VOID
+EnableDebugAgent (
+  VOID
+  )
+{
+  //
+  // Initialize Debug Agent to support source level debug in DXE phase
+  //
+  InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);
+}
+
+/**
+  Get the pointer to CPU MP Data structure.
+
+  @return  The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+  VOID
+  )
+{
+  ASSERT (mCpuMpData != NULL);
+  return mCpuMpData;
+}
+
+/**
+  Save the pointer to CPU MP Data structure.
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+  IN CPU_MP_DATA  *CpuMpData
+  )
+{
+  mCpuMpData = CpuMpData;
+}
+
+/**
+  Get available EfiBootServicesCode memory below 4GB by specified size.
+
+  This buffer is required to safely transfer AP from real address mode to
+  protected mode or long mode, due to the fact that the buffer returned by
+  GetWakeupBuffer() may be marked as non-executable.
+
+  @param[in] BufferSize   Wakeup transition buffer size.
+
+  @retval other   Return wakeup transition buffer address below 4GB.
+  @retval 0       Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+  IN UINTN  BufferSize
+  )
+{
+  return 0;
+}
+
+/**
+  Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+  VOID
+  )
+{
+  UINTN        ProcessorNumber;
+  EFI_STATUS   Status;
+  CPU_MP_DATA  *CpuMpData;
+
+  CpuMpData = GetCpuMpData ();
+
+  //
+  // First, check whether pending StartupAllAPs() exists.
+  //
+  if (CpuMpData->WaitEvent != NULL) {
+    Status = CheckAllAPs ();
+    //
+    // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
+    //
+    if (Status != EFI_NOT_READY) {
+      Status               = gBS->SignalEvent (CpuMpData->WaitEvent);
+      CpuMpData->WaitEvent = NULL;
+    }
+  }
+
+  //
+  // Second, check whether pending StartupThisAPs() callings exist.
+  //
+  for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+    if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {
+      continue;
+    }
+
+    Status = CheckThisAP (ProcessorNumber);
+
+    if (Status != EFI_NOT_READY) {
+      gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);
+      CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;
+    }
+  }
+}
+
+/**
+  Checks APs' status periodically.
+
+  This function is triggered by timer periodically to check the
+  state of APs for StartupAllAPs() and StartupThisAP() executed
+  in non-blocking mode.
+
+  @param[in]  Event    Event triggered.
+  @param[in]  Context  Parameter passed with the event.
+
+**/
+VOID
+EFIAPI
+CheckApsStatus (
+  IN  EFI_EVENT  Event,
+  IN  VOID       *Context
+  )
+{
+  //
+  // If CheckApsStatus() is not stopped, otherwise return immediately.
+  //
+  if (!mStopCheckAllApsStatus) {
+    CheckAndUpdateApsStatus ();
+  }
+}
+
+/**
+  Initialize global data for MP support.
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+  IN CPU_MP_DATA  *CpuMpData
+  )
+{
+  EFI_STATUS  Status;
+
+  SaveCpuMpData (CpuMpData);
+
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  CheckApsStatus,
+                  NULL,
+                  &mCheckAllApsEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Set timer to check all APs status.
+  //
+  Status = gBS->SetTimer (
+                  mCheckAllApsEvent,
+                  TimerPeriodic,
+                  EFI_TIMER_PERIOD_MICROSECONDS (
+                    PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds)
+                    )
+                  );
+  ASSERT_EFI_ERROR (Status);
+}
+
+/**
+  This service executes a caller provided function on all enabled APs.
+
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  SingleThread            If TRUE, then all the enabled APs execute
+                                      the function specified by Procedure one by
+                                      one, in ascending order of processor handle
+                                      number.  If FALSE, then all the enabled APs
+                                      execute the function specified by Procedure
+                                      simultaneously.
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until all APs finish
+                                      or TimeoutInMicroSeconds expires.  If it's
+                                      not NULL, then execute in non-blocking mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on all the enabled
+                                      APs, and go on executing immediately. If
+                                      all return from Procedure, or TimeoutInMicroSeconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or WaitForEvent()
+                                      services to check the state of event.  Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      all APs return from Procedure, then Procedure
+                                      on the failed APs is terminated. All enabled
+                                      APs are available for next function assigned
+                                      by MpInitLibStartupAllAPs() or
+                                      MPInitLibStartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] FailedCpuList           If NULL, this parameter is ignored. Otherwise,
+                                      if all APs finish successfully, then its
+                                      content is set to NULL. If not all APs
+                                      finish before timeout expires, then its
+                                      content is set to address of the buffer
+                                      holding handle numbers of the failed APs.
+                                      The buffer is allocated by MP Initialization
+                                      library, and it's the caller's responsibility to
+                                      free the buffer with FreePool() service.
+                                      In blocking mode, it is ready for consumption
+                                      when the call returns. In non-blocking mode,
+                                      it is ready when WaitEvent is signaled.  The
+                                      list of failed CPU is terminated by
+                                      END_OF_CPU_LIST.
+
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished before
+                                  the timeout expired.
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
+                                  to all enabled APs.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_UNSUPPORTED         WaitEvent is not NULL if non-blocking mode is not
+                                  supported.
+  @retval EFI_DEVICE_ERROR        Caller processor is AP.
+  @retval EFI_NOT_STARTED         No enabled APs exist in the system.
+  @retval EFI_NOT_READY           Any enabled APs are busy.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  all enabled APs have finished.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllAPs (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  BOOLEAN           SingleThread,
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL,
+  OUT UINTN             **FailedCpuList         OPTIONAL
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
+  //
+  mStopCheckAllApsStatus = TRUE;
+
+  Status = StartupAllCPUsWorker (
+             Procedure,
+             SingleThread,
+             TRUE,
+             WaitEvent,
+             TimeoutInMicroseconds,
+             ProcedureArgument,
+             FailedCpuList
+             );
+
+  //
+  // Start checkAllApsStatus
+  //
+  mStopCheckAllApsStatus = FALSE;
+
+  return Status;
+}
+
+/**
+  This service lets the caller get one enabled AP to execute a caller-provided
+  function.
+
+  @param[in]  Procedure               A pointer to the function to be run on the
+                                      designated AP of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber         The handle number of the AP. The range is
+                                      from 0 to the total number of logical
+                                      processors minus 1. The total number of
+                                      logical processors can be retrieved by
+                                      MpInitLibGetNumberOfProcessors().
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until this AP finish
+                                      or TimeoutInMicroSeconds expires.  If it's
+                                      not NULL, then execute in non-blocking mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on this AP,
+                                      and go on executing immediately. If this AP
+                                      return from Procedure or TimeoutInMicroSeconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or WaitForEvent()
+                                      services to check the state of event.  Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      this AP to finish this Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      this AP returns from Procedure, then Procedure
+                                      on the AP is terminated. The
+                                      AP is available for next function assigned
+                                      by MpInitLibStartupAllAPs() or
+                                      MpInitLibStartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure on the
+                                      specified AP.
+  @param[out] Finished                If NULL, this parameter is ignored.  In
+                                      blocking mode, this parameter is ignored.
+                                      In non-blocking mode, if AP returns from
+                                      Procedure before the timeout expires, its
+                                      content is set to TRUE. Otherwise, the
+                                      value is set to FALSE. The caller can
+                                      determine if the AP returned from Procedure
+                                      by evaluating this value.
+
+  @retval EFI_SUCCESS             In blocking mode, specified AP finished before
+                                  the timeout expires.
+  @retval EFI_SUCCESS             In non-blocking mode, the function has been
+                                  dispatched to specified AP.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_UNSUPPORTED         WaitEvent is not NULL if non-blocking mode is not
+                                  supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  the specified AP has finished.
+  @retval EFI_NOT_READY           The specified AP is busy.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupThisAP (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  UINTN             ProcessorNumber,
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL,
+  OUT BOOLEAN           *Finished               OPTIONAL
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // temporarily stop checkAllApsStatus for avoid resource dead-lock.
+  //
+  mStopCheckAllApsStatus = TRUE;
+
+  Status = StartupThisAPWorker (
+             Procedure,
+             ProcessorNumber,
+             WaitEvent,
+             TimeoutInMicroseconds,
+             ProcedureArgument,
+             Finished
+             );
+
+  mStopCheckAllApsStatus = FALSE;
+
+  return Status;
+}
+
+/**
+  This service switches the requested AP to be the BSP from that point onward.
+  This service changes the BSP for all purposes. This call can only be performed
+  by the current BSP.
+
+  @param[in] ProcessorNumber   The handle number of AP that is to become the new
+                               BSP. The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               MpInitLibGetNumberOfProcessors().
+  @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
+                               enabled AP. Otherwise, it will be disabled.
+
+  @retval EFI_SUCCESS             BSP successfully switched.
+  @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to
+                                  this service returning.
+  @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or
+                                  a disabled AP.
+  @retval EFI_NOT_READY           The specified AP is busy.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+  IN UINTN    ProcessorNumber,
+  IN BOOLEAN  EnableOldBSP
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This service lets the caller enable or disable an AP from this point onward.
+  This service may only be called from the BSP.
+
+  @param[in] ProcessorNumber   The handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               MpInitLibGetNumberOfProcessors().
+  @param[in] EnableAP          Specifies the new state for the processor for
+                               enabled, FALSE for disabled.
+  @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
+                               the new health status of the AP. This flag
+                               corresponds to StatusFlag defined in
+                               EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+                               the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+                               bits are ignored.  If it is NULL, this parameter
+                               is ignored.
+
+  @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed
+                                  prior to this service returning.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
+                                  does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+  IN  UINTN    ProcessorNumber,
+  IN  BOOLEAN  EnableAP,
+  IN  UINT32   *HealthFlag OPTIONAL
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c b/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c
new file mode 100644
index 0000000000..c18671e95f
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c
@@ -0,0 +1,1626 @@
+/** @file
+  LoongArch64 CPU MP Initialize Library common functions.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#define INVALID_APIC_ID  0xFFFFFFFF
+
+EFI_GUID  mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
+
+/**
+  Get the Application Processors state.
+
+  @param[in]  CpuData    The pointer to CPU_AP_DATA of specified AP
+
+  @return  The AP status
+**/
+CPU_STATE
+GetApState (
+  IN  CPU_AP_DATA  *CpuData
+  )
+{
+  return CpuData->State;
+}
+
+/**
+  Set the Application Processors state.
+
+  @param[in]   CpuData    The pointer to CPU_AP_DATA of specified AP
+  @param[in]   State      The AP status
+**/
+VOID
+SetApState (
+  IN  CPU_AP_DATA  *CpuData,
+  IN  CPU_STATE    State
+  )
+{
+  AcquireSpinLock (&CpuData->ApLock);
+  CpuData->State = State;
+  ReleaseSpinLock (&CpuData->ApLock);
+}
+
+/**
+  Get APIC ID of the executing processor.
+
+  @return  32-bit APIC ID of the executing processor.
+**/
+UINT32
+GetApicId (
+  VOID
+  )
+{
+  UINTN  CpuNum;
+
+  CpuNum = CsrRead (LOONGARCH_CSR_CPUNUM);
+
+  return CpuNum & 0x3ff;
+}
+
+/**
+  Find the current Processor number by APIC ID.
+
+  @param[in]  CpuMpData         Pointer to PEI CPU MP Data
+  @param[out] ProcessorNumber   Return the pocessor number found
+
+  @retval EFI_SUCCESS          ProcessorNumber is found and returned.
+  @retval EFI_NOT_FOUND        ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+  IN CPU_MP_DATA  *CpuMpData,
+  OUT UINTN       *ProcessorNumber
+  )
+{
+  UINTN            TotalProcessorNumber;
+  UINTN            Index;
+  CPU_INFO_IN_HOB  *CpuInfoInHob;
+
+  CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+
+  TotalProcessorNumber = CpuMpData->CpuCount;
+  for (Index = 0; Index < TotalProcessorNumber; Index++) {
+    if (CpuInfoInHob[Index].ApicId == GetApicId ()) {
+      *ProcessorNumber = Index;
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Sort the APIC ID of all processors.
+
+  This function sorts the APIC ID of all processors so that processor number is
+  assigned in the ascending order of APIC ID which eases MP debugging.
+
+  @param[in] CpuMpData        Pointer to PEI CPU MP Data
+**/
+VOID
+SortApicId (
+  IN CPU_MP_DATA  *CpuMpData
+  )
+{
+  UINTN            Index1;
+  UINTN            Index2;
+  UINTN            Index3;
+  UINT32           ApicId;
+  CPU_INFO_IN_HOB  CpuInfo;
+  UINT32           ApCount;
+  CPU_INFO_IN_HOB  *CpuInfoInHob;
+  volatile UINT32  *StartupApSignal;
+
+  ApCount      = CpuMpData->CpuCount - 1;
+  CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+  if (ApCount != 0) {
+    Index2 = 0;
+    for (Index1 = (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1); Index1 > 0; Index1--) {
+      if (CpuInfoInHob[Index1].ApicId != INVALID_APIC_ID) {
+        if (Index1 == ApCount) {
+          break;
+        } else {
+          for ( ; Index2 <= ApCount; Index2++) {
+            if (CpuInfoInHob[Index2].ApicId == INVALID_APIC_ID) {
+              CopyMem (&CpuInfoInHob[Index2], &CpuInfoInHob[Index1], sizeof (CPU_INFO_IN_HOB));
+              CpuMpData->CpuData[Index2]  = CpuMpData->CpuData[Index1];
+              CpuInfoInHob[Index1].ApicId = INVALID_APIC_ID;
+              break;
+            }
+          }
+        }
+      } else {
+        continue;
+      }
+    }
+
+    for (Index1 = 0; Index1 < ApCount; Index1++) {
+      Index3 = Index1;
+      //
+      // Sort key is the hardware default APIC ID
+      //
+      ApicId = CpuInfoInHob[Index1].ApicId;
+      for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
+        if (ApicId > CpuInfoInHob[Index2].ApicId) {
+          Index3 = Index2;
+          ApicId = CpuInfoInHob[Index2].ApicId;
+        }
+      }
+
+      if (Index3 != Index1) {
+        CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof (CPU_INFO_IN_HOB));
+        CopyMem (
+          &CpuInfoInHob[Index3],
+          &CpuInfoInHob[Index1],
+          sizeof (CPU_INFO_IN_HOB)
+          );
+        CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));
+
+        //
+        // Also exchange the StartupApSignal.
+        //
+        StartupApSignal                            = CpuMpData->CpuData[Index3].StartupApSignal;
+        CpuMpData->CpuData[Index3].StartupApSignal =
+          CpuMpData->CpuData[Index1].StartupApSignal;
+        CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;
+      }
+    }
+
+    //
+    // Get the processor number for the BSP
+    //
+    ApicId = GetApicId ();
+    for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
+      if (CpuInfoInHob[Index1].ApicId == ApicId) {
+        CpuMpData->BspNumber = (UINT32)Index1;
+        break;
+      }
+    }
+  }
+}
+
+/**
+  Get pointer to Processor Resource Data structure from GUIDd HOB.
+
+  @return  The pointer to Processor Resource Data structure.
+**/
+PROCESSOR_RESOURCE_DATA *
+GetProcessorResourceDataFromGuidedHob (
+  VOID
+  )
+{
+  EFI_HOB_GUID_TYPE        *GuidHob;
+  VOID                     *DataInHob;
+  PROCESSOR_RESOURCE_DATA  *ResourceData;
+
+  ResourceData = NULL;
+  GuidHob      = GetFirstGuidHob (&gProcessorResourceHobGuid);
+  if (GuidHob != NULL) {
+    DataInHob    = GET_GUID_HOB_DATA (GuidHob);
+    ResourceData = (PROCESSOR_RESOURCE_DATA *)(*(UINTN *)DataInHob);
+  }
+
+  return ResourceData;
+}
+
+/**
+  This function will get CPU count in the system.
+
+  @param[in] CpuMpData        Pointer to PEI CPU MP Data
+
+  @return  CPU count detected
+**/
+UINTN
+CollectProcessorCount (
+  IN CPU_MP_DATA  *CpuMpData
+  )
+{
+  PROCESSOR_RESOURCE_DATA  *ProcessorResourceData;
+  CPU_INFO_IN_HOB          *CpuInfoInHob;
+  UINTN                    Index;
+
+  ProcessorResourceData = NULL;
+
+  //
+  // Set the default loop mode for APs.
+  //
+  CpuMpData->ApLoopMode = ApInRunLoop;
+
+  //
+  // Beacuse LoongArch does not have SIPI now, the APIC ID must be obtained before
+  // calling IPI to wake up the APs. If NULL is obtained, NODE0 Core0 Mailbox0 is used
+  // as the first broadcast method to wake up all APs, and all of APs will read NODE0
+  // Core0 Mailbox0 in an infinit loop.
+  //
+  ProcessorResourceData = GetProcessorResourceDataFromGuidedHob ();
+
+  if (ProcessorResourceData != NULL) {
+    CpuMpData->ApLoopMode = ApInHltLoop;
+    CpuMpData->CpuCount   = ProcessorResourceData->NumberOfProcessor;
+    CpuInfoInHob          = (CPU_INFO_IN_HOB *)(UINTN)(CpuMpData->CpuInfoInHob);
+
+    for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+      CpuInfoInHob[Index].ApicId = ProcessorResourceData->ApicId[Index];
+    }
+  }
+
+  //
+  // Send 1st broadcast IPI to APs to wakeup APs
+  //
+  CpuMpData->InitFlag = ApInitConfig;
+  WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, FALSE);
+  CpuMpData->InitFlag = ApInitDone;
+
+  //
+  // When InitFlag == ApInitConfig, WakeUpAP () guarantees all APs are checked in.
+  // FinishedCount is the number of check-in APs.
+  //
+  CpuMpData->CpuCount = CpuMpData->FinishedCount + 1;
+  ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
+
+  //
+  // Wait for all APs finished the initialization
+  //
+  while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+    CpuPause ();
+  }
+
+  //
+  // Sort BSP/Aps by CPU APIC ID in ascending order
+  //
+  SortApicId (CpuMpData);
+
+  DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
+
+  return CpuMpData->CpuCount;
+}
+
+/**
+  Initialize CPU AP Data when AP is wakeup at the first time.
+
+  @param[in, out] CpuMpData        Pointer to PEI CPU MP Data
+  @param[in]      ProcessorNumber  The handle number of processor
+  @param[in]      BistData         Processor BIST data
+
+**/
+VOID
+InitializeApData (
+  IN OUT CPU_MP_DATA  *CpuMpData,
+  IN     UINTN        ProcessorNumber,
+  IN     UINT32       BistData
+  )
+{
+  CPU_INFO_IN_HOB  *CpuInfoInHob;
+
+  CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)(CpuMpData->CpuInfoInHob);
+
+  CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();
+  CpuInfoInHob[ProcessorNumber].Health = BistData;
+
+  CpuMpData->CpuData[ProcessorNumber].Waiting    = FALSE;
+  CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
+
+  InitializeSpinLock (&CpuMpData->CpuData[ProcessorNumber].ApLock);
+  SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
+}
+
+/**
+  Ap wake up function.
+
+  Ap will wait for scheduling here, and if the IPI or wake-up signal is enabled,
+  Ap will preform the corresponding functions.
+
+  @param[in] ApIndex          Number of current executing AP
+  @param[in] ExchangeInfo     Pointer to the MP exchange info buffer
+**/
+VOID
+EFIAPI
+ApWakeupFunction (
+  IN UINTN                 ApIndex,
+  IN MP_CPU_EXCHANGE_INFO  *ExchangeInfo
+  )
+{
+  CPU_MP_DATA       *CpuMpData;
+  UINTN             ProcessorNumber;
+  volatile UINT32   *ApStartupSignalBuffer;
+  EFI_AP_PROCEDURE  Procedure;
+  VOID              *Parameter;
+
+  CpuMpData = ExchangeInfo->CpuMpData;
+
+  while (TRUE) {
+    if (CpuMpData->InitFlag == ApInitConfig) {
+      ProcessorNumber = ApIndex;
+      //
+      // If the AP can running to here, then the BIST must be zero.
+      //
+      InitializeApData (CpuMpData, ProcessorNumber, 0);
+      ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+    } else {
+      //
+      // Execute AP function if AP is ready
+      //
+      GetProcessorNumber (CpuMpData, &ProcessorNumber);
+
+      //
+      // Clear AP start-up signal when AP waken up
+      //
+      ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+      InterlockedCompareExchange32 (
+        (UINT32 *)ApStartupSignalBuffer,
+        WAKEUP_AP_SIGNAL,
+        0
+        );
+
+      //
+      // Invoke AP function here
+      //
+      if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
+        Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
+        Parameter = (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
+        if (Procedure != NULL) {
+          SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
+          Procedure (Parameter);
+        }
+
+        SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
+      }
+    }
+
+    //
+    // Updates the finished count
+    //
+    InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount);
+
+    while (TRUE) {
+      //
+      // Clean per-core mail box registers.
+      //
+      IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, 0x0);
+      IoCsrWrite64 (LOONGARCH_IOCSR_MBUF1, 0x0);
+      IoCsrWrite64 (LOONGARCH_IOCSR_MBUF2, 0x0);
+      IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, 0x0);
+
+      //
+      // Enable IPI interrupt and global interrupt
+      //
+      EnableLocalInterrupts (BIT12);
+      IoCsrWrite32 (LOONGARCH_IOCSR_IPI_EN, 0xFFFFFFFFU);
+      EnableInterrupts ();
+
+      //
+      // Ap entry HLT mode
+      //
+      CpuSleep ();
+
+      //
+      // Disable global interrupts when wake up
+      //
+      DisableInterrupts ();
+
+      //
+      // Update CpuMpData
+      //
+      if (CpuMpData != ExchangeInfo->CpuMpData) {
+        CpuMpData = ExchangeInfo->CpuMpData;
+        GetProcessorNumber (CpuMpData, &ProcessorNumber);
+        ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+      }
+
+      //
+      // Break out of the loop if wake up signal is not NULL.
+      //
+      if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
+        break;
+      }
+    }
+  }
+}
+
+/**
+  Calculate timeout value and return the current performance counter value.
+
+  Calculate the number of performance counter ticks required for a timeout.
+  If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+  as infinity.
+
+  @param[in]  TimeoutInMicroseconds   Timeout value in microseconds.
+  @param[out] CurrentTime             Returns the current value of the performance counter.
+
+  @return Expected time stamp counter for timeout.
+          If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+          as infinity.
+
+**/
+UINT64
+CalculateTimeout (
+  IN  UINTN   TimeoutInMicroseconds,
+  OUT UINT64  *CurrentTime
+  )
+{
+  UINT64  TimeoutInSeconds;
+  UINT64  TimestampCounterFreq;
+
+  //
+  // Read the current value of the performance counter
+  //
+  *CurrentTime = GetPerformanceCounter ();
+
+  //
+  // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+  // as infinity.
+  //
+  if (TimeoutInMicroseconds == 0) {
+    return 0;
+  }
+
+  //
+  // GetPerformanceCounterProperties () returns the timestamp counter's frequency
+  // in Hz.
+  //
+  TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);
+
+  //
+  // Check the potential overflow before calculate the number of ticks for the timeout value.
+  //
+  if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {
+    //
+    // Convert microseconds into seconds if direct multiplication overflows
+    //
+    TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);
+    //
+    // Assertion if the final tick count exceeds MAX_UINT64
+    //
+    ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);
+    return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);
+  } else {
+    //
+    // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
+    // it by 1,000,000, to get the number of ticks for the timeout value.
+    //
+    return DivU64x32 (
+             MultU64x64 (
+               TimestampCounterFreq,
+               TimeoutInMicroseconds
+               ),
+             1000000
+             );
+  }
+}
+
+/**
+  Checks whether timeout expires.
+
+  Check whether the number of elapsed performance counter ticks required for
+  a timeout condition has been reached.
+  If Timeout is zero, which means infinity, return value is always FALSE.
+
+  @param[in, out]  PreviousTime   On input,  the value of the performance counter
+                                  when it was last read.
+                                  On output, the current value of the performance
+                                  counter
+  @param[in]       TotalTime      The total amount of elapsed time in performance
+                                  counter ticks.
+  @param[in]       Timeout        The number of performance counter ticks required
+                                  to reach a timeout condition.
+
+  @retval TRUE                    A timeout condition has been reached.
+  @retval FALSE                   A timeout condition has not been reached.
+
+**/
+BOOLEAN
+CheckTimeout (
+  IN OUT UINT64  *PreviousTime,
+  IN     UINT64  *TotalTime,
+  IN     UINT64  Timeout
+  )
+{
+  UINT64  Start;
+  UINT64  End;
+  UINT64  CurrentTime;
+  INT64   Delta;
+  INT64   Cycle;
+
+  if (Timeout == 0) {
+    return FALSE;
+  }
+
+  GetPerformanceCounterProperties (&Start, &End);
+  Cycle = End - Start;
+  if (Cycle < 0) {
+    Cycle = -Cycle;
+  }
+
+  Cycle++;
+  CurrentTime = GetPerformanceCounter ();
+  Delta       = (INT64)(CurrentTime - *PreviousTime);
+  if (Start > End) {
+    Delta = -Delta;
+  }
+
+  if (Delta < 0) {
+    Delta += Cycle;
+  }
+
+  *TotalTime   += Delta;
+  *PreviousTime = CurrentTime;
+  if (*TotalTime > Timeout) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Helper function that waits until the finished AP count reaches the specified
+  limit, or the specified timeout elapses (whichever comes first).
+
+  @param[in] CpuMpData        Pointer to CPU MP Data.
+  @param[in] FinishedApLimit  The number of finished APs to wait for.
+  @param[in] TimeLimit        The number of microseconds to wait for.
+**/
+VOID
+TimedWaitForApFinish (
+  IN CPU_MP_DATA  *CpuMpData,
+  IN UINT32       FinishedApLimit,
+  IN UINT32       TimeLimit
+  )
+{
+  //
+  // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
+  // "infinity", so check for (TimeLimit == 0) explicitly.
+  //
+  if (TimeLimit == 0) {
+    return;
+  }
+
+  CpuMpData->TotalTime    = 0;
+  CpuMpData->ExpectedTime = CalculateTimeout (
+                              TimeLimit,
+                              &CpuMpData->CurrentTime
+                              );
+  while (CpuMpData->FinishedCount < FinishedApLimit &&
+         !CheckTimeout (
+            &CpuMpData->CurrentTime,
+            &CpuMpData->TotalTime,
+            CpuMpData->ExpectedTime
+            ))
+  {
+    CpuPause ();
+  }
+
+  if (CpuMpData->FinishedCount >= FinishedApLimit) {
+    DEBUG ((
+      DEBUG_VERBOSE,
+      "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
+      __func__,
+      FinishedApLimit,
+      DivU64x64Remainder (
+        MultU64x32 (CpuMpData->TotalTime, 1000000),
+        GetPerformanceCounterProperties (NULL, NULL),
+        NULL
+        )
+      ));
+  }
+}
+
+/**
+  Wait for AP wakeup and write AP start-up signal till AP is waken up.
+
+  @param[in] ApStartupSignalBuffer  Pointer to AP wakeup signal
+**/
+VOID
+WaitApWakeup (
+  IN volatile UINT32  *ApStartupSignalBuffer
+  )
+{
+  //
+  // If AP is waken up, StartupApSignal should be cleared.
+  // Otherwise, write StartupApSignal again till AP waken up.
+  //
+  while (InterlockedCompareExchange32 (
+           (UINT32 *)ApStartupSignalBuffer,
+           WAKEUP_AP_SIGNAL,
+           WAKEUP_AP_SIGNAL
+           ) != 0)
+  {
+    CpuPause ();
+  }
+}
+
+/**
+  This function will fill the exchange info structure.
+
+  @param[in] CpuMpData          Pointer to CPU MP Data
+
+**/
+VOID
+FillExchangeInfoData (
+  IN CPU_MP_DATA  *CpuMpData
+  )
+{
+  volatile MP_CPU_EXCHANGE_INFO  *ExchangeInfo;
+
+  if (!CpuMpData->MpCpuExchangeInfo) {
+    CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *)AllocatePool (sizeof (MP_CPU_EXCHANGE_INFO));
+  }
+
+  ExchangeInfo            = CpuMpData->MpCpuExchangeInfo;
+  ExchangeInfo->CpuMpData = CpuMpData;
+}
+
+/**
+  This function will be called by BSP to wakeup AP.
+
+  @param[in] CpuMpData          Pointer to CPU MP Data
+  @param[in] Broadcast          TRUE:  Send broadcast IPI to all APs
+                                FALSE: Send IPI to AP by ApicId
+  @param[in] ProcessorNumber    The handle number of specified processor
+  @param[in] Procedure          The function to be invoked by AP
+  @param[in] ProcedureArgument  The argument to be passed into AP function
+  @param[in] WakeUpDisabledAps  Whether need to wake up disabled APs in broadcast mode. Currently not used on LoongArch.
+**/
+VOID
+WakeUpAP (
+  IN CPU_MP_DATA       *CpuMpData,
+  IN BOOLEAN           Broadcast,
+  IN UINTN             ProcessorNumber,
+  IN EFI_AP_PROCEDURE  Procedure               OPTIONAL,
+  IN VOID              *ProcedureArgument      OPTIONAL,
+  IN BOOLEAN           WakeUpDisabledAps
+  )
+{
+  volatile MP_CPU_EXCHANGE_INFO  *ExchangeInfo;
+  UINTN                          Index;
+  CPU_AP_DATA                    *CpuData;
+  CPU_INFO_IN_HOB                *CpuInfoInHob;
+
+  CpuMpData->FinishedCount = 0;
+
+  CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+
+  if (CpuMpData->InitFlag != ApInitDone) {
+    FillExchangeInfoData (CpuMpData);
+  }
+
+  ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
+  //
+  // If InitFlag is ApInitConfig, broadcasts all APs to initize themselves.
+  //
+  if (CpuMpData->InitFlag == ApInitConfig) {
+    DEBUG ((DEBUG_INFO, "%a: func 0x%llx, ExchangeInfo 0x%llx\n", __func__, ApWakeupFunction, (UINTN)ExchangeInfo));
+    if (CpuMpData->ApLoopMode == ApInHltLoop) {
+      for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+        if (Index != CpuMpData->BspNumber) {
+          IoCsrWrite64 (
+            LOONGARCH_IOCSR_MBUF_SEND,
+            (IOCSR_MBUF_SEND_BLOCKING |
+             (IOCSR_MBUF_SEND_BOX_HI (0x3) << IOCSR_MBUF_SEND_BOX_SHIFT) |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+             ((UINTN)(ExchangeInfo) & IOCSR_MBUF_SEND_H32_MASK))
+            );
+          IoCsrWrite64 (
+            LOONGARCH_IOCSR_MBUF_SEND,
+            (IOCSR_MBUF_SEND_BLOCKING |
+             (IOCSR_MBUF_SEND_BOX_LO (0x3) << IOCSR_MBUF_SEND_BOX_SHIFT) |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+             ((UINTN)ExchangeInfo) << IOCSR_MBUF_SEND_BUF_SHIFT)
+            );
+
+          IoCsrWrite64 (
+            LOONGARCH_IOCSR_MBUF_SEND,
+            (IOCSR_MBUF_SEND_BLOCKING |
+             (IOCSR_MBUF_SEND_BOX_HI (0x0) << IOCSR_MBUF_SEND_BOX_SHIFT) |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+             ((UINTN)(ApWakeupFunction) & IOCSR_MBUF_SEND_H32_MASK))
+            );
+          IoCsrWrite64 (
+            LOONGARCH_IOCSR_MBUF_SEND,
+            (IOCSR_MBUF_SEND_BLOCKING |
+             (IOCSR_MBUF_SEND_BOX_LO (0x0) << IOCSR_MBUF_SEND_BOX_SHIFT) |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+             ((UINTN)ApWakeupFunction) << IOCSR_MBUF_SEND_BUF_SHIFT)
+            );
+
+          //
+          // Send IPI 4 interrupt to wake up APs.
+          //
+          IoCsrWrite64 (
+            LOONGARCH_IOCSR_IPI_SEND,
+            (IOCSR_MBUF_SEND_BLOCKING |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+             0x2 // Bit 2
+            )
+            );
+        }
+      }
+    } else {
+      IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, (UINTN)ExchangeInfo);
+      IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, (UINTN)ApWakeupFunction);
+    }
+
+    TimedWaitForApFinish (
+      CpuMpData,
+      PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
+      PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
+      );
+  } else {
+    if (Broadcast) {
+      for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+        if (Index != CpuMpData->BspNumber) {
+          CpuData = &CpuMpData->CpuData[Index];
+          if ((GetApState (CpuData) == CpuStateDisabled) && !WakeUpDisabledAps) {
+            continue;
+          }
+
+          CpuData->ApFunction         = (UINTN)Procedure;
+          CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;
+          SetApState (CpuData, CpuStateReady);
+          *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
+
+          //
+          // Send IPI 4 interrupt to wake up APs.
+          //
+          IoCsrWrite64 (
+            LOONGARCH_IOCSR_IPI_SEND,
+            (IOCSR_MBUF_SEND_BLOCKING |
+             (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+             0x2 // Bit 2
+            )
+            );
+        }
+      }
+
+      //
+      // Wait all APs waken up.
+      //
+      for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+        CpuData = &CpuMpData->CpuData[Index];
+        if (Index != CpuMpData->BspNumber) {
+          WaitApWakeup (CpuData->StartupApSignal);
+        }
+      }
+    } else {
+      CpuData                     = &CpuMpData->CpuData[ProcessorNumber];
+      CpuData->ApFunction         = (UINTN)Procedure;
+      CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;
+      SetApState (CpuData, CpuStateReady);
+      //
+      // Wakeup specified AP
+      //
+      *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
+
+      //
+      // Send IPI 4 interrupt to wake up APs.
+      //
+      IoCsrWrite64 (
+        LOONGARCH_IOCSR_IPI_SEND,
+        (IOCSR_MBUF_SEND_BLOCKING |
+         (CpuInfoInHob[ProcessorNumber].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+         0x2 // Bit 2
+        )
+        );
+
+      //
+      // Wait specified AP waken up
+      //
+      WaitApWakeup (CpuData->StartupApSignal);
+    }
+  }
+}
+
+/**
+  Searches for the next waiting AP.
+
+  Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
+
+  @param[out]  NextProcessorNumber  Pointer to the processor number of the next waiting AP.
+
+  @retval EFI_SUCCESS          The next waiting AP has been found.
+  @retval EFI_NOT_FOUND        No waiting AP exists.
+
+**/
+EFI_STATUS
+GetNextWaitingProcessorNumber (
+  OUT UINTN  *NextProcessorNumber
+  )
+{
+  UINTN        ProcessorNumber;
+  CPU_MP_DATA  *CpuMpData;
+
+  CpuMpData = GetCpuMpData ();
+
+  for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+    if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+      *NextProcessorNumber = ProcessorNumber;
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/** Checks status of specified AP.
+
+  This function checks whether the specified AP has finished the task assigned
+  by StartupThisAP(), and whether timeout expires.
+
+  @param[in]  ProcessorNumber       The handle number of processor.
+
+  @retval EFI_SUCCESS           Specified AP has finished task assigned by StartupThisAPs().
+  @retval EFI_TIMEOUT           The timeout expires.
+  @retval EFI_NOT_READY         Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckThisAP (
+  IN UINTN  ProcessorNumber
+  )
+{
+  CPU_MP_DATA  *CpuMpData;
+  CPU_AP_DATA  *CpuData;
+
+  CpuMpData = GetCpuMpData ();
+  CpuData   = &CpuMpData->CpuData[ProcessorNumber];
+
+  //
+  // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
+  //
+  if (GetApState (CpuData) == CpuStateFinished) {
+    if (CpuData->Finished != NULL) {
+      *(CpuData->Finished) = TRUE;
+    }
+
+    SetApState (CpuData, CpuStateIdle);
+    return EFI_SUCCESS;
+  } else {
+    //
+    // If timeout expires for StartupThisAP(), report timeout.
+    //
+    if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
+      if (CpuData->Finished != NULL) {
+        *(CpuData->Finished) = FALSE;
+      }
+
+      return EFI_TIMEOUT;
+    }
+  }
+
+  return EFI_NOT_READY;
+}
+
+/**
+  Checks status of all APs.
+
+  This function checks whether all APs have finished task assigned by StartupAllAPs(),
+  and whether timeout expires.
+
+  @retval EFI_SUCCESS           All APs have finished task assigned by StartupAllAPs().
+  @retval EFI_TIMEOUT           The timeout expires.
+  @retval EFI_NOT_READY         APs have not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckAllAPs (
+  VOID
+  )
+{
+  UINTN        ProcessorNumber;
+  UINTN        NextProcessorNumber;
+  EFI_STATUS   Status;
+  CPU_MP_DATA  *CpuMpData;
+  CPU_AP_DATA  *CpuData;
+
+  CpuMpData = GetCpuMpData ();
+
+  NextProcessorNumber = 0;
+
+  //
+  // Go through all APs that are responsible for the StartupAllAPs().
+  //
+  for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+    if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
+      continue;
+    }
+
+    CpuData = &CpuMpData->CpuData[ProcessorNumber];
+    //
+    // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
+    // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
+    // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
+    //
+    if (GetApState (CpuData) == CpuStateFinished) {
+      CpuMpData->RunningCount--;
+      CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+      SetApState (CpuData, CpuStateIdle);
+
+      //
+      // If in Single Thread mode, then search for the next waiting AP for execution.
+      //
+      if (CpuMpData->SingleThread) {
+        Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
+
+        if (!EFI_ERROR (Status)) {
+          WakeUpAP (
+            CpuMpData,
+            FALSE,
+            (UINT32)NextProcessorNumber,
+            CpuMpData->Procedure,
+            CpuMpData->ProcArguments,
+            TRUE
+            );
+        }
+      }
+    }
+  }
+
+  //
+  // If all APs finish, return EFI_SUCCESS.
+  //
+  if (CpuMpData->RunningCount == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // If timeout expires, report timeout.
+  //
+  if (CheckTimeout (
+        &CpuMpData->CurrentTime,
+        &CpuMpData->TotalTime,
+        CpuMpData->ExpectedTime
+        )
+      )
+  {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_NOT_READY;
+}
+
+/**
+  Worker function to execute a caller provided function on all enabled APs.
+
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system.
+  @param[in]  SingleThread            If TRUE, then all the enabled APs execute
+                                      the function specified by Procedure one by
+                                      one, in ascending order of processor handle
+                                      number.  If FALSE, then all the enabled APs
+                                      execute the function specified by Procedure
+                                      simultaneously.
+  @param[in]  ExcludeBsp              Whether let BSP also trig this task.
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode.
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] FailedCpuList           If all APs finish successfully, then its
+                                      content is set to NULL. If not all APs
+                                      finish before timeout expires, then its
+                                      content is set to address of the buffer
+                                      holding handle numbers of the failed APs.
+
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished before
+                                  the timeout expired.
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
+                                  to all enabled APs.
+  @retval others                  Failed to Startup all APs.
+
+**/
+EFI_STATUS
+StartupAllCPUsWorker (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  BOOLEAN           SingleThread,
+  IN  BOOLEAN           ExcludeBsp,
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL,
+  OUT UINTN             **FailedCpuList         OPTIONAL
+  )
+{
+  EFI_STATUS   Status;
+  CPU_MP_DATA  *CpuMpData;
+  UINTN        ProcessorCount;
+  UINTN        ProcessorNumber;
+  UINTN        CallerNumber;
+  CPU_AP_DATA  *CpuData;
+  BOOLEAN      HasEnabledAp;
+  CPU_STATE    ApState;
+
+  CpuMpData = GetCpuMpData ();
+
+  if (FailedCpuList != NULL) {
+    *FailedCpuList = NULL;
+  }
+
+  if ((CpuMpData->CpuCount == 1) && ExcludeBsp) {
+    return EFI_NOT_STARTED;
+  }
+
+  if (Procedure == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check whether caller processor is BSP
+  //
+  MpInitLibWhoAmI (&CallerNumber);
+  if (CallerNumber != CpuMpData->BspNumber) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Update AP state
+  //
+  CheckAndUpdateApsStatus ();
+
+  ProcessorCount = CpuMpData->CpuCount;
+  HasEnabledAp   = FALSE;
+  //
+  // Check whether all enabled APs are idle.
+  // If any enabled AP is not idle, return EFI_NOT_READY.
+  //
+  for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+    CpuData = &CpuMpData->CpuData[ProcessorNumber];
+    if (ProcessorNumber != CpuMpData->BspNumber) {
+      ApState = GetApState (CpuData);
+      if (ApState != CpuStateDisabled) {
+        HasEnabledAp = TRUE;
+        if (ApState != CpuStateIdle) {
+          //
+          // If any enabled APs are busy, return EFI_NOT_READY.
+          //
+          return EFI_NOT_READY;
+        }
+      }
+    }
+  }
+
+  if (!HasEnabledAp && ExcludeBsp) {
+    //
+    // If no enabled AP exists and not include Bsp to do the procedure, return EFI_NOT_STARTED.
+    //
+    return EFI_NOT_STARTED;
+  }
+
+  CpuMpData->RunningCount = 0;
+  for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+    CpuData          = &CpuMpData->CpuData[ProcessorNumber];
+    CpuData->Waiting = FALSE;
+    if (ProcessorNumber != CpuMpData->BspNumber) {
+      if (CpuData->State == CpuStateIdle) {
+        //
+        // Mark this processor as responsible for current calling.
+        //
+        CpuData->Waiting = TRUE;
+        CpuMpData->RunningCount++;
+      }
+    }
+  }
+
+  CpuMpData->Procedure     = Procedure;
+  CpuMpData->ProcArguments = ProcedureArgument;
+  CpuMpData->SingleThread  = SingleThread;
+  CpuMpData->FinishedCount = 0;
+  CpuMpData->ExpectedTime  = CalculateTimeout (
+                               TimeoutInMicroseconds,
+                               &CpuMpData->CurrentTime
+                               );
+  CpuMpData->TotalTime = 0;
+  CpuMpData->WaitEvent = WaitEvent;
+
+  if (!SingleThread) {
+    WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE);
+  } else {
+    for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+      if (ProcessorNumber == CallerNumber) {
+        continue;
+      }
+
+      if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+        WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
+        break;
+      }
+    }
+  }
+
+  if (!ExcludeBsp) {
+    //
+    // Start BSP.
+    //
+    Procedure (ProcedureArgument);
+  }
+
+  Status = EFI_SUCCESS;
+  if (WaitEvent == NULL) {
+    do {
+      Status = CheckAllAPs ();
+    } while (Status == EFI_NOT_READY);
+  }
+
+  return Status;
+}
+
+/**
+  Worker function to let the caller get one enabled AP to execute a caller-provided
+  function.
+
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system.
+  @param[in]  ProcessorNumber         The handle number of the AP.
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode.
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] Finished                If AP returns from Procedure before the
+                                      timeout expires, its content is set to TRUE.
+                                      Otherwise, the value is set to FALSE.
+
+  @retval EFI_SUCCESS             In blocking mode, specified AP finished before
+                                  the timeout expires.
+  @retval others                  Failed to Startup AP.
+
+**/
+EFI_STATUS
+StartupThisAPWorker (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  UINTN             ProcessorNumber,
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL,
+  OUT BOOLEAN           *Finished               OPTIONAL
+  )
+{
+  EFI_STATUS   Status;
+  CPU_MP_DATA  *CpuMpData;
+  CPU_AP_DATA  *CpuData;
+  UINTN        CallerNumber;
+
+  CpuMpData = GetCpuMpData ();
+
+  if (Finished != NULL) {
+    *Finished = FALSE;
+  }
+
+  //
+  // Check whether caller processor is BSP
+  //
+  MpInitLibWhoAmI (&CallerNumber);
+  if (CallerNumber != CpuMpData->BspNumber) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Check whether processor with the handle specified by ProcessorNumber exists
+  //
+  if (ProcessorNumber >= CpuMpData->CpuCount) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Check whether specified processor is BSP
+  //
+  if (ProcessorNumber == CpuMpData->BspNumber) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check parameter Procedure
+  //
+  if (Procedure == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Update AP state
+  //
+  CheckAndUpdateApsStatus ();
+
+  //
+  // Check whether specified AP is disabled
+  //
+  if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CpuData               = &CpuMpData->CpuData[ProcessorNumber];
+  CpuData->WaitEvent    = WaitEvent;
+  CpuData->Finished     = Finished;
+  CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);
+  CpuData->TotalTime    = 0;
+
+  WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, FALSE);
+
+  //
+  // If WaitEvent is NULL, execute in blocking mode.
+  // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
+  //
+  Status = EFI_SUCCESS;
+  if (WaitEvent == NULL) {
+    do {
+      Status = CheckThisAP (ProcessorNumber);
+    } while (Status == EFI_NOT_READY);
+  }
+
+  return Status;
+}
+
+/**
+  This service executes a caller provided function on all enabled CPUs.
+
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity. TimeoutInMicroseconds is ignored
+                                      for BSP.
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+
+  @retval EFI_SUCCESS             In blocking mode, all CPUs have finished before
+                                  the timeout expired.
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
+                                  to all enabled CPUs.
+  @retval EFI_DEVICE_ERROR        Caller processor is AP.
+  @retval EFI_NOT_READY           Any enabled APs are busy.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  all enabled APs have finished.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllCPUs (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL
+  )
+{
+  return StartupAllCPUsWorker (
+           Procedure,
+           TRUE,
+           FALSE,
+           NULL,
+           TimeoutInMicroseconds,
+           ProcedureArgument,
+           NULL
+           );
+}
+
+/**
+  MP Initialize Library initialization.
+
+  This service will allocate AP reset vector and wakeup all APs to do APs
+  initialization.
+
+  This service must be invoked before all other MP Initialize Library
+  service are invoked.
+
+  @retval  EFI_SUCCESS           MP initialization succeeds.
+  @retval  Others                MP initialization fails.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibInitialize (
+  VOID
+  )
+{
+  CPU_MP_DATA      *OldCpuMpData;
+  CPU_INFO_IN_HOB  *CpuInfoInHob;
+  UINT32           MaxLogicalProcessorNumber;
+  UINTN            BufferSize;
+  UINTN            MonitorBufferSize;
+  VOID             *MpBuffer;
+  CPU_MP_DATA      *CpuMpData;
+  UINTN            Index;
+
+  OldCpuMpData = GetCpuMpDataFromGuidedHob ();
+  if (OldCpuMpData == NULL) {
+    MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+  } else {
+    MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
+  }
+
+  ASSERT (MaxLogicalProcessorNumber != 0);
+
+  MonitorBufferSize = sizeof (WAKEUP_AP_SIGNAL) * MaxLogicalProcessorNumber;
+
+  BufferSize  = 0;
+  BufferSize += MonitorBufferSize;
+  BufferSize += sizeof (CPU_MP_DATA);
+  BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
+  MpBuffer    = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
+  ASSERT (MpBuffer != NULL);
+  ZeroMem (MpBuffer, BufferSize);
+
+  CpuMpData = (CPU_MP_DATA *)MpBuffer;
+
+  CpuMpData->CpuCount     = 1;
+  CpuMpData->BspNumber    = 0;
+  CpuMpData->CpuData      = (CPU_AP_DATA *)(CpuMpData + 1);
+  CpuMpData->CpuInfoInHob = (UINT64)(UINTN)(CpuMpData->CpuData + MaxLogicalProcessorNumber);
+
+  InitializeSpinLock (&CpuMpData->MpLock);
+
+  //
+  // Set BSP basic information
+  //
+  InitializeApData (CpuMpData, 0, 0);
+
+  //
+  // Set up APs wakeup signal buffer and initialization APs ApicId status.
+  //
+  for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
+    CpuMpData->CpuData[Index].StartupApSignal =
+      (UINT32 *)((MpBuffer + BufferSize - MonitorBufferSize) + (sizeof (WAKEUP_AP_SIGNAL) * Index));
+    if ((OldCpuMpData == NULL) && (Index != CpuMpData->BspNumber)) {
+      ((CPU_INFO_IN_HOB  *)CpuMpData->CpuInfoInHob)[Index].ApicId = INVALID_APIC_ID;
+    }
+  }
+
+  if (OldCpuMpData == NULL) {
+    if (MaxLogicalProcessorNumber > 1) {
+      //
+      // Wakeup all APs and calculate the processor count in system
+      //
+      CollectProcessorCount (CpuMpData);
+    }
+  } else {
+    //
+    // APs have been wakeup before, just get the CPU Information
+    // from HOB
+    //
+    CpuMpData->CpuCount          = OldCpuMpData->CpuCount;
+    CpuMpData->BspNumber         = OldCpuMpData->BspNumber;
+    CpuMpData->CpuInfoInHob      = OldCpuMpData->CpuInfoInHob;
+    CpuMpData->MpCpuExchangeInfo = OldCpuMpData->MpCpuExchangeInfo;
+
+    CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+    for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+      InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
+      CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0) ? TRUE : FALSE;
+    }
+
+    if (CpuMpData->CpuCount > 1) {
+      //
+      // Only needs to use this flag for DXE phase to update the wake up
+      // buffer. Wakeup buffer allocated in PEI phase is no longer valid
+      // in DXE.
+      //
+      CpuMpData->InitFlag = ApInitReconfig;
+      WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE);
+
+      //
+      // Wait for all APs finished initialization
+      //
+      while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+        CpuPause ();
+      }
+
+      CpuMpData->InitFlag = ApInitDone;
+    }
+
+    if (MaxLogicalProcessorNumber > 1) {
+      for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+        SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
+      }
+    }
+  }
+
+  //
+  // Initialize global data for MP support
+  //
+  InitMpGlobalData (CpuMpData);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Gets detailed MP-related information on the requested processor at the
+  instant this call is made. This service may only be called from the BSP.
+
+  @param[in]  ProcessorNumber       The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
+                                    the requested processor is deposited.
+  @param[out]  HealthData            Return processor health data.
+
+  @retval EFI_SUCCESS             Processor information was returned.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist in the platform.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetProcessorInfo (
+  IN  UINTN                      ProcessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer,
+  OUT EFI_HEALTH_FLAGS           *HealthData  OPTIONAL
+  )
+{
+  CPU_MP_DATA      *CpuMpData;
+  UINTN            CallerNumber;
+  CPU_INFO_IN_HOB  *CpuInfoInHob;
+
+  CpuMpData    = GetCpuMpData ();
+  CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+
+  //
+  // Check whether caller processor is BSP
+  //
+  MpInitLibWhoAmI (&CallerNumber);
+  if (CallerNumber != CpuMpData->BspNumber) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (ProcessorInfoBuffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (ProcessorNumber >= CpuMpData->CpuCount) {
+    return EFI_NOT_FOUND;
+  }
+
+  ProcessorInfoBuffer->ProcessorId = (UINT64)CpuInfoInHob[ProcessorNumber].ApicId;
+  ProcessorInfoBuffer->StatusFlag  = 0;
+  if (ProcessorNumber == CpuMpData->BspNumber) {
+    ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+  }
+
+  if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
+    ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
+  }
+
+  if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
+    ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+  } else {
+    ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+  }
+
+  if (HealthData != NULL) {
+    HealthData->Uint32 = CpuInfoInHob[ProcessorNumber].Health;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This return the handle number for the calling processor.  This service may be
+  called from the BSP and APs.
+
+  @param[out] ProcessorNumber  Pointer to the handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               MpInitLibGetNumberOfProcessors().
+
+  @retval EFI_SUCCESS             The current processor handle number was returned
+                                  in ProcessorNumber.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibWhoAmI (
+  OUT UINTN  *ProcessorNumber
+  )
+{
+  CPU_MP_DATA  *CpuMpData;
+
+  if (ProcessorNumber == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CpuMpData = GetCpuMpData ();
+
+  return GetProcessorNumber (CpuMpData, ProcessorNumber);
+}
+
+/**
+  Retrieves the number of logical processor in the platform and the number of
+  those logical processors that are enabled on this boot. This service may only
+  be called from the BSP.
+
+  @param[out] NumberOfProcessors          Pointer to the total number of logical
+                                          processors in the system, including the BSP
+                                          and disabled APs.
+  @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled logical
+                                          processors that exist in system, including
+                                          the BSP.
+
+  @retval EFI_SUCCESS             The number of logical processors and enabled
+                                  logical processors was retrieved.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL and NumberOfEnabledProcessors
+                                  is NULL.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetNumberOfProcessors (
+  OUT UINTN  *NumberOfProcessors        OPTIONAL,
+  OUT UINTN  *NumberOfEnabledProcessors OPTIONAL
+  )
+{
+  CPU_MP_DATA  *CpuMpData;
+  UINTN        CallerNumber;
+  UINTN        ProcessorNumber;
+  UINTN        EnabledProcessorNumber;
+  UINTN        Index;
+
+  CpuMpData = GetCpuMpData ();
+
+  if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check whether caller processor is BSP
+  //
+  MpInitLibWhoAmI (&CallerNumber);
+  if (CallerNumber != CpuMpData->BspNumber) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  ProcessorNumber        = CpuMpData->CpuCount;
+  EnabledProcessorNumber = 0;
+  for (Index = 0; Index < ProcessorNumber; Index++) {
+    if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
+      EnabledProcessorNumber++;
+    }
+  }
+
+  if (NumberOfProcessors != NULL) {
+    *NumberOfProcessors = ProcessorNumber;
+  }
+
+  if (NumberOfEnabledProcessors != NULL) {
+    *NumberOfEnabledProcessors = EnabledProcessorNumber;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get pointer to CPU MP Data structure from GUIDed HOB.
+
+  @return  The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpDataFromGuidedHob (
+  VOID
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+  VOID               *DataInHob;
+  CPU_MP_DATA        *CpuMpData;
+
+  CpuMpData = NULL;
+  GuidHob   = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
+
+  if (GuidHob != NULL) {
+    DataInHob = GET_GUID_HOB_DATA (GuidHob);
+    CpuMpData = (CPU_MP_DATA *)(*(UINTN *)DataInHob);
+  }
+
+  return CpuMpData;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h b/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h
new file mode 100644
index 0000000000..3e18e95f5b
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h
@@ -0,0 +1,350 @@
+/** @file
+  Common header file for LoongArch MP Initialize Library.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_LIB_H_
+#define MP_LIB_H_
+
+#include <PiPei.h>
+#include <Guid/ProcessorResourceHob.h>
+#include <Library/PeiServicesLib.h>
+
+#include <Library/MpInitLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CpuLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TimerLib.h>
+#include <Library/HobLib.h>
+
+#define WAKEUP_AP_SIGNAL  SIGNATURE_32 ('S', 'T', 'A', 'P')
+
+#define CPU_INIT_MP_LIB_HOB_GUID \
+  { \
+    0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \
+  }
+
+//
+// AP loop state when APs are in idle state
+// It's value is the same with PcdCpuApLoopMode
+//
+typedef enum {
+  ApInHltLoop = 1,
+  ApInRunLoop = 2
+} AP_LOOP_MODE;
+
+//
+// AP initialization state during APs wakeup
+//
+typedef enum {
+  ApInitConfig   = 1,
+  ApInitReconfig = 2,
+  ApInitDone     = 3
+} AP_INIT_STATE;
+
+//
+// AP state
+//
+typedef enum {
+  CpuStateIdle,
+  CpuStateReady,
+  CpuStateBusy,
+  CpuStateFinished,
+  CpuStateDisabled
+} CPU_STATE;
+
+//
+// AP related data
+//
+typedef struct {
+  SPIN_LOCK             ApLock;
+  volatile UINT32       *StartupApSignal;
+  volatile UINTN        ApFunction;
+  volatile UINTN        ApFunctionArgument;
+  BOOLEAN               CpuHealthy;
+  volatile CPU_STATE    State;
+  BOOLEAN               Waiting;
+  BOOLEAN               *Finished;
+  UINT64                ExpectedTime;
+  UINT64                CurrentTime;
+  UINT64                TotalTime;
+  EFI_EVENT             WaitEvent;
+} CPU_AP_DATA;
+
+//
+// Basic CPU information saved in Guided HOB.
+// Because the contents will be shard between PEI and DXE,
+// we need to make sure the each fields offset same in different
+// architecture.
+//
+#pragma pack (1)
+typedef struct {
+  UINT32    ApicId;
+  UINT32    Health;
+} CPU_INFO_IN_HOB;
+#pragma pack ()
+
+typedef struct MP_CPU_DATA CPU_MP_DATA;
+
+#pragma pack(1)
+
+//
+// MP CPU exchange information for AP reset code
+// This structure is required to be packed because fixed field offsets
+// into this structure are used in assembly code in this module
+//
+typedef struct {
+  CPU_MP_DATA    *CpuMpData;
+} MP_CPU_EXCHANGE_INFO;
+
+#pragma pack()
+
+//
+// CPU MP Data save in memory
+//
+struct MP_CPU_DATA {
+  UINT64                           CpuInfoInHob;
+  UINT32                           CpuCount;
+  UINT32                           BspNumber;
+  //
+  // The above fields data will be passed from PEI to DXE
+  // Please make sure the fields offset same in the different
+  // architecture.
+  //
+  SPIN_LOCK                        MpLock;
+
+  volatile UINT32                  FinishedCount;
+  UINT32                           RunningCount;
+  BOOLEAN                          SingleThread;
+  EFI_AP_PROCEDURE                 Procedure;
+  VOID                             *ProcArguments;
+  BOOLEAN                          *Finished;
+  UINT64                           ExpectedTime;
+  UINT64                           CurrentTime;
+  UINT64                           TotalTime;
+  EFI_EVENT                        WaitEvent;
+
+  AP_INIT_STATE                    InitFlag;
+  UINT8                            ApLoopMode;
+  CPU_AP_DATA                      *CpuData;
+  volatile MP_CPU_EXCHANGE_INFO    *MpCpuExchangeInfo;
+};
+
+extern EFI_GUID  mCpuInitMpLibHobGuid;
+
+/**
+  Get the pointer to CPU MP Data structure.
+
+  @return  The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+  VOID
+  );
+
+/**
+  Save the pointer to CPU MP Data structure.
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+  IN CPU_MP_DATA  *CpuMpData
+  );
+
+/**
+  This function will be called by BSP to wakeup AP.
+
+  @param[in] CpuMpData          Pointer to CPU MP Data
+  @param[in] Broadcast          TRUE:  Send broadcast IPI to all APs
+                                FALSE: Send IPI to AP by ApicId
+  @param[in] ProcessorNumber    The handle number of specified processor
+  @param[in] Procedure          The function to be invoked by AP
+  @param[in] ProcedureArgument  The argument to be passed into AP function
+  @param[in] WakeUpDisabledAps  Whether need to wake up disabled APs in broadcast mode.
+**/
+VOID
+WakeUpAP (
+  IN CPU_MP_DATA       *CpuMpData,
+  IN BOOLEAN           Broadcast,
+  IN UINTN             ProcessorNumber,
+  IN EFI_AP_PROCEDURE  Procedure               OPTIONAL,
+  IN VOID              *ProcedureArgument      OPTIONAL,
+  IN BOOLEAN           WakeUpDisabledAps
+  );
+
+/**
+  Initialize global data for MP support.
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+  IN CPU_MP_DATA  *CpuMpData
+  );
+
+/**
+  Worker function to execute a caller provided function on all enabled APs.
+
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system.
+  @param[in]  SingleThread            If TRUE, then all the enabled APs execute
+                                      the function specified by Procedure one by
+                                      one, in ascending order of processor handle
+                                      number.  If FALSE, then all the enabled APs
+                                      execute the function specified by Procedure
+                                      simultaneously.
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode.
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] FailedCpuList           If all APs finish successfully, then its
+                                      content is set to NULL. If not all APs
+                                      finish before timeout expires, then its
+                                      content is set to address of the buffer
+                                      holding handle numbers of the failed APs.
+
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished before
+                                  the timeout expired.
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
+                                  to all enabled APs.
+  @retval others                  Failed to Startup all APs.
+
+**/
+EFI_STATUS
+StartupAllCPUsWorker (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  BOOLEAN           SingleThread,
+  IN  BOOLEAN           ExcludeBsp,
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL,
+  OUT UINTN             **FailedCpuList         OPTIONAL
+  );
+
+/**
+  Worker function to let the caller get one enabled AP to execute a caller-provided
+  function.
+
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system.
+  @param[in]  ProcessorNumber         The handle number of the AP.
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode.
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] Finished                If AP returns from Procedure before the
+                                      timeout expires, its content is set to TRUE.
+                                      Otherwise, the value is set to FALSE.
+
+  @retval EFI_SUCCESS             In blocking mode, specified AP finished before
+                                  the timeout expires.
+  @retval others                  Failed to Startup AP.
+
+**/
+EFI_STATUS
+StartupThisAPWorker (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  UINTN             ProcessorNumber,
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL,
+  OUT BOOLEAN           *Finished               OPTIONAL
+  );
+
+/**
+  Worker function to let the caller enable or disable an AP from this point onward.
+  This service may only be called from the BSP.
+  This instance will be added in the future.
+
+  @param[in] ProcessorNumber   The handle number of AP.
+  @param[in] EnableAP          Specifies the new state for the processor for
+                               enabled, FALSE for disabled.
+  @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
+                               the new health status of the AP.
+
+  @retval EFI_SUCCESS          The specified AP was enabled or disabled successfully.
+  @retval others               Failed to Enable/Disable AP.
+
+**/
+EFI_STATUS
+EnableDisableApWorker (
+  IN  UINTN    ProcessorNumber,
+  IN  BOOLEAN  EnableAP,
+  IN  UINT32   *HealthFlag OPTIONAL
+  );
+
+/**
+  Get pointer to CPU MP Data structure from GUIDed HOB.
+
+  @return  The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpDataFromGuidedHob (
+  VOID
+  );
+
+/** Checks status of specified AP.
+
+  This function checks whether the specified AP has finished the task assigned
+  by StartupThisAP(), and whether timeout expires.
+
+  @param[in]  ProcessorNumber       The handle number of processor.
+
+  @retval EFI_SUCCESS           Specified AP has finished task assigned by StartupThisAPs().
+  @retval EFI_TIMEOUT           The timeout expires.
+  @retval EFI_NOT_READY         Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckThisAP (
+  IN UINTN  ProcessorNumber
+  );
+
+/**
+  Checks status of all APs.
+
+  This function checks whether all APs have finished task assigned by StartupAllAPs(),
+  and whether timeout expires.
+
+  @retval EFI_SUCCESS           All APs have finished task assigned by StartupAllAPs().
+  @retval EFI_TIMEOUT           The timeout expires.
+  @retval EFI_NOT_READY         APs have not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckAllAPs (
+  VOID
+  );
+
+/**
+  Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+  VOID
+  );
+
+/**
+  Enable Debug Agent to support source debugging on AP function.
+  This instance will added in the future.
+
+**/
+VOID
+EnableDebugAgent (
+  VOID
+  );
+
+#endif
diff --git a/UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c
new file mode 100644
index 0000000000..7c92922677
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c
@@ -0,0 +1,381 @@
+/** @file
+  LoongArch64 MP initialize support functions for PEI phase.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+/**
+  Enable Debug Agent to support source debugging on AP function.
+
+**/
+VOID
+EnableDebugAgent (
+  VOID
+  )
+{
+}
+
+/**
+  Get pointer to CPU MP Data structure.
+
+  @return  The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+  VOID
+  )
+{
+  CPU_MP_DATA  *CpuMpData;
+
+  CpuMpData = GetCpuMpDataFromGuidedHob ();
+  ASSERT (CpuMpData != NULL);
+  return CpuMpData;
+}
+
+/**
+  Save the pointer to CPU MP Data structure.
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+  IN CPU_MP_DATA  *CpuMpData
+  )
+{
+  UINT64  Data64;
+
+  //
+  // Build location of CPU MP DATA buffer in HOB
+  //
+  Data64 = (UINT64)(UINTN)CpuMpData;
+  BuildGuidDataHob (
+    &mCpuInitMpLibHobGuid,
+    (VOID *)&Data64,
+    sizeof (UINT64)
+    );
+}
+
+/**
+  Get available EfiBootServicesCode memory below 4GB by specified size.
+
+  This buffer is required to safely transfer AP from real address mode to
+  protected mode or long mode, due to the fact that the buffer returned by
+  GetWakeupBuffer() may be marked as non-executable.
+
+  @param[in] BufferSize   Wakeup transition buffer size.
+
+  @retval other   Return wakeup transition buffer address below 4GB.
+  @retval 0       Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+  IN UINTN  BufferSize
+  )
+{
+  //
+  // PEI phase doesn't need to do such transition. So simply return 0.
+  //
+  return 0;
+}
+
+/**
+  Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+  VOID
+  )
+{
+}
+
+/**
+  Initialize global data for MP support.
+
+  @param[in] CpuMpData  The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+  IN CPU_MP_DATA  *CpuMpData
+  )
+{
+  SaveCpuMpData (CpuMpData);
+}
+
+/**
+  This service executes a caller provided function on all enabled APs.
+
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  SingleThread            If TRUE, then all the enabled APs execute
+                                      the function specified by Procedure one by
+                                      one, in ascending order of processor handle
+                                      number.  If FALSE, then all the enabled APs
+                                      execute the function specified by Procedure
+                                      simultaneously.
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until all APs finish
+                                      or TimeoutInMicroSeconds expires.  If it's
+                                      not NULL, then execute in non-blocking mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on all the enabled
+                                      APs, and go on executing immediately. If
+                                      all return from Procedure, or TimeoutInMicroSeconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or WaitForEvent()
+                                      services to check the state of event.  Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      all APs return from Procedure, then Procedure
+                                      on the failed APs is terminated. All enabled
+                                      APs are available for next function assigned
+                                      by MpInitLibStartupAllAPs() or
+                                      MPInitLibStartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] FailedCpuList           If NULL, this parameter is ignored. Otherwise,
+                                      if all APs finish successfully, then its
+                                      content is set to NULL. If not all APs
+                                      finish before timeout expires, then its
+                                      content is set to address of the buffer
+                                      holding handle numbers of the failed APs.
+                                      The buffer is allocated by MP Initialization
+                                      library, and it's the caller's responsibility to
+                                      free the buffer with FreePool() service.
+                                      In blocking mode, it is ready for consumption
+                                      when the call returns. In non-blocking mode,
+                                      it is ready when WaitEvent is signaled.  The
+                                      list of failed CPU is terminated by
+                                      END_OF_CPU_LIST.
+
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished before
+                                  the timeout expired.
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
+                                  to all enabled APs.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_UNSUPPORTED         WaitEvent is not NULL if non-blocking mode is not
+                                  supported.
+  @retval EFI_DEVICE_ERROR        Caller processor is AP.
+  @retval EFI_NOT_STARTED         No enabled APs exist in the system.
+  @retval EFI_NOT_READY           Any enabled APs are busy.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  all enabled APs have finished.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllAPs (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  BOOLEAN           SingleThread,
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL,
+  OUT UINTN             **FailedCpuList         OPTIONAL
+  )
+{
+  if (WaitEvent != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return StartupAllCPUsWorker (
+           Procedure,
+           SingleThread,
+           TRUE,
+           NULL,
+           TimeoutInMicroseconds,
+           ProcedureArgument,
+           FailedCpuList
+           );
+}
+
+/**
+  This service lets the caller get one enabled AP to execute a caller-provided
+  function.
+
+  @param[in]  Procedure               A pointer to the function to be run on the
+                                      designated AP of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber         The handle number of the AP. The range is
+                                      from 0 to the total number of logical
+                                      processors minus 1. The total number of
+                                      logical processors can be retrieved by
+                                      MpInitLibGetNumberOfProcessors().
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until this AP finish
+                                      or TimeoutInMicroSeconds expires.  If it's
+                                      not NULL, then execute in non-blocking mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on this AP,
+                                      and go on executing immediately. If this AP
+                                      return from Procedure or TimeoutInMicroSeconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or WaitForEvent()
+                                      services to check the state of event.  Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      this AP to finish this Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      this AP returns from Procedure, then Procedure
+                                      on the AP is terminated. The
+                                      AP is available for next function assigned
+                                      by MpInitLibStartupAllAPs() or
+                                      MpInitLibStartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure on the
+                                      specified AP.
+  @param[out] Finished                If NULL, this parameter is ignored.  In
+                                      blocking mode, this parameter is ignored.
+                                      In non-blocking mode, if AP returns from
+                                      Procedure before the timeout expires, its
+                                      content is set to TRUE. Otherwise, the
+                                      value is set to FALSE. The caller can
+                                      determine if the AP returned from Procedure
+                                      by evaluating this value.
+
+  @retval EFI_SUCCESS             In blocking mode, specified AP finished before
+                                  the timeout expires.
+  @retval EFI_SUCCESS             In non-blocking mode, the function has been
+                                  dispatched to specified AP.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_UNSUPPORTED         WaitEvent is not NULL if non-blocking mode is not
+                                  supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  the specified AP has finished.
+  @retval EFI_NOT_READY           The specified AP is busy.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupThisAP (
+  IN  EFI_AP_PROCEDURE  Procedure,
+  IN  UINTN             ProcessorNumber,
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,
+  IN  UINTN             TimeoutInMicroseconds,
+  IN  VOID              *ProcedureArgument      OPTIONAL,
+  OUT BOOLEAN           *Finished               OPTIONAL
+  )
+{
+  if (WaitEvent != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return StartupThisAPWorker (
+           Procedure,
+           ProcessorNumber,
+           NULL,
+           TimeoutInMicroseconds,
+           ProcedureArgument,
+           Finished
+           );
+}
+
+/**
+  This service switches the requested AP to be the BSP from that point onward.
+  This service changes the BSP for all purposes. This call can only be performed
+  by the current BSP.
+
+  @param[in] ProcessorNumber   The handle number of AP that is to become the new
+                               BSP. The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               MpInitLibGetNumberOfProcessors().
+  @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
+                               enabled AP. Otherwise, it will be disabled.
+
+  @retval EFI_SUCCESS             BSP successfully switched.
+  @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to
+                                  this service returning.
+  @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or
+                                  a disabled AP.
+  @retval EFI_NOT_READY           The specified AP is busy.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+  IN UINTN     ProcessorNumber,
+  IN  BOOLEAN  EnableOldBSP
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This service lets the caller enable or disable an AP from this point onward.
+  This service may only be called from the BSP.
+
+  @param[in] ProcessorNumber   The handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               MpInitLibGetNumberOfProcessors().
+  @param[in] EnableAP          Specifies the new state for the processor for
+                               enabled, FALSE for disabled.
+  @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
+                               the new health status of the AP. This flag
+                               corresponds to StatusFlag defined in
+                               EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+                               the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+                               bits are ignored.  If it is NULL, this parameter
+                               is ignored.
+
+  @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed
+                                  prior to this service returning.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
+                                  does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+  IN  UINTN    ProcessorNumber,
+  IN  BOOLEAN  EnableAP,
+  IN  UINT32   *HealthFlag OPTIONAL
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 599ca36bc2..3ba15c149e 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -2,6 +2,7 @@
 #  MP Initialize Library instance for PEI driver.
 #
 #  Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -18,7 +19,7 @@ [Defines]
 #
 # The following information is for reference only and not required by the build tools.
 #
-#  VALID_ARCHITECTURES           = IA32 X64
+#  VALID_ARCHITECTURES           = IA32 X64 LOONGARCH64
 #
 
 [Sources.IA32]
@@ -29,7 +30,7 @@ [Sources.X64]
   X64/AmdSev.c
   X64/MpFuncs.nasm
 
-[Sources.common]
+[Sources.IA32, Sources.X64]
   AmdSev.c
   Microcode.c
   MpEqu.inc
@@ -38,6 +39,11 @@ [Sources.common]
   MpHandOff.h
   PeiMpLib.c
 
+[Sources.LoongArch64]
+  LoongArch64/PeiMpLib.c
+  LoongArch64/MpLib.c
+  LoongArch64/MpLib.h
+
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
@@ -45,17 +51,19 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
-  CcExitLib
   CpuLib
   HobLib
-  LocalApicLib
   MemoryAllocationLib
-  MicrocodeLib
-  MtrrLib
   PcdLib
   PeiServicesLib
   SynchronizationLib
 
+[LibraryClasses.IA32, LibraryClasses.X64]
+  CcExitLib
+  LocalApicLib
+  MicrocodeLib
+  MtrrLib
+
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
   gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr       ## CONSUMES
@@ -77,3 +85,6 @@ [Ppis]
 [Guids]
   gEdkiiS3SmmInitDoneGuid
   gEdkiiMicrocodePatchHobGuid
+
+[Guids.LoongArch64]
+  gProcessorResourceHobGuid              ## SOMETIMES_CONSUMES  ## HOB
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117658): https://edk2.groups.io/g/devel/message/117658
Mute This Topic: https://groups.io/mt/105478502/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 12/13] UefiCpuPkg: Add CpuDxe driver for LoongArch64
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (10 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 11/13] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-15  2:12   ` Ni, Ray
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 13/13] UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field Chao Li
  2024-04-15  2:15 ` [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Ni, Ray
  13 siblings, 1 reply; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann, Baoqi Zhang, Dongyan Qian

Added LoongArch64 CPU driver into CpuDxe.

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/CpuDxe/CpuDxe.inf              |  25 +-
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c    | 439 +++++++++++++++++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h    | 288 ++++++++++++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c     | 544 ++++++++++++++++++++++
 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c | 159 +++++++
 5 files changed, 1451 insertions(+), 4 deletions(-)
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c

diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
index 9e1c673283..fca74c44b3 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
@@ -3,6 +3,7 @@
 #
 #  Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
 #  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -22,7 +23,7 @@ [Packages]
   MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
-[LibraryClasses]
+[LibraryClasses.common]
   BaseLib
   BaseMemoryLib
   CpuExceptionHandlerLib
@@ -30,9 +31,7 @@ [LibraryClasses]
   DebugLib
   DxeServicesTableLib
   HobLib
-  LocalApicLib
   MemoryAllocationLib
-  MtrrLib
   MpInitLib
   PeCoffGetEntryPointLib
   ReportStatusCodeLib
@@ -41,7 +40,15 @@ [LibraryClasses]
   UefiDriverEntryPoint
   UefiLib
 
-[Sources]
+[LibraryClasses.IA32, LibraryClasses.X64]
+  LocalApicLib
+  MtrrLib
+
+[LibraryClasses.LoongArch64]
+  CacheMaintenanceLib
+  CpuMmuLib
+
+[Sources.IA32, Sources.X64]
   CpuDxe.c
   CpuDxe.h
   CpuGdt.c
@@ -59,6 +66,13 @@ [Sources.X64]
   X64/CpuAsm.nasm
   X64/PagingAttribute.c
 
+[Sources.LoongArch64]
+  CpuMp.h
+  LoongArch64/CpuDxe.c
+  LoongArch64/CpuMp.c
+  LoongArch64/Exception.c
+  LoongArch64/CpuDxe.h
+
 [Protocols]
   gEfiCpuArchProtocolGuid                       ## PRODUCES
   gEfiMpServiceProtocolGuid                     ## PRODUCES
@@ -81,6 +95,9 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList              ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize                    ## CONSUMES
 
+[Pcd.LoongArch64]
+  gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress      ## CONSUMES
+
 [Depex]
   TRUE
 
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
new file mode 100644
index 0000000000..24b9d51ee7
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
@@ -0,0 +1,439 @@
+/** @file CpuDxe.c
+
+  CPU DXE Module to produce CPU ARCH Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+#include <Guid/IdleLoopEvent.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/TimerLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+UINT64  mTimerPeriod = 0;
+
+/**
+  IPI Interrupt Handler.
+
+  @param InterruptType    The type of interrupt that occurred
+  @param SystemContext    A pointer to the system context when the interrupt occurred
+**/
+VOID
+EFIAPI
+IpiInterruptHandler (
+  IN EFI_EXCEPTION_TYPE  InterruptType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE             mCpuHandle = NULL;
+EFI_CPU_ARCH_PROTOCOL  gCpu       = {
+  CpuFlushCpuDataCache,
+  CpuEnableInterrupt,
+  CpuDisableInterrupt,
+  CpuGetInterruptState,
+  CpuInit,
+  CpuRegisterInterruptHandler,
+  CpuGetTimerValue,
+  CpuSetMemoryAttributes,
+  0,          // NumberOfTimers
+  4,          // DmaBufferAlignment
+};
+
+/**
+  This function flushes the range of addresses from Start to Start+Length
+  from the processor's data cache. If Start is not aligned to a cache line
+  boundary, then the bytes before Start to the preceding cache line boundary
+  are also flushed. If Start+Length is not aligned to a cache line boundary,
+  then the bytes past Start+Length to the end of the next cache line boundary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+  supported. If the data cache is fully coherent with all DMA operations, then
+  this function can just return EFI_SUCCESS. If the processor does not support
+  flushing a range of the data cache, then the entire data cache can be flushed.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start            The beginning physical address to flush from the processor's data
+                           cache.
+  @param  Length           The number of bytes to flush from the processor's data cache. This
+                           function may flush more bytes than Length specifies depending upon
+                           the granularity of the flush operation that the processor supports.
+  @param  FlushType        Specifies the type of flush operation to perform.
+
+  @retval EFI_SUCCESS           The address range from Start to Start+Length was flushed from
+                                the processor's data cache.
+  @retval EFI_INVALID_PARAMETER The processor does not support the cache flush type specified
+                                by FlushType.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   Start,
+  IN UINT64                 Length,
+  IN EFI_CPU_FLUSH_TYPE     FlushType
+  )
+{
+  switch (FlushType) {
+    case EfiCpuFlushTypeWriteBack:
+      WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+      break;
+    case EfiCpuFlushTypeInvalidate:
+      InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+      break;
+    case EfiCpuFlushTypeWriteBackInvalidate:
+      WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+      break;
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function enables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are enabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  )
+{
+  EnableInterrupts ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function disables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are disabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  )
+{
+  DisableInterrupts ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function retrieves the processor's current interrupt state a returns it in
+  State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+  are currently disabled, then FALSE is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  State            A pointer to the processor's current interrupt state. Set to TRUE if
+                           interrupts are enabled and FALSE if interrupts are disabled.
+
+  @retval EFI_SUCCESS           The processor's current interrupt state was returned in State.
+  @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  OUT BOOLEAN                *State
+  )
+{
+  if (State == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *State = GetInterruptState ();
+  return EFI_SUCCESS;
+}
+
+/**
+  This function generates an INIT on the processor. If this function succeeds, then the
+  processor will be reset, and control will not be returned to the caller. If InitType is
+  not supported by this processor, or the processor cannot programmatically generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+  occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  InitType         The type of processor INIT to perform.
+
+  @retval EFI_SUCCESS           The processor INIT was performed. This return code should never be seen.
+  @retval EFI_UNSUPPORTED       The processor INIT operation specified by InitType is not supported
+                                by this processor.
+  @retval EFI_DEVICE_ERROR      The processor INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_CPU_INIT_TYPE      InitType
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Registers a function to be called from the CPU interrupt handler.
+
+  @param  This                   Protocol instance structure
+  @param  InterruptType          Defines which interrupt to hook. IA-32
+                                 valid range is 0x00 through 0xFF
+  @param  InterruptHandler       A pointer to a function of type
+                                 EFI_CPU_INTERRUPT_HANDLER that is called
+                                 when a processor interrupt occurs.  A null
+                                 pointer is an error condition.
+
+  @retval EFI_SUCCESS            If handler installed or uninstalled.
+  @retval EFI_ALREADY_STARTED    InterruptHandler is not NULL, and a handler
+                                 for InterruptType was previously installed.
+  @retval EFI_INVALID_PARAMETER  InterruptHandler is NULL, and a handler for
+                                 InterruptType was not previously installed.
+  @retval EFI_UNSUPPORTED        The interrupt specified by InterruptType
+                                 is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+  IN EFI_CPU_ARCH_PROTOCOL      *This,
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  return RegisterInterruptHandler (InterruptType, InterruptHandler);
+}
+
+/**
+  Returns a timer value from one of the CPU's internal timers. There is no
+  inherent time interval between ticks but is a function of the CPU frequency.
+
+  @param  This                - Protocol instance structure.
+  @param  TimerIndex          - Specifies which CPU timer is requested.
+  @param  TimerValue          - Pointer to the returned timer value.
+  @param  TimerPeriod         - A pointer to the amount of time that passes
+                                in femtoseconds (10-15) for each increment
+                                of TimerValue. If TimerValue does not
+                                increment at a predictable rate, then 0 is
+                                returned.  The amount of time that has
+                                passed between two calls to GetTimerValue()
+                                can be calculated with the formula
+                                (TimerValue2 - TimerValue1) * TimerPeriod.
+                                This parameter is optional and may be NULL.
+
+  @retval EFI_SUCCESS           - If the CPU timer count was returned.
+  @retval EFI_UNSUPPORTED       - If the CPU does not have any readable timers.
+  @retval EFI_DEVICE_ERROR      - If an error occurred while reading the timer.
+  @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  IN  UINT32                 TimerIndex,
+  OUT UINT64                 *TimerValue,
+  OUT UINT64                 *TimerPeriod   OPTIONAL
+  )
+{
+  UINT64  BeginValue;
+  UINT64  EndValue;
+
+  if (TimerValue == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (TimerIndex != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *TimerValue = AsmReadStableCounter ();
+
+  if (TimerPeriod != NULL) {
+    if (mTimerPeriod == 0) {
+      //
+      // Read time stamp counter before and after delay of 100 microseconds
+      //
+      BeginValue = AsmReadStableCounter ();
+      MicroSecondDelay (100);
+      EndValue = AsmReadStableCounter ();
+      //
+      // Calculate the actual frequency
+      //
+      mTimerPeriod = DivU64x64Remainder (
+                       MultU64x32 (
+                         1000 * 1000 * 1000,
+                         100
+                         ),
+                       EndValue - BeginValue,
+                       NULL
+                       );
+    }
+
+    *TimerPeriod = mTimerPeriod;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function modifies the attributes for the memory region specified by BaseAddress and
+  Length from their current attributes to the attributes specified by Attributes.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  BaseAddress      The physical address that is the start address of a memory region.
+  @param  Length           The size in bytes of the memory region.
+  @param  EfiAttributes    The bit mask of attributes to set for the memory region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+                                The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   BaseAddress,
+  IN UINT64                 Length,
+  IN UINT64                 EfiAttributes
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       PageTable;
+  UINT64      PageWalkCfg;
+
+  Status      = EFI_SUCCESS;
+  PageTable   = CsrRead (LOONGARCH_CSR_PGDL);
+  PageWalkCfg = ((UINT64)CsrRead (LOONGARCH_CSR_PWCTL1)) << 32 | CsrRead (LOONGARCH_CSR_PWCTL0);
+
+  if ((BaseAddress & (EFI_PAGE_SIZE - 1)) != 0) {
+    //
+    // Minimum granularity is SIZE_4KB.
+    //
+    DEBUG ((
+      DEBUG_INFO,
+      "MemoryRegionMap(%lx, %lx, %lx, %lx, %lx): Minimum granularity is SIZE_4KB\n",
+      &PageTable,
+      PageWalkCfg,
+      BaseAddress,
+      Length,
+      EfiAttributes
+      ));
+
+    Status = EFI_UNSUPPORTED;
+
+    return Status;
+  }
+
+  Status = MemoryRegionMap (
+             &PageTable,
+             PageWalkCfg,
+             BaseAddress,
+             Length,
+             EfiAttributes,
+             0x0
+             );
+
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Callback function for idle events.
+
+  @param  Event                 Event whose notification function is being invoked.
+  @param  Context               The pointer to the notification function's context,
+                                which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+IdleLoopEventCallback (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  CpuSleep ();
+}
+
+/**
+  Initialize the state information for the CPU Architectural Protocol.
+
+  @param ImageHandle     Image handle this driver.
+  @param SystemTable     Pointer to the System Table.
+
+  @retval EFI_SUCCESS           Thread can be successfully created
+  @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure
+  @retval EFI_DEVICE_ERROR      Cannot create the thread
+
+**/
+EFI_STATUS
+InitializeCpu (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   IdleLoopEvent;
+
+  InitializeExceptions (&gCpu);
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mCpuHandle,
+                  &gEfiCpuArchProtocolGuid,
+                  &gCpu,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gCpu.RegisterInterruptHandler (
+                  &gCpu,
+                  EXCEPT_LOONGARCH_INT_IPI,
+                  IpiInterruptHandler
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Setup a callback for idle events
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  IdleLoopEventCallback,
+                  NULL,
+                  &gIdleLoopEventGuid,
+                  &IdleLoopEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  InitializeMpSupport ();
+
+  return Status;
+}
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
new file mode 100644
index 0000000000..8bfbfa3442
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
@@ -0,0 +1,288 @@
+/** @file CpuDxe.c
+
+  CPU DXE Module to produce CPU ARCH Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef CPU_DXE_H_
+#define CPU_DXE_H_
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MpInitLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/DebugImageInfoTable.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/LoadedImage.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
+
+/*
+  This function flushes the range of addresses from Start to Start+Length
+  from the processor's data cache. If Start is not aligned to a cache line
+  boundary, then the bytes before Start to the preceding cache line boundary
+  are also flushed. If Start+Length is not aligned to a cache line boundary,
+  then the bytes past Start+Length to the end of the next cache line boundary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+  supported. If the data cache is fully coherent with all DMA operations, then
+  this function can just return EFI_SUCCESS. If the processor does not support
+  flushing a range of the data cache, then the entire data cache can be flushed.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start            The beginning physical address to flush from the processor's data
+                           cache.
+  @param  Length           The number of bytes to flush from the processor's data cache. This
+                           function may flush more bytes than Length specifies depending upon
+                           the granularity of the flush operation that the processor supports.
+  @param  FlushType        Specifies the type of flush operation to perform.
+
+  @retval EFI_SUCCESS           The address range from Start to Start+Length was flushed from
+                                the processor's data cache.
+  @retval EFI_UNSUPPORTEDT      The processor does not support the cache flush type specified
+                                by FlushType.
+  @retval EFI_DEVICE_ERROR      The address range from Start to Start+Length could not be flushed
+                                from the processor's data cache.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   Start,
+  IN UINT64                 Length,
+  IN EFI_CPU_FLUSH_TYPE     FlushType
+  );
+
+/**
+  This function enables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are enabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  );
+
+/**
+  This function disables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are disabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  );
+
+/**
+  This function retrieves the processor's current interrupt state a returns it in
+  State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+  are currently disabled, then FALSE is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  State            A pointer to the processor's current interrupt state. Set to TRUE if
+                           interrupts are enabled and FALSE if interrupts are disabled.
+
+  @retval EFI_SUCCESS           The processor's current interrupt state was returned in State.
+  @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  OUT BOOLEAN                *State
+  );
+
+/**
+  This function generates an INIT on the processor. If this function succeeds, then the
+  processor will be reset, and control will not be returned to the caller. If InitType is
+  not supported by this processor, or the processor cannot programmatically generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+  occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  InitType         The type of processor INIT to perform.
+
+  @retval EFI_SUCCESS           The processor INIT was performed. This return code should never be seen.
+  @retval EFI_UNSUPPORTED       The processor INIT operation specified by InitType is not supported
+                                by this processor.
+  @retval EFI_DEVICE_ERROR      The processor INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_CPU_INIT_TYPE      InitType
+  );
+
+/**
+  Registers a function to be called from the CPU interrupt handler.
+
+  @param  This                   Protocol instance structure
+  @param  InterruptType          Defines which interrupt to hook. IA-32
+                                 valid range is 0x00 through 0xFF
+  @param  InterruptHandler       A pointer to a function of type
+                                 EFI_CPU_INTERRUPT_HANDLER that is called
+                                 when a processor interrupt occurs.  A null
+                                 pointer is an error condition.
+
+  @retval EFI_SUCCESS            If handler installed or uninstalled.
+  @retval EFI_ALREADY_STARTED    InterruptHandler is not NULL, and a handler
+                                 for InterruptType was previously installed.
+  @retval EFI_INVALID_PARAMETER  InterruptHandler is NULL, and a handler for
+                                 InterruptType was not previously installed.
+  @retval EFI_UNSUPPORTED        The interrupt specified by InterruptType
+                                 is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+  IN EFI_CPU_ARCH_PROTOCOL      *This,
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  );
+
+/**
+  Returns a timer value from one of the CPU's internal timers. There is no
+  inherent time interval between ticks but is a function of the CPU frequency.
+
+  @param  This                - Protocol instance structure.
+  @param  TimerIndex          - Specifies which CPU timer is requested.
+  @param  TimerValue          - Pointer to the returned timer value.
+  @param  TimerPeriod         - A pointer to the amount of time that passes
+                                in femtoseconds (10-15) for each increment
+                                of TimerValue. If TimerValue does not
+                                increment at a predictable rate, then 0 is
+                                returned.  The amount of time that has
+                                passed between two calls to GetTimerValue()
+                                can be calculated with the formula
+                                (TimerValue2 - TimerValue1) * TimerPeriod.
+                                This parameter is optional and may be NULL.
+
+  @retval EFI_SUCCESS           - If the CPU timer count was returned.
+  @retval EFI_UNSUPPORTED       - If the CPU does not have any readable timers.
+  @retval EFI_DEVICE_ERROR      - If an error occurred while reading the timer.
+  @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  IN  UINT32                 TimerIndex,
+  OUT UINT64                 *TimerValue,
+  OUT UINT64                 *TimerPeriod   OPTIONAL
+  );
+
+/**
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+                           when a processor interrupt occurs. If this parameter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  );
+
+/**
+  This function modifies the attributes for the memory region specified by BaseAddress and
+  Length from their current attributes to the attributes specified by Attributes.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  BaseAddress      The physical address that is the start address of a memory region.
+  @param  Length           The size in bytes of the memory region.
+  @param  Attributes       The bit mask of attributes to set for the memory region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+                                The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   BaseAddress,
+  IN UINT64                 Length,
+  IN UINT64                 Attributes
+  );
+
+/**
+  Initialize interrupt handling for DXE phase.
+
+  @param  Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
+
+  @return VOID.
+
+**/
+VOID
+InitializeExceptions (
+  IN EFI_CPU_ARCH_PROTOCOL  *gCpu
+  );
+
+/**
+  Converts EFI Attributes to corresponding architecture Attributes.
+
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  Corresponding architecture attributes.
+**/
+UINTN
+EFIAPI
+EfiAttributeConverse (
+  IN UINTN  EfiAttributes
+  );
+
+#endif // CPU_DXE_H_
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c b/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
new file mode 100644
index 0000000000..3325914e53
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
@@ -0,0 +1,544 @@
+/** @file
+  CPU DXE Module to produce CPU MP Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+
+EFI_HANDLE  mMpServiceHandle    = NULL;
+UINTN       mNumberOfProcessors = 1;
+
+EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate = {
+  GetNumberOfProcessors,
+  GetProcessorInfo,
+  StartupAllAPs,
+  StartupThisAP,
+  SwitchBSP,
+  EnableDisableAP,
+  WhoAmI
+};
+
+/**
+  This service retrieves the number of logical processor in the platform
+  and the number of those logical processors that are enabled on this boot.
+  This service may only be called from the BSP.
+
+  This function is used to retrieve the following information:
+    - The number of logical processors that are present in the system.
+    - The number of enabled logical processors in the system at the instant
+      this call is made.
+
+  Because MP Service Protocol provides services to enable and disable processors
+  dynamically, the number of enabled logical processors may vary during the
+  course of a boot session.
+
+  If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+  If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+  EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+  is returned in NumberOfProcessors, the number of currently enabled processor
+  is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+  @param[in]  This                        A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                          instance.
+  @param[out] NumberOfProcessors          Pointer to the total number of logical
+                                          processors in the system, including the BSP
+                                          and disabled APs.
+  @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled logical
+                                          processors that exist in system, including
+                                          the BSP.
+
+  @retval EFI_SUCCESS             The number of logical processors and enabled
+                                  logical processors was retrieved.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL.
+  @retval EFI_INVALID_PARAMETER   NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  OUT UINTN                     *NumberOfProcessors,
+  OUT UINTN                     *NumberOfEnabledProcessors
+  )
+{
+  if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return MpInitLibGetNumberOfProcessors (
+           NumberOfProcessors,
+           NumberOfEnabledProcessors
+           );
+}
+
+/**
+  Gets detailed MP-related information on the requested processor at the
+  instant this call is made. This service may only be called from the BSP.
+
+  This service retrieves detailed MP-related information about any processor
+  on the platform. Note the following:
+    - The processor information may change during the course of a boot session.
+    - The information presented here is entirely MP related.
+
+  Information regarding the number of caches and their sizes, frequency of operation,
+  slot numbers is all considered platform-related information and is not provided
+  by this service.
+
+  @param[in]  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                    instance.
+  @param[in]  ProcessorNumber       The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
+                                    the requested processor is deposited.
+
+  @retval EFI_SUCCESS             Processor information was returned.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+  IN  EFI_MP_SERVICES_PROTOCOL   *This,
+  IN  UINTN                      ProcessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer
+  )
+{
+  return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
+}
+
+/**
+  This service executes a caller provided function on all enabled APs. APs can
+  run either simultaneously or one at a time in sequence. This service supports
+  both blocking and non-blocking requests. The non-blocking requests use EFI
+  events so the BSP can detect when the APs have finished. This service may only
+  be called from the BSP.
+
+  This function is used to dispatch all the enabled APs to the function specified
+  by Procedure.  If any enabled AP is busy, then EFI_NOT_READY is returned
+  immediately and Procedure is not started on any AP.
+
+  If SingleThread is TRUE, all the enabled APs execute the function specified by
+  Procedure one by one, in ascending order of processor handle number. Otherwise,
+  all the enabled APs execute the function specified by Procedure simultaneously.
+
+  If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
+  APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
+  mode, and the BSP returns from this service without waiting for APs. If a
+  non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+  is signaled, then EFI_UNSUPPORTED must be returned.
+
+  If the timeout specified by TimeoutInMicroseconds expires before all APs return
+  from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+  are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+  and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
+  content points to the list of processor handle numbers in which Procedure was
+  terminated.
+
+  Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+  to make sure that the nature of the code that is executed on the BSP and the
+  dispatched APs is well controlled. The MP Services Protocol does not guarantee
+  that the Procedure function is MP-safe. Hence, the tasks that can be run in
+  parallel are limited to certain independent tasks and well-controlled exclusive
+  code. EFI services and protocols may not be called by APs unless otherwise
+  specified.
+
+  In blocking execution mode, BSP waits until all APs finish or
+  TimeoutInMicroseconds expires.
+
+  In non-blocking execution mode, BSP is freed to return to the caller and then
+  proceed to the next task without having to wait for APs. The following
+  sequence needs to occur in a non-blocking execution mode:
+
+    -# The caller that intends to use this MP Services Protocol in non-blocking
+       mode creates WaitEvent by calling the EFI CreateEvent() service.  The caller
+       invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
+       is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
+       the function specified by Procedure to be started on all the enabled APs,
+       and releases the BSP to continue with other tasks.
+    -# The caller can use the CheckEvent() and WaitForEvent() services to check
+       the state of the WaitEvent created in step 1.
+    -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
+       Service signals WaitEvent by calling the EFI SignalEvent() function. If
+       FailedCpuList is not NULL, its content is available when WaitEvent is
+       signaled. If all APs returned from Procedure prior to the timeout, then
+       FailedCpuList is set to NULL. If not all APs return from Procedure before
+       the timeout, then FailedCpuList is filled in with the list of the failed
+       APs. The buffer is allocated by MP Service Protocol using AllocatePool().
+       It is the caller's responsibility to free the buffer with FreePool() service.
+    -# This invocation of SignalEvent() function informs the caller that invoked
+       EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
+       the specified task or a timeout occurred. The contents of FailedCpuList
+       can be examined to determine which APs did not complete the specified task
+       prior to the timeout.
+
+  @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                      instance.
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  SingleThread            If TRUE, then all the enabled APs execute
+                                      the function specified by Procedure one by
+                                      one, in ascending order of processor handle
+                                      number.  If FALSE, then all the enabled APs
+                                      execute the function specified by Procedure
+                                      simultaneously.
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until all APs finish
+                                      or TimeoutInMicroseconds expires.  If it's
+                                      not NULL, then execute in non-blocking mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on all the enabled
+                                      APs, and go on executing immediately. If
+                                      all return from Procedure, or TimeoutInMicroseconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or WaitForEvent()
+                                      services to check the state of event.  Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      all APs return from Procedure, then Procedure
+                                      on the failed APs is terminated. All enabled
+                                      APs are available for next function assigned
+                                      by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+                                      or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] FailedCpuList           If NULL, this parameter is ignored. Otherwise,
+                                      if all APs finish successfully, then its
+                                      content is set to NULL. If not all APs
+                                      finish before timeout expires, then its
+                                      content is set to address of the buffer
+                                      holding handle numbers of the failed APs.
+                                      The buffer is allocated by MP Service Protocol,
+                                      and it's the caller's responsibility to
+                                      free the buffer with FreePool() service.
+                                      In blocking mode, it is ready for consumption
+                                      when the call returns. In non-blocking mode,
+                                      it is ready when WaitEvent is signaled.  The
+                                      list of failed CPU is terminated by
+                                      END_OF_CPU_LIST.
+
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished before
+                                  the timeout expired.
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
+                                  to all enabled APs.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_DEVICE_ERROR        Caller processor is AP.
+  @retval EFI_NOT_STARTED         No enabled APs exist in the system.
+  @retval EFI_NOT_READY           Any enabled APs are busy.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  all enabled APs have finished.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  EFI_AP_PROCEDURE          Procedure,
+  IN  BOOLEAN                   SingleThread,
+  IN  EFI_EVENT                 WaitEvent               OPTIONAL,
+  IN  UINTN                     TimeoutInMicroseconds,
+  IN  VOID                      *ProcedureArgument      OPTIONAL,
+  OUT UINTN                     **FailedCpuList         OPTIONAL
+  )
+{
+  return MpInitLibStartupAllAPs (
+           Procedure,
+           SingleThread,
+           WaitEvent,
+           TimeoutInMicroseconds,
+           ProcedureArgument,
+           FailedCpuList
+           );
+}
+
+/**
+  This service lets the caller get one enabled AP to execute a caller-provided
+  function. The caller can request the BSP to either wait for the completion
+  of the AP or just proceed with the next task by using the EFI event mechanism.
+  See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+  execution support.  This service may only be called from the BSP.
+
+  This function is used to dispatch one enabled AP to the function specified by
+  Procedure passing in the argument specified by ProcedureArgument.  If WaitEvent
+  is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
+  TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
+  BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
+  is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
+  then EFI_UNSUPPORTED must be returned.
+
+  If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+  from Procedure, then execution of Procedure by the AP is terminated. The AP is
+  available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+  EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+  @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                      instance.
+  @param[in]  Procedure               A pointer to the function to be run on the
+                                      designated AP of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber         The handle number of the AP. The range is
+                                      from 0 to the total number of logical
+                                      processors minus 1. The total number of
+                                      logical processors can be retrieved by
+                                      EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until this AP finish
+                                      or TimeoutInMicroSeconds expires.  If it's
+                                      not NULL, then execute in non-blocking mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on this AP,
+                                      and go on executing immediately. If this AP
+                                      return from Procedure or TimeoutInMicroSeconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or WaitForEvent()
+                                      services to check the state of event.  Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      this AP to finish this Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      this AP returns from Procedure, then Procedure
+                                      on the AP is terminated. The
+                                      AP is available for next function assigned
+                                      by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+                                      or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure on the
+                                      specified AP.
+  @param[out] Finished                If NULL, this parameter is ignored.  In
+                                      blocking mode, this parameter is ignored.
+                                      In non-blocking mode, if AP returns from
+                                      Procedure before the timeout expires, its
+                                      content is set to TRUE. Otherwise, the
+                                      value is set to FALSE. The caller can
+                                      determine if the AP returned from Procedure
+                                      by evaluating this value.
+
+  @retval EFI_SUCCESS             In blocking mode, specified AP finished before
+                                  the timeout expires.
+  @retval EFI_SUCCESS             In non-blocking mode, the function has been
+                                  dispatched to specified AP.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  the specified AP has finished.
+  @retval EFI_NOT_READY           The specified AP is busy.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  EFI_AP_PROCEDURE          Procedure,
+  IN  UINTN                     ProcessorNumber,
+  IN  EFI_EVENT                 WaitEvent               OPTIONAL,
+  IN  UINTN                     TimeoutInMicroseconds,
+  IN  VOID                      *ProcedureArgument      OPTIONAL,
+  OUT BOOLEAN                   *Finished               OPTIONAL
+  )
+{
+  return MpInitLibStartupThisAP (
+           Procedure,
+           ProcessorNumber,
+           WaitEvent,
+           TimeoutInMicroseconds,
+           ProcedureArgument,
+           Finished
+           );
+}
+
+/**
+  This service switches the requested AP to be the BSP from that point onward.
+  This service changes the BSP for all purposes.   This call can only be performed
+  by the current BSP.
+
+  This service switches the requested AP to be the BSP from that point onward.
+  This service changes the BSP for all purposes. The new BSP can take over the
+  execution of the old BSP and continue seamlessly from where the old one left
+  off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+  is signaled.
+
+  If the BSP cannot be switched prior to the return from this service, then
+  EFI_UNSUPPORTED must be returned.
+
+  @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+  @param[in] ProcessorNumber   The handle number of AP that is to become the new
+                               BSP. The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+  @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
+                               enabled AP. Otherwise, it will be disabled.
+
+  @retval EFI_SUCCESS             BSP successfully switched.
+  @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to
+                                  this service returning.
+  @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or
+                                  a disabled AP.
+  @retval EFI_NOT_READY           The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchBSP (
+  IN EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  UINTN                    ProcessorNumber,
+  IN  BOOLEAN                  EnableOldBSP
+  )
+{
+  return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
+}
+
+/**
+  This service lets the caller enable or disable an AP from this point onward.
+  This service may only be called from the BSP.
+
+  This service allows the caller enable or disable an AP from this point onward.
+  The caller can optionally specify the health status of the AP by Health. If
+  an AP is being disabled, then the state of the disabled AP is implementation
+  dependent. If an AP is enabled, then the implementation must guarantee that a
+  complete initialization sequence is performed on the AP, so the AP is in a state
+  that is compatible with an MP operating system. This service may not be supported
+  after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
+
+  If the enable or disable AP operation cannot be completed prior to the return
+  from this service, then EFI_UNSUPPORTED must be returned.
+
+  @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+  @param[in] ProcessorNumber   The handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+  @param[in] EnableAP          Specifies the new state for the processor for
+                               enabled, FALSE for disabled.
+  @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
+                               the new health status of the AP. This flag
+                               corresponds to StatusFlag defined in
+                               EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+                               the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+                               bits are ignored.  If it is NULL, this parameter
+                               is ignored.
+
+  @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed
+                                  prior to this service returning.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
+                                  does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  UINTN                     ProcessorNumber,
+  IN  BOOLEAN                   EnableAP,
+  IN  UINT32                    *HealthFlag OPTIONAL
+  )
+{
+  return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
+}
+
+/**
+  This return the handle number for the calling processor.  This service may be
+  called from the BSP and APs.
+
+  This service returns the processor handle number for the calling processor.
+  The returned value is in the range from 0 to the total number of logical
+  processors minus 1. The total number of logical processors can be retrieved
+  with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
+  called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+  is returned. Otherwise, the current processors handle number is returned in
+  ProcessorNumber, and EFI_SUCCESS is returned.
+
+  @param[in]  This             A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+  @param[out] ProcessorNumber  Pointer to the handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+  @retval EFI_SUCCESS             The current processor handle number was returned
+                                  in ProcessorNumber.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+  IN EFI_MP_SERVICES_PROTOCOL  *This,
+  OUT UINTN                    *ProcessorNumber
+  )
+{
+  return MpInitLibWhoAmI (ProcessorNumber);
+}
+
+/**
+  Initialize Multi-processor support.
+**/
+VOID
+InitializeMpSupport (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       NumberOfProcessors;
+  UINTN       NumberOfEnabledProcessors;
+
+  //
+  // Wakeup APs to do initialization
+  //
+  Status = MpInitLibInitialize ();
+  ASSERT_EFI_ERROR (Status);
+
+  MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors);
+  mNumberOfProcessors = NumberOfProcessors;
+  DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mMpServiceHandle,
+                  &gEfiMpServiceProtocolGuid,
+                  &mMpServicesTemplate,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+}
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c b/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c
new file mode 100644
index 0000000000..754549cd0e
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c
@@ -0,0 +1,159 @@
+/** @file Exception.c
+
+  CPU DXE Module initialization exception instance.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include <Guid/VectorHandoffTable.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+VOID
+ExceptionEntryStart (
+  VOID
+  );
+
+VOID
+ExceptionEntryEnd (
+  VOID
+  );
+
+/**
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+                           when a processor interrupt occurs. If this parameter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, InterruptHandler);
+}
+
+/**
+  Update the exception start entry code.
+
+  @retval EFI_SUCCESS           Update the exception start entry code down.
+  @retval EFI_OUT_OF_RESOURCES  The start entry code size out of bounds.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateExceptionStartEntry (
+  VOID
+  )
+{
+  EFI_PHYSICAL_ADDRESS  ExceptionStartEntry;
+  UINTN                 VectorLength;
+  UINTN                 MaxLength;
+  UINTN                 MaxSizeOfVector;
+
+  VectorLength = (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntryStart;
+
+  //
+  // A vector is up to 512 bytes.
+  //
+  MaxSizeOfVector = 512;
+  MaxLength       = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * MaxSizeOfVector;
+
+  if (VectorLength > MaxLength) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ExceptionStartEntry = PcdGet64 (PcdLoongArchExceptionVectorBaseAddress);
+
+  InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength);
+  CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, VectorLength);
+  InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength);
+  InvalidateDataCache ();
+
+  //
+  // If PcdLoongArchExceptionVectorBaseAddress is not used during SEC and PEI stages, the exception
+  // base addres is set to PcdLoongArchExceptionVectorBaseAddress.
+  //
+  if (CsrRead (LOONGARCH_CSR_EBASE) != ExceptionStartEntry) {
+    SetExceptionBaseAddress (ExceptionStartEntry);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize interrupt handling for DXE phase.
+
+  @param  Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
+
+  @return VOID.
+
+**/
+VOID
+InitializeExceptions (
+  IN EFI_CPU_ARCH_PROTOCOL  *Cpu
+  )
+{
+  EFI_STATUS               Status;
+  EFI_VECTOR_HANDOFF_INFO  *VectorInfoList;
+  EFI_VECTOR_HANDOFF_INFO  *VectorInfo;
+  BOOLEAN                  IrqEnabled;
+
+  VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL;
+  Status     = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
+
+  if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) {
+    VectorInfo = VectorInfoList;
+  }
+
+  //
+  // Disable interrupts
+  //
+  Cpu->GetInterruptState (Cpu, &IrqEnabled);
+  if (IrqEnabled) {
+    Cpu->DisableInterrupt (Cpu);
+  }
+
+  //
+  // Update the Exception Start Entry code to point into CpuDxe.
+  //
+  Status = UpdateExceptionStartEntry ();
+  if (EFI_ERROR (Status)) {
+    DebugPrint (EFI_D_ERROR, "[%a]: Exception start entry code out of bounds!\n", __func__);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  //
+  // Intialize the CpuExceptionHandlerLib so we take over the exception vector table from the DXE Core
+  //
+  Status = InitializeCpuExceptionHandlers (VectorInfo);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Enable interrupts
+  //
+  DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled = %x\n", IrqEnabled);
+  if (!IrqEnabled) {
+    Status = Cpu->EnableInterrupt (Cpu);
+  }
+
+  ASSERT_EFI_ERROR (Status);
+}
-- 
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117659): https://edk2.groups.io/g/devel/message/117659
Mute This Topic: https://groups.io/mt/105478503/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [edk2-devel] [PATCH v3 13/13] UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (11 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 12/13] UefiCpuPkg: Add CpuDxe driver " Chao Li
@ 2024-04-12  7:34 ` Chao Li
  2024-04-15  2:14   ` Ni, Ray
  2024-04-15  2:15 ` [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Ni, Ray
  13 siblings, 1 reply; 22+ messages in thread
From: Chao Li @ 2024-04-12  7:34 UTC (permalink / raw)
  To: devel; +Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann

LoongArch64 requires CpuMmio2Dxe, add it into LoongArch64 field.

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>
---
 UefiCpuPkg/UefiCpuPkg.dsc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index e92ceb6466..1af5a0c525 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -213,6 +213,7 @@ [Components.RISCV64]
 
 [Components.LOONGARCH64]
   UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
+  UefiCpuPkg/CpuMmio2Dxe/CpuMmio2Dxe.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 (#117660): https://edk2.groups.io/g/devel/message/117660
Mute This Topic: https://groups.io/mt/105478504/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [edk2-devel] [PATCH v3 10/13] UefiCpuPkg: Add a new GUID to store the processors resource
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 10/13] UefiCpuPkg: Add a new GUID to store the processors resource Chao Li
@ 2024-04-15  2:10   ` Ni, Ray
  2024-04-16  1:50     ` Chao Li
  0 siblings, 1 reply; 22+ messages in thread
From: Ni, Ray @ 2024-04-15  2:10 UTC (permalink / raw)
  To: Chao Li, devel@edk2.groups.io; +Cc: Kumar, Rahul R, Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 658 bytes --]


+
+typedef struct {
+  UINT32    NumberOfProcessor;
+  UINTN     *ApicId;

[Ray] How about "UINTN  ApicId[]"? The difference between the two is your version contains an 8-byte pointer pointing to somewhere else. My version implies the APIC ID array is just after "NumberOfProcessor".


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117738): https://edk2.groups.io/g/devel/message/117738
Mute This Topic: https://groups.io/mt/105478501/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 1912 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [edk2-devel] [PATCH v3 07/13] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 07/13] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
@ 2024-04-15  2:10   ` Ni, Ray
  0 siblings, 0 replies; 22+ messages in thread
From: Ni, Ray @ 2024-04-15  2:10 UTC (permalink / raw)
  To: Chao Li, devel@edk2.groups.io
  Cc: Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm, Ard Biesheuvel,
	Sami Mujawar, Sunil V L, Warkentin, Andrei

[-- Attachment #1: Type: text/plain, Size: 4387 bytes --]

Reviewed-by: Ray Ni <ray.ni@intel.com>

Thanks,
Ray
________________________________
From: Chao Li <lichao@loongson.cn>
Sent: Friday, April 12, 2024 15:34
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Ni, Ray <ray.ni@intel.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Leif Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>; Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei <andrei.warkentin@intel.com>
Subject: [PATCH v3 07/13] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg

Add a new header file CpuMmuLib.h, whitch is referenced from
ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
LoongArch64 is added, and more architectures can be accommodated in the
future.

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>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Andrei Warkentin <andrei.warkentin@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Include/Library/CpuMmuLib.h | 41 ++++++++++++++++++++++++++
 UefiCpuPkg/UefiCpuPkg.dec              |  4 +++
 2 files changed, 45 insertions(+)
 create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h

diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h b/UefiCpuPkg/Include/Library/CpuMmuLib.h
new file mode 100644
index 0000000000..e6cfbd5168
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
@@ -0,0 +1,41 @@
+/** @file
+
+  Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_MMU_LIB_H_
+#define CPU_MMU_LIB_H_
+
+#include <Uefi/UefiBaseType.h>
+
+/**
+  Maps the memory region in the page table to the specified attributes.
+
+  @param[in, out] PageTable      The pointer to the page table to update, or pointer to NULL
+                                 if a new page table is to be created.
+  @param[in]      PageWalkCfg    The page walk controller configure.
+  @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 bitmask of attributes to set, which refer to UEFI SPEC
+                                 7.2.3(EFI_BOOT_SERVICES.GetMemoryMap()).
+  @param[in]      AttributeMask  Mask of memory attributes to take into account.
+
+  @retval EFI_SUCCESS            The Attributes was set successfully or Length is 0.
+  @retval EFI_INVALID_PARAMETER  PageTable is NULL.
+  @retval EFI_UNSUPPORTED        *PageTable is NULL.
+**/
+EFI_STATUS
+EFIAPI
+MemoryRegionMap (
+  IN OUT UINTN                 *PageTable  OPTIONAL,
+  IN     UINT64                PageWalkCfg,
+  IN     EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN     UINT64                Length,
+  IN     UINT64                Attributes,
+  IN     UINT64                AttributeMask
+  );
+
+#endif // CPU_MMU_LIB_H_
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 571b59b36f..ca744fab55 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -72,6 +72,10 @@ [LibraryClasses.RISCV64]
   ##
   RiscVMmuLib|Include/Library/BaseRiscVMmuLib.h

+[LibraryClasses.LoongArch64]
+  ##  @libraryclass  Provides functions for the memory management unit.
+  CpuMmuLib|Include/Library/CpuMmuLib.h
+
 [Guids]
   gUefiCpuPkgTokenSpaceGuid      = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }}
   gMsegSmramGuid                 = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }}
--
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117739): https://edk2.groups.io/g/devel/message/117739
Mute This Topic: https://groups.io/mt/105478496/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 8153 bytes --]

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [edk2-devel] [PATCH v3 08/13] UefiCpuPkg: Added a new PCD named PcdLoongArchExceptionVectorBaseAddress
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 08/13] UefiCpuPkg: Added a new PCD named PcdLoongArchExceptionVectorBaseAddress Chao Li
@ 2024-04-15  2:10   ` Ni, Ray
  0 siblings, 0 replies; 22+ messages in thread
From: Ni, Ray @ 2024-04-15  2:10 UTC (permalink / raw)
  To: Chao Li, devel@edk2.groups.io; +Cc: Kumar, Rahul R, Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 2504 bytes --]

Reviewed-by: Ray Ni <ray.ni@intel.com>

Thanks,
Ray
________________________________
From: Chao Li <lichao@loongson.cn>
Sent: Friday, April 12, 2024 15:34
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Ni, Ray <ray.ni@intel.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>
Subject: [PATCH v3 08/13] UefiCpuPkg: Added a new PCD named PcdLoongArchExceptionVectorBaseAddress

Added PcdLoongArchExceptionVectorBaseAddress use for storing the CPU
exception vector base address. This PCD can be populated at build time
or changed at runtime, and is used only by LoongArch.

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/UefiCpuPkg.dec | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index ca744fab55..1b890e975c 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -3,6 +3,7 @@
 #
 # Copyright (c) 2007 - 2023, Intel Corporation. All rights reserved.<BR>
 # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -414,6 +415,11 @@ [PcdsFixedAtBuild.RISCV64]
   #  10 - 57bit mode.
   gUefiCpuPkgTokenSpaceGuid.PcdCpuRiscVMmuMaxSatpMode|10|UINT32|0x60000021

+[PcdsFixedAtBuild.LOONGARCH64, PcdsPatchableInModule.LOONGARCH64, PcdsDynamic.LOONGARCH64, PcdsDynamicEx.LOONGARCH64]
+  ## This PCD Contains the pointer to a CPU exception vector base address.
+  # @Prompt The pointer to a CPU exception vector base address.
+  gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress|0x0|UINT64|0x60000022
+
 [PcdsDynamic, PcdsDynamicEx]
   ## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA.
   # @Prompt The pointer to a CPU S3 data buffer.
--
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117740): https://edk2.groups.io/g/devel/message/117740
Mute This Topic: https://groups.io/mt/105478499/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 4630 bytes --]

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [edk2-devel] [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg Chao Li
@ 2024-04-15  2:11   ` Ni, Ray
  0 siblings, 0 replies; 22+ messages in thread
From: Ni, Ray @ 2024-04-15  2:11 UTC (permalink / raw)
  To: Chao Li, devel@edk2.groups.io
  Cc: Kumar, Rahul R, Gerd Hoffmann, Baoqi Zhang, Dongyan Qian,
	Xianglai Li, Bibo Mao

[-- Attachment #1: Type: text/plain, Size: 32309 bytes --]

Acked-by: Ray Ni <ray.ni@intel.com>

Thanks,
Ray
________________________________
From: Chao Li <lichao@loongson.cn>
Sent: Friday, April 12, 2024 15:34
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Ni, Ray <ray.ni@intel.com>; Kumar, Rahul R <rahul.r.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: [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf    |  39 +
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni    |  14 +
 .../Library/CpuMmuLib/LoongArch64/CpuMmu.c    | 785 ++++++++++++++++++
 .../Library/CpuMmuLib/LoongArch64/Page.h      |  33 +
 .../LoongArch64/TlbExceptionHandle.S          |  51 ++
 .../LoongArch64/TlbExceptionHandle.h          |  36 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.S        |  24 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.h        |  24 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |   3 +
 9 files changed, 1009 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/TlbExceptionHandle.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.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..5eecfb4838
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
@@ -0,0 +1,39 @@
+## @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/TlbExceptionHandle.S | GCC
+  LoongArch64/CpuMmu.c
+  LoongArch64/Page.h
+  LoongArch64/TlbInvalid.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  MemoryAllocationLib
+
+[Pcd.LoongArch64]
+  gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress      ## CONSUMES
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..6d77a1221f
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/CpuMmu.c
@@ -0,0 +1,785 @@
+/** @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/CacheMaintenanceLib.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/DebugSupport.h>
+#include <Register/LoongArch64/Csr.h>
+#include "TlbInvalid.h"
+#include "TlbExceptionHandle.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;
+}
+
+/**
+  Parse max page table level.
+
+  @param[in]  PageWalkCfg  Page table configure value.
+
+  @return         5   MAX page level is 5
+                  4   MAX page level is 4
+                  3   MAX page level is 3
+                  0   Invalid
+**/
+STATIC
+UINTN
+ParseMaxPageTableLevel (
+  IN  UINT64  PageWalkCfg
+  )
+{
+  UINT32  Pwctl0;
+  UINT32  Pwctl1;
+
+  Pwctl0 = PageWalkCfg & MAX_UINT32;
+  Pwctl1 = (PageWalkCfg >> 32) & MAX_UINT32;
+
+  if (((Pwctl1 >> 18) & 0x3F) != 0x0) {
+    return LEVEL5;
+  } else if (((Pwctl1 >> 6) & 0x3F) != 0x0) {
+    return LEVEL4;
+  } else if (((Pwctl0 >> 25) & 0x3F) != 0x0) {
+    return LEVEL3;
+  }
+
+  return 0;
+}
+
+/**
+  Parse page table bit width.
+
+  Assume that the bit width of the page table that each level is the same to PTwidth.
+
+  @param[in]  PageWalkCfg  Page table configure value.
+
+  @return         page table bit width
+
+**/
+STATIC
+UINTN
+ParsePageTableBitWidth (
+  IN  UINT64  PageWalkCfg
+  )
+{
+  //
+  // PTwidth
+  //
+  return ((PageWalkCfg >> 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.
+  @param    PageWalkCfg  Page table configure value.
+
+  @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,
+  IN  UINT64  PageWalkCfg
+  )
+{
+  if (Level == (ParseMaxPageTableLevel (PageWalkCfg) - 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.
+  @param    PageWalkCfg  Page table configure value.
+
+  @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,
+  IN  UINT64  PageWalkCfg
+  )
+{
+  if (Level == (ParseMaxPageTableLevel (PageWalkCfg) - 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  PageWalkCfg       Page table configure value.
+  @param  Level             The current level.
+
+**/
+STATIC
+VOID
+FreePageTablesRecursive (
+  IN  UINTN   *TranslationTable,
+  IN  UINT64  PageWalkCfg,
+  IN  UINTN   Level
+  )
+{
+  UINTN  Index;
+  UINTN  TableEntryNum;
+
+  TableEntryNum = (1 << ParsePageTableBitWidth (PageWalkCfg));
+
+  if (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 1)) {
+    for (Index = 0; Index < TableEntryNum; Index++) {
+      if (IsTableEntry (TranslationTable[Index], Level, PageWalkCfg)) {
+        FreePageTablesRecursive (
+          (UINTN *)(GetPpnfromPte ((TranslationTable[Index])) <<
+                    LOONGARCH_MMU_PAGE_SHIFT),
+          PageWalkCfg,
+          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  PageWalkCfg           Page table configure value.
+  @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  UINT64   PageWalkCfg,
+  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 < ParseMaxPageTableLevel (PageWalkCfg));
+  ASSERT (((RegionStart | RegionEnd) & EFI_PAGE_MASK) == 0);
+
+  TableBitWidth = ParsePageTableBitWidth (PageWalkCfg);
+  BlockShift    = (ParseMaxPageTableLevel (PageWalkCfg) - 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, PageWalkCfg))
+    {
+      ASSERT (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 1));
+      if (!IsTableEntry (*Entry, Level, PageWalkCfg)) {
+        //
+        // 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, PageWalkCfg)) {
+          //
+          // 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,
+                     PageWalkCfg,
+                     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,
+                 PageWalkCfg,
+                 NextTableIsLive
+                 );
+      if (EFI_ERROR (Status)) {
+        if (!IsTableEntry (*Entry, Level, PageWalkCfg)) {
+          //
+          // 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, PageWalkCfg, Level + 1);
+        }
+
+        return Status;
+      }
+
+      if (!IsTableEntry (*Entry, Level, PageWalkCfg)) {
+        EntryValue = SetPpnToPte (0, (UINTN)TranslationTable);
+        ReplaceTableEntry (
+          Entry,
+          EntryValue,
+          RegionStart,
+          TableIsLive
+          );
+      }
+    } else {
+      EntryValue = (*Entry & ~AttributeClearMask) | AttributeSetMask;
+
+      EntryValue = SetPpnToPte (EntryValue, RegionStart);
+      EntryValue = SetValidPte (EntryValue);
+
+      if (Level < (ParseMaxPageTableLevel (PageWalkCfg) - 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  PageWalkCfg           Page table configure value.
+  @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  UINT64   PageWalkCfg,
+  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,
+           PageWalkCfg,
+           TableIsLive
+           );
+}
+
+/**
+  Convert EFI Attributes to Loongarch Attributes.
+
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  Corresponding architecture attributes.
+**/
+UINT64
+EFIAPI
+EfiAttributeConverse (
+  IN UINT64  EfiAttributes
+  )
+{
+  UINT64  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:
+      LoongArchAttributes |= CACHE_CC;
+      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;
+}
+
+/**
+  TLB refill handler configure.
+
+  @param  VOID.
+
+  @retval  EFI_SUCCESS      TLB refill handler configure successfully.
+           EFI_UNSUPPORTED  Size not aligned.
+**/
+EFI_STATUS
+TlbRefillHandlerConfigure (
+  VOID
+  )
+{
+  UINTN  Length;
+  UINTN  TlbReEntry;
+  UINTN  TlbReEntryOffset;
+  UINTN  Remaining;
+
+  //
+  // 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 (PcdLoongArchExceptionVectorBaseAddress) + TlbReEntryOffset;
+  if ((TlbReEntryOffset + Length) > SIZE_64KB) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Ensure that TLB refill exception base address alignment is equals to 4KB and is valid.
+  //
+  if (TlbReEntry & (SIZE_4KB - 1)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
+  InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length);
+
+  //
+  // Set the address of TLB refill exception handler
+  //
+  SetTlbRebaseAddress ((UINTN)TlbReEntry);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Maps the memory region in the page table to the specified attributes.
+
+  @param[in, out] PageTable      The pointer to the page table to update, or pointer to NULL
+                                 if a new page table is to be created.
+  @param[in]      PageWalkCfg    The page walk controller configure.
+  @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 bitmask of attributes to set, which refer to UEFI SPEC
+                                 7.2.3(EFI_BOOT_SERVICES.GetMemoryMap()).
+  @param[in]      AttributeMask  Mask of memory attributes to take into account.
+
+  @retval EFI_SUCCESS            The Attributes was set successfully or Length is 0.
+  @retval EFI_INVALID_PARAMETER  PageTable is NULL, PageWalkCfg is invalid.
+  @retval EFI_UNSUPPORTED        *PageTable is NULL.
+**/
+EFI_STATUS
+EFIAPI
+MemoryRegionMap (
+  IN OUT UINTN                 *PageTable  OPTIONAL,
+  IN     UINT64                PageWalkCfg,
+  IN     EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN     UINT64                Length,
+  IN     UINT64                Attributes,
+  IN     UINT64                AttributeMask
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      LoongArchAttributes;
+  BOOLEAN     Initialization;
+  BOOLEAN     CreateNew;
+  UINTN       PageTableBitWidth;
+  UINTN       MaxLevel;
+  UINTN       PgdSize;
+
+  if ((PageTable == NULL) || (PageWalkCfg == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PageTableBitWidth = ParsePageTableBitWidth (PageWalkCfg);
+  MaxLevel          = ParseMaxPageTableLevel (PageWalkCfg);
+
+  if ((!PageTableBitWidth && !MaxLevel) || (PageTableBitWidth > 0x1F) || (MaxLevel > LEVEL5)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Initialization = FALSE;
+  CreateNew      = FALSE;
+
+  //
+  // *PageTable is NULL, create a new and return.
+  //
+  if (*PageTable == 0) {
+    CreateNew = TRUE;
+    //
+    // If the MMU has not been configured yet, configure it later.
+    //
+    if (!MmuIsInit ()) {
+      Initialization = TRUE;
+    }
+  }
+
+  if (Length == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (Initialization == TRUE) {
+    Status = TlbRefillHandlerConfigure ();
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  if (CreateNew == TRUE) {
+    //
+    // Create a new page table.
+    //
+    PgdSize    =  (1 << PageTableBitWidth) * sizeof (UINTN);
+    *PageTable = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PgdSize));
+    ZeroMem ((VOID *)*PageTable, PgdSize);
+
+    if ((VOID *)*PageTable == NULL) {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  LoongArchAttributes = EfiAttributeConverse (Attributes);
+
+  //
+  // Update the page table attributes.
+  //
+  // If the MMU has been configured and *PageTable == CSR_PGDL, the page table in use will update.
+  //
+  // If *PageTable != CSR_PGDL, only the page table structure in memory is update, but some TLB
+  // region may be invalidated during the mapping process. So at this time the caller must ensure
+  // that the execution environment must be safe. It is recommended to use the DA mode!
+  //
+  Status = UpdateRegionMapping (
+             BaseAddress,
+             Length,
+             PageWalkCfg,
+             LoongArchAttributes,
+             PTE_ATTRIBUTES_MASK,
+             (UINTN *)(*PageTable),
+             (MmuIsEnabled () && !CreateNew)
+             );
+
+  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..b115245d68
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/Page.h
@@ -0,0 +1,33 @@
+/** @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 LEVEL2  2
+#define LEVEL1  1
+
+#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
+
+//
+// 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
+
+#endif // PAGE_H_
diff --git a/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.S
new file mode 100644
index 0000000000..4395b574f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/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/CpuMmuLib/LoongArch64/TlbExceptionHandle.h b/UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h
new file mode 100644
index 0000000000..c164db567d
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuMmuLib/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/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 (#117741): https://edk2.groups.io/g/devel/message/117741
Mute This Topic: https://groups.io/mt/105478500/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 54836 bytes --]

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [edk2-devel] [PATCH v3 12/13] UefiCpuPkg: Add CpuDxe driver for LoongArch64
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 12/13] UefiCpuPkg: Add CpuDxe driver " Chao Li
@ 2024-04-15  2:12   ` Ni, Ray
  0 siblings, 0 replies; 22+ messages in thread
From: Ni, Ray @ 2024-04-15  2:12 UTC (permalink / raw)
  To: Chao Li, devel@edk2.groups.io
  Cc: Kumar, Rahul R, Gerd Hoffmann, Baoqi Zhang, Dongyan Qian

[-- Attachment #1: Type: text/plain, Size: 65848 bytes --]

Acked-by: Ray Ni <ray.ni@intel.com>

Thanks,
Ray
________________________________
From: Chao Li <lichao@loongson.cn>
Sent: Friday, April 12, 2024 15:34
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Ni, Ray <ray.ni@intel.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Baoqi Zhang <zhangbaoqi@loongson.cn>; Dongyan Qian <qiandongyan@loongson.cn>
Subject: [PATCH v3 12/13] UefiCpuPkg: Add CpuDxe driver for LoongArch64

Added LoongArch64 CPU driver into CpuDxe.

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
---
 UefiCpuPkg/CpuDxe/CpuDxe.inf              |  25 +-
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c    | 439 +++++++++++++++++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h    | 288 ++++++++++++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c     | 544 ++++++++++++++++++++++
 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c | 159 +++++++
 5 files changed, 1451 insertions(+), 4 deletions(-)
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c

diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
index 9e1c673283..fca74c44b3 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
@@ -3,6 +3,7 @@
 #
 #  Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
 #  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -22,7 +23,7 @@ [Packages]
   MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec

-[LibraryClasses]
+[LibraryClasses.common]
   BaseLib
   BaseMemoryLib
   CpuExceptionHandlerLib
@@ -30,9 +31,7 @@ [LibraryClasses]
   DebugLib
   DxeServicesTableLib
   HobLib
-  LocalApicLib
   MemoryAllocationLib
-  MtrrLib
   MpInitLib
   PeCoffGetEntryPointLib
   ReportStatusCodeLib
@@ -41,7 +40,15 @@ [LibraryClasses]
   UefiDriverEntryPoint
   UefiLib

-[Sources]
+[LibraryClasses.IA32, LibraryClasses.X64]
+  LocalApicLib
+  MtrrLib
+
+[LibraryClasses.LoongArch64]
+  CacheMaintenanceLib
+  CpuMmuLib
+
+[Sources.IA32, Sources.X64]
   CpuDxe.c
   CpuDxe.h
   CpuGdt.c
@@ -59,6 +66,13 @@ [Sources.X64]
   X64/CpuAsm.nasm
   X64/PagingAttribute.c

+[Sources.LoongArch64]
+  CpuMp.h
+  LoongArch64/CpuDxe.c
+  LoongArch64/CpuMp.c
+  LoongArch64/Exception.c
+  LoongArch64/CpuDxe.h
+
 [Protocols]
   gEfiCpuArchProtocolGuid                       ## PRODUCES
   gEfiMpServiceProtocolGuid                     ## PRODUCES
@@ -81,6 +95,9 @@ [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList              ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize                    ## CONSUMES

+[Pcd.LoongArch64]
+  gUefiCpuPkgTokenSpaceGuid.PcdLoongArchExceptionVectorBaseAddress      ## CONSUMES
+
 [Depex]
   TRUE

diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
new file mode 100644
index 0000000000..24b9d51ee7
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
@@ -0,0 +1,439 @@
+/** @file CpuDxe.c
+
+  CPU DXE Module to produce CPU ARCH Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+#include <Guid/IdleLoopEvent.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/TimerLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+UINT64  mTimerPeriod = 0;
+
+/**
+  IPI Interrupt Handler.
+
+  @param InterruptType    The type of interrupt that occurred
+  @param SystemContext    A pointer to the system context when the interrupt occurred
+**/
+VOID
+EFIAPI
+IpiInterruptHandler (
+  IN EFI_EXCEPTION_TYPE  InterruptType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE             mCpuHandle = NULL;
+EFI_CPU_ARCH_PROTOCOL  gCpu       = {
+  CpuFlushCpuDataCache,
+  CpuEnableInterrupt,
+  CpuDisableInterrupt,
+  CpuGetInterruptState,
+  CpuInit,
+  CpuRegisterInterruptHandler,
+  CpuGetTimerValue,
+  CpuSetMemoryAttributes,
+  0,          // NumberOfTimers
+  4,          // DmaBufferAlignment
+};
+
+/**
+  This function flushes the range of addresses from Start to Start+Length
+  from the processor's data cache. If Start is not aligned to a cache line
+  boundary, then the bytes before Start to the preceding cache line boundary
+  are also flushed. If Start+Length is not aligned to a cache line boundary,
+  then the bytes past Start+Length to the end of the next cache line boundary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+  supported. If the data cache is fully coherent with all DMA operations, then
+  this function can just return EFI_SUCCESS. If the processor does not support
+  flushing a range of the data cache, then the entire data cache can be flushed.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start            The beginning physical address to flush from the processor's data
+                           cache.
+  @param  Length           The number of bytes to flush from the processor's data cache. This
+                           function may flush more bytes than Length specifies depending upon
+                           the granularity of the flush operation that the processor supports.
+  @param  FlushType        Specifies the type of flush operation to perform.
+
+  @retval EFI_SUCCESS           The address range from Start to Start+Length was flushed from
+                                the processor's data cache.
+  @retval EFI_INVALID_PARAMETER The processor does not support the cache flush type specified
+                                by FlushType.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   Start,
+  IN UINT64                 Length,
+  IN EFI_CPU_FLUSH_TYPE     FlushType
+  )
+{
+  switch (FlushType) {
+    case EfiCpuFlushTypeWriteBack:
+      WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+      break;
+    case EfiCpuFlushTypeInvalidate:
+      InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+      break;
+    case EfiCpuFlushTypeWriteBackInvalidate:
+      WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+      break;
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function enables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are enabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  )
+{
+  EnableInterrupts ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function disables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are disabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  )
+{
+  DisableInterrupts ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function retrieves the processor's current interrupt state a returns it in
+  State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+  are currently disabled, then FALSE is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  State            A pointer to the processor's current interrupt state. Set to TRUE if
+                           interrupts are enabled and FALSE if interrupts are disabled.
+
+  @retval EFI_SUCCESS           The processor's current interrupt state was returned in State.
+  @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  OUT BOOLEAN                *State
+  )
+{
+  if (State == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *State = GetInterruptState ();
+  return EFI_SUCCESS;
+}
+
+/**
+  This function generates an INIT on the processor. If this function succeeds, then the
+  processor will be reset, and control will not be returned to the caller. If InitType is
+  not supported by this processor, or the processor cannot programmatically generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+  occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  InitType         The type of processor INIT to perform.
+
+  @retval EFI_SUCCESS           The processor INIT was performed. This return code should never be seen.
+  @retval EFI_UNSUPPORTED       The processor INIT operation specified by InitType is not supported
+                                by this processor.
+  @retval EFI_DEVICE_ERROR      The processor INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_CPU_INIT_TYPE      InitType
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Registers a function to be called from the CPU interrupt handler.
+
+  @param  This                   Protocol instance structure
+  @param  InterruptType          Defines which interrupt to hook. IA-32
+                                 valid range is 0x00 through 0xFF
+  @param  InterruptHandler       A pointer to a function of type
+                                 EFI_CPU_INTERRUPT_HANDLER that is called
+                                 when a processor interrupt occurs.  A null
+                                 pointer is an error condition.
+
+  @retval EFI_SUCCESS            If handler installed or uninstalled.
+  @retval EFI_ALREADY_STARTED    InterruptHandler is not NULL, and a handler
+                                 for InterruptType was previously installed.
+  @retval EFI_INVALID_PARAMETER  InterruptHandler is NULL, and a handler for
+                                 InterruptType was not previously installed.
+  @retval EFI_UNSUPPORTED        The interrupt specified by InterruptType
+                                 is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+  IN EFI_CPU_ARCH_PROTOCOL      *This,
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  return RegisterInterruptHandler (InterruptType, InterruptHandler);
+}
+
+/**
+  Returns a timer value from one of the CPU's internal timers. There is no
+  inherent time interval between ticks but is a function of the CPU frequency.
+
+  @param  This                - Protocol instance structure.
+  @param  TimerIndex          - Specifies which CPU timer is requested.
+  @param  TimerValue          - Pointer to the returned timer value.
+  @param  TimerPeriod         - A pointer to the amount of time that passes
+                                in femtoseconds (10-15) for each increment
+                                of TimerValue. If TimerValue does not
+                                increment at a predictable rate, then 0 is
+                                returned.  The amount of time that has
+                                passed between two calls to GetTimerValue()
+                                can be calculated with the formula
+                                (TimerValue2 - TimerValue1) * TimerPeriod.
+                                This parameter is optional and may be NULL.
+
+  @retval EFI_SUCCESS           - If the CPU timer count was returned.
+  @retval EFI_UNSUPPORTED       - If the CPU does not have any readable timers.
+  @retval EFI_DEVICE_ERROR      - If an error occurred while reading the timer.
+  @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  IN  UINT32                 TimerIndex,
+  OUT UINT64                 *TimerValue,
+  OUT UINT64                 *TimerPeriod   OPTIONAL
+  )
+{
+  UINT64  BeginValue;
+  UINT64  EndValue;
+
+  if (TimerValue == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (TimerIndex != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *TimerValue = AsmReadStableCounter ();
+
+  if (TimerPeriod != NULL) {
+    if (mTimerPeriod == 0) {
+      //
+      // Read time stamp counter before and after delay of 100 microseconds
+      //
+      BeginValue = AsmReadStableCounter ();
+      MicroSecondDelay (100);
+      EndValue = AsmReadStableCounter ();
+      //
+      // Calculate the actual frequency
+      //
+      mTimerPeriod = DivU64x64Remainder (
+                       MultU64x32 (
+                         1000 * 1000 * 1000,
+                         100
+                         ),
+                       EndValue - BeginValue,
+                       NULL
+                       );
+    }
+
+    *TimerPeriod = mTimerPeriod;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function modifies the attributes for the memory region specified by BaseAddress and
+  Length from their current attributes to the attributes specified by Attributes.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  BaseAddress      The physical address that is the start address of a memory region.
+  @param  Length           The size in bytes of the memory region.
+  @param  EfiAttributes    The bit mask of attributes to set for the memory region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+                                The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   BaseAddress,
+  IN UINT64                 Length,
+  IN UINT64                 EfiAttributes
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       PageTable;
+  UINT64      PageWalkCfg;
+
+  Status      = EFI_SUCCESS;
+  PageTable   = CsrRead (LOONGARCH_CSR_PGDL);
+  PageWalkCfg = ((UINT64)CsrRead (LOONGARCH_CSR_PWCTL1)) << 32 | CsrRead (LOONGARCH_CSR_PWCTL0);
+
+  if ((BaseAddress & (EFI_PAGE_SIZE - 1)) != 0) {
+    //
+    // Minimum granularity is SIZE_4KB.
+    //
+    DEBUG ((
+      DEBUG_INFO,
+      "MemoryRegionMap(%lx, %lx, %lx, %lx, %lx): Minimum granularity is SIZE_4KB\n",
+      &PageTable,
+      PageWalkCfg,
+      BaseAddress,
+      Length,
+      EfiAttributes
+      ));
+
+    Status = EFI_UNSUPPORTED;
+
+    return Status;
+  }
+
+  Status = MemoryRegionMap (
+             &PageTable,
+             PageWalkCfg,
+             BaseAddress,
+             Length,
+             EfiAttributes,
+             0x0
+             );
+
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Callback function for idle events.
+
+  @param  Event                 Event whose notification function is being invoked.
+  @param  Context               The pointer to the notification function's context,
+                                which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+IdleLoopEventCallback (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  CpuSleep ();
+}
+
+/**
+  Initialize the state information for the CPU Architectural Protocol.
+
+  @param ImageHandle     Image handle this driver.
+  @param SystemTable     Pointer to the System Table.
+
+  @retval EFI_SUCCESS           Thread can be successfully created
+  @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure
+  @retval EFI_DEVICE_ERROR      Cannot create the thread
+
+**/
+EFI_STATUS
+InitializeCpu (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   IdleLoopEvent;
+
+  InitializeExceptions (&gCpu);
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mCpuHandle,
+                  &gEfiCpuArchProtocolGuid,
+                  &gCpu,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gCpu.RegisterInterruptHandler (
+                  &gCpu,
+                  EXCEPT_LOONGARCH_INT_IPI,
+                  IpiInterruptHandler
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Setup a callback for idle events
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  IdleLoopEventCallback,
+                  NULL,
+                  &gIdleLoopEventGuid,
+                  &IdleLoopEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  InitializeMpSupport ();
+
+  return Status;
+}
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
new file mode 100644
index 0000000000..8bfbfa3442
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
@@ -0,0 +1,288 @@
+/** @file CpuDxe.c
+
+  CPU DXE Module to produce CPU ARCH Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef CPU_DXE_H_
+#define CPU_DXE_H_
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MpInitLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/DebugImageInfoTable.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/LoadedImage.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
+
+/*
+  This function flushes the range of addresses from Start to Start+Length
+  from the processor's data cache. If Start is not aligned to a cache line
+  boundary, then the bytes before Start to the preceding cache line boundary
+  are also flushed. If Start+Length is not aligned to a cache line boundary,
+  then the bytes past Start+Length to the end of the next cache line boundary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+  supported. If the data cache is fully coherent with all DMA operations, then
+  this function can just return EFI_SUCCESS. If the processor does not support
+  flushing a range of the data cache, then the entire data cache can be flushed.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start            The beginning physical address to flush from the processor's data
+                           cache.
+  @param  Length           The number of bytes to flush from the processor's data cache. This
+                           function may flush more bytes than Length specifies depending upon
+                           the granularity of the flush operation that the processor supports.
+  @param  FlushType        Specifies the type of flush operation to perform.
+
+  @retval EFI_SUCCESS           The address range from Start to Start+Length was flushed from
+                                the processor's data cache.
+  @retval EFI_UNSUPPORTEDT      The processor does not support the cache flush type specified
+                                by FlushType.
+  @retval EFI_DEVICE_ERROR      The address range from Start to Start+Length could not be flushed
+                                from the processor's data cache.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   Start,
+  IN UINT64                 Length,
+  IN EFI_CPU_FLUSH_TYPE     FlushType
+  );
+
+/**
+  This function enables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are enabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  );
+
+/**
+  This function disables interrupt processing by the processor.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS           Interrupts are disabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts could not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  );
+
+/**
+  This function retrieves the processor's current interrupt state a returns it in
+  State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+  are currently disabled, then FALSE is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  State            A pointer to the processor's current interrupt state. Set to TRUE if
+                           interrupts are enabled and FALSE if interrupts are disabled.
+
+  @retval EFI_SUCCESS           The processor's current interrupt state was returned in State.
+  @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  OUT BOOLEAN                *State
+  );
+
+/**
+  This function generates an INIT on the processor. If this function succeeds, then the
+  processor will be reset, and control will not be returned to the caller. If InitType is
+  not supported by this processor, or the processor cannot programmatically generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+  occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  InitType         The type of processor INIT to perform.
+
+  @retval EFI_SUCCESS           The processor INIT was performed. This return code should never be seen.
+  @retval EFI_UNSUPPORTED       The processor INIT operation specified by InitType is not supported
+                                by this processor.
+  @retval EFI_DEVICE_ERROR      The processor INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_CPU_INIT_TYPE      InitType
+  );
+
+/**
+  Registers a function to be called from the CPU interrupt handler.
+
+  @param  This                   Protocol instance structure
+  @param  InterruptType          Defines which interrupt to hook. IA-32
+                                 valid range is 0x00 through 0xFF
+  @param  InterruptHandler       A pointer to a function of type
+                                 EFI_CPU_INTERRUPT_HANDLER that is called
+                                 when a processor interrupt occurs.  A null
+                                 pointer is an error condition.
+
+  @retval EFI_SUCCESS            If handler installed or uninstalled.
+  @retval EFI_ALREADY_STARTED    InterruptHandler is not NULL, and a handler
+                                 for InterruptType was previously installed.
+  @retval EFI_INVALID_PARAMETER  InterruptHandler is NULL, and a handler for
+                                 InterruptType was not previously installed.
+  @retval EFI_UNSUPPORTED        The interrupt specified by InterruptType
+                                 is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+  IN EFI_CPU_ARCH_PROTOCOL      *This,
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  );
+
+/**
+  Returns a timer value from one of the CPU's internal timers. There is no
+  inherent time interval between ticks but is a function of the CPU frequency.
+
+  @param  This                - Protocol instance structure.
+  @param  TimerIndex          - Specifies which CPU timer is requested.
+  @param  TimerValue          - Pointer to the returned timer value.
+  @param  TimerPeriod         - A pointer to the amount of time that passes
+                                in femtoseconds (10-15) for each increment
+                                of TimerValue. If TimerValue does not
+                                increment at a predictable rate, then 0 is
+                                returned.  The amount of time that has
+                                passed between two calls to GetTimerValue()
+                                can be calculated with the formula
+                                (TimerValue2 - TimerValue1) * TimerPeriod.
+                                This parameter is optional and may be NULL.
+
+  @retval EFI_SUCCESS           - If the CPU timer count was returned.
+  @retval EFI_UNSUPPORTED       - If the CPU does not have any readable timers.
+  @retval EFI_DEVICE_ERROR      - If an error occurred while reading the timer.
+  @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  IN  UINT32                 TimerIndex,
+  OUT UINT64                 *TimerValue,
+  OUT UINT64                 *TimerPeriod   OPTIONAL
+  );
+
+/**
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+                           when a processor interrupt occurs. If this parameter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  );
+
+/**
+  This function modifies the attributes for the memory region specified by BaseAddress and
+  Length from their current attributes to the attributes specified by Attributes.
+
+  @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  BaseAddress      The physical address that is the start address of a memory region.
+  @param  Length           The size in bytes of the memory region.
+  @param  Attributes       The bit mask of attributes to set for the memory region.
+
+  @retval EFI_SUCCESS           The attributes were set for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+                                The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   BaseAddress,
+  IN UINT64                 Length,
+  IN UINT64                 Attributes
+  );
+
+/**
+  Initialize interrupt handling for DXE phase.
+
+  @param  Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
+
+  @return VOID.
+
+**/
+VOID
+InitializeExceptions (
+  IN EFI_CPU_ARCH_PROTOCOL  *gCpu
+  );
+
+/**
+  Converts EFI Attributes to corresponding architecture Attributes.
+
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  Corresponding architecture attributes.
+**/
+UINTN
+EFIAPI
+EfiAttributeConverse (
+  IN UINTN  EfiAttributes
+  );
+
+#endif // CPU_DXE_H_
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c b/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
new file mode 100644
index 0000000000..3325914e53
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
@@ -0,0 +1,544 @@
+/** @file
+  CPU DXE Module to produce CPU MP Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+
+EFI_HANDLE  mMpServiceHandle    = NULL;
+UINTN       mNumberOfProcessors = 1;
+
+EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate = {
+  GetNumberOfProcessors,
+  GetProcessorInfo,
+  StartupAllAPs,
+  StartupThisAP,
+  SwitchBSP,
+  EnableDisableAP,
+  WhoAmI
+};
+
+/**
+  This service retrieves the number of logical processor in the platform
+  and the number of those logical processors that are enabled on this boot.
+  This service may only be called from the BSP.
+
+  This function is used to retrieve the following information:
+    - The number of logical processors that are present in the system.
+    - The number of enabled logical processors in the system at the instant
+      this call is made.
+
+  Because MP Service Protocol provides services to enable and disable processors
+  dynamically, the number of enabled logical processors may vary during the
+  course of a boot session.
+
+  If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+  If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+  EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+  is returned in NumberOfProcessors, the number of currently enabled processor
+  is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+  @param[in]  This                        A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                          instance.
+  @param[out] NumberOfProcessors          Pointer to the total number of logical
+                                          processors in the system, including the BSP
+                                          and disabled APs.
+  @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled logical
+                                          processors that exist in system, including
+                                          the BSP.
+
+  @retval EFI_SUCCESS             The number of logical processors and enabled
+                                  logical processors was retrieved.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL.
+  @retval EFI_INVALID_PARAMETER   NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  OUT UINTN                     *NumberOfProcessors,
+  OUT UINTN                     *NumberOfEnabledProcessors
+  )
+{
+  if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return MpInitLibGetNumberOfProcessors (
+           NumberOfProcessors,
+           NumberOfEnabledProcessors
+           );
+}
+
+/**
+  Gets detailed MP-related information on the requested processor at the
+  instant this call is made. This service may only be called from the BSP.
+
+  This service retrieves detailed MP-related information about any processor
+  on the platform. Note the following:
+    - The processor information may change during the course of a boot session.
+    - The information presented here is entirely MP related.
+
+  Information regarding the number of caches and their sizes, frequency of operation,
+  slot numbers is all considered platform-related information and is not provided
+  by this service.
+
+  @param[in]  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                    instance.
+  @param[in]  ProcessorNumber       The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
+                                    the requested processor is deposited.
+
+  @retval EFI_SUCCESS             Processor information was returned.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+  IN  EFI_MP_SERVICES_PROTOCOL   *This,
+  IN  UINTN                      ProcessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer
+  )
+{
+  return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
+}
+
+/**
+  This service executes a caller provided function on all enabled APs. APs can
+  run either simultaneously or one at a time in sequence. This service supports
+  both blocking and non-blocking requests. The non-blocking requests use EFI
+  events so the BSP can detect when the APs have finished. This service may only
+  be called from the BSP.
+
+  This function is used to dispatch all the enabled APs to the function specified
+  by Procedure.  If any enabled AP is busy, then EFI_NOT_READY is returned
+  immediately and Procedure is not started on any AP.
+
+  If SingleThread is TRUE, all the enabled APs execute the function specified by
+  Procedure one by one, in ascending order of processor handle number. Otherwise,
+  all the enabled APs execute the function specified by Procedure simultaneously.
+
+  If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
+  APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
+  mode, and the BSP returns from this service without waiting for APs. If a
+  non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+  is signaled, then EFI_UNSUPPORTED must be returned.
+
+  If the timeout specified by TimeoutInMicroseconds expires before all APs return
+  from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+  are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+  and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
+  content points to the list of processor handle numbers in which Procedure was
+  terminated.
+
+  Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+  to make sure that the nature of the code that is executed on the BSP and the
+  dispatched APs is well controlled. The MP Services Protocol does not guarantee
+  that the Procedure function is MP-safe. Hence, the tasks that can be run in
+  parallel are limited to certain independent tasks and well-controlled exclusive
+  code. EFI services and protocols may not be called by APs unless otherwise
+  specified.
+
+  In blocking execution mode, BSP waits until all APs finish or
+  TimeoutInMicroseconds expires.
+
+  In non-blocking execution mode, BSP is freed to return to the caller and then
+  proceed to the next task without having to wait for APs. The following
+  sequence needs to occur in a non-blocking execution mode:
+
+    -# The caller that intends to use this MP Services Protocol in non-blocking
+       mode creates WaitEvent by calling the EFI CreateEvent() service.  The caller
+       invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
+       is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
+       the function specified by Procedure to be started on all the enabled APs,
+       and releases the BSP to continue with other tasks.
+    -# The caller can use the CheckEvent() and WaitForEvent() services to check
+       the state of the WaitEvent created in step 1.
+    -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
+       Service signals WaitEvent by calling the EFI SignalEvent() function. If
+       FailedCpuList is not NULL, its content is available when WaitEvent is
+       signaled. If all APs returned from Procedure prior to the timeout, then
+       FailedCpuList is set to NULL. If not all APs return from Procedure before
+       the timeout, then FailedCpuList is filled in with the list of the failed
+       APs. The buffer is allocated by MP Service Protocol using AllocatePool().
+       It is the caller's responsibility to free the buffer with FreePool() service.
+    -# This invocation of SignalEvent() function informs the caller that invoked
+       EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
+       the specified task or a timeout occurred. The contents of FailedCpuList
+       can be examined to determine which APs did not complete the specified task
+       prior to the timeout.
+
+  @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                      instance.
+  @param[in]  Procedure               A pointer to the function to be run on
+                                      enabled APs of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  SingleThread            If TRUE, then all the enabled APs execute
+                                      the function specified by Procedure one by
+                                      one, in ascending order of processor handle
+                                      number.  If FALSE, then all the enabled APs
+                                      execute the function specified by Procedure
+                                      simultaneously.
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until all APs finish
+                                      or TimeoutInMicroseconds expires.  If it's
+                                      not NULL, then execute in non-blocking mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on all the enabled
+                                      APs, and go on executing immediately. If
+                                      all return from Procedure, or TimeoutInMicroseconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or WaitForEvent()
+                                      services to check the state of event.  Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      APs to return from Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      all APs return from Procedure, then Procedure
+                                      on the failed APs is terminated. All enabled
+                                      APs are available for next function assigned
+                                      by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+                                      or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure for
+                                      all APs.
+  @param[out] FailedCpuList           If NULL, this parameter is ignored. Otherwise,
+                                      if all APs finish successfully, then its
+                                      content is set to NULL. If not all APs
+                                      finish before timeout expires, then its
+                                      content is set to address of the buffer
+                                      holding handle numbers of the failed APs.
+                                      The buffer is allocated by MP Service Protocol,
+                                      and it's the caller's responsibility to
+                                      free the buffer with FreePool() service.
+                                      In blocking mode, it is ready for consumption
+                                      when the call returns. In non-blocking mode,
+                                      it is ready when WaitEvent is signaled.  The
+                                      list of failed CPU is terminated by
+                                      END_OF_CPU_LIST.
+
+  @retval EFI_SUCCESS             In blocking mode, all APs have finished before
+                                  the timeout expired.
+  @retval EFI_SUCCESS             In non-blocking mode, function has been dispatched
+                                  to all enabled APs.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_DEVICE_ERROR        Caller processor is AP.
+  @retval EFI_NOT_STARTED         No enabled APs exist in the system.
+  @retval EFI_NOT_READY           Any enabled APs are busy.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  all enabled APs have finished.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  EFI_AP_PROCEDURE          Procedure,
+  IN  BOOLEAN                   SingleThread,
+  IN  EFI_EVENT                 WaitEvent               OPTIONAL,
+  IN  UINTN                     TimeoutInMicroseconds,
+  IN  VOID                      *ProcedureArgument      OPTIONAL,
+  OUT UINTN                     **FailedCpuList         OPTIONAL
+  )
+{
+  return MpInitLibStartupAllAPs (
+           Procedure,
+           SingleThread,
+           WaitEvent,
+           TimeoutInMicroseconds,
+           ProcedureArgument,
+           FailedCpuList
+           );
+}
+
+/**
+  This service lets the caller get one enabled AP to execute a caller-provided
+  function. The caller can request the BSP to either wait for the completion
+  of the AP or just proceed with the next task by using the EFI event mechanism.
+  See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+  execution support.  This service may only be called from the BSP.
+
+  This function is used to dispatch one enabled AP to the function specified by
+  Procedure passing in the argument specified by ProcedureArgument.  If WaitEvent
+  is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
+  TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
+  BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
+  is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
+  then EFI_UNSUPPORTED must be returned.
+
+  If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+  from Procedure, then execution of Procedure by the AP is terminated. The AP is
+  available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+  EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+  @param[in]  This                    A pointer to the EFI_MP_SERVICES_PROTOCOL
+                                      instance.
+  @param[in]  Procedure               A pointer to the function to be run on the
+                                      designated AP of the system. See type
+                                      EFI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber         The handle number of the AP. The range is
+                                      from 0 to the total number of logical
+                                      processors minus 1. The total number of
+                                      logical processors can be retrieved by
+                                      EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+  @param[in]  WaitEvent               The event created by the caller with CreateEvent()
+                                      service.  If it is NULL, then execute in
+                                      blocking mode. BSP waits until this AP finish
+                                      or TimeoutInMicroSeconds expires.  If it's
+                                      not NULL, then execute in non-blocking mode.
+                                      BSP requests the function specified by
+                                      Procedure to be started on this AP,
+                                      and go on executing immediately. If this AP
+                                      return from Procedure or TimeoutInMicroSeconds
+                                      expires, this event is signaled. The BSP
+                                      can use the CheckEvent() or WaitForEvent()
+                                      services to check the state of event.  Type
+                                      EFI_EVENT is defined in CreateEvent() in
+                                      the Unified Extensible Firmware Interface
+                                      Specification.
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for
+                                      this AP to finish this Procedure, either for
+                                      blocking or non-blocking mode. Zero means
+                                      infinity.  If the timeout expires before
+                                      this AP returns from Procedure, then Procedure
+                                      on the AP is terminated. The
+                                      AP is available for next function assigned
+                                      by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+                                      or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+                                      If the timeout expires in blocking mode,
+                                      BSP returns EFI_TIMEOUT.  If the timeout
+                                      expires in non-blocking mode, WaitEvent
+                                      is signaled with SignalEvent().
+  @param[in]  ProcedureArgument       The parameter passed into Procedure on the
+                                      specified AP.
+  @param[out] Finished                If NULL, this parameter is ignored.  In
+                                      blocking mode, this parameter is ignored.
+                                      In non-blocking mode, if AP returns from
+                                      Procedure before the timeout expires, its
+                                      content is set to TRUE. Otherwise, the
+                                      value is set to FALSE. The caller can
+                                      determine if the AP returned from Procedure
+                                      by evaluating this value.
+
+  @retval EFI_SUCCESS             In blocking mode, specified AP finished before
+                                  the timeout expires.
+  @retval EFI_SUCCESS             In non-blocking mode, the function has been
+                                  dispatched to specified AP.
+  @retval EFI_UNSUPPORTED         A non-blocking mode request was made after the
+                                  UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+                                  signaled.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_TIMEOUT             In blocking mode, the timeout expired before
+                                  the specified AP has finished.
+  @retval EFI_NOT_READY           The specified AP is busy.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP or disabled AP.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  EFI_AP_PROCEDURE          Procedure,
+  IN  UINTN                     ProcessorNumber,
+  IN  EFI_EVENT                 WaitEvent               OPTIONAL,
+  IN  UINTN                     TimeoutInMicroseconds,
+  IN  VOID                      *ProcedureArgument      OPTIONAL,
+  OUT BOOLEAN                   *Finished               OPTIONAL
+  )
+{
+  return MpInitLibStartupThisAP (
+           Procedure,
+           ProcessorNumber,
+           WaitEvent,
+           TimeoutInMicroseconds,
+           ProcedureArgument,
+           Finished
+           );
+}
+
+/**
+  This service switches the requested AP to be the BSP from that point onward.
+  This service changes the BSP for all purposes.   This call can only be performed
+  by the current BSP.
+
+  This service switches the requested AP to be the BSP from that point onward.
+  This service changes the BSP for all purposes. The new BSP can take over the
+  execution of the old BSP and continue seamlessly from where the old one left
+  off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+  is signaled.
+
+  If the BSP cannot be switched prior to the return from this service, then
+  EFI_UNSUPPORTED must be returned.
+
+  @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+  @param[in] ProcessorNumber   The handle number of AP that is to become the new
+                               BSP. The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+  @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an
+                               enabled AP. Otherwise, it will be disabled.
+
+  @retval EFI_SUCCESS             BSP successfully switched.
+  @retval EFI_UNSUPPORTED         Switching the BSP cannot be completed prior to
+                                  this service returning.
+  @retval EFI_UNSUPPORTED         Switching the BSP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the current BSP or
+                                  a disabled AP.
+  @retval EFI_NOT_READY           The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchBSP (
+  IN EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  UINTN                    ProcessorNumber,
+  IN  BOOLEAN                  EnableOldBSP
+  )
+{
+  return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
+}
+
+/**
+  This service lets the caller enable or disable an AP from this point onward.
+  This service may only be called from the BSP.
+
+  This service allows the caller enable or disable an AP from this point onward.
+  The caller can optionally specify the health status of the AP by Health. If
+  an AP is being disabled, then the state of the disabled AP is implementation
+  dependent. If an AP is enabled, then the implementation must guarantee that a
+  complete initialization sequence is performed on the AP, so the AP is in a state
+  that is compatible with an MP operating system. This service may not be supported
+  after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
+
+  If the enable or disable AP operation cannot be completed prior to the return
+  from this service, then EFI_UNSUPPORTED must be returned.
+
+  @param[in] This              A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+  @param[in] ProcessorNumber   The handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+  @param[in] EnableAP          Specifies the new state for the processor for
+                               enabled, FALSE for disabled.
+  @param[in] HealthFlag        If not NULL, a pointer to a value that specifies
+                               the new health status of the AP. This flag
+                               corresponds to StatusFlag defined in
+                               EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+                               the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+                               bits are ignored.  If it is NULL, this parameter
+                               is ignored.
+
+  @retval EFI_SUCCESS             The specified AP was enabled or disabled successfully.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP cannot be completed
+                                  prior to this service returning.
+  @retval EFI_UNSUPPORTED         Enabling or disabling an AP is not supported.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_NOT_FOUND           Processor with the handle specified by ProcessorNumber
+                                  does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  UINTN                     ProcessorNumber,
+  IN  BOOLEAN                   EnableAP,
+  IN  UINT32                    *HealthFlag OPTIONAL
+  )
+{
+  return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
+}
+
+/**
+  This return the handle number for the calling processor.  This service may be
+  called from the BSP and APs.
+
+  This service returns the processor handle number for the calling processor.
+  The returned value is in the range from 0 to the total number of logical
+  processors minus 1. The total number of logical processors can be retrieved
+  with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
+  called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+  is returned. Otherwise, the current processors handle number is returned in
+  ProcessorNumber, and EFI_SUCCESS is returned.
+
+  @param[in]  This             A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+  @param[out] ProcessorNumber  Pointer to the handle number of AP.
+                               The range is from 0 to the total number of
+                               logical processors minus 1. The total number of
+                               logical processors can be retrieved by
+                               EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+  @retval EFI_SUCCESS             The current processor handle number was returned
+                                  in ProcessorNumber.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+  IN EFI_MP_SERVICES_PROTOCOL  *This,
+  OUT UINTN                    *ProcessorNumber
+  )
+{
+  return MpInitLibWhoAmI (ProcessorNumber);
+}
+
+/**
+  Initialize Multi-processor support.
+**/
+VOID
+InitializeMpSupport (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       NumberOfProcessors;
+  UINTN       NumberOfEnabledProcessors;
+
+  //
+  // Wakeup APs to do initialization
+  //
+  Status = MpInitLibInitialize ();
+  ASSERT_EFI_ERROR (Status);
+
+  MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors);
+  mNumberOfProcessors = NumberOfProcessors;
+  DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mMpServiceHandle,
+                  &gEfiMpServiceProtocolGuid,
+                  &mMpServicesTemplate,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+}
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c b/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c
new file mode 100644
index 0000000000..754549cd0e
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c
@@ -0,0 +1,159 @@
+/** @file Exception.c
+
+  CPU DXE Module initialization exception instance.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include <Guid/VectorHandoffTable.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+VOID
+ExceptionEntryStart (
+  VOID
+  );
+
+VOID
+ExceptionEntryEnd (
+  VOID
+  );
+
+/**
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+                           are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+                           when a processor interrupt occurs. If this parameter is NULL, then the handler
+                           will be uninstalled.
+
+  @retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE         InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, InterruptHandler);
+}
+
+/**
+  Update the exception start entry code.
+
+  @retval EFI_SUCCESS           Update the exception start entry code down.
+  @retval EFI_OUT_OF_RESOURCES  The start entry code size out of bounds.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateExceptionStartEntry (
+  VOID
+  )
+{
+  EFI_PHYSICAL_ADDRESS  ExceptionStartEntry;
+  UINTN                 VectorLength;
+  UINTN                 MaxLength;
+  UINTN                 MaxSizeOfVector;
+
+  VectorLength = (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntryStart;
+
+  //
+  // A vector is up to 512 bytes.
+  //
+  MaxSizeOfVector = 512;
+  MaxLength       = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * MaxSizeOfVector;
+
+  if (VectorLength > MaxLength) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ExceptionStartEntry = PcdGet64 (PcdLoongArchExceptionVectorBaseAddress);
+
+  InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength);
+  CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, VectorLength);
+  InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength);
+  InvalidateDataCache ();
+
+  //
+  // If PcdLoongArchExceptionVectorBaseAddress is not used during SEC and PEI stages, the exception
+  // base addres is set to PcdLoongArchExceptionVectorBaseAddress.
+  //
+  if (CsrRead (LOONGARCH_CSR_EBASE) != ExceptionStartEntry) {
+    SetExceptionBaseAddress (ExceptionStartEntry);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize interrupt handling for DXE phase.
+
+  @param  Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
+
+  @return VOID.
+
+**/
+VOID
+InitializeExceptions (
+  IN EFI_CPU_ARCH_PROTOCOL  *Cpu
+  )
+{
+  EFI_STATUS               Status;
+  EFI_VECTOR_HANDOFF_INFO  *VectorInfoList;
+  EFI_VECTOR_HANDOFF_INFO  *VectorInfo;
+  BOOLEAN                  IrqEnabled;
+
+  VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL;
+  Status     = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
+
+  if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) {
+    VectorInfo = VectorInfoList;
+  }
+
+  //
+  // Disable interrupts
+  //
+  Cpu->GetInterruptState (Cpu, &IrqEnabled);
+  if (IrqEnabled) {
+    Cpu->DisableInterrupt (Cpu);
+  }
+
+  //
+  // Update the Exception Start Entry code to point into CpuDxe.
+  //
+  Status = UpdateExceptionStartEntry ();
+  if (EFI_ERROR (Status)) {
+    DebugPrint (EFI_D_ERROR, "[%a]: Exception start entry code out of bounds!\n", __func__);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  //
+  // Intialize the CpuExceptionHandlerLib so we take over the exception vector table from the DXE Core
+  //
+  Status = InitializeCpuExceptionHandlers (VectorInfo);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Enable interrupts
+  //
+  DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled = %x\n", IrqEnabled);
+  if (!IrqEnabled) {
+    Status = Cpu->EnableInterrupt (Cpu);
+  }
+
+  ASSERT_EFI_ERROR (Status);
+}
--
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117742): https://edk2.groups.io/g/devel/message/117742
Mute This Topic: https://groups.io/mt/105478503/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 130305 bytes --]

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [edk2-devel] [PATCH v3 13/13] UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 13/13] UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field Chao Li
@ 2024-04-15  2:14   ` Ni, Ray
  0 siblings, 0 replies; 22+ messages in thread
From: Ni, Ray @ 2024-04-15  2:14 UTC (permalink / raw)
  To: Chao Li, devel@edk2.groups.io; +Cc: Kumar, Rahul R, Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 1505 bytes --]

Reviewed-by: Ray Ni <ray.ni@intel.com>

Thanks,
Ray
________________________________
From: Chao Li <lichao@loongson.cn>
Sent: Friday, April 12, 2024 15:34
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Ni, Ray <ray.ni@intel.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>
Subject: [PATCH v3 13/13] UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field

LoongArch64 requires CpuMmio2Dxe, add it into LoongArch64 field.

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>
---
 UefiCpuPkg/UefiCpuPkg.dsc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index e92ceb6466..1af5a0c525 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -213,6 +213,7 @@ [Components.RISCV64]

 [Components.LOONGARCH64]
   UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf
+  UefiCpuPkg/CpuMmio2Dxe/CpuMmio2Dxe.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 (#117743): https://edk2.groups.io/g/devel/message/117743
Mute This Topic: https://groups.io/mt/105478504/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 3419 bytes --]

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg
  2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
                   ` (12 preceding siblings ...)
  2024-04-12  7:34 ` [edk2-devel] [PATCH v3 13/13] UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field Chao Li
@ 2024-04-15  2:15 ` Ni, Ray
  13 siblings, 0 replies; 22+ messages in thread
From: Ni, Ray @ 2024-04-15  2:15 UTC (permalink / raw)
  To: Chao Li, devel@edk2.groups.io
  Cc: Kumar, Rahul R, Gerd Hoffmann, Sami Mujawar, Sunil V L, Bibo Mao,
	Dongyan Qian

[-- Attachment #1: Type: text/plain, Size: 7626 bytes --]

Chao,
I've replied all of your patches.
Only for patch "[edk2-devel] [PATCH v3 10/13] UefiCpuPkg: Add a new GUID to store the processors resource", I have one comment. Others look good to me.

Thanks,
Ray
________________________________
From: Chao Li <lichao@loongson.cn>
Sent: Friday, April 12, 2024 15:32
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Ni, Ray <ray.ni@intel.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Sami Mujawar <sami.mujawar@arm.com>; Sunil V L <sunilvl@ventanamicro.com>; Bibo Mao <maobibo@loongson.cn>; Dongyan Qian <qiandongyan@loongson.cn>
Subject: [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg

This patch set adjusted some order in UefiCpuPig alphabetically, added
LoongArch libraries and drivers into UefiCpuPkg, it is a continuation of
the first patch series v8 submitted at
https://edk2.groups.io/g/devel/message/114526.

And also separated from https://edk2.groups.io/g/devel/message/116583.

This series only contents the changes for UefiCpuPkg.

Patch1-Patch4: Reorder some INF files located in UefiCpuPkg
alphabetically.

Patch5-Patch13: Added Timer, CpuMmuLib, CpuMmuInitLib, MpInitLib, CpuDxe
for LoongArch, and added some PCD and header files requested by the
above libraries and drivers.

Modfied modules: UefiCpuPkg

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

PR: https://github.com/tianocore/edk2/pull/5483

V1 -> V2:
1. Removed PcdCpuMmuIsEnabled.
2. Removed API GetMemoryRegionAttributes API as it is no longer needed.
3. Patch3, added two empty line in DXE and PEI INF files.
4. Patch5, added the Status check in GetTimeInnanoSecond function.
5. Separated into two series, this is series one, and the second one is
OvmfPkg.

V2 -> V3:
1. Remove CpuMmuInitLib.
2. Added a new GUID HOB named PROCESSOR_RESOURCE_HOG_GUID.
3. Following Ray suggest, adjust CpuMmuLib API, rename the API name.
4. Rename the PcdCpuExceptionVectorBaseAddress to
PcdLoongArch64ExceptionVectorBaseAddress.
5. Enable CpuMmio2Dxe in LoongArch.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Dongyan Qian <qiandongyan@loongson.cn>

Chao Li (13):
  UefiCpuPkg/CpuTimerLib: Reorder the INF file alphabetically
  UefiCpuPkg/CpuExceptionHandlerLib: Reorder the INF files
    alphabetically
  UefiCpuPkg/MpInitLib: Reorder the INF files alphabetically
  UefiCpuPkg/CpuDxe: Reorder the INF file alphabetically
  UefiCpuPkg: Add LoongArch64 CPU Timer instance
  UefiCpuPkg: Add CPU exception library for LoongArch
  UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
  UefiCpuPkg: Added a new PCD named
    PcdLoongArchExceptionVectorBaseAddress
  UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg
  UefiCpuPkg: Add a new GUID to store the processors resource
  UefiCpuPkg: Add multiprocessor library for LoongArch64
  UefiCpuPkg: Add CpuDxe driver for LoongArch64
  UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field

 UefiCpuPkg/CpuDxe/CpuDxe.inf                  |   39 +-
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c        |  439 +++++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h        |  288 +++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c         |  544 ++++++
 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c     |  159 ++
 .../Include/Guid/ProcessorResourceHob.h       |   29 +
 UefiCpuPkg/Include/Library/CpuMmuLib.h        |   41 +
 .../DxeCpuExceptionHandlerLib.inf             |   37 +-
 .../LoongArch/DxeExceptionLib.c               |  198 ++
 .../LoongArch/ExceptionCommon.c               |  171 ++
 .../LoongArch/ExceptionCommon.h               |  131 ++
 .../LoongArch64/ArchExceptionHandler.c        |  268 +++
 .../LoongArch64/ExceptionHandlerAsm.S         |  366 ++++
 .../LoongArch/SecPeiExceptionLib.c            |  102 ++
 .../PeiCpuExceptionHandlerLib.inf             |   16 +-
 .../SecPeiCpuExceptionHandlerLib.inf          |   31 +-
 .../SmmCpuExceptionHandlerLib.inf             |   16 +-
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.inf    |   39 +
 UefiCpuPkg/Library/CpuMmuLib/CpuMmuLib.uni    |   14 +
 .../Library/CpuMmuLib/LoongArch64/CpuMmu.c    |  785 ++++++++
 .../Library/CpuMmuLib/LoongArch64/Page.h      |   33 +
 .../LoongArch64/TlbExceptionHandle.S          |   51 +
 .../LoongArch64/TlbExceptionHandle.h          |   36 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.S        |   24 +
 .../CpuMmuLib/LoongArch64/TlbInvalid.h        |   24 +
 .../Library/CpuTimerLib/BaseCpuTimerLib.inf   |   17 +-
 .../CpuTimerLib/LoongArch64/CpuTimerLib.c     |  250 +++
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   42 +-
 .../Library/MpInitLib/LoongArch64/DxeMpLib.c  |  480 +++++
 .../Library/MpInitLib/LoongArch64/MpLib.c     | 1626 +++++++++++++++++
 .../Library/MpInitLib/LoongArch64/MpLib.h     |  350 ++++
 .../Library/MpInitLib/LoongArch64/PeiMpLib.c  |  381 ++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   40 +-
 UefiCpuPkg/UefiCpuPkg.dec                     |   13 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |    7 +
 35 files changed, 7008 insertions(+), 79 deletions(-)
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c
 create mode 100644 UefiCpuPkg/Include/Guid/ProcessorResourceHob.h
 create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/DxeExceptionLib.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/ExceptionCommon.h
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ArchExceptionHandler.c
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/LoongArch64/ExceptionHandlerAsm.S
 create mode 100644 UefiCpuPkg/Library/CpuExceptionHandlerLib/LoongArch/SecPeiExceptionLib.c
 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/TlbExceptionHandle.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbExceptionHandle.h
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.S
 create mode 100644 UefiCpuPkg/Library/CpuMmuLib/LoongArch64/TlbInvalid.h
 create mode 100644 UefiCpuPkg/Library/CpuTimerLib/LoongArch64/CpuTimerLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/DxeMpLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/MpLib.h
 create mode 100644 UefiCpuPkg/Library/MpInitLib/LoongArch64/PeiMpLib.c

--
2.27.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117744): https://edk2.groups.io/g/devel/message/117744
Mute This Topic: https://groups.io/mt/105478478/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 13103 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [edk2-devel] [PATCH v3 10/13] UefiCpuPkg: Add a new GUID to store the processors resource
  2024-04-15  2:10   ` Ni, Ray
@ 2024-04-16  1:50     ` Chao Li
  0 siblings, 0 replies; 22+ messages in thread
From: Chao Li @ 2024-04-16  1:50 UTC (permalink / raw)
  To: devel, ray.ni; +Cc: Kumar, Rahul R, Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 822 bytes --]

Hi Ray,


Thanks,
Chao
On 2024/4/15 10:10, Ni, Ray wrote:
>
> +
> +typedef struct {
> +  UINT32    NumberOfProcessor;
> +  UINTN     *ApicId;
>
> [Ray] How about "UINTN  ApicId[]"? The difference between the two is 
> your version contains an 8-byte pointer pointing to somewhere else. My 
> version implies the APIC ID array is just after "NumberOfProcessor".
Of curse, using the flexible arrays is better than my version and I will 
adjust this in V3.
> 


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117816): https://edk2.groups.io/g/devel/message/117816
Mute This Topic: https://groups.io/mt/105478501/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 2795 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2024-04-16  1:51 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-12  7:32 [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Chao Li
2024-04-12  7:33 ` [edk2-devel] [PATCH v3 01/13] UefiCpuPkg/CpuTimerLib: Reorder the INF file alphabetically Chao Li
2024-04-12  7:33 ` [edk2-devel] [PATCH v3 02/13] UefiCpuPkg/CpuExceptionHandlerLib: Reorder the INF files alphabetically Chao Li
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 03/13] UefiCpuPkg/MpInitLib: " Chao Li
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 04/13] UefiCpuPkg/CpuDxe: Reorder the INF file alphabetically Chao Li
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 05/13] UefiCpuPkg: Add LoongArch64 CPU Timer instance Chao Li
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 06/13] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 07/13] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
2024-04-15  2:10   ` Ni, Ray
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 08/13] UefiCpuPkg: Added a new PCD named PcdLoongArchExceptionVectorBaseAddress Chao Li
2024-04-15  2:10   ` Ni, Ray
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 09/13] UefiCpuPkg: Add CpuMmuLib to UefiCpuPkg Chao Li
2024-04-15  2:11   ` Ni, Ray
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 10/13] UefiCpuPkg: Add a new GUID to store the processors resource Chao Li
2024-04-15  2:10   ` Ni, Ray
2024-04-16  1:50     ` Chao Li
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 11/13] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 12/13] UefiCpuPkg: Add CpuDxe driver " Chao Li
2024-04-15  2:12   ` Ni, Ray
2024-04-12  7:34 ` [edk2-devel] [PATCH v3 13/13] UefiCpuPkg/UefiCpuPkg.dsc: Add CpuMmio2Dxe.inf to LoongArch64 field Chao Li
2024-04-15  2:14   ` Ni, Ray
2024-04-15  2:15 ` [edk2-devel] [PATCH v3 00/13] Part 2 patch set to add LoongArch support into UefiCpuPkg Ni, Ray

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox