public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support.
@ 2022-11-11  8:25 xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 01/15] Platform/Loongson: Add Serial Port library xianglai
                   ` (14 more replies)
  0 siblings, 15 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

The uploaded code generates firmware to support Linux launching on the LoongArch platform under qemu,
So it will run in a virtual machine.

LoongArch is the general processor architecture of Loongson.
You can get the latest LoongArch documents or LoongArch tools at https://github.com/loongson/.

You can also view the code through the Loongson community.
The edk2 code in Loongson community:
https://github.com/loongson/edk2/tree/LoongArch
The edk2-platform code in Loonson community:
https://github.com/loongson/edk2-platforms
The qemu code in Loongson community:
https://gitlab.com/qemu-project/qemu.git
The LoongArch Documentation in Loongson community:
https://github.com/loongson/LoongArch-Documentation/tree/main/docs
The all patches at:
https://github.com/loongson/edk2-platforms/tree/devel-LoongArch-patch

v2 changes:
 - Remove the inline assembly from StableTimerLib.
 - troubleshoot TAB strings, convert TAB characters to spaces.
 - remove smm related code, loongarch has no smm mode.

v3 changes:
 - delete ExtractHandler related code.
 - Boot UEFI with low 256M memory.
 - Modify common interrupt handling.

v4 changes:
 - Remove qemu flash related code.
 - Modify fdt base address.

v5 changes:
 - Add Udf driver support.
 - Split readme file into a separate patch.
 - Modify the code style
   - delete extra blank lines
   - use the assembly function definition macros in MdePkg
   - sort out the PCD variable Token value.

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>

xianglai li (15):
  Platform/Loongson: Add Serial Port library
  Platform/Loongson: Support SEC
  Platform/Loongson: Add PeiServicesTablePointerLib.
  Platform/Loongson: Add QemuFwCfgLib.
  Platform/Loongson: Add MmuLib.
  Platform/Loongson: Add StableTimerLib.
  Platform/Loongson: Support PEI phase.
  Platform/Loongson: Add CPU DXE driver.
  Platform/Loongson: Add PciCpuIoDxe driver.
  Platform/Loongson:  Add timer Dxe driver.
  Platform/Loongson: Add RealTime Clock lib.
  Platform/Loongson: Add Platform Boot Manager Lib.
  Platform/Loongson: Add Reset System Lib.
  Platform/Loongson: Support Dxe
  Platform/Loongson: Add Readme.

 .../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c  | 367 ++++++++
 .../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h  | 199 +++++
 .../Drivers/CpuDxe/CpuDxe.inf                 |  59 ++
 .../Drivers/CpuDxe/LoongArch64/Exception.c    | 335 +++++++
 .../Drivers/CpuDxe/LoongArch64/Fpu.S          |  97 ++
 .../Drivers/CpuDxe/LoongArch64/LoongArch.S    | 321 +++++++
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c       | 538 ++++++++++++
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h       | 207 +++++
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf     |  44 +
 .../Drivers/StableTimerDxe/Timer.c            | 388 ++++++++
 .../Drivers/StableTimerDxe/Timer.h            | 172 ++++
 .../Drivers/StableTimerDxe/TimerConfig.S      |  38 +
 .../Drivers/StableTimerDxe/TimerDxe.inf       |  44 +
 .../LoongArchQemuPkg/Include/Library/Cpu.h    | 237 +++++
 .../LoongArchQemuPkg/Include/Library/MmuLib.h |  85 ++
 .../Include/Library/QemuFwCfgLib.h            | 174 ++++
 .../Include/Library/StableTimer.h             |  59 ++
 .../Include/LoongArchQemuPlatform.h           |  95 ++
 .../LsRealTimeClockLib/LsRealTimeClock.h      |  40 +
 .../LsRealTimeClockLib/LsRealTimeClockLib.c   | 335 +++++++
 .../LsRealTimeClockLib/LsRealTimeClockLib.inf |  44 +
 .../LoongArchQemuPkg/Library/MmuLib/Mmu.S     | 155 ++++
 .../Library/MmuLib/MmuBaseLib.inf             |  40 +
 .../Library/MmuLib/MmuBaseLibPei.inf          |  47 +
 .../Library/MmuLib/MmuLibCore.c               | 831 ++++++++++++++++++
 .../Library/MmuLib/MmuLibCore.h               |  40 +
 .../Library/MmuLib/MmuLibCorePei.c            | 231 +++++
 .../LoongArchQemuPkg/Library/MmuLib/mmu.h     | 190 ++++
 .../LoongArchQemuPkg/Library/MmuLib/page.h    | 280 ++++++
 .../LoongArchQemuPkg/Library/MmuLib/pte.h     |  57 ++
 .../PeiServicesTablePointer.c                 |  79 ++
 .../PeiServicesTablePointer.h                 |  39 +
 .../PeiServicesTablePointerLib.S              |  40 +
 .../PeiServicesTablePointerLib.inf            |  32 +
 .../PlatformBootManagerLib/PlatformBm.c       | 742 ++++++++++++++++
 .../PlatformBootManagerLib/PlatformBm.h       | 112 +++
 .../PlatformBootManagerLib.inf                |  75 ++
 .../PlatformBootManagerLib/QemuKernel.c       |  81 ++
 .../QemuFwCfgLib/QemuFwCfgLibInternal.h       |  63 ++
 .../Library/QemuFwCfgLib/QemuFwCfgPei.c       | 117 +++
 .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.c    | 463 ++++++++++
 .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf  |  46 +
 .../BaseResetSystemAcpiGed.c                  | 146 +++
 .../BaseResetSystemAcpiGedLib.inf             |  37 +
 .../DxeResetSystemAcpiGed.c                   | 257 ++++++
 .../DxeResetSystemAcpiGedLib.inf              |  41 +
 .../ResetSystemAcpiLib/ResetSystemAcpiGed.c   | 128 +++
 .../ResetSystemAcpiLib/ResetSystemAcpiGed.h   |  23 +
 .../Library/SerialPortLib/SerialPortLib.c     | 593 +++++++++++++
 .../Library/SerialPortLib/SerialPortLib.inf   |  39 +
 .../Library/StableTimerLib/Count.S            |  52 ++
 .../Library/StableTimerLib/TimerLib.c         | 236 +++++
 .../Library/StableTimerLib/TimerLib.inf       |  32 +
 .../Loongson/LoongArchQemuPkg/Loongson.dec    |  74 ++
 .../Loongson/LoongArchQemuPkg/Loongson.dsc    | 607 +++++++++++++
 .../Loongson/LoongArchQemuPkg/Loongson.fdf    | 349 ++++++++
 .../LoongArchQemuPkg/Loongson.fdf.inc         |  63 ++
 .../LoongArchQemuPkg/PlatformPei/Fv.c         |  58 ++
 .../LoongArchQemuPkg/PlatformPei/MemDetect.c  | 104 +++
 .../LoongArchQemuPkg/PlatformPei/Platform.c   | 261 ++++++
 .../LoongArchQemuPkg/PlatformPei/Platform.h   |  86 ++
 .../PlatformPei/PlatformPei.inf               |  72 ++
 Platform/Loongson/LoongArchQemuPkg/Readme.md  |  60 ++
 .../LoongArchQemuPkg/Sec/LoongArch64/Start.S  |  84 ++
 .../Loongson/LoongArchQemuPkg/Sec/SecMain.c   | 494 +++++++++++
 .../Loongson/LoongArchQemuPkg/Sec/SecMain.inf |  51 ++
 Readme.md                                     |   9 +
 67 files changed, 11594 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerConfig.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.dec
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Readme.md
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf

-- 
2.31.1


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

* [edk2-platforms][PATCH V5 01/15] Platform/Loongson: Add Serial Port library
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 02/15] Platform/Loongson: Support SEC xianglai
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Serial Port library for LoongarchQemuPkg

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../LoongArchQemuPkg/Include/Library/Cpu.h    | 237 +++++++
 .../Include/LoongArchQemuPlatform.h           |  95 +++
 .../Library/SerialPortLib/SerialPortLib.c     | 593 ++++++++++++++++++
 .../Library/SerialPortLib/SerialPortLib.inf   |  39 ++
 4 files changed, 964 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h
new file mode 100644
index 0000000000..c6599c6ed7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h
@@ -0,0 +1,237 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - EXC     - Exception
+    - INT     - Interrupt
+    - FPU     - Floating Point Unit
+    - CSR     - CPU Status Register
+    - READQ   - Read Quad Word
+**/
+#ifndef LOONGARCH_CPU_H_
+#define LOONGARCH_CPU_H_
+
+/* Exception types decoded by machdep exception decoder */
+#define EXC_INT                     0       /* HW interrupt */
+#define EXC_TLBL                    1       /* TLB miss on a load */
+#define EXC_TLBS                    2       /* TLB miss on a store */
+#define EXC_TLBI                    3       /* TLB miss on a ifetch */
+#define EXC_TLBM                    4       /* TLB modified fault */
+#define EXC_TLBRI                   5       /* TLB Read-Inhibit exception */
+#define EXC_TLBXI                   6       /* TLB Execution-Inhibit exception */
+#define EXC_TLBPE                   7       /* TLB Privilege Error */
+#define EXC_ADE                     8       /* Address Error */
+#define EXC_ALE                     9       /* Unalign Access */
+#define EXC_OOB                     10      /* Out of bounds */
+#define EXC_SYS                     11      /* System call */
+#define EXC_BP                      12      /* Breakpoint */
+#define EXC_INE                     13      /* Inst. Not Exist */
+#define EXC_IPE                     14      /* Inst. Privileged Error */
+#define EXC_FPDIS                   15      /* FPU Disabled */
+#define EXC_LSXDIS                  16      /* LSX Disabled */
+#define EXC_LASXDIS                 17      /* LASX Disabled */
+#define EXC_FPE                     18      /* Floating Point Exception */
+#define EXC_WATCH                   19      /* Watch address reference */
+#define EXC_BAD                     255     /* Undecodeable */
+
+#define COPY_SIGCODE    // copy sigcode above user stack in exec
+#define ZERO                        $r0 /* wired zero */
+#define RA                          $r1 /* return address */
+#define GP                          $r2 /* global pointer - caller saved for PIC */
+#define SP                          $r3 /* stack pointer */
+#define V0                          $r4 /* return value - caller saved */
+#define V1                          $r5
+#define A0                          $r4 /* argument registers */
+#define A1                          $r5
+#define A2                          $r6
+#define A3                          $r7
+#define A4                          $r8 /* arg reg 64 bit; caller saved in 32 bit */
+#define A5                          $r9
+#define A6                          $r10
+#define A7                          $r11
+#define T0                          $r12 /* caller saved */
+#define T1                          $r13
+#define T2                          $r14
+#define T3                          $r15
+#define T4                          $r16 /* callee saved */
+#define T5                          $r17
+#define T6                          $r18
+#define T7                          $r19
+#define T8                          $r20 /* caller saved */
+#define TP                          $r21 /* TLS */
+#define FP                          $r22 /* frame pointer */
+#define S0                          $r23 /* callee saved */
+#define S1                          $r24
+#define S2                          $r25
+#define S3                          $r26
+#define S4                          $r27
+#define S5                          $r28
+#define S6                          $r29
+#define S7                          $r30
+#define S8                          $r31 /* callee saved */
+
+#define FCSR0                       $r0
+
+//
+// Location of the saved registers relative to ZERO.
+// Usage is p->p_regs[XX].
+//
+#define RA_NUM                      1
+#define GP_NUM                      2
+#define SP_NUM                      3
+#define A0_NUM                      4
+#define A1_NUM                      5
+#define A2_NUM                      6
+#define A3_NUM                      7
+#define A4_NUM                      8
+#define A5_NUM                      9
+#define A6_NUM                      10
+#define A7_NUM                      11
+#define T0_NUM                      12
+#define T1_NUM                      13
+#define T2_NUM                      14
+#define T3_NUM                      15
+#define T4_NUM                      16
+#define T5_NUM                      17
+#define T6_NUM                      18
+#define T7_NUM                      19
+#define T8_NUM                      20
+#define TP_NUM                      21
+#define FP_NUM                      22
+#define S0_NUM                      23
+#define S1_NUM                      24
+#define S2_NUM                      25
+#define S3_NUM                      26
+#define S4_NUM                      27
+#define S5_NUM                      28
+#define S6_NUM                      29
+#define S7_NUM                      30
+#define S8_NUM                      31
+
+#define FP0_NUM                     0
+#define FP1_NUM                     1
+#define FP2_NUM                     2
+#define FP3_NUM                     3
+#define FP4_NUM                     4
+#define FP5_NUM                     5
+#define FP6_NUM                     6
+#define FP7_NUM                     7
+#define FP8_NUM                     8
+#define FP9_NUM                     9
+#define FP10_NUM                    10
+#define FP11_NUM                    11
+#define FP12_NUM                    12
+#define FP13_NUM                    13
+#define FP14_NUM                    14
+#define FP15_NUM                    15
+#define FP16_NUM                    16
+#define FP17_NUM                    17
+#define FP18_NUM                    18
+#define FP19_NUM                    19
+#define FP20_NUM                    20
+#define FP21_NUM                    21
+#define FP22_NUM                    22
+#define FP23_NUM                    23
+#define FP24_NUM                    24
+#define FP25_NUM                    25
+#define FP26_NUM                    26
+#define FP27_NUM                    27
+#define FP28_NUM                    28
+#define FP29_NUM                    29
+#define FP30_NUM                    30
+#define FP31_NUM                    31
+#define FCSR_NUM                    32
+#define FCC_NUM                     33
+
+#ifdef __ASSEMBLY__
+#define _ULCAST_
+#define _U64CAST_
+#else
+#define _ULCAST_ (unsigned long)
+#define _U64CAST_ (u64)
+#endif
+
+#define LOONGARCH_CSR_CRMD          0
+#define LOONGARCH_CSR_PRMD          1
+#define LOONGARCH_CSR_EUEN          2
+#define CSR_EUEN_LBTEN_SHIFT        3
+#define CSR_EUEN_LBTEN              (_ULCAST_(0x1) << CSR_EUEN_LBTEN_SHIFT)
+#define CSR_EUEN_LASXEN_SHIFT       2
+#define CSR_EUEN_LASXEN             (_ULCAST_(0x1) << CSR_EUEN_LASXEN_SHIFT)
+#define CSR_EUEN_LSXEN_SHIFT        1
+#define CSR_EUEN_LSXEN              (_ULCAST_(0x1) << CSR_EUEN_LSXEN_SHIFT)
+#define CSR_EUEN_FPEN_SHIFT         0
+#define CSR_EUEN_FPEN               (_ULCAST_(0x1) << CSR_EUEN_FPEN_SHIFT)
+#define LOONGARCH_CSR_ECFG          4
+
+/* Exception status */
+#define LOONGARCH_CSR_ESTAT         5
+#define CSR_ESTAT_ESUBCODE_SHIFT    22
+#define CSR_ESTAT_ESUBCODE_WIDTH    9
+#define CSR_ESTAT_ESUBCODE          (_ULCAST_(0x1ff) << CSR_ESTAT_ESUBCODE_SHIFT)
+#define CSR_ESTAT_EXC_SHIFT         16
+#define CSR_ESTAT_EXC_WIDTH         6
+#define CSR_ESTAT_EXC               (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT)
+#define CSR_ESTAT_IS_SHIFT          0
+#define CSR_ESTAT_IS_WIDTH          15
+#define CSR_ESTAT_IS                (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT)
+
+#define LOONGARCH_CSR_EPC           6
+#define LOONGARCH_CSR_BADV          7
+#define LOONGARCH_CSR_BADINST       8
+#define LOONGARCH_CSR_BADI          8
+#define LOONGARCH_CSR_EBASE         0xc     /* Exception entry base address */
+#define LOONGARCH_CSR_CPUNUM        0x20    /* CPU core number */
+
+/* register number save in stack on exception */
+#define FP_BASE_NUM                 34
+#define BASE_NUM                    32
+#define CSR_NUM                     10
+#define FP_BASE_INDEX               (CSR_NUM + BASE_NUM)
+#define BOOTCORE_ID                 0
+
+#define LOONGSON_IOCSR_IPI_STATUS   0x1000
+#define LOONGSON_IOCSR_IPI_EN       0x1004
+#define LOONGSON_IOCSR_IPI_SET      0x1008
+#define LOONGSON_IOCSR_IPI_CLEAR    0x100c
+#define LOONGSON_CSR_MAIL_BUF0      0x1020
+#define LOONGSON_CSR_MAIL_BUF1      0x1028
+#define LOONGSON_CSR_MAIL_BUF2      0x1030
+#define LOONGSON_CSR_MAIL_BUF3      0x1038
+
+/* Bit Domains for CFG registers */
+#define LOONGARCH_CPUCFG4           0x4
+#define LOONGARCH_CPUCFG5           0x5
+
+/* Kscratch registers */
+#define LOONGARCH_CSR_KS0           0x30
+#define LOONGARCH_CSR_KS1           0x31
+
+/* Stable timer registers */
+#define LOONGARCH_CSR_TMCFG         0x41
+#define LOONGARCH_CSR_TMCFG_EN      (1ULL << 0)
+#define LOONGARCH_CSR_TMCFG_PERIOD  (1ULL << 1)
+#define LOONGARCH_CSR_TMCFG_TIMEVAL (0x3fffffffffffULL << 2)
+#define LOONGARCH_CSR_TVAL          0x42    /* Timer value */
+#define LOONGARCH_CSR_CNTC          0x43    /* Timer offset */
+#define LOONGARCH_CSR_TINTCLR       0x44    /* Timer interrupt clear */
+
+/* TLB refill exception base address */
+#define LOONGARCH_CSR_TLBREBASE     0x88
+#define LOONGARCH_CSR_TLBRSAVE      0x8b    /* KScratch for TLB refill exception */
+#define LOONGARCH_CSR_PGD           0x1b    /* Page table base */
+
+/* Invalid addr with global=1 or matched asid in current tlb */
+#define INVTLB_ADDR_GTRUE_OR_ASID   0x6
+
+/* Bits 8 and 9 of FPU Status Register specify the rounding mode */
+#define FPU_CSR_RM                  0x300
+#define FPU_CSR_RN                  0x000   /* nearest */
+#define FPU_CSR_RZ                  0x100   /* towards zero */
+#define FPU_CSR_RU                  0x200   /* towards +Infinity */
+#define FPU_CSR_RD                  0x300   /* towards -Infinity */
+
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
new file mode 100644
index 0000000000..e942e6a994
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
@@ -0,0 +1,95 @@
+/** @file
+   LoongArch Qemu Platform macro definition.
+
+   Copyright (c) 2022, Loongson Limited. All rights reserved.
+
+   SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#ifndef LOONGARCH_QEMU_PLATFORM_H_
+#define LOONGARCH_QEMU_PLATFORM_H_
+
+/* Acpi pm device */
+#define LS7A_PCH_REG_BASE             0x10000000UL
+#define LS7A_ACPI_REG_BASE            (LS7A_PCH_REG_BASE  + 0x000D0000)
+#define LS7A_PM_CNT_BLK               (0x14) /* 2 bytes */
+#define LS7A_GPE0_RESET_REG           (0x30) /* 4 bytes */
+
+#define ACPI_BITMASK_SLEEP_TYPE       0x1C00
+#define ACPI_BITMASK_SLEEP_ENABLE     0x2000
+
+//---------------------------------------------
+// UART Register Offsets
+//---------------------------------------------
+#define BAUD_LOW_OFFSET               0x00
+#define BAUD_HIGH_OFFSET              0x01
+#define IER_OFFSET                    0x01
+#define LCR_SHADOW_OFFSET             0x01
+#define FCR_SHADOW_OFFSET             0x02
+#define IR_CONTROL_OFFSET             0x02
+#define FCR_OFFSET                    0x02
+#define EIR_OFFSET                    0x02
+#define BSR_OFFSET                    0x03
+#define LCR_OFFSET                    0x03
+#define MCR_OFFSET                    0x04
+#define LSR_OFFSET                    0x05
+#define MSR_OFFSET                    0x06
+
+/* character format control register */
+#define CFCR_DLAB                     0x80  /* divisor latch */
+#define CFCR_SBREAK                   0x40  /* send break */
+#define CFCR_PZERO                    0x30  /* zero parity */
+#define CFCR_PONE                     0x20  /* one parity */
+#define CFCR_PEVEN                    0x10  /* even parity */
+#define CFCR_PODD                     0x00  /* odd parity */
+#define CFCR_PENAB                    0x08  /* parity enable */
+#define CFCR_STOPB                    0x04  /* 2 stop bits */
+#define CFCR_8BITS                    0x03  /* 8 data bits */
+#define CFCR_7BITS                    0x02  /* 7 data bits */
+#define CFCR_6BITS                    0x01  /* 6 data bits */
+#define CFCR_5BITS                    0x00  /* 5 data bits */
+/* modem control register */
+#define MCR_LOOPBACK                  0x10  /* loopback */
+#define MCR_IENABLE                   0x08  /* output 2 = int enable */
+#define MCR_DRS                       0x04  /* output 1 = xxx */
+#define MCR_RTS                       0x02  /* enable RTS */
+#define MCR_DTR                       0x01  /* enable DTR */
+
+/* line status register */
+#define LSR_RCV_FIFO                  0x80  /* error in receive fifo */
+#define LSR_TSRE                      0x40  /* transmitter empty */
+#define LSR_TXRDY                     0x20  /* transmitter ready */
+#define LSR_BI                        0x10  /* break detected */
+#define LSR_FE                        0x08  /* framing error */
+#define LSR_PE                        0x04  /* parity error */
+#define LSR_OE                        0x02  /* overrun error */
+#define LSR_RXRDY                     0x01  /* receiver ready */
+#define LSR_RCV_MASK                  0x1f
+
+/* 16550 UART register offsets and bitfields */
+#define R_UART_RXBUF                  0
+#define R_UART_TXBUF                  0
+#define R_UART_BAUD_LOW               0
+#define R_UART_BAUD_HIGH              1
+#define R_UART_FCR                    2
+#define B_UART_FCR_FIFOE              BIT0
+#define B_UART_FCR_FIFO64             BIT5
+#define R_UART_LCR                    3
+#define B_UART_LCR_DLAB               BIT7
+#define R_UART_MCR                    4
+#define B_UART_MCR_DTRC               BIT0
+#define B_UART_MCR_RTS                BIT1
+#define R_UART_LSR                    5
+#define B_UART_LSR_RXRDY              BIT0
+#define B_UART_LSR_TXRDY              BIT5
+#define B_UART_LSR_TEMT               BIT6
+#define R_UART_MSR                    6
+#define B_UART_MSR_CTS                BIT4
+#define B_UART_MSR_DSR                BIT5
+#define B_UART_MSR_RI                 BIT6
+#define B_UART_MSR_DCD                BIT7
+#define UART_BASE_ADDRESS             (0x1fe001e0)
+#define UART_BPS                      (115200)
+#define UART_WAIT_TIMOUT              (1000000)
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c
new file mode 100644
index 0000000000..7044db81ee
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c
@@ -0,0 +1,593 @@
+/** @file
+  UART Serial Port library functions
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Bps - Bit Per Second
+    - CTL - Control
+    - Config - Configure
+**/
+
+#include <Base.h>
+#include <Library/Cpu.h>
+#include <Library/IoLib.h>
+#include <Library/SerialPortLib.h>
+#include <LoongArchQemuPlatform.h>
+
+UINTN   gUartBase = UART_BASE_ADDRESS;
+UINTN   gBps      = UART_BPS;
+
+/**
+  Initialize the serial device hardware.
+
+  If no initialization is required, then return RETURN_SUCCESS.
+  If the serial device was successfuly initialized, then return RETURN_SUCCESS.
+  If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
+
+  @retval RETURN_SUCCESS        The serial device was initialized.
+  @retval RETURN_DEVICE_ERROR   The serail device could not be initialized.
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+  VOID
+  )
+{
+  UINTN  TimeOut;
+  //
+  // wait for Tx fifo to completely drain */
+  //
+  TimeOut = UART_WAIT_TIMOUT;
+  while (!(MmioRead8 ((UINTN) gUartBase + LSR_OFFSET) & LSR_TSRE)) {
+    if (--TimeOut == 0) {
+      break;
+    }
+  }
+  //
+  // Set communications format
+  //
+  MmioWrite8 ((UINTN) (gUartBase + LCR_OFFSET), CFCR_DLAB);
+
+  //
+  // Configure baud rate
+  //
+
+  MmioWrite8 ((UINTN) (gUartBase + LCR_OFFSET), CFCR_8BITS);
+  MmioWrite8 ((UINTN) (gUartBase + MCR_OFFSET), MCR_IENABLE | MCR_DTR | MCR_RTS);
+
+  return RETURN_SUCCESS;
+}
+
+/**
+  Write data from buffer to serial device.
+
+  Writes NumberOfBytes data bytes from Buffer to the serial device.
+  The number of bytes actually written to the serial device is returned.
+  If the return value is less than NumberOfBytes, then the write operation failed.
+
+  If Buffer is NULL, then ASSERT ().
+
+  If NumberOfBytes is zero, then return 0.
+
+  @param  Buffer           Pointer to the data buffer to be written.
+  @param  NumberOfBytes    Number of bytes to written to the serial device.
+
+  @retval 0                NumberOfBytes is 0.
+  @retval >0               The number of bytes written to the serial device.
+                           If this value is less than NumberOfBytes, then the read operation failed.
+**/
+UINTN
+EFIAPI
+UartCtlWrite (
+  IN UINT8     *Buffer,
+  IN UINTN     NumberOfBytes,
+  IN UINTN     CtlAddr
+)
+{
+  UINTN  Result;
+  UINT8  Data;
+
+  if (Buffer == NULL) {
+    return 0;
+  }
+
+  Result = NumberOfBytes;
+
+  while (NumberOfBytes--) {
+    //
+    // Wait for the serail port to be ready.
+    //
+    do {
+      Data = MmioRead8 (CtlAddr + LSR_OFFSET);
+    } while ((Data & LSR_TXRDY) == 0);
+    MmioWrite8 (CtlAddr, *Buffer++);
+  }
+  return Result;
+}
+/**
+  Writes data to serial port.
+
+  @param  Buffer           Pointer to the data buffer to store the data writed to serial port.
+  @param  NumberOfBytes    Number of bytes to write to the serial port.
+
+  @retval 0                NumberOfBytes is 0.
+  @retval >0               The number of bytes write the serial port.
+                           If this value is less than NumberOfBytes, then the write operation failed.
+**/
+UINTN
+EFIAPI
+SerialPortWrite (
+  IN UINT8     *Buffer,
+  IN UINTN     NumberOfBytes
+)
+{
+  return UartCtlWrite (Buffer, NumberOfBytes, gUartBase);
+}
+/**
+  Reads data from a serial device into a buffer.
+
+  @param  Buffer           Pointer to the data buffer to store the data read from the serial device.
+  @param  NumberOfBytes    Number of bytes to read from the serial device.
+
+  @retval 0                NumberOfBytes is 0.
+  @retval >0               The number of bytes read from the serial device.
+                           If this value is less than NumberOfBytes, then the read operation failed.
+**/
+UINTN
+EFIAPI
+UartCtlRead (
+  OUT UINT8     *Buffer,
+  IN  UINTN     NumberOfBytes,
+  IN  UINTN     CtlAddr
+)
+{
+  UINTN  Result;
+  UINT8  Data;
+
+  if (NULL == Buffer) {
+    return 0;
+  }
+
+  Result = NumberOfBytes;
+
+  while (NumberOfBytes--) {
+    //
+    // Wait for the serail port to be ready.
+    //
+    do {
+      Data = MmioRead8 (CtlAddr + LSR_OFFSET);
+    } while ((Data & LSR_RXRDY) == 0);
+
+    *Buffer++ = MmioRead8 (CtlAddr);
+  }
+  return Result;
+}
+/**
+  Read data from serial port.
+
+  @param  Buffer           Pointer to the data buffer to store the data read from serial port.
+  @param  NumberOfBytes    Number of bytes to read from the serial port.
+
+  @retval 0                NumberOfBytes is 0.
+  @retval >0               The number of bytes read from the serial port.
+                           If this value is less than NumberOfBytes, then the read operation failed.
+**/
+UINTN
+EFIAPI
+SerialPortRead (
+  OUT UINT8     *Buffer,
+  IN  UINTN     NumberOfBytes
+)
+{
+  return UartCtlRead (Buffer, NumberOfBytes, gUartBase);
+}
+/**
+  Polls a serial device to see if there is any data waiting to be read.
+
+  Polls aserial device to see if there is any data waiting to be read.
+  If there is data waiting to be read from the serial device, then TRUE is returned.
+  If there is no data waiting to be read from the serial device, then FALSE is returned.
+
+  @retval TRUE             Data is waiting to be read from the serial device.
+  @retval FALSE            There is no data waiting to be read from the serial device.
+**/
+BOOLEAN
+EFIAPI
+SerialPortPoll (
+  VOID
+  )
+{
+  UINT8  Data;
+
+  //
+  // Read the serial port status.
+  //
+  Data = MmioRead8 ((UINTN) gUartBase + LSR_OFFSET);
+
+  return (BOOLEAN) ((Data & LSR_RXRDY) != 0);
+}
+/**
+  To get serial register base address.
+
+  @param  VOID
+
+  @return  serial register base address.
+**/
+UINTN
+GetSerialRegisterBase (
+  VOID
+  )
+{
+  return gUartBase;
+}
+/**
+  Read an 8-bit register.
+  @param  Base    The base address register of UART device.
+  @param  Offset  The offset of the register to read.
+
+  @return The value read from the 16550 register.
+**/
+UINT8
+SerialPortReadRegister (
+  UINTN  Base,
+  UINTN  Offset
+  )
+{
+  return MmioRead8 (Base + Offset);
+}
+
+/**
+  Write an 8-bit register.
+  @param  Base    The base address register of UART device.
+  @param  Offset  The offset of the register to write.
+  @param  Value   The value to write to the register specified by Offset.
+
+  @return The value written to the 16550 register.
+**/
+UINT8
+SerialPortWriteRegister (
+  UINTN  Base,
+  UINTN  Offset,
+  UINT8  Value
+  )
+{
+  return MmioWrite8 (Base + Offset, Value);
+}
+
+/**
+  Sets the control bits on a serial device.
+
+  @param Control                Sets the bits of Control that are settable.
+
+  @retval RETURN_SUCCESS        The new control bits were set on the serial device.
+  @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
+  @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetControl (
+  IN UINT32 Control
+  )
+{
+  UINTN SerialRegisterBase;
+  UINT8 Mcr;
+
+  //
+  // First determine the parameter is invalid.
+  //
+  if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
+                    EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0)
+  {
+    return RETURN_UNSUPPORTED;
+  }
+
+  SerialRegisterBase = GetSerialRegisterBase ();
+  if (SerialRegisterBase ==0) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  //
+  // Read the Modem Control Register.
+  //
+  Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
+  Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));
+
+  if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
+    Mcr |= B_UART_MCR_DTRC;
+  }
+
+  if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
+    Mcr |= B_UART_MCR_RTS;
+  }
+
+  //
+  // Write the Modem Control Register.
+  //
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
+
+  return RETURN_SUCCESS;
+}
+
+/**
+  Retrieve the status of the control bits on a serial device.
+
+  @param Control                A pointer to return the current control signals from the serial device.
+
+  @retval RETURN_SUCCESS        The control bits were read from the serial device.
+  @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
+  @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortGetControl (
+  OUT UINT32 *Control
+  )
+{
+  UINTN SerialRegisterBase;
+  UINT8 Msr;
+  UINT8 Mcr;
+  UINT8 Lsr;
+
+  SerialRegisterBase = GetSerialRegisterBase ();
+  if (SerialRegisterBase ==0) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  *Control = 0;
+
+  //
+  // Read the Modem Status Register.
+  //
+  Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);
+
+  if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {
+    *Control |= EFI_SERIAL_CLEAR_TO_SEND;
+  }
+
+  if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {
+    *Control |= EFI_SERIAL_DATA_SET_READY;
+  }
+
+  if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {
+    *Control |= EFI_SERIAL_RING_INDICATE;
+  }
+
+  if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {
+    *Control |= EFI_SERIAL_CARRIER_DETECT;
+  }
+
+  //
+  // Read the Modem Control Register.
+  //
+  Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
+
+  if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {
+    *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
+  }
+
+  if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {
+    *Control |= EFI_SERIAL_REQUEST_TO_SEND;
+  }
+
+  if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+    *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
+  }
+
+  //
+  // Read the Line Status Register.
+  //
+  Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);
+
+  if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
+    *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
+  }
+
+  if ((Lsr & B_UART_LSR_RXRDY) == 0) {
+    *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
+  }
+
+  return RETURN_SUCCESS;
+}
+
+/**
+  Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
+  data bits, and stop bits on a serial device.
+
+  @param BaudRate           The requested baud rate. A BaudRate value of 0 will use the
+                            device's default interface speed.
+                            On output, the value actually set.
+  @param ReveiveFifoDepth   The requested depth of the FIFO on the receive side of the
+                            serial interface. A ReceiveFifoDepth value of 0 will use
+                            the device's default FIFO depth.
+                            On output, the value actually set.
+  @param Timeout            The requested time out for a single character in microseconds.
+                            This timeout applies to both the transmit and receive side of the
+                            interface. A Timeout value of 0 will use the device's default time
+                            out value.
+                            On output, the value actually set.
+  @param Parity             The type of parity to use on this serial device. A Parity value of
+                            DefaultParity will use the device's default parity value.
+                            On output, the value actually set.
+  @param DataBits           The number of data bits to use on the serial device. A DataBits
+                            vaule of 0 will use the device's default data bit setting.
+                            On output, the value actually set.
+  @param StopBits           The number of stop bits to use on this serial device. A StopBits
+                            value of DefaultStopBits will use the device's default number of
+                            stop bits.
+                            On output, the value actually set.
+
+  @retval RETURN_SUCCESS            The new attributes were set on the serial device.
+  @retval RETURN_UNSUPPORTED        The serial device does not support this operation.
+  @retval RETURN_INVALID_PARAMETER  One or more of the attributes has an unsupported value.
+  @retval RETURN_DEVICE_ERROR       The serial device is not functioning correctly.
+**/
+RETURN_STATUS
+EFIAPI
+UartCtlConfig (
+  IN OUT UINT64             *BaudRate,
+  IN OUT UINT32             *ReceiveFifoDepth,
+  IN OUT UINT32             *Timeout,
+  IN OUT EFI_PARITY_TYPE    *Parity,
+  IN OUT UINT8              *DataBits,
+  IN OUT EFI_STOP_BITS_TYPE *StopBits,
+  IN UINTN                   CtlAddr
+  )
+{
+  UINTN     SerialRegisterBase;
+  UINT8     Lcr;
+  UINT8     LcrData;
+  UINT8     LcrParity;
+  UINT8     LcrStop;
+
+  SerialRegisterBase = CtlAddr;
+  if (SerialRegisterBase ==0) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  //
+  // Check for default settings and fill in actual values.
+  //
+  if (*BaudRate == 0) {
+    *BaudRate = PcdGet32 (PcdSerialBaudRate);
+  }
+
+  if (*DataBits == 0) {
+    LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);
+    *DataBits = LcrData + 5;
+  } else {
+    if ((*DataBits < 5)
+      || (*DataBits > 8))
+    {
+      return RETURN_INVALID_PARAMETER;
+    }
+    //
+    // Map 5..8 to 0..3
+    //
+    LcrData = (UINT8) (*DataBits - (UINT8) 5);
+  }
+
+  if (*Parity == DefaultParity) {
+    LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);
+    switch (LcrParity) {
+      case 0:
+        *Parity = NoParity;
+        break;
+
+      case 3:
+        *Parity = EvenParity;
+        break;
+
+      case 1:
+        *Parity = OddParity;
+        break;
+
+      case 7:
+        *Parity = SpaceParity;
+        break;
+
+      case 5:
+        *Parity = MarkParity;
+        break;
+
+      default:
+        break;
+    }
+  } else {
+    switch (*Parity) {
+      case NoParity:
+        LcrParity = 0;
+        break;
+
+      case EvenParity:
+        LcrParity = 3;
+        break;
+
+      case OddParity:
+        LcrParity = 1;
+        break;
+
+      case SpaceParity:
+        LcrParity = 7;
+        break;
+
+      case MarkParity:
+        LcrParity = 5;
+        break;
+
+      default:
+        return RETURN_INVALID_PARAMETER;
+    }
+  }
+
+  if (*StopBits == DefaultStopBits) {
+    LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);
+    switch (LcrStop) {
+      case 0:
+        *StopBits = OneStopBit;
+        break;
+
+      case 1:
+        if (*DataBits == 5) {
+          *StopBits = OneFiveStopBits;
+        } else {
+          *StopBits = TwoStopBits;
+        }
+        break;
+
+      default:
+        break;
+    }
+  } else {
+    switch (*StopBits) {
+      case OneStopBit:
+        LcrStop = 0;
+        break;
+
+      case OneFiveStopBits:
+      case TwoStopBits:
+        LcrStop = 1;
+        break;
+
+      default:
+        return RETURN_INVALID_PARAMETER;
+    }
+  }
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
+
+  //
+  // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
+  // Strip reserved bits from line control value
+  //
+  Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);
+  SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));
+
+  return RETURN_SUCCESS;
+}
+/**
+  Set the serial port Attributes.
+
+  @param  VOID
+
+  @return  serial register base address.
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetAttributes (
+  IN OUT UINT64             *BaudRate,
+  IN OUT UINT32             *ReceiveFifoDepth,
+  IN OUT UINT32             *Timeout,
+  IN OUT EFI_PARITY_TYPE    *Parity,
+  IN OUT UINT8              *DataBits,
+  IN OUT EFI_STOP_BITS_TYPE *StopBits
+  )
+{
+  UINTN     SerialRegisterBase;
+
+  SerialRegisterBase = GetSerialRegisterBase ();
+
+  return  UartCtlConfig (&gBps, ReceiveFifoDepth, Timeout, Parity, DataBits, StopBits,
+            SerialRegisterBase);
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
new file mode 100644
index 0000000000..22cf82cf79
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
@@ -0,0 +1,39 @@
+## @file
+#  UART Serial Port library functions
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PcAtSerialPortLib
+  FILE_GUID                      = f4fb883d-8138-4f29-bb0c-c574e9312c74
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = SerialPortLib
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  SerialPortLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+  BaseLib
+  IoLib
+  PcdLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate                ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl             ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate               ## CONSUMES
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 02/15] Platform/Loongson: Support SEC
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 01/15] Platform/Loongson: Add Serial Port library xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 03/15] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Add SEC Code And Readme.md for LoongArchQemu

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li  <lixianglai@loongson.cn>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../Include/LoongArchQemuPlatform.h           |   2 +-
 .../Loongson/LoongArchQemuPkg/Loongson.dec    |  38 ++
 .../Loongson/LoongArchQemuPkg/Loongson.dsc    | 122 +++++
 .../Loongson/LoongArchQemuPkg/Loongson.fdf    |  53 ++
 .../LoongArchQemuPkg/Loongson.fdf.inc         |  21 +
 .../LoongArchQemuPkg/Sec/LoongArch64/Start.S  |  84 +++
 .../Loongson/LoongArchQemuPkg/Sec/SecMain.c   | 494 ++++++++++++++++++
 .../Loongson/LoongArchQemuPkg/Sec/SecMain.inf |  51 ++
 8 files changed, 864 insertions(+), 1 deletion(-)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.dec
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
index e942e6a994..d003b9013d 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
@@ -92,4 +92,4 @@
 #define UART_BASE_ADDRESS             (0x1fe001e0)
 #define UART_BPS                      (115200)
 #define UART_WAIT_TIMOUT              (1000000)
-#endif
+#endif // LOONGARCH_QEMU_PLATFORM_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
new file mode 100644
index 0000000000..61f600b20d
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
@@ -0,0 +1,38 @@
+## @file
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  DEC_SPECIFICATION              = 0x00010005
+  PACKAGE_NAME                   = LoongArchQemuPkg
+  PACKAGE_GUID                   = b51d765a-41da-45fc-a537-de3ee785c0f6
+  PACKAGE_VERSION                = 0.1
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+#                   Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+#  BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+#  DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+[Includes.common]
+  Include                        # Root include for the package
+
+[Guids]
+  gLoongArchQemuPkgTokenSpaceGuid  = { 0x0e0383ce, 0x0151, 0x4d01, { 0x80, 0x0e, 0x3f, 0xef, 0x8b, 0x27, 0x6d, 0x52 } }
+
+## In the PcdsFixedAtBuild and PcdsDynamic areas, numbers start at 0x0.
+[PcdsFixedAtBuild, PcdsDynamic]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase|0x0|UINT64|0x00000000
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize|0x0|UINT32|0x00000001
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase|0|UINT64|0x0000000b
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize|0|UINT32|0x0000000c
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase|0x0|UINT64|0x0000000f
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize|0x0|UINT32|0x00000010
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
new file mode 100644
index 0000000000..b506f70625
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
@@ -0,0 +1,122 @@
+## @file
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+###############################################################################
+[Defines]
+  PLATFORM_NAME                  = LoongArchQemu
+  PLATFORMPKG_NAME               = LoongArchQemu
+  PLATFORM_GUID                  = 7926ea52-b0dc-4ee8-ac63-341eebd84ed4
+  PLATFORM_VERSION               = 0.1
+  DSC_SPECIFICATION              = 0x00010005
+  OUTPUT_DIRECTORY               = Build/$(PLATFORM_NAME)
+  SUPPORTED_ARCHITECTURES        = LOONGARCH64
+  BUILD_TARGETS                  = DEBUG|RELEASE
+  SKUID_IDENTIFIER               = DEFAULT
+  FLASH_DEFINITION               = Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
+  TTY_TERMINAL                   = FALSE
+
+############################################################################
+#
+# Defines for default states.  These can be changed on the command line.
+# -D FLAG=VALUE
+############################################################################
+[BuildOptions]
+  GCC:RELEASE_*_*_CC_FLAGS       = -DSPEEDUP
+
+  #
+  # Disable deprecated APIs.
+  #
+  GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+
+[BuildOptions.LOONGARCH64.EDKII.SEC]
+  *_*_*_CC_FLAGS                 =
+
+[BuildOptions.common.EDKII.DXE_CORE,BuildOptions.common.EDKII.DXE_DRIVER,BuildOptions.common.EDKII.UEFI_DRIVER,BuildOptions.common.EDKII.UEFI_APPLICATION]
+  GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000
+
+[BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
+  GCC:*_*_LOONGARCH64_DLINK_FLAGS = -z common-page-size=0x10000
+
+################################################################################
+#
+# Library Class section - list of all Library Classes needed by this Platform.
+#
+################################################################################
+
+!include MdePkg/MdeLibs.dsc.inc
+
+[LibraryClasses.common]
+  PcdLib                           | MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  PrintLib                         | MdePkg/Library/BasePrintLib/BasePrintLib.inf
+  BaseMemoryLib                    | MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+  BaseLib                          | MdePkg/Library/BaseLib/BaseLib.inf
+  PeCoffLib                        | MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+  PeCoffGetEntryPointLib           | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+  IoLib                            | MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+  SerialPortLib                    | Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
+  DebugPrintErrorLevelLib          | MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+  PeCoffExtraActionLib             | MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+  DebugAgentLib                    | MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform.
+#
+################################################################################
+[PcdsFixedAtBuild]
+## BaseLib ##
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength               | 1000000
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength                 | 1000000
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength                  | 1000000
+
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel                     | 0x8000004F
+  # DEBUG_INIT      0x00000001  // Initialization
+  # DEBUG_WARN      0x00000002  // Warnings
+  # DEBUG_LOAD      0x00000004  // Load events
+  # DEBUG_FS        0x00000008  // EFI File system
+  # DEBUG_POOL      0x00000010  // Alloc & Free (pool)
+  # DEBUG_PAGE      0x00000020  // Alloc & Free (page)
+  # DEBUG_INFO      0x00000040  // Informational debug messages
+  # DEBUG_DISPATCH  0x00000080  // PEI/DXE/SMM Dispatchers
+  # DEBUG_VARIABLE  0x00000100  // Variable
+  # DEBUG_BM        0x00000400  // Boot Manager
+  # DEBUG_BLKIO     0x00001000  // BlkIo Driver
+  # DEBUG_NET       0x00004000  // Network Io Driver
+  # DEBUG_UNDI      0x00010000  // UNDI Driver
+  # DEBUG_LOADFILE  0x00020000  // LoadFile
+  # DEBUG_EVENT     0x00080000  // Event messages
+  # DEBUG_GCD       0x00100000  // Global Coherency Database changes
+  # DEBUG_CACHE     0x00200000  // Memory range cachability changes
+  # DEBUG_VERBOSE   0x00400000  // Detailed debug messages that may
+  # DEBUG_ERROR     0x80000000  // Error
+
+!if $(TARGET) == RELEASE
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask                        | 0x21
+!else
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask                        | 0x2f
+!endif
+  # DEBUG_ASSERT_ENABLED       0x01
+  # DEBUG_PRINT_ENABLED        0x02
+  # DEBUG_CODE_ENABLED         0x04
+  # CLEAR_MEMORY_ENABLED       0x08
+  # ASSERT_BREAKPOINT_ENABLED  0x10
+  # ASSERT_DEADLOOP_ENABLED    0x20
+
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase                 | 0x10000
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize                 | 0x10000
+
+[Components]
+
+  #
+  # SEC Phase modules
+  #
+  Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
new file mode 100644
index 0000000000..9685795cda
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
@@ -0,0 +1,53 @@
+## @file
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+#####################################################################################################
+[Defines]
+!include Loongson.fdf.inc
+
+#####################################################################################################
+[FD.QEMU_EFI]
+BaseAddress   = $(FD_BASE_ADDRESS)
+Size          = $(FD_SIZE)
+ErasePolarity = 1
+BlockSize     = $(BLOCK_SIZE)
+NumBlocks     = $(FD_BLOCKS)
+
+$(SECFV_OFFSET)|$(SECFV_SIZE)
+gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase|gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
+FV = SECFV
+
+#####################################################################################################
+[FV.SECFV]
+FvNameGuid         = 587d4265-5e71-41da-9c35-4258551f1e22
+BlockSize          = $(BLOCK_SIZE)
+FvAlignment        = 16
+ERASE_POLARITY     = 1
+MEMORY_MAPPED      = TRUE
+STICKY_WRITE       = TRUE
+LOCK_CAP           = TRUE
+LOCK_STATUS        = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP  = TRUE
+WRITE_STATUS       = TRUE
+WRITE_LOCK_CAP     = TRUE
+WRITE_LOCK_STATUS  = TRUE
+READ_DISABLED_CAP  = TRUE
+READ_ENABLED_CAP   = TRUE
+READ_STATUS        = TRUE
+READ_LOCK_CAP      = TRUE
+READ_LOCK_STATUS   = TRUE
+
+INF  Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
+
+#####################################################################################################
+[Rule.Common.SEC]
+  FILE SEC = $(NAMED_GUID) {
+    TE       TE Align = Auto   $(INF_OUTPUT)/$(MODULE_NAME).efi
+    UI       STRING ="$(MODULE_NAME)" Optional
+  }
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
new file mode 100644
index 0000000000..6f17909748
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
@@ -0,0 +1,21 @@
+## @file
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+DEFINE BLOCK_SIZE                 = 0x1000
+
+############################################################################
+# fd total
+DEFINE FD_BASE_ADDRESS            = 0x1c000000
+DEFINE FD_BLOCKS                  = 0x400
+DEFINE FD_SIZE                    = 0x400000
+
+############################################################################
+#flash code layout
+#Set Sec base address and size in flash
+DEFINE SECFV_OFFSET               = 0x00000000
+DEFINE SECFV_SIZE                 = 0x00010000
diff --git a/Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S b/Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S
new file mode 100644
index 0000000000..5d7ce313c0
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S
@@ -0,0 +1,84 @@
+#------------------------------------------------------------------------------
+#
+# Start for LoongArch
+#
+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#  @par Glossary:
+#    - CSR - CPU Status Register
+#    - EBASE - Exception Base Address
+#------------------------------------------------------------------------------
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include <Library/Cpu.h>
+
+ASM_GLOBAL ASM_PFX(_ModuleEntryPoint)
+ASM_GLOBAL ASM_PFX(DeadLoop)
+
+.text
+ASM_PFX(_ModuleEntryPoint):
+    /* configure reset ebase */
+    la.pcrel    T0, DeadLoop
+    csrwr   T0, LOONGARCH_CSR_EBASE
+
+    /*disable interrupt*/
+    li.d    T0, (1 << 2)
+    csrxchg ZERO, T0, LOONGARCH_CSR_CRMD
+
+    /* read physical cpu number id */
+    csrrd   T0, LOONGARCH_CSR_CPUNUM
+    andi    T0, T0, 0x3ff
+    li.d    A0, BOOTCORE_ID  //0
+    bne     T0, A0, slave_main
+
+call_centry:
+    /*call C function make sure parameter true*/
+    li.d    A1, FixedPcdGet64(PcdSecPeiTempRamBase) + FixedPcdGet32(PcdSecPeiTempRamSize)  # stack base
+    li.d    A0, FixedPcdGet64(PcdFlashPeiFvBase) # PEI Fv base
+    move    SP, A1
+    addi.d  SP, SP, -0x8
+    bl      SecCoreStartupWithStack
+
+slave_main:
+    # clear mailbox
+    li.d      T1, LOONGSON_CSR_MAIL_BUF0
+    iocsrwr.d ZERO, T1
+
+    # enable IPI interrupt
+    li.d      T0, (1 << 12)
+    csrxchg   T0, T0, LOONGARCH_CSR_ECFG
+
+    addi.d    T0, ZERO, -1
+    li.d      T1, LOONGSON_IOCSR_IPI_EN
+    iocsrwr.w T0, T1
+
+1:
+    # wait for wakeup
+    idle 0
+    nop
+    iocsrrd.w T0, T1
+    beqz      T0, 1b
+
+    # read and clear ipi interrupt
+    li.d      T1, LOONGSON_IOCSR_IPI_STATUS
+    iocsrrd.w T0, T1
+    li.d      T1, LOONGSON_IOCSR_IPI_CLEAR
+    iocsrwr.w T0, T1
+
+    # disable IPI interrupt
+    li.d      T0, (1 << 12)
+    csrxchg   ZERO, T0, LOONGARCH_CSR_ECFG
+
+    # read mail buf and jump to specified entry
+    li.d      T1, LOONGSON_CSR_MAIL_BUF0
+    iocsrrd.d T0, T1
+    or        RA, T0, ZERO
+    jirl      ZERO, RA, 0x0
+
+.align 12
+ASM_PFX(DeadLoop):
+    b DeadLoop
diff --git a/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c b/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c
new file mode 100644
index 0000000000..3f1998c48c
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c
@@ -0,0 +1,494 @@
+/** @file
+  Main SEC phase code.  Transitions to PEI.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/IoLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+
+#include <Ppi/TemporaryRamSupport.h>
+
+/**
+  temporary memory to permanent memory and do stack switching.
+
+  @param[in]  PeiServices     Pointer to the PEI Services Table.
+  @param[in]  TemporaryMemoryBase    Temporary Memory Base address.
+  @param[in]  PermanentMemoryBase   Permanent Memory Base address.
+  @param[in]  CopySize   The size of memory that needs to be migrated.
+
+  @retval   EFI_SUCCESS  Migration successful.
+**/
+EFI_STATUS
+EFIAPI
+TemporaryRamMigration (
+  IN CONST EFI_PEI_SERVICES   **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
+  IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
+  IN UINTN                    CopySize
+  );
+
+EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
+  TemporaryRamMigration
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {
+  {
+    (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+    &gEfiTemporaryRamSupportPpiGuid,
+    &mTemporaryRamSupportPpi
+  },
+};
+
+/**
+  Locates a section within a series of sections
+  with the specified section type.
+
+  The Instance parameter indicates which instance of the section
+  type to return. (0 is first instance, 1 is second...)
+
+  @param[in]   Sections        The sections to search
+  @param[in]   SizeOfSections  Total size of all sections
+  @param[in]   SectionType     The section type to locate
+  @param[in]   Instance        The section instance number
+  @param[out]  FoundSection    The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+**/
+EFI_STATUS
+FindFfsSectionInstance (
+  IN  VOID                             *Sections,
+  IN  UINTN                            SizeOfSections,
+  IN  EFI_SECTION_TYPE                 SectionType,
+  IN  UINTN                            Instance,
+  OUT EFI_COMMON_SECTION_HEADER        **FoundSection
+  )
+{
+  EFI_PHYSICAL_ADDRESS        CurrentAddress;
+  UINT32                      Size;
+  EFI_PHYSICAL_ADDRESS        EndOfSections;
+  EFI_COMMON_SECTION_HEADER   *Section;
+  EFI_PHYSICAL_ADDRESS        EndOfSection;
+
+  //
+  // Loop through the FFS file sections within the PEI Core FFS file
+  //
+  EndOfSection = (EFI_PHYSICAL_ADDRESS) (UINTN) Sections;
+  EndOfSections = EndOfSection + SizeOfSections;
+  for (;;) {
+    if (EndOfSection == EndOfSections) {
+      break;
+    }
+    CurrentAddress = (EndOfSection + 3) & ~(3ULL);
+    if (CurrentAddress >= EndOfSections) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    Section = (EFI_COMMON_SECTION_HEADER*) (UINTN) CurrentAddress;
+
+    Size = SECTION_SIZE (Section);
+    if (Size < sizeof (*Section)) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    EndOfSection = CurrentAddress + Size;
+    if (EndOfSection > EndOfSections) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    //
+    // Look for the requested section type
+    //
+    if (Section->Type == SectionType) {
+      if (Instance == 0) {
+        *FoundSection = Section;
+        return EFI_SUCCESS;
+      } else {
+        Instance--;
+      }
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Locates a section within a series of sections
+  with the specified section type.
+
+  @param[in]   Sections        The sections to search
+  @param[in]   SizeOfSections  Total size of all sections
+  @param[in]   SectionType     The section type to locate
+  @param[out]  FoundSection    The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+**/
+EFI_STATUS
+FindFfsSectionInSections (
+  IN  VOID                             *Sections,
+  IN  UINTN                            SizeOfSections,
+  IN  EFI_SECTION_TYPE                 SectionType,
+  OUT EFI_COMMON_SECTION_HEADER        **FoundSection
+  )
+{
+  return FindFfsSectionInstance (
+           Sections,
+           SizeOfSections,
+           SectionType,
+           0,
+           FoundSection
+           );
+}
+
+/**
+  Locates a FFS file with the specified file type and a section
+  within that file with the specified section type.
+
+  @param[in]   Fv            The firmware volume to search
+  @param[in]   FileType      The file type to locate
+  @param[in]   SectionType   The section type to locate
+  @param[out]  FoundSection  The FFS section if found
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+**/
+EFI_STATUS
+FindFfsFileAndSection (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
+  IN  EFI_FV_FILETYPE                  FileType,
+  IN  EFI_SECTION_TYPE                 SectionType,
+  OUT EFI_COMMON_SECTION_HEADER        **FoundSection
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_PHYSICAL_ADDRESS        CurrentAddress;
+  EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
+  EFI_FFS_FILE_HEADER         *File;
+  UINT32                      Size;
+  EFI_PHYSICAL_ADDRESS        EndOfFile;
+
+  if (Fv->Signature != EFI_FVH_SIGNATURE) {
+    DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header signature\n", Fv));
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  CurrentAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv;
+  EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
+
+  //
+  // Loop through the FFS files in the Boot Firmware Volume
+  //
+  for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
+
+    CurrentAddress = (EndOfFile + 7) & ~(7ULL);
+    if (CurrentAddress > EndOfFirmwareVolume) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    File = (EFI_FFS_FILE_HEADER*) (UINTN) CurrentAddress;
+    Size = *(UINT32*) File->Size & 0xffffff;
+    if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    EndOfFile = CurrentAddress + Size;
+    if (EndOfFile > EndOfFirmwareVolume) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    //
+    // Look for the request file type
+    //
+    if (File->Type != FileType) {
+      continue;
+    }
+
+    Status = FindFfsSectionInSections (
+               (VOID*) (File + 1),
+               (UINTN) EndOfFile - (UINTN) (File + 1),
+               SectionType,
+               FoundSection
+               );
+    if (!EFI_ERROR (Status)
+      || (Status == EFI_VOLUME_CORRUPTED))
+    {
+      return Status;
+    }
+  }
+}
+
+/**
+  Locates the PEI Core entry point address
+
+  @param[in]  Fv                 The firmware volume to search
+  @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
+
+  @retval EFI_SUCCESS           The file and section was found
+  @retval EFI_NOT_FOUND         The file and section was not found
+  @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
+**/
+EFI_STATUS
+FindPeiCoreImageBaseInFv (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
+  OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_COMMON_SECTION_HEADER   *Section;
+
+  Status = FindFfsFileAndSection (
+             Fv,
+             EFI_FV_FILETYPE_PEI_CORE,
+             EFI_SECTION_PE32,
+             &Section
+             );
+  if (EFI_ERROR (Status)) {
+    Status = FindFfsFileAndSection (
+               Fv,
+               EFI_FV_FILETYPE_PEI_CORE,
+               EFI_SECTION_TE,
+               &Section
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));
+      return Status;
+    }
+  }
+
+  *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
+  return EFI_SUCCESS;
+}
+
+/**
+  Find and return Pei Core entry point.
+
+  It also find SEC and PEI Core file debug information. It will report them if
+  remote debug is enabled.
+**/
+VOID
+FindAndReportEntryPoints (
+  IN  EFI_FIRMWARE_VOLUME_HEADER       **BootFirmwareVolumePtr,
+  OUT EFI_PEI_CORE_ENTRY_POINT         *PeiCoreEntryPoint
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_PHYSICAL_ADDRESS             PeiCoreImageBase = 0;
+  PE_COFF_LOADER_IMAGE_CONTEXT     ImageContext;
+
+  Status = FindPeiCoreImageBaseInFv (*BootFirmwareVolumePtr, &PeiCoreImageBase);
+  ASSERT (Status == EFI_SUCCESS);
+
+  ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+
+  //
+  // Report PEI Core debug information when remote debug is enabled
+  //
+  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
+  ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
+  PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+
+  //
+  // Find PEI Core entry point
+  //
+  Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);
+  if (EFI_ERROR (Status)) {
+    *PeiCoreEntryPoint = 0;
+  }
+
+  return;
+}
+
+/**
+  Find the peicore entry point and jump to the entry point to execute.
+
+  @param[in] Context    The first input parameter of InitializeDebugAgent().
+**/
+VOID
+EFIAPI
+SecStartupPhase2 (
+  IN VOID                     *Context
+  )
+{
+  EFI_SEC_PEI_HAND_OFF        *SecCoreData;
+  EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
+  EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
+
+  SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
+
+  //
+  // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
+  // is enabled.
+  //
+  BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
+  FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
+  SecCoreData->BootFirmwareVolumeBase = BootFv;
+  SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
+
+  DEBUG ((DEBUG_INFO, "Find Pei EntryPoint=%p\n", PeiCoreEntryPoint));
+
+  //
+  // Transfer the control to the PEI core
+  //
+  DEBUG ((DEBUG_INFO, "SecStartupPhase2 %p\n", PeiCoreEntryPoint));
+
+  (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
+
+  //
+  // If we get here then the PEI Core returned, which is not recoverable.
+  //
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
+/**
+  Entry point to the C language phase of SEC. initialize some temporary memory and set up the stack,
+  the control is transferred to this function.
+
+  @param[in]  BootFv   The pointer to the PEI FV in memory.
+  @param[in]  TopOfCurrentStack  Top of Current Stack.
+**/
+VOID
+EFIAPI
+SecCoreStartupWithStack (
+  IN EFI_FIRMWARE_VOLUME_HEADER       *BootFv,
+  IN VOID                             *TopOfCurrentStack
+  )
+{
+  EFI_SEC_PEI_HAND_OFF             SecCoreData;
+  EFI_FIRMWARE_VOLUME_HEADER       *BootPeiFv = (EFI_FIRMWARE_VOLUME_HEADER*) BootFv;
+
+  DEBUG ((DEBUG_INFO, "Entering C environment\n"));
+
+  ProcessLibraryConstructorList (NULL, NULL);
+
+  DEBUG ((DEBUG_INFO,
+    "SecCoreStartupWithStack (0x%lx, 0x%lx)\n",
+    (UINTN)BootFv,
+    (UINTN)TopOfCurrentStack
+    ));
+  DEBUG ((DEBUG_INFO,
+    "(0x%lx, 0x%lx)\n",
+    (UINTN) (PcdGet64 (PcdSecPeiTempRamBase)),
+    (UINTN) (PcdGet32 (PcdSecPeiTempRamSize))
+    ));
+
+  // |-------------|       <-- TopOfCurrentStack
+  // |   Stack     | 32k
+  // |-------------|
+  // |    Heap     | 32k
+  // |-------------|       <-- SecCoreData.TemporaryRamBase
+  //
+
+  ASSERT ((UINTN) (PcdGet64 (PcdSecPeiTempRamBase) +
+                   PcdGet32 (PcdSecPeiTempRamSize)) ==
+          (UINTN) TopOfCurrentStack);
+
+  //
+  // Initialize SEC hand-off state
+  //
+  SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
+
+  SecCoreData.TemporaryRamSize       = (UINTN) PcdGet32 (PcdSecPeiTempRamSize);
+  SecCoreData.TemporaryRamBase       = (VOID *) PcdGet64 (PcdSecPeiTempRamBase);
+
+  SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
+  SecCoreData.PeiTemporaryRamSize    = SecCoreData.TemporaryRamSize >> 1;
+
+  SecCoreData.StackBase              = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
+  SecCoreData.StackSize              = SecCoreData.TemporaryRamSize >> 1;
+
+  SecCoreData.BootFirmwareVolumeBase = BootPeiFv;
+  SecCoreData.BootFirmwareVolumeSize = (UINTN) BootPeiFv->FvLength;
+
+  DEBUG ((DEBUG_INFO,
+    "&SecCoreData.BootFirmwareVolumeBase=%lx SecCoreData.BootFirmwareVolumeBase=%lx\n",
+    (UINT64)&(SecCoreData.BootFirmwareVolumeBase),
+    (UINT64) (SecCoreData.BootFirmwareVolumeBase)));
+  DEBUG ((DEBUG_INFO,
+    "&SecCoreData.BootFirmwareVolumeSize=%lx SecCoreData.BootFirmwareVolumeSize=%lx\n",
+    (UINT64)&(SecCoreData.BootFirmwareVolumeSize),
+    (UINT64) (SecCoreData.BootFirmwareVolumeSize)));
+
+  //
+  // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
+  //
+  InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL);
+  SecStartupPhase2 (&SecCoreData);
+}
+
+/**
+  temporary memory to permanent memory and do stack switching.
+
+  @param[in]  PeiServices     Pointer to the PEI Services Table.
+  @param[in]  TemporaryMemoryBase    Temporary Memory Base address.
+  @param[in]  PermanentMemoryBase   Permanent Memory Base address.
+  @param[in]  CopySize   The size of memory that needs to be migrated.
+
+  @retval   EFI_SUCCESS  Migration successful.
+**/
+EFI_STATUS
+EFIAPI
+TemporaryRamMigration (
+  IN CONST EFI_PEI_SERVICES   **PeiServices,
+  IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
+  IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
+  IN UINTN                    CopySize
+  )
+{
+  VOID                             *OldHeap;
+  VOID                             *NewHeap;
+  VOID                             *OldStack;
+  VOID                             *NewStack;
+  BASE_LIBRARY_JUMP_BUFFER         JumpBuffer;
+
+  DEBUG ((DEBUG_INFO,
+    "TemporaryRamMigration (0x%Lx, 0x%Lx, 0x%Lx)\n",
+    TemporaryMemoryBase,
+    PermanentMemoryBase,
+    (UINT64)CopySize
+    ));
+
+  OldHeap = (VOID*) (UINTN)TemporaryMemoryBase;
+  NewHeap = (VOID*) ((UINTN)PermanentMemoryBase + (CopySize >> 1));
+
+  OldStack = (VOID*) ((UINTN)TemporaryMemoryBase + (CopySize >> 1));
+  NewStack = (VOID*) (UINTN)PermanentMemoryBase;
+
+  //
+  // Migrate Heap
+  //
+  CopyMem (NewHeap, OldHeap, CopySize >> 1);
+
+  //
+  // Migrate Stack
+  //
+  CopyMem (NewStack, OldStack, CopySize >> 1);
+
+  // Use SetJump ()/LongJump () to switch to a new stack.
+  //
+  if (SetJump (&JumpBuffer) == 0) {
+    JumpBuffer.SP = JumpBuffer.SP - (UINTN)OldStack + (UINTN)NewStack ;
+    LongJump (&JumpBuffer, (UINTN)-1);
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf b/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
new file mode 100644
index 0000000000..c0d5439d53
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
@@ -0,0 +1,51 @@
+## @file
+#  SEC Driver
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SecMain
+  FILE_GUID                      = 57d02d4f-5a5d-4bfa-b7d6-ba0a4d2c72ce
+  MODULE_TYPE                    = SEC
+  VERSION_STRING                 = 1.0
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  LoongArch64/Start.S
+  SecMain.c
+
+[Packages]
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  BaseMemoryLib
+  PcdLib
+  DebugAgentLib
+  IoLib
+  PeCoffLib
+  PeCoffGetEntryPointLib
+  PeCoffExtraActionLib
+
+[Ppis]
+  gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
+
+[FixedPcd]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize
+
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 03/15] Platform/Loongson: Add PeiServicesTablePointerLib.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 01/15] Platform/Loongson: Add Serial Port library xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 02/15] Platform/Loongson: Support SEC xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 04/15] Platform/Loongson: Add QemuFwCfgLib xianglai
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Use a register to save PeiServicesTable pointer,
This lib Provides PeiServicesTable pointer saving
and retrieval services.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../PeiServicesTablePointer.c                 | 79 +++++++++++++++++++
 .../PeiServicesTablePointer.h                 | 39 +++++++++
 .../PeiServicesTablePointerLib.S              | 40 ++++++++++
 .../PeiServicesTablePointerLib.inf            | 32 ++++++++
 4 files changed, 190 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c
new file mode 100644
index 0000000000..204def3bde
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c
@@ -0,0 +1,79 @@
+/** @file
+  PEI Services Table Pointer Library.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "PeiServicesTablePointer.h"
+
+/**
+  Caches a pointer PEI Services Table.
+
+  Caches the pointer to the PEI Services Table specified by PeiServicesTablePointer
+  in a platform specific manner.
+
+  If PeiServicesTablePointer is NULL, then ASSERT ().
+
+  @param    PeiServicesTablePointer   The address of PeiServices pointer.
+**/
+VOID
+EFIAPI
+SetPeiServicesTablePointer (
+  IN CONST EFI_PEI_SERVICES ** PeiServicesTablePointer
+  )
+{
+  LoongarchWriteqKs0 ((UINTN)PeiServicesTablePointer);
+}
+
+/**
+  Retrieves the cached value of the PEI Services Table pointer.
+
+  Returns the cached value of the PEI Services Table pointer in a CPU specific manner
+  as specified in the CPU binding section of the Platform Initialization Pre-EFI
+  Initialization Core Interface Specification.
+
+  If the cached PEI Services Table pointer is NULL, then ASSERT ().
+
+  @return  The pointer to PeiServices.
+**/
+CONST EFI_PEI_SERVICES **
+EFIAPI
+GetPeiServicesTablePointer (
+  VOID
+  )
+{
+  UINTN  val;
+
+  LoongarchReadqKs0 (&val);
+
+  return (CONST EFI_PEI_SERVICES **)val;
+}
+
+/**
+Perform CPU specific actions required to migrate the PEI Services Table
+pointer from temporary RAM to permanent RAM.
+
+For IA32 CPUs, the PEI Services Table pointer is stored in the 4 bytes
+immediately preceding the Interrupt Descriptor Table (IDT) in memory.
+For X64 CPUs, the PEI Services Table pointer is stored in the 8 bytes
+immediately preceding the Interrupt Descriptor Table (IDT) in memory.
+For Itanium and ARM CPUs, a the PEI Services Table Pointer is stored in
+a dedicated CPU register.  This means that there is no memory storage
+associated with storing the PEI Services Table pointer, so no additional
+migration actions are required for Itanium or ARM CPUs.
+*/
+VOID
+EFIAPI
+MigratePeiServicesTablePointer (
+VOID
+)
+{
+  return;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.h b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.h
new file mode 100644
index 0000000000..5bcbc810d0
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.h
@@ -0,0 +1,39 @@
+/** @file
+  PeiServicesTablePointer
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PEISERVICESTABLEPOINTER_H_
+#define PEISERVICESTABLEPOINTER_H_
+
+/**
+  Write Csr KS0 register.
+
+ @param A0 The value used to write to the KS0 register
+
+  @retval none
+**/
+extern
+VOID
+LoongarchWriteqKs0 (
+  IN UINT64  Val
+  );
+
+/**
+  Read Csr KS0 register.
+
+ @param  Val Pointer to the variable used to store the KS0 register value
+
+  @retval none
+**/
+extern
+VOID
+LoongarchReadqKs0 (
+  IN UINT64  *Val
+  );
+
+#endif // PEISERVICESTABLEPOINTER_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.S b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.S
new file mode 100644
index 0000000000..7c6170c5d6
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.S
@@ -0,0 +1,40 @@
+#------------------------------------------------------------------------------
+#
+# Timer Cfg for LoongArch
+#
+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include "Library/Cpu.h"
+
+ASM_GLOBAL ASM_PFX(LoongarchWriteqKs0)
+ASM_GLOBAL ASM_PFX(LoongarchReadqKs0)
+
+#
+# Write Csr KS0 register.
+# @param A0 The value used to write to the KS0 register
+# @retval  none
+#
+
+ASM_PFX(LoongarchWriteqKs0):
+    csrwr   A0, LOONGARCH_CSR_KS0
+    jirl    ZERO, RA,0
+
+#
+# Write Csr KS0 register.
+# @param A0 Pointer to the variable used to store the KS0 register value
+# @retval  none
+#
+
+ASM_PFX(LoongarchReadqKs0):
+    csrrd T0, LOONGARCH_CSR_KS0
+    stptr.d T0, A0, 0
+    jirl    ZERO, RA,0
+    jirl    ZERO, RA,0
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
new file mode 100644
index 0000000000..2ab0d53d4c
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
@@ -0,0 +1,32 @@
+## @file
+#  PEI Services Table Pointer Library.
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PeiServicesTablePointerLib
+  FILE_GUID                      = C3C9C4ED-EB8A-4548-BE1B-ABB0B6F35B1E
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PeiServicesTablePointerLib|PEIM PEI_CORE SEC
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  PeiServicesTablePointer.c
+  PeiServicesTablePointerLib.S
+
+[Packages]
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  DebugLib
+
+[Pcd]
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 04/15] Platform/Loongson: Add QemuFwCfgLib.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (2 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 03/15] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 05/15] Platform/Loongson: Add MmuLib xianglai
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

QemuFwCfgLib for PEI phase.
This library obtains the QemuFWCfg base address by
directly parsing the fdt, and reads and writes the data
in the QemuFWCfg by operating on the QemuFWCfg base address.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../Include/Library/QemuFwCfgLib.h            | 174 +++++++
 .../QemuFwCfgLib/QemuFwCfgLibInternal.h       |  63 +++
 .../Library/QemuFwCfgLib/QemuFwCfgPei.c       | 117 +++++
 .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.c    | 463 ++++++++++++++++++
 .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf  |  46 ++
 5 files changed, 863 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h
new file mode 100644
index 0000000000..11da4d0b8a
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h
@@ -0,0 +1,174 @@
+/** @file
+  QEMU/KVM Firmware Configuration access
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - FW or Fw    - Firmware
+    - Cfg         - Configure
+**/
+
+#ifndef QEMU_FW_CFG_LIB_
+#define QEMU_FW_CFG_LIB_
+
+#include <IndustryStandard/QemuFwCfg.h>
+
+typedef enum {
+  EfiAcpiAddressRangeMemory   = 1,
+  EfiAcpiAddressRangeReserved = 2,
+  EfiAcpiAddressRangeACPI     = 3,
+  EfiAcpiAddressRangeNVS      = 4
+} EFI_ACPI_MEMORY_TYPE;
+
+typedef struct {
+  UINT64  BaseAddr;
+  UINT64  Length;
+  UINT32  Type;
+  UINT32  Reserved;
+} LOONGARCH_MEMMAP_ENTRY;
+
+/**
+  Returns a boolean indicating if the firmware configuration interface
+  is available or not.
+
+  This function may change fw_cfg state.
+
+  @retval    TRUE   The interface is available
+  @retval    FALSE  The interface is not available
+**/
+BOOLEAN
+EFIAPI
+QemuFwCfgIsAvailable (
+  VOID
+  );
+
+/**
+  Selects a firmware configuration item for reading.
+
+  Following this call, any data read from this item will start from
+  the beginning of the configuration item's data.
+
+  @param[in] QemuFwCfgItem - Firmware Configuration item to read
+**/
+VOID
+EFIAPI
+QemuFwCfgSelectItem (
+  IN FIRMWARE_CONFIG_ITEM   QemuFwCfgItem
+  );
+
+/**
+  Reads firmware configuration bytes into a buffer
+
+  If called multiple times, then the data read will
+  continue at the offset of the firmware configuration
+  item where the previous read ended.
+
+  @param[in] Size - Size in bytes to read
+  @param[in] Buffer - Buffer to store data into
+**/
+VOID
+EFIAPI
+QemuFwCfgReadBytes (
+  IN UINTN                  Size,
+  IN VOID                   *Buffer  OPTIONAL
+  );
+
+/**
+  Writes firmware configuration bytes from a buffer
+
+  If called multiple times, then the data written will
+  continue at the offset of the firmware configuration
+  item where the previous write ended.
+
+  @param[in] Size - Size in bytes to write
+  @param[in] Buffer - Buffer to read data from
+**/
+VOID
+EFIAPI
+QemuFwCfgWriteBytes (
+  IN UINTN                  Size,
+  IN VOID                   *Buffer
+  );
+
+/**
+  Skip bytes in the firmware configuration item.
+
+  Increase the offset of the firmware configuration item without transferring
+  bytes between the item and a caller-provided buffer. Subsequent read, write
+  or skip operations will commence at the increased offset.
+
+  @param[in] Size  Number of bytes to skip.
+**/
+VOID
+EFIAPI
+QemuFwCfgSkipBytes (
+  IN UINTN                  Size
+  );
+
+/**
+  Reads a UINT8 firmware configuration value
+
+  @retval    Value of Firmware Configuration item read
+**/
+UINT8
+EFIAPI
+QemuFwCfgRead8 (
+  VOID
+  );
+
+/**
+  Reads a UINT16 firmware configuration value
+
+  @retval    Value of Firmware Configuration item read
+**/
+UINT16
+EFIAPI
+QemuFwCfgRead16 (
+  VOID
+  );
+
+/**
+  Reads a UINT32 firmware configuration value
+
+  @retval    Value of Firmware Configuration item read
+**/
+UINT32
+EFIAPI
+QemuFwCfgRead32 (
+  VOID
+  );
+
+/**
+  Reads a UINT64 firmware configuration value
+
+  @retval    Value of Firmware Configuration item read
+**/
+UINT64
+EFIAPI
+QemuFwCfgRead64 (
+  VOID
+  );
+
+/**
+  Find the configuration item corresponding to the firmware configuration file.
+
+  @param[in]  Name - Name of file to look up.
+  @param[out] Item - Configuration item corresponding to the file, to be passed
+                     to QemuFwCfgSelectItem ().
+  @param[out] Size - Number of bytes in the file.
+
+  @retval    RETURN_SUCCESS       If file is found.
+             RETURN_NOT_FOUND     If file is not found.
+             RETURN_UNSUPPORTED   If firmware configuration is unavailable.
+**/
+RETURN_STATUS
+EFIAPI
+QemuFwCfgFindFile (
+  IN   CONST CHAR8           *Name,
+  OUT  FIRMWARE_CONFIG_ITEM  *Item,
+  OUT  UINTN                 *Size
+  );
+
+#endif // QEMU_FW_CFG_LIB_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
new file mode 100644
index 0000000000..229c080961
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
@@ -0,0 +1,63 @@
+/** @file
+  fw_cfg library implementation.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - FwCfg   - firmWare  Configure
+**/
+
+#ifndef QEMU_FW_CFG_LIB_INTERNAL_H_
+#define QEMU_FW_CFG_LIB_INTERNAL_H_
+
+/**
+  Returns a boolean indicating if the firmware configuration interface is
+  available for library-internal purposes.
+
+  This function never changes fw_cfg state.
+
+  @retval    TRUE   The interface is available internally.
+  @retval    FALSE  The interface is not available internally.
+**/
+BOOLEAN
+InternalQemuFwCfgIsAvailable (
+  VOID
+  );
+
+/**
+  Returns a boolean indicating whether QEMU provides the DMA-like access method
+  for fw_cfg.
+
+  @retval    TRUE   The DMA-like access method is available.
+  @retval    FALSE  The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+  VOID
+  );
+
+/**
+  Transfer an array of bytes, or skip a number of bytes, using the DMA
+  interface.
+
+  @param[in]     Size     Size in bytes to transfer or skip.
+
+  @param[in,out] Buffer   Buffer to read data into or write data from. Ignored,
+                          and may be NULL, if Size is zero, or Control is
+                          FW_CFG_DMA_CTL_SKIP.
+
+  @param[in]     Control  One of the following:
+                          FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
+                          FW_CFG_DMA_CTL_READ  - read from fw_cfg into Buffer.
+                          FW_CFG_DMA_CTL_SKIP  - skip bytes in fw_cfg.
+**/
+VOID
+InternalQemuFwCfgDmaBytes (
+  IN     UINT32   Size,
+  IN OUT VOID     *Buffer OPTIONAL,
+  IN     UINT32   Control
+  );
+
+#endif // QEMU_FW_CFG_LIB_INTERNAL_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
new file mode 100644
index 0000000000..b170c953f3
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
@@ -0,0 +1,117 @@
+/** @file
+  fw_cfg library implementation.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - FwCfg   - firmWare  Configure
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/QemuFwCfgLib.h>
+
+#include "QemuFwCfgLibInternal.h"
+
+/**
+  Returns a boolean indicating if the firmware configuration interface
+  is available or not.
+
+  This function may change fw_cfg state.
+
+  @retval    TRUE   The interface is available
+  @retval    FALSE  The interface is not available
+**/
+BOOLEAN
+EFIAPI
+QemuFwCfgIsAvailable (
+  VOID
+  )
+{
+  UINT32 Signature;
+  UINT32 Revision;
+
+  QemuFwCfgSelectItem (QemuFwCfgItemSignature);
+  Signature = QemuFwCfgRead32 ();
+  DEBUG ((DEBUG_INFO, "FW CFG Signature: 0x%x\n", Signature));
+  QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
+  Revision = QemuFwCfgRead32 ();
+  DEBUG ((DEBUG_INFO, "FW CFG Revision: 0x%x\n", Revision));
+  if ((Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U'))
+    || (Revision < 1))
+  {
+    DEBUG ((DEBUG_INFO, "QemuFwCfg interface not supported.\n"));
+    return FALSE;
+  }
+
+  DEBUG ((DEBUG_INFO, "QemuFwCfg interface is supported.\n"));
+  return TRUE;
+}
+
+/**
+  Returns a boolean indicating if the firmware configuration interface is
+  available for library-internal purposes.
+
+  This function never changes fw_cfg state.
+
+  @retval    TRUE   The interface is available internally.
+  @retval    FALSE  The interface is not available internally.
+**/
+BOOLEAN
+InternalQemuFwCfgIsAvailable (
+  VOID
+  )
+{
+  //
+  // We always return TRUE, because the consumer of this library ought to have
+  // called QemuFwCfgIsAvailable before making other calls which would hit this
+  // path.
+  //
+  return TRUE;
+}
+
+/**
+  Returns a boolean indicating whether QEMU provides the DMA-like access method
+  for fw_cfg.
+
+  @retval    TRUE   The DMA-like access method is available.
+  @retval    FALSE  The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+/**
+  Transfer an array of bytes, or skip a number of bytes, using the DMA
+  interface.
+
+  @param[in]     Size     Size in bytes to transfer or skip.
+
+  @param[in, out] Buffer   Buffer to read data into or write data from. Ignored,
+                          and may be NULL, if Size is zero, or Control is
+                          FW_CFG_DMA_CTL_SKIP.
+
+  @param[in]     Control  One of the following:
+                          FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
+                          FW_CFG_DMA_CTL_READ  - read from fw_cfg into Buffer.
+                          FW_CFG_DMA_CTL_SKIP  - skip bytes in fw_cfg.
+**/
+VOID
+InternalQemuFwCfgDmaBytes (
+  IN     UINT32   Size,
+  IN OUT VOID     *Buffer OPTIONAL,
+  IN     UINT32   Control
+  )
+{
+  //
+  // We should never reach here
+  //
+  ASSERT (FALSE);
+  CpuDeadLoop ();
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c
new file mode 100644
index 0000000000..5593856b82
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.c
@@ -0,0 +1,463 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - FwCfg   - firmWare  Configure
+    - CTL   - Control
+**/
+
+#include "Uefi.h"
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <libfdt.h>
+#include "QemuFwCfgLibInternal.h"
+
+STATIC UINTN mFwCfgSelectorAddress;
+STATIC UINTN mFwCfgDataAddress;
+/**
+  To get firmware configure selector address.
+
+  @param VOID
+
+  @retval  firmware configure selector address
+**/
+UINTN
+EFIAPI
+QemuGetFwCfgSelectorAddress (
+  VOID
+  )
+{
+  UINTN FwCfgSelectorAddress = mFwCfgSelectorAddress;
+  if (FwCfgSelectorAddress == 0) {
+    FwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);
+  }
+  return FwCfgSelectorAddress;
+}
+/**
+  To get firmware configure Data address.
+
+  @param VOID
+
+  @retval  firmware configure data address
+**/
+UINTN
+EFIAPI
+QemuGetFwCfgDataAddress (
+  VOID
+  )
+{
+  UINTN FwCfgDataAddress = mFwCfgDataAddress;
+  if (FwCfgDataAddress == 0) {
+    FwCfgDataAddress = (UINTN)PcdGet64 (PcdFwCfgDataAddress);
+  }
+  return FwCfgDataAddress;
+}
+/**
+  Selects a firmware configuration item for reading.
+
+  Following this call, any data read from this item will start from
+  the beginning of the configuration item's data.
+
+  @param[in] QemuFwCfgItem - Firmware Configuration item to read
+**/
+VOID
+EFIAPI
+QemuFwCfgSelectItem (
+  IN FIRMWARE_CONFIG_ITEM   QemuFwCfgItem
+  )
+{
+  UINTN FwCfgSelectorAddress;
+  FwCfgSelectorAddress = QemuGetFwCfgSelectorAddress ();
+  MmioWrite16 (FwCfgSelectorAddress, SwapBytes16((UINT16) (UINTN)QemuFwCfgItem));
+}
+
+/**
+  Slow READ_BYTES_FUNCTION.
+
+  @param[in]  The size of the data to be read.
+  @param[in]  Buffer    The buffer that stores the readout data.
+**/
+VOID
+EFIAPI
+MmioReadBytes (
+  IN UINTN Size,
+  IN VOID  *Buffer OPTIONAL
+  )
+{
+  UINTN Left;
+  UINT8 *Ptr;
+  UINT8 *End;
+  UINTN FwCfgDataAddress;
+  Left = Size & 7;
+
+  Size -= Left;
+  Ptr = Buffer;
+  End = Ptr + Size;
+  FwCfgDataAddress = QemuGetFwCfgDataAddress ();
+  while (Ptr < End) {
+    *(UINT64 *)Ptr = MmioRead64 (FwCfgDataAddress);
+    Ptr += 8;
+  }
+  if (Left & 4) {
+    *(UINT32 *)Ptr = MmioRead32 (FwCfgDataAddress);
+    Ptr += 4;
+  }
+  if (Left & 2) {
+    *(UINT16 *)Ptr = MmioRead16 (FwCfgDataAddress);
+    Ptr += 2;
+  }
+  if (Left & 1) {
+    *Ptr = MmioRead8 (FwCfgDataAddress);
+  }
+}
+
+/**
+  Slow WRITE_BYTES_FUNCTION.
+
+  @param[in]  The size of the data to be write.
+  @param[in]  Buffer    The buffer that stores the writein data.
+**/
+VOID
+EFIAPI
+MmioWriteBytes (
+  IN UINTN Size,
+  IN VOID  *Buffer OPTIONAL
+  )
+{
+  UINTN Idx;
+  UINTN FwCfgDataAddress;
+  FwCfgDataAddress = QemuGetFwCfgDataAddress ();
+  for (Idx = 0; Idx < Size; ++Idx) {
+    MmioWrite8 (FwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
+  }
+}
+
+/**
+  Reads firmware configuration bytes into a buffer
+
+  @param[in] Size - Size in bytes to read
+  @param[in] Buffer - Buffer to store data into  (OPTIONAL if Size is 0)
+**/
+VOID
+EFIAPI
+InternalQemuFwCfgReadBytes (
+  IN UINTN                  Size,
+  IN VOID                   *Buffer  OPTIONAL
+  )
+{
+  if ((InternalQemuFwCfgDmaIsAvailable ())
+    && (Size <= MAX_UINT32))
+  {
+    InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_READ);
+    return;
+  }
+  MmioReadBytes (Size, Buffer);
+}
+
+/**
+  Reads firmware configuration bytes into a buffer
+
+  If called multiple times, then the data read will
+  continue at the offset of the firmware configuration
+  item where the previous read ended.
+
+  @param[in] Size - Size in bytes to read
+  @param[in] Buffer - Buffer to store data into
+**/
+VOID
+EFIAPI
+QemuFwCfgReadBytes (
+  IN UINTN                  Size,
+  IN VOID                   *Buffer
+  )
+{
+  if (InternalQemuFwCfgIsAvailable ()) {
+    InternalQemuFwCfgReadBytes (Size, Buffer);
+  } else {
+    ZeroMem (Buffer, Size);
+  }
+}
+
+/**
+  Write firmware configuration bytes from a buffer
+
+  If called multiple times, then the data written will
+  continue at the offset of the firmware configuration
+  item where the previous write ended.
+
+  @param[in] Size - Size in bytes to write
+  @param[in] Buffer - Buffer to read data from
+**/
+VOID
+EFIAPI
+QemuFwCfgWriteBytes (
+  IN UINTN                  Size,
+  IN VOID                   *Buffer
+  )
+{
+  if (InternalQemuFwCfgIsAvailable ()) {
+    if ((InternalQemuFwCfgDmaIsAvailable ())
+      && (Size <= MAX_UINT32))
+    {
+      InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_WRITE);
+      return;
+    }
+    MmioWriteBytes (Size, Buffer);
+  }
+}
+
+/**
+  Skip bytes in the firmware configuration item.
+
+  Increase the offset of the firmware configuration item without transferring
+  bytes between the item and a caller-provided buffer. Subsequent read, write
+  or skip operations will commence at the increased offset.
+
+  @param[in] Size  Number of bytes to skip.
+**/
+VOID
+EFIAPI
+QemuFwCfgSkipBytes (
+  IN UINTN                  Size
+  )
+{
+  UINTN ChunkSize;
+  UINT8 SkipBuffer[256];
+
+  if (!InternalQemuFwCfgIsAvailable ()) {
+    return;
+  }
+
+  if ((InternalQemuFwCfgDmaIsAvailable ())
+    && (Size <= MAX_UINT32))
+  {
+    InternalQemuFwCfgDmaBytes ((UINT32)Size, NULL, FW_CFG_DMA_CTL_SKIP);
+    return;
+  }
+
+  //
+  // Emulate the skip by reading data in chunks, and throwing it away. The
+  // implementation below is suitable even for phases where RAM or dynamic
+  // allocation is not available or appropriate. It also doesn't affect the
+  // static data footprint for client modules. Large skips are not expected,
+  // therefore this fallback is not performance critical. The size of
+  // SkipBuffer is thought not to exert a large pressure on the stack in any
+  // phase.
+  //
+  while (Size > 0) {
+    ChunkSize = MIN (Size, sizeof SkipBuffer);
+    MmioReadBytes (ChunkSize, SkipBuffer);
+    Size -= ChunkSize;
+  }
+}
+
+/**
+  Reads a UINT8 firmware configuration value
+
+  @return    Value of Firmware Configuration item read
+**/
+UINT8
+EFIAPI
+QemuFwCfgRead8 (
+  VOID
+  )
+{
+  UINT8 Result;
+
+  QemuFwCfgReadBytes (sizeof (Result), &Result);
+
+  return Result;
+}
+
+/**
+  Reads a UINT16 firmware configuration value
+
+  @return    Value of Firmware Configuration item read
+**/
+UINT16
+EFIAPI
+QemuFwCfgRead16 (
+  VOID
+  )
+{
+  UINT16 Result;
+
+  QemuFwCfgReadBytes (sizeof (Result), &Result);
+
+  return Result;
+}
+
+/**
+  Reads a UINT32 firmware configuration value
+
+  @return    Value of Firmware Configuration item read
+**/
+UINT32
+EFIAPI
+QemuFwCfgRead32 (
+  VOID
+  )
+{
+  UINT32 Result;
+
+  QemuFwCfgReadBytes (sizeof (Result), &Result);
+
+  return Result;
+}
+
+/**
+  Reads a UINT64 firmware configuration value
+
+  @return    Value of Firmware Configuration item read
+**/
+UINT64
+EFIAPI
+QemuFwCfgRead64 (
+  VOID
+  )
+{
+  UINT64 Result;
+
+  QemuFwCfgReadBytes (sizeof (Result), &Result);
+
+  return Result;
+}
+
+/**
+  Find the configuration item corresponding to the firmware configuration file.
+
+  @param[in]  Name - Name of file to look up.
+  @param[out] Item - Configuration item corresponding to the file, to be passed
+                     to QemuFwCfgSelectItem ().
+  @param[out] Size - Number of bytes in the file.
+
+  @return    RETURN_SUCCESS       If file is found.
+             RETURN_NOT_FOUND     If file is not found.
+             RETURN_UNSUPPORTED   If firmware configuration is unavailable.
+**/
+RETURN_STATUS
+EFIAPI
+QemuFwCfgFindFile (
+  IN   CONST CHAR8           *Name,
+  OUT  FIRMWARE_CONFIG_ITEM  *Item,
+  OUT  UINTN                 *Size
+  )
+{
+  UINT32 Count;
+  UINT32 Idx;
+
+  if (!InternalQemuFwCfgIsAvailable ()) {
+    return RETURN_UNSUPPORTED;
+  }
+
+  QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
+  Count = SwapBytes32 (QemuFwCfgRead32 ());
+
+  for (Idx = 0; Idx < Count; ++Idx) {
+    UINT32 FileSize;
+    UINT16 FileSelect;
+    CHAR8  FileName[QEMU_FW_CFG_FNAME_SIZE];
+
+    FileSize     = QemuFwCfgRead32 ();
+    FileSelect   = QemuFwCfgRead16 ();
+    QemuFwCfgRead16 (); // skip the field called "reserved"
+    InternalQemuFwCfgReadBytes (sizeof (FileName), FileName);
+
+    if (AsciiStrCmp (Name, FileName) == 0) {
+      *Item = SwapBytes16 (FileSelect);
+      *Size = SwapBytes32 (FileSize);
+      return RETURN_SUCCESS;
+    }
+  }
+
+  return RETURN_NOT_FOUND;
+}
+
+/**
+  firmware config initialize.
+
+  @param  VOID
+
+  @return    RETURN_SUCCESS  Initialization succeeded.
+**/
+RETURN_STATUS
+EFIAPI
+QemuFwCfgInitialize (
+  VOID
+  )
+{
+  VOID              *DeviceTreeBase;
+  INT32             Node;
+  INT32             Prev;
+  CONST CHAR8       *Type;
+  INT32             Len;
+  CONST UINT64      *RegProp;
+  UINT64            FwCfgSelectorAddress;
+  UINT64            FwCfgDataAddress;
+  UINT64            FwCfgDataSize;
+  RETURN_STATUS     PcdStatus;
+
+  DeviceTreeBase = (VOID *) (UINTN)PcdGet64 (PcdDeviceTreeBase);
+  ASSERT (DeviceTreeBase != NULL);
+  //
+  // Make sure we have a valid device tree blob
+  //
+  ASSERT (fdt_check_header (DeviceTreeBase) == 0);
+
+  for (Prev = 0;; Prev = Node) {
+    Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
+    if (Node < 0) {
+      break;
+    }
+
+    //
+    // Check for memory node
+    //
+    Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
+    if ((Type)
+      && (AsciiStrnCmp (Type, "qemu,fw-cfg-mmio", Len) == 0))
+    {
+      //
+      // Get the 'reg' property of this node. For now, we will assume
+      // two 8 byte quantities for base and size, respectively.
+      //
+      RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
+      if ((RegProp != 0)
+        && (Len == (2 * sizeof (UINT64))))
+      {
+        FwCfgDataAddress      = SwapBytes64 (RegProp[0]);
+        FwCfgDataSize         = 8;
+        FwCfgSelectorAddress  = FwCfgDataAddress + FwCfgDataSize;
+
+        mFwCfgSelectorAddress = FwCfgSelectorAddress;
+        mFwCfgDataAddress = FwCfgDataAddress;
+
+        PcdStatus = PcdSet64S (
+          PcdFwCfgSelectorAddress,
+          FwCfgSelectorAddress
+          );
+        ASSERT_RETURN_ERROR (PcdStatus);
+        PcdStatus = PcdSet64S (
+          PcdFwCfgDataAddress,
+          FwCfgDataAddress
+          );
+        ASSERT_RETURN_ERROR (PcdStatus);
+        break;
+      } else {
+        DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT QemuCfg node\n",
+          __FUNCTION__));
+        break;
+      }
+    }
+  }
+  return RETURN_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
new file mode 100644
index 0000000000..8609d615e7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
@@ -0,0 +1,46 @@
+## @file
+#  initialized fw_cfg library.
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = QemuFwCfgSecLib
+  FILE_GUID                      = cdf9a9d5-7422-4dcb-b41d-607151ad320b
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = QemuFwCfgLib|PEIM
+  CONSTRUCTOR                    = QemuFwCfgInitialize
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  QemuFwCfgLibInternal.h
+  QemuFwCfgPeiLib.c
+  QemuFwCfgPei.c
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  IoLib
+  MemoryAllocationLib
+  FdtLib
+  PcdLib
+
+[Pcd]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgSelectorAddress
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgDataAddress
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 05/15] Platform/Loongson: Add MmuLib.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (3 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 04/15] Platform/Loongson: Add QemuFwCfgLib xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 06/15] Platform/Loongson: Add StableTimerLib xianglai
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Read the memory map information through the QemuFwCfg interface,
then build the page table through the memory map information,
and finally enable Mmu.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../LoongArchQemuPkg/Include/Library/MmuLib.h |  85 ++
 .../LoongArchQemuPkg/Library/MmuLib/Mmu.S     | 155 ++++
 .../Library/MmuLib/MmuBaseLib.inf             |  40 +
 .../Library/MmuLib/MmuBaseLibPei.inf          |  47 +
 .../Library/MmuLib/MmuLibCore.c               | 831 ++++++++++++++++++
 .../Library/MmuLib/MmuLibCore.h               |  40 +
 .../Library/MmuLib/MmuLibCorePei.c            | 231 +++++
 .../LoongArchQemuPkg/Library/MmuLib/mmu.h     | 190 ++++
 .../LoongArchQemuPkg/Library/MmuLib/page.h    | 280 ++++++
 .../LoongArchQemuPkg/Library/MmuLib/pte.h     |  57 ++
 10 files changed, 1956 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h

diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
new file mode 100644
index 0000000000..9880fc385c
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
@@ -0,0 +1,85 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - EXC     - execute
+**/
+#ifndef MMU_LIB_H_
+#define MMU_LIB_H_
+/**
+  write operation is performed Count times from the first element of Buffer.
+  Convert EFI Attributes to Loongarch Attributes.
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  LoongArch Attributes.
+**/
+UINTN
+EfiAttributeToLoongArchAttribute (
+  IN UINTN  EfiAttributes
+  );
+
+/**
+  Finds the length and memory properties of the memory region corresponding to the specified base address.
+
+  @param[in]  BaseAddress    To find the base address of the memory region.
+  @param[in]  EndAddress     To find the end address of the memory region.
+  @param[out]  RegionLength    The length of the memory region found.
+  @param[out]  RegionAttributes    Properties of the memory region found.
+
+  @retval  EFI_SUCCESS    The corresponding memory area was successfully found
+           EFI_NOT_FOUND    No memory area found
+**/
+EFI_STATUS
+GetLoongArchMemoryRegion (
+  IN     UINTN  BaseAddress,
+  IN     UINTN  EndAddress,
+  OUT    UINTN  *RegionLength,
+  OUT    UINTN  *RegionAttributes
+  );
+
+/**
+  Sets the Attributes  of the specified memory region
+
+  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
+  @param[in]  Length       The length of the memory region to set the Attributes.
+  @param[in]  Attributes   The Attributes to be set.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN                 Length,
+  IN UINTN                 Attributes
+  );
+
+/**
+  Sets the non-executable Attributes for the specified memory region
+
+  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
+  @param[in]  Length       The length of the memory region to set the Attributes.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryRegionNoExec (
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN  UINTN                Length
+  );
+
+/**
+  Create a page table and initialize the MMU.
+
+  @param[] VOID
+
+  @retval  VOID
+**/
+VOID
+EFIAPI
+ConfigureMmu (
+  VOID
+  );
+#endif // MMU_LIB_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
new file mode 100644
index 0000000000..d5863de072
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
@@ -0,0 +1,155 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch for LoongArch
+#
+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-----------------------------------------------------------------------------
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include "Library/Cpu.h"
+#include "mmu.h"
+
+ASM_GLOBAL ASM_PFX(HandleTlbRefill)
+ASM_GLOBAL HandleTlbRefillEnd
+ASM_GLOBAL ASM_PFX(LoongarchInvalidTlb)
+ASM_GLOBAL ASM_PFX(SetTlbRefillFuncBase)
+ASM_GLOBAL ASM_PFX(WriteCsrPageSize)
+ASM_GLOBAL ASM_PFX(WriteCsrTlbRefillPageSize)
+ASM_GLOBAL ASM_PFX(WriteCsrStlbPageSize)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPwctl0)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPwctl1)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPgdl)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrPgdh)
+ASM_GLOBAL ASM_PFX(LoongArchXchgCsrCrmd)
+
+#
+#  Refill the page table.
+#  @param  VOID
+#  @retval  VOID
+#
+
+ASM_PFX(HandleTlbRefill):
+  csrwr T0, LOONGARCH_CSR_TLBRSAVE
+  csrrd T0, LOONGARCH_CSR_PGD
+  lddir T0, T0, 3   #Put pud BaseAddress into T0
+  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
+  csrrd T0, LOONGARCH_CSR_TLBRSAVE
+  ertn
+HandleTlbRefillEnd:
+
+#
+# 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(LoongarchInvalidTlb):
+    invtlb  INVTLB_ADDR_GTRUE_OR_ASID, ZERO, A0
+    jirl    ZERO, RA, 0
+
+#
+# Set Tlb Refill function to hardware
+# @param A0 The address of tlb refill function
+# @retval  none
+#
+
+ASM_PFX(SetTlbRefillFuncBase):
+    csrwr   A0, LOONGARCH_CSR_TLBREBASE
+    jirl    ZERO, RA,0
+
+#
+#  Set Cpu Status Register Page Size.
+#  @param  A0  Page Size.
+#  @retval  none
+#
+
+ASM_PFX(WriteCsrPageSize):
+    li.d    T0, CSR_TLBIDX_SIZE
+    sll.d   A0, A0, T0
+    li.d    T0, CSR_TLBIDX_SIZE_MASK
+    csrxchg A0, T0, LOONGARCH_CSR_TLBIDX
+    jirl    ZERO, RA,0
+
+#
+#  Set Cpu Status Register TLBREFILL Page Size.
+#  @param  A0  Page Size.
+#  @retval  none
+#
+
+ASM_PFX(WriteCsrTlbRefillPageSize):
+    li.d    T0, CSR_TLBREHI_PS_SHIFT
+    sll.d   A0, A0, T0
+    li.d    T0, CSR_TLBREHI_PS
+    csrxchg A0, T0, LOONGARCH_CSR_TLBREHI
+    jirl    ZERO, RA,0
+
+#
+#  Set Cpu Status Register STLB Page Size.
+#  @param val  Page Size.
+#  @retval  VOID
+#
+
+ASM_PFX(WriteCsrStlbPageSize):
+    csrwr  A0, LOONGARCH_CSR_STLBPGSIZE
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr PWCTL0 register.
+#  @param  A0  The value used to write to the PWCTL0 register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrPwctl0):
+    csrwr A0, LOONGARCH_CSR_PWCTL0
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr PWCTL1 register.
+#  @param  A0  The value used to write to the PWCTL1 register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrPwctl1):
+    csrwr A0, LOONGARCH_CSR_PWCTL1
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr PGDL register.
+#  @param  A0  The value used to write to the PGDL register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrPgdl):
+    csrwr A0, LOONGARCH_CSR_PGDL
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr PGDH register.
+#  @param  A0  The value used to write to the PGDH register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrPgdh):
+    csrwr A0, LOONGARCH_CSR_PGDH
+    jirl    ZERO, RA,0
+
+#
+#  Exchange specified bit data with the Csr CRMD register.
+#  @param[IN]  A0   The value Exchanged with the CSR CRMD register.
+#  @param[IN]  A1   Specifies the mask for swapping bits
+#  @retval  VOID
+#
+
+ASM_PFX(LoongArchXchgCsrCrmd):
+    csrxchg A0, A1, LOONGARCH_CSR_CRMD
+    jirl    ZERO, RA,0
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
new file mode 100644
index 0000000000..abd864a324
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
@@ -0,0 +1,40 @@
+## @file
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MmuBaseLib
+  FILE_GUID                      = da8f0232-fb14-42f0-922c-63104d2c70be
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MmuLib
+  CONSTRUCTOR                    = MmuInitialize
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  MmuLibCore.c
+  Mmu.S
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[PCD]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
+
+[LibraryClasses]
+  MemoryAllocationLib
+  PcdLib
+  DebugLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
new file mode 100644
index 0000000000..12848eecfe
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
@@ -0,0 +1,47 @@
+## @file
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MmuPeiLib
+  FILE_GUID                      = da8f0232-fb14-42f0-922c-63104d2c70bd
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MmuLib | SEC PEIM
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  MmuLibCorePei.c
+  Mmu.S
+  MmuLibCore.h
+  MmuLibCore.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  OvmfPkg/OvmfPkg.dec
+
+[PCD]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
+
+[LibraryClasses]
+  MemoryAllocationLib
+  CacheMaintenanceLib
+  PcdLib
+  DebugLib
+  QemuFwCfgLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
new file mode 100644
index 0000000000..b932e3d568
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
@@ -0,0 +1,831 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Pgd or Pgd or PGD    - Page Global Directory
+    - Pud or Pud or PUD    - Page Upper Directory
+    - Pmd or Pmd or PMD    - Page Middle Directory
+    - Pte or pte or PTE    - Page Table Entry
+    - Val or VAL or val    - Value
+    - Dir    - Directory
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "pte.h"
+#include "page.h"
+#include "mmu.h"
+
+BOOLEAN  mMmuInited = FALSE;
+/**
+  Check to see if mmu successfully initializes.
+
+  @param  VOID.
+
+  @retval  TRUE  Initialization has been completed.
+           FALSE Initialization did not complete.
+**/
+BOOLEAN
+MmuIsInit (VOID) {
+  if ((mMmuInited == TRUE) ||
+      (PcdGet64 (PcdSwapPageDir) != 0)) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+  Iterates through the page directory to initialize it.
+
+  @param  Dst  A pointer to the directory of the page to initialize.
+  @param  Num  The number of page directories to initialize.
+  @param  Src  A pointer to the data used to initialize the page directory.
+
+  @retval VOID.
+**/
+VOID
+PageDirInit (
+  IN VOID *Dst,
+  IN UINTN Num,
+  IN VOID *Src
+  )
+{
+  UINTN *Ptr;
+  UINTN *End;
+  UINTN Entry;
+
+  Entry = (UINTN)Src;
+  Ptr = (UINTN *)Dst;
+  End = Ptr + Num;
+
+  for ( ;Ptr < End; Ptr++) {
+    *Ptr = Entry;
+  }
+
+  return ;
+}
+
+/**
+  Gets the virtual address corresponding to the page global directory table entry.
+
+  @param  Address  the virtual address for the table entry.
+
+  @retval PGD A pointer to get the table item.
+**/
+PGD *
+PgdOffset (
+  IN UINTN Address
+  )
+{
+  return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address);
+}
+
+/**
+  Gets the virtual address corresponding to the page upper directory table entry.
+
+  @param  Pgd  A pointer to a page global directory table entry.
+  @param  Address  the virtual address for the table entry.
+
+  @retval PUD A pointer to get the table item.
+**/
+PUD *
+PudOffset (
+  IN PGD *Pgd,
+  IN UINTN Address
+  )
+{
+  UINTN PgdVal = (UINTN)PGD_VAL (*Pgd);
+  return (PUD *)PgdVal + PUD_INDEX (Address);
+}
+
+/**
+  Gets the virtual address corresponding to the page middle directory table entry.
+
+  @param  Pud  A pointer to a page upper directory table entry.
+  @param  Address  the virtual address for the table entry.
+
+  @retval PMD A pointer to get the table item.
+**/
+PMD *
+PmdOffset (
+  IN PUD *Pud,
+  IN UINTN Address
+  )
+{
+  UINTN PudVal = PUD_VAL (*Pud);
+  return (PMD *)PudVal + PMD_INDEX (Address);
+}
+
+/**
+  Gets the virtual address corresponding to the page table entry.
+
+  @param  Pmd  A pointer to a page middle directory table entry.
+  @param  Address  the virtual address for the table entry.
+
+  @retval PTE A pointer to get the table item.
+**/
+PTE *
+PteOffset (
+  IN PMD *Pmd,
+  IN UINTN Address
+  )
+{
+  UINTN PmdVal = (UINTN)PMD_VAL (*Pmd);
+  return (PTE *)PmdVal + PTE_INDEX (Address);
+}
+
+/**
+  Sets the value of the page table entry.
+
+  @param  Pte  A pointer to a page table entry.
+  @param  PteVal  The value of the page table entry to set.
+
+  @retval VOID
+**/
+VOID
+SetPte (
+  IN PTE *Pte,
+  IN PTE PteVal
+  )
+{
+  *Pte = PteVal;
+}
+
+/**
+  Sets the value of the page global directory.
+
+  @param  Pgd  A pointer to a page global directory.
+  @param  Pud  The value of the page global directory to set.
+
+  @retval VOID
+**/
+VOID
+SetPgd (
+  IN PGD *Pgd,
+  IN PUD *Pud
+  )
+{
+  *Pgd = (PGD) {((UINTN)Pud)};
+}
+
+/**
+  Sets the value of the page upper directory.
+
+  @param  Pud  A pointer to a page upper directory.
+  @param  Pmd  The value of the page upper directory to set.
+
+  @retval VOID
+**/
+VOID
+SetPud (
+  IN PUD *Pud,
+  IN PMD *Pmd
+  )
+{
+  *Pud = (PUD) {((UINTN)Pmd)};
+}
+
+/**
+  Sets the value of the page middle directory.
+
+  @param  Pmd  A pointer to a page middle directory.
+  @param  Pte  The value of the page middle directory to set.
+
+  @retval VOID
+**/
+VOID
+SetPmd (
+  IN PMD *Pmd,
+  IN PTE *Pte
+  )
+{
+  *Pmd = (PMD) {((UINTN)Pte)};
+}
+
+/**
+  Free up memory space occupied by page tables.
+
+  @param  Pte  A pointer to the page table.
+
+  @retval VOID
+**/
+VOID
+PteFree (
+  IN PTE *Pte
+  )
+{
+  FreePages ((VOID *)Pte, 1);
+}
+
+/**
+  Free up memory space occupied by page middle directory.
+
+  @param  Pmd  A pointer to the page middle directory.
+
+  @retval VOID
+**/
+VOID
+PmdFree (
+  IN PMD *Pmd
+  )
+{
+  FreePages ((VOID *)Pmd, 1);
+}
+
+/**
+  Free up memory space occupied by page upper directory.
+
+  @param  Pud  A pointer to the page upper directory.
+
+  @retval VOID
+**/
+VOID
+PudFree (
+  IN PUD *Pud
+  )
+{
+  FreePages ((VOID *)Pud, 1);
+}
+
+/**
+  Requests the memory space required for the page upper directory,
+  initializes it, and places it in the specified page global directory
+
+  @param  Pgd  A pointer to the page global directory.
+
+  @retval  EFI_SUCCESS  Memory request successful.
+  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
+**/
+INTN
+PudAlloc (
+  IN PGD *Pgd
+  )
+{
+  PUD *Pud = (PUD *) AllocatePages (1);
+  if (!Pud) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPmd));
+
+  if (pgd_none (*Pgd)) {
+    SetPgd (Pgd, Pud);
+  } else { /* Another has populated it */
+    PudFree (Pud);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Requests the memory space required for the page middle directory,
+  initializes it, and places it in the specified page upper directory
+
+  @param  Pud  A pointer to the page upper directory.
+
+  @retval  EFI_SUCCESS  Memory request successful.
+  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
+**/
+EFI_STATUS
+PmdAlloc (
+  IN PUD *Pud
+  )
+{
+  PMD *Pmd;
+
+  Pmd = (PMD *) AllocatePages (1);
+  if (!Pmd) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPte));
+
+  if (pud_none (*Pud)) {
+    SetPud (Pud, Pmd);
+  } else {/* Another has populated it */
+    PmdFree (Pmd);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Requests the memory space required for the page table,
+  initializes it, and places it in the specified page middle directory
+
+  @param  Pmd  A pointer to the page middle directory.
+
+  @retval  EFI_SUCCESS  Memory request successful.
+  @retval  EFI_OUT_OF_RESOURCES  Resource exhaustion cannot be requested to memory.
+**/
+INTN
+PteAlloc (
+  IN PMD *Pmd
+  )
+{
+  PTE *Pte;
+
+  Pte = (PTE *) AllocatePages (1);
+  if (!Pte) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
+
+  if (pmd_none (*Pmd)) {
+    SetPmd (Pmd, Pte);
+  } else { /* Another has populated it */
+    PteFree (Pte);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Requests the memory space required for the page upper directory,
+  initializes it, and places it in the specified page global directory,
+  and get the page upper directory entry corresponding to the virtual address
+
+  @param  Pgd  A pointer to the page global directory.
+
+  @retval   Gets the page upper directory entry
+**/
+PUD *
+PudAllocGet (
+  IN PGD *Pgd,
+  IN UINTN Address
+  )
+{
+  return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ?
+           NULL : PudOffset (Pgd, Address));
+}
+
+/**
+  Requests the memory space required for the page middle directory,
+  initializes it, and places it in the specified page upper directory,
+  and get the page middle directory entry corresponding to the virtual address
+
+  @param  Pud  A pointer to the page upper directory.
+
+  @retval   Gets the page middle directory entry
+**/
+PMD *
+PmdAllocGet (
+  IN PUD *Pud,
+  IN UINTN Address
+  )
+{
+  PMD * ret =  (pud_none (*Pud) && PmdAlloc (Pud))?
+            NULL: PmdOffset (Pud, Address);
+  DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", __func__, __LINE__,
+    Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) ));
+
+  return ret;
+}
+
+/**
+  Requests the memory space required for the page table,
+  initializes it, and places it in the specified page middle directory,
+  and get the page table entry corresponding to the virtual address
+
+  @param  Pmd  A pointer to the page upper directory.
+
+  @retval   Gets the page table entry
+**/
+PTE *
+PteAllocGet (
+  IN PMD *Pmd,
+  IN UINTN Address
+  )
+{
+  return (pmd_none (*Pmd) && PteAlloc (Pmd))?
+    NULL: PteOffset (Pmd, Address);
+}
+
+/**
+  Gets the physical address of the page table entry corresponding to the specified virtual address.
+
+  @param  Address  the corresponding virtual address of the page table entry.
+
+  @retval     A pointer to the page table entry.
+  @retval  NULL
+**/
+PTE *
+GetPteAddress (
+  IN UINTN Address
+  )
+{
+  PGD *Pgd;
+  PUD *Pud;
+  PMD *Pmd;
+
+  Pgd = PgdOffset (Address);
+
+  if (pgd_none (*Pgd)) {
+    return NULL;
+  }
+
+  Pud = PudOffset (Pgd, Address);
+
+  if (pud_none (*Pud)) {
+    return NULL;
+  }
+
+  Pmd = PmdOffset (Pud, Address);
+  if (pmd_none (*Pmd)) {
+    return NULL;
+  }
+
+  if (IS_HUGE_PAGE (Pmd->PmdVal)) {
+    return ((PTE *)Pmd);
+  }
+
+  return PteOffset (Pmd, Address);
+}
+
+/**
+  Establishes a page table entry based on the specified memory region.
+
+  @param  Pmd  A pointer to the page middle directory.
+  @param  Address  The memory space start address.
+  @param  End  The end address of the memory space.
+  @param  Attributes  Memory space Attributes.
+
+  @retval     EFI_SUCCESS   The page table entry was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page table entry establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPteRange (
+  IN PMD *Pmd,
+  IN UINTN Address,
+  IN UINTN End,
+  IN UINTN Attributes
+  )
+{
+  PTE *Pte;
+  PTE PteVal;
+  BOOLEAN UpDate;
+
+  Pte = PteAllocGet (Pmd, Address);
+  if (!Pte) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    UpDate = FALSE;
+    PteVal = MAKE_PTE (Address, Attributes);
+    DEBUG ((DEBUG_VERBOSE,
+      "%a %d Address %p  PGD_INDEX %p PUD_INDEX   %p PMD_INDEX  %p PTE_INDEX  %p MAKE_PTE  %p\n",
+      __func__, __LINE__,  Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
+      PTE_INDEX (Address), PteVal));
+
+    if ((!pte_none (*Pte)) &&
+        (PTE_VAL(*Pte) != PTE_VAL(PteVal)))
+    {
+      UpDate = TRUE;
+    }
+
+    SetPte (Pte, PteVal);
+    if (UpDate) {
+      LoongarchInvalidTlb(Address);
+    }
+  } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Establishes a page middle directory based on the specified memory region.
+
+  @param  Pud  A pointer to the page upper directory.
+  @param  Address  The memory space start address.
+  @param  End  The end address of the memory space.
+  @param  Attributes  Memory space Attributes.
+
+  @retval     EFI_SUCCESS   The page middle directory was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page middle directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPmdRange (
+  IN PUD *Pud,
+  IN UINTN Address,
+  IN UINTN End,
+  IN UINTN Attributes
+  )
+{
+  PMD *Pmd;
+  PTE *Pte;
+  UINTN Next;
+  UINTN AddressStart_HugePage;
+  UINTN AddressEnd_HugePage;
+
+  Pmd = PmdAllocGet (Pud, Address);
+  if (!Pmd) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    Next = PMD_ADDRESS_END (Address, End);
+    if (((Address & (~PMD_MASK)) == 0) &&
+        ((Next &  (~PMD_MASK)) == 0) &&
+        (pmd_none (*Pmd)))
+    {
+      DEBUG ((DEBUG_VERBOSE,
+        "%a %d Address %p  PGD_INDEX %p PUD_INDEX   %p PMD_INDEX  %p MAKE_HUGE_PTE  %p\n",
+        __func__, __LINE__,  Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
+        MAKE_HUGE_PTE (Address, Attributes)));
+
+      SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes));
+    } else {
+       if ((pmd_none (*Pmd)) ||
+          ((!pmd_none (*Pmd)) &&
+           (!IS_HUGE_PAGE (Pmd->PmdVal))))
+       {
+         if (MemoryMapPteRange (Pmd, Address, Next, Attributes)) {
+           return EFI_OUT_OF_RESOURCES;
+         }
+       } else {
+         SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte));
+         AddressStart_HugePage = Address & PMD_MASK;
+         AddressEnd_HugePage = AddressStart_HugePage + HUGE_PAGE_SIZE;
+         if (MemoryMapPteRange (Pmd, AddressStart_HugePage, AddressEnd_HugePage, Attributes)) {
+           return EFI_OUT_OF_RESOURCES;
+         }
+         Pte = GetPteAddress (AddressStart_HugePage);
+         if (Pte == NULL) {
+           continue ;
+         }
+         if (AddressEnd_HugePage > End) {
+           Next = End;
+         }
+       }
+    }
+  } while (Pmd++, Address = Next, Address != End);
+
+  return 0;
+}
+
+/**
+  Establishes a page upper directory based on the specified memory region.
+
+  @param  Pgd  A pointer to the page global directory.
+  @param  Address  The memory space start address.
+  @param  End  The end address of the memory space.
+  @param  Attributes  Memory space Attributes.
+
+  @retval     EFI_SUCCESS   The page upper directory was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page upper directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPudRange (
+  IN PGD *Pgd,
+  IN UINTN Address,
+  IN UINTN End,
+  IN UINTN Attributes
+  )
+{
+  PUD *Pud;
+  UINTN Next;
+
+  Pud = PudAllocGet (Pgd, Address);
+  if (!Pud) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    Next = PUD_ADDRESS_END (Address, End);
+    if (MemoryMapPmdRange (Pud, Address, Next, Attributes)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } while (Pud++, Address = Next, Address != End);
+  return EFI_SUCCESS;
+}
+
+/**
+  Establishes a page global directory based on the specified memory region.
+
+  @param  Start  The memory space start address.
+  @param  End  The end address of the memory space.
+  @param  Attributes  Memory space Attributes.
+
+  @retval     EFI_SUCCESS   The page global directory was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page global directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPageRange (
+  IN UINTN Start,
+  IN UINTN End,
+  IN UINTN Attributes
+  )
+{
+  PGD *Pgd;
+  UINTN Next;
+  UINTN Address = Start;
+  EFI_STATUS Err;
+
+  Pgd = PgdOffset (Address);
+  do {
+    Next = PGD_ADDRESS_END (Address, End);
+    Err = MemoryMapPudRange (Pgd, Address, Next, Attributes);
+    if (Err) {
+      return Err;
+    }
+  } while (Pgd++, Address = Next, Address != End);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Page tables are established from memory-mapped tables.
+
+  @param  MemoryRegion   A pointer to a memory-mapped table entry.
+
+  @retval     EFI_SUCCESS   The page table was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page table  establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+FillTranslationTable (
+  IN  MEMORY_REGION_DESCRIPTOR  *MemoryRegion
+  )
+{
+  return MemoryMapPageRange (MemoryRegion->VirtualBase,
+           (MemoryRegion->Length + MemoryRegion->VirtualBase),
+           MemoryRegion->Attributes);
+}
+
+/**
+  write operation is performed Count times from the first element of Buffer.
+  Convert EFI Attributes to Loongarch Attributes.
+  @param[in]  EfiAttributes     Efi Attributes.
+
+  @retval  LoongArch Attributes.
+**/
+UINTN
+EfiAttributeToLoongArchAttribute (
+  IN UINTN  EfiAttributes
+  )
+{
+  UINTN  LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | CACHE_CC | PAGE_USER | PAGE_GLOBAL;
+  switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
+    case EFI_MEMORY_UC:
+      LoongArchAttributes |= CACHE_SUC;
+      break;
+    case EFI_MEMORY_WC:
+    case EFI_MEMORY_WT:
+    case EFI_MEMORY_WB:
+      LoongArchAttributes |= CACHE_CC;
+      break;
+    default :
+       LoongArchAttributes |= CACHE_CC;
+      break;
+  }
+
+  // Write protection attributes
+  if ((EfiAttributes & EFI_MEMORY_RO) != 0) {
+    LoongArchAttributes &= ~PAGE_DIRTY;
+  }
+
+  //eXecute protection attribute
+  if ((EfiAttributes & EFI_MEMORY_XP) != 0) {
+    LoongArchAttributes |= PAGE_NO_EXEC;
+  }
+
+  return LoongArchAttributes;
+}
+
+/**
+  Finds the length and memory properties of the memory region corresponding to the specified base address.
+
+  @param[in]  BaseAddress    To find the base address of the memory region.
+  @param[in]  EndAddress     To find the end address of the memory region.
+  @param[out]  RegionLength    The length of the memory region found.
+  @param[out]  RegionAttributes    Properties of the memory region found.
+
+  @retval  EFI_SUCCESS    The corresponding memory area was successfully found
+           EFI_NOT_FOUND    No memory area found
+**/
+EFI_STATUS
+GetLoongArchMemoryRegion (
+  IN     UINTN  BaseAddress,
+  IN     UINTN  EndAddress,
+  OUT    UINTN  *RegionLength,
+  OUT    UINTN  *RegionAttributes
+  )
+{
+  PTE *Pte;
+  UINTN Attributes;
+  UINTN AttributesTmp;
+  UINTN MaxAddress;
+  MaxAddress     = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
+  Pte = GetPteAddress (BaseAddress);
+
+  if (!MmuIsInit ()) {
+    return EFI_SUCCESS;
+  }
+  if (Pte == NULL) {
+    return EFI_NOT_FOUND;
+  }
+  Attributes = GET_PAGE_ATTRIBUTES (*Pte);
+  if (IS_HUGE_PAGE (Pte->PteVal)) {
+    *RegionAttributes = Attributes & (~(PAGE_HUGE));
+    *RegionLength += HUGE_PAGE_SIZE;
+  } else {
+    *RegionLength += EFI_PAGE_SIZE;
+    *RegionAttributes = Attributes;
+  }
+
+  while (BaseAddress <= MaxAddress) {
+    Pte = GetPteAddress (BaseAddress);
+    if (Pte == NULL) {
+      return EFI_SUCCESS;
+    }
+    AttributesTmp = GET_PAGE_ATTRIBUTES (*Pte);
+    if (IS_HUGE_PAGE (Pte->PteVal)) {
+      if (AttributesTmp == Attributes) {
+         *RegionLength += HUGE_PAGE_SIZE;
+      }
+      BaseAddress += HUGE_PAGE_SIZE;
+    } else {
+      if (AttributesTmp == Attributes) {
+        *RegionLength += EFI_PAGE_SIZE;
+      }
+      BaseAddress += EFI_PAGE_SIZE;
+    }
+
+    if (BaseAddress > EndAddress) {
+      break;
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Sets the Attributes  of the specified memory region
+
+  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
+  @param[in]  Length       The length of the memory region to set the Attributes.
+  @param[in]  Attributes   The Attributes to be set.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryAttributes (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN                 Length,
+  IN UINTN                 Attributes
+  )
+{
+
+  if (!MmuIsInit ()) {
+    return EFI_SUCCESS;
+  }
+  Attributes = EfiAttributeToLoongArchAttribute (Attributes);
+  DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes));
+  MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Sets the non-executable Attributes for the specified memory region
+
+  @param[in]  BaseAddress  The base address of the memory region to set the Attributes.
+  @param[in]  Length       The length of the memory region to set the Attributes.
+
+  @retval  EFI_SUCCESS    The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryRegionNoExec (
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN  UINTN                Length
+  )
+{
+  if (MmuIsInit ()) {
+    Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
+    LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Check to see if mmu successfully initializes and saves the result.
+
+  @param  VOID.
+
+  @retval  EFI_SUCCESS    Initialization succeeded.
+**/
+EFI_STATUS
+MmuInitialize (VOID)
+{
+   if (PcdGet64 (PcdSwapPageDir) != 0) {
+     mMmuInited = TRUE;
+   }
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
new file mode 100644
index 0000000000..7a5e8ea0dd
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
@@ -0,0 +1,40 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Dir    - Directory
+**/
+#ifndef  MMU_LIB_CORE_H_
+#define  MMU_LIB_CORE_H_
+/**
+  Iterates through the page directory to initialize it.
+
+  @param  Dst  A pointer to the directory of the page to initialize.
+  @param  Num  The number of page directories to initialize.
+  @param  Src  A pointer to the data used to initialize the page directory.
+
+  @retval VOID.
+**/
+VOID
+PageDirInit (
+  IN VOID *dest,
+  IN UINTN Count,
+  IN VOID *src
+  );
+
+/**
+  Page tables are established from memory-mapped tables.
+
+  @param  MemoryRegion   A pointer to a memory-mapped table entry.
+
+  @retval     EFI_SUCCESS   The page table was created successfully.
+  @retval     EFI_OUT_OF_RESOURCES  Page table  establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+FillTranslationTable (
+  IN  MEMORY_REGION_DESCRIPTOR  *MemoryRegion
+  );
+#endif // MMU_LIB_CORE_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
new file mode 100644
index 0000000000..32a7fc0beb
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
@@ -0,0 +1,231 @@
+/** @file
+  Platform PEI driver
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - FwCfg    - Firmeware Config
+    - Tlb      - Translation Lookaside Buffer
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "pte.h"
+#include "page.h"
+#include "mmu.h"
+#include <Library/QemuFwCfgLib.h>
+#include "MmuLibCore.h"
+#include <Library/CacheMaintenanceLib.h>
+
+/**
+  Return the Virtual Memory Map of your platform
+
+  This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
+  on your platform.
+
+  @param[out]   VirtualMemoryMap    Array of MEMORY_REGION_DESCRIPTOR
+                                    describing a Physical-to-Virtual Memory
+                                    mapping. This array must be ended by a
+                                    zero-filled entry. The allocated memory
+                                    will not be freed.
+**/
+VOID
+GetMemoryMapFromFwCfg (
+  OUT MEMORY_REGION_DESCRIPTOR  **VirtualMemoryMap
+  )
+{
+
+  EFI_STATUS           Status;
+  FIRMWARE_CONFIG_ITEM FwCfgItem;
+  UINTN                FwCfgSize;
+  LOONGARCH_MEMMAP_ENTRY  MemoryMapEntry;
+  LOONGARCH_MEMMAP_ENTRY  *StartEntry;
+  LOONGARCH_MEMMAP_ENTRY  *pEntry;
+  UINTN                Processed;
+  MEMORY_REGION_DESCRIPTOR  *VirtualMemoryTable;
+  UINTN  Index = 0;
+  ASSERT (VirtualMemoryMap != NULL);
+
+  VirtualMemoryTable = AllocatePool (
+                         sizeof (MEMORY_REGION_DESCRIPTOR) *
+                         MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
+                         );
+  VirtualMemoryTable[Index].PhysicalBase = 0x10000000;
+  VirtualMemoryTable[Index].VirtualBase  = VirtualMemoryTable[Index].PhysicalBase;
+  VirtualMemoryTable[Index].Length       = 0x10000000;
+  VirtualMemoryTable[Index].Attributes   = PAGE_VALID | PLV_KERNEL |  CACHE_SUC | PAGE_DIRTY | PAGE_GLOBAL;
+  ++Index;
+
+  Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status));
+    ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
+    *VirtualMemoryMap = VirtualMemoryTable;
+    return ;
+  }
+  if (FwCfgSize % sizeof MemoryMapEntry != 0) {
+    DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize));
+  }
+
+  QemuFwCfgSelectItem (FwCfgItem);
+  StartEntry = AllocatePages  (EFI_SIZE_TO_PAGES (FwCfgSize));
+  QemuFwCfgReadBytes (FwCfgSize, StartEntry);
+  for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) {
+    pEntry = StartEntry + Processed;
+    if (pEntry->Length == 0) {
+      continue;
+    }
+
+    DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p  type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type));
+    VirtualMemoryTable[Index].PhysicalBase = pEntry->BaseAddr;
+    VirtualMemoryTable[Index].VirtualBase  = VirtualMemoryTable[Index].PhysicalBase;
+    VirtualMemoryTable[Index].Length       = pEntry->Length;
+    VirtualMemoryTable[Index].Attributes   = PAGE_VALID | PLV_KERNEL |  CACHE_CC | PAGE_DIRTY | PAGE_GLOBAL;
+    ++Index;
+  }
+
+  FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize));
+  // End of Table
+  ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
+  *VirtualMemoryMap = VirtualMemoryTable;
+  return ;
+}
+
+/**
+  Create a page table and initialize the MMU.
+
+  @param[] VOID
+
+  @retval  VOID
+**/
+EFIAPI
+VOID
+ConfigureMmu (VOID)
+{
+  PGD *SwapperPageDir = NULL;
+  PGD *InvalidPgd = NULL;
+  PUD *InvalidPudTable = NULL;
+  PMD *InvalidPmdTable = NULL;
+  PTE *InvalidPteTable = NULL;
+  MEMORY_REGION_DESCRIPTOR  *MemoryTable = NULL;
+  RETURN_STATUS PcdStatus;
+  UINTN PgdShift = PGD_SHIFT;
+  UINTN PgdWide = PGD_WIDE;
+  UINTN PudShift = PUD_SHIFT;
+  UINTN PudWide = PUD_WIDE;
+  UINTN PmdShift = PMD_SHIFT;
+  UINTN PmdWide = PMD_WIDE;
+  UINTN PteShift = PTE_SHIFT;
+  UINTN PteWide = PTE_WIDE;
+  UINTN PageEnable = 1 << 4;
+  VOID *TlbReEntry;
+
+  SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  InvalidPgd = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  InvalidPudTable = AllocatePages (EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
+  InvalidPmdTable = AllocatePages (EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
+  InvalidPteTable = AllocatePages (EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
+  ZeroMem (InvalidPteTable, PTE_TABLE_SIZE);
+
+  if ((!InvalidPgd) ||
+      (!InvalidPudTable) ||
+      (!InvalidPmdTable) ||
+      (!InvalidPteTable))
+  {
+    goto FreeTranslationTable;
+  }
+
+  /*pgd init*/
+  PageDirInit (SwapperPageDir , ENTRYS_PER_PGD, InvalidPudTable);
+  /*pgd init*/
+  PageDirInit (InvalidPgd, ENTRYS_PER_PGD, InvalidPudTable);
+  /*pud init*/
+  PageDirInit (InvalidPudTable, ENTRYS_PER_PUD, InvalidPmdTable);
+  /*pmd init*/
+  PageDirInit (InvalidPmdTable, ENTRYS_PER_PMD, InvalidPteTable);
+  GetMemoryMapFromFwCfg (&MemoryTable);
+
+  PcdStatus |= PcdSet64S (PcdSwapPageDir, (UINTN)SwapperPageDir);
+  PcdStatus |= PcdSet64S (PcdInvalidPgd, (UINTN)InvalidPgd);
+  PcdStatus |= PcdSet64S (PcdInvalidPud, (UINTN)InvalidPudTable);
+  PcdStatus |= PcdSet64S (PcdInvalidPmd, (UINTN)InvalidPmdTable);
+  PcdStatus |= PcdSet64S (PcdInvalidPte, (UINTN)InvalidPteTable);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  while (MemoryTable->Length != 0) {
+    DEBUG ((DEBUG_VERBOSE, "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", __func__, __LINE__,
+      MemoryTable->VirtualBase,
+      (MemoryTable->Length + MemoryTable->VirtualBase),
+      MemoryTable->Attributes));
+
+    PcdStatus = FillTranslationTable (MemoryTable);
+    if (EFI_ERROR (PcdStatus)) {
+      goto FreeTranslationTable;
+    }
+    MemoryTable++;
+  }
+
+  TlbReEntry = AllocatePages (1);
+  if (TlbReEntry == NULL) {
+    goto FreeTranslationTable;
+  }
+  CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - HandleTlbRefill));
+  InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefill, (UINTN)(HandleTlbRefillEnd - HandleTlbRefill));
+
+  DEBUG ((DEBUG_VERBOSE,
+    "%a  %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudWide %d PgdShift %d PgdWide %d.\n",
+    __func__, __LINE__,
+    PteShift, PteWide, PmdShift, PmdWide,PudShift, PudWide, PgdShift, PgdWide));
+
+  SetTlbRefillFuncBase ((UINTN)TlbReEntry);
+  /*set page size*/
+  WriteCsrPageSize (DEFAULT_PAGE_SIZE);
+  WriteCsrStlbPageSize (DEFAULT_PAGE_SIZE);
+  WriteCsrTlbRefillPageSize (DEFAULT_PAGE_SIZE);
+
+  LoongArchWriteqCsrPwctl0 ((PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25
+              ));
+  LoongArchWriteqCsrPwctl1 (PgdShift | PgdWide << 6);
+  LoongArchWriteqCsrPgdl ((UINTN)SwapperPageDir);
+  LoongArchWriteqCsrPgdh ((UINTN)InvalidPgd);
+
+  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
+  LoongArchXchgCsrCrmd ( PageEnable, 1 << 4);
+  DEBUG ((DEBUG_INFO, "%a %d Enable Mmu End.\n", __func__, __LINE__));
+
+  return ;
+
+FreeTranslationTable:
+  if (SwapperPageDir) {
+    FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  }
+
+  if (InvalidPgd) {
+    FreePages (InvalidPgd, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+  }
+
+  if (InvalidPudTable) {
+    FreePages (InvalidPudTable, EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
+  }
+
+  if (InvalidPmdTable) {
+    FreePages (InvalidPmdTable, EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
+  }
+
+  if (InvalidPteTable) {
+    FreePages (InvalidPteTable, EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
+  }
+
+  PcdSet64S (PcdSwapPageDir, (UINTN)0);
+  PcdSet64S (PcdInvalidPgd, (UINTN)0);
+  PcdSet64S (PcdInvalidPud, (UINTN)0);
+  PcdSet64S (PcdInvalidPmd, (UINTN)0);
+  PcdSet64S (PcdInvalidPte, (UINTN)0);
+
+  return ;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
new file mode 100644
index 0000000000..8e284a2ecd
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
@@ -0,0 +1,190 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Tlb or TLB     - Translation Lookaside Buffer
+    - CSR            - Cpu State Register
+    - PGDL           - Page Global Directory Low
+    - PGDH           - Page Global Directory High
+    - TLBIDX         - TLB Index
+    - TLBREHI        - TLB Refill Entry High
+    - PWCTL          - Page Walk Control
+    - STLB           - Singular Page Size TLB
+    - PS             - Page Size
+**/
+#ifndef MMU_H_
+#define MMU_H_
+/*page size 4k*/
+#define DEFAULT_PAGE_SIZE         0x0c
+#define LOONGARCH_CSR_PGDL        0x19 /* Page table base address when VA[47] = 0 */
+#define LOONGARCH_CSR_PGDH        0x1a /* Page table base address when VA[47] = 1 */
+#define LOONGARCH_CSR_TLBIDX      0x10 /* TLB Index, EHINV, PageSize, NP */
+#define LOONGARCH_CSR_TLBEHI      0x11 /* TLB EntryHi */
+#define LOONGARCH_CSR_TLBELO0     0x12 /* TLB EntryLo0 */
+#define LOONGARCH_CSR_TLBELO1     0x13 /* TLB EntryLo1 */
+#define LOONGARCH_CSR_TLBREHI     0x8e /* TLB refill entryhi */
+#define LOONGARCH_CSR_PWCTL0      0x1c /* PWCtl0 */
+#define LOONGARCH_CSR_PWCTL1      0x1d /* PWCtl1 */
+#define LOONGARCH_CSR_STLBPGSIZE  0x1e
+#define CSR_TLBIDX_SIZE_MASK      0x3f000000
+#define CSR_TLBIDX_PS_SHIFT       24
+#define CSR_TLBIDX_SIZE           CSR_TLBIDX_PS_SHIFT
+
+#define  CSR_TLBREHI_PS_SHIFT     0
+#define  CSR_TLBREHI_PS           0x3f
+
+#define EFI_MEMORY_CACHETYPE_MASK     (EFI_MEMORY_UC  | \
+                                       EFI_MEMORY_WC  | \
+                                       EFI_MEMORY_WT  | \
+                                       EFI_MEMORY_WB  | \
+                                       EFI_MEMORY_UCE   \
+                                       )
+
+typedef struct {
+  EFI_PHYSICAL_ADDRESS PhysicalBase;
+  EFI_VIRTUAL_ADDRESS  VirtualBase;
+  UINTN                Length;
+  UINTN                Attributes;
+} MEMORY_REGION_DESCRIPTOR;
+
+// The total number of descriptors, including the final "end-of-table" descriptor.
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)
+
+extern CHAR8 HandleTlbRefill[], HandleTlbRefillEnd[];
+
+/*
+ Invalid corresponding TLB entries are based on the address given
+
+ @param Address The address corresponding to the invalid page table entry
+
+ @retval  none
+*/
+extern
+VOID
+LoongarchInvalidTlb (
+  UINTN Address
+  );
+
+/*
+ Set Tlb Refill function to hardware
+
+ @param A0 The address of tlb refill function
+
+ @retval  none
+*/
+extern
+VOID
+SetTlbRefillFuncBase (
+  UINTN Address
+  );
+
+/*
+  Set Cpu Status Register Page Size.
+
+  @param  PageSize  Page Size.
+
+  @retval  none
+*/
+extern
+VOID
+WriteCsrPageSize (
+  UINTN PageSize
+  );
+
+/*
+  Set Cpu Status Register TLBREFILL Page Size.
+
+  @param  PageSize  Page Size.
+
+  @retval  none
+*/
+extern
+VOID
+WriteCsrTlbRefillPageSize (
+  UINTN PageSize
+  );
+
+/*
+  Set Cpu Status Register STLB Page Size.
+
+  @param PageSize  Page Size.
+
+  @retval  VOID
+*/
+extern
+VOID
+WriteCsrStlbPageSize (
+  UINTN PageSize
+);
+
+/*
+  Write Csr PWCTL0 register.
+
+  @param  Val  The value used to write to the PWCTL0 register
+
+  @retval  none
+*/
+extern
+VOID
+LoongArchWriteqCsrPwctl0 (
+  UINTN Val
+  );
+
+/*
+  Write Csr PWCTL1 register.
+
+  @param  Val  The value used to write to the PWCTL1 register
+
+  @retval  none
+*/
+extern
+VOID
+LoongArchWriteqCsrPwctl1 (
+  UINTN Val
+  );
+
+/*
+  Write Csr PGDL register.
+
+  @param  Val  The value used to write to the PGDL register
+
+  @retval  none
+*/
+extern
+VOID
+LoongArchWriteqCsrPgdl (
+  UINTN Val
+  );
+
+/*
+  Write Csr PGDH register.
+
+  @param  Val  The value used to write to the PGDH register
+
+  @retval  none
+*/
+extern
+VOID
+LoongArchWriteqCsrPgdh (
+  UINTN Val
+  );
+
+/*
+  Exchange specified bit data with the Csr CRMD register.
+
+  @param[IN]  Val   The value Exchanged with the CSR CRMD register.
+  @param[IN]  Mask   Specifies the mask for swapping bits
+
+  @retval  VOID
+*/
+extern
+VOID
+LoongArchXchgCsrCrmd (
+  UINTN Val,
+  UINTN Mask
+  );
+
+#endif // MMU_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
new file mode 100644
index 0000000000..6ab07e7900
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
@@ -0,0 +1,280 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Pgd or Pgd or PGD    - Page Global Directory
+    - Pud or Pud or PUD    - Page Upper Directory
+    - Pmd or Pmd or PMD    - Page Middle Directory
+    - Pte or pte or PTE    - Page Table Entry
+    - Val or VAL or val    - Value
+    - Dir    - Directory
+**/
+#ifndef PAGE_H_
+#define PAGE_H_
+
+#define MAX_VA_BITS                         47
+#define PGD_WIDE                            (8)
+#define PUD_WIDE                            (9)
+#define PMD_WIDE                            (9)
+#define PTE_WIDE                            (9)
+
+#define ENTRYS_PER_PGD                      (1 << PGD_WIDE)
+#define ENTRYS_PER_PUD                      (1 << PUD_WIDE)
+#define ENTRYS_PER_PMD                      (1 << PMD_WIDE)
+#define ENTRYS_PER_PTE                      (1 << PTE_WIDE)
+
+#define PGD_SHIFT                           (PUD_SHIFT + PUD_WIDE)
+#define PUD_SHIFT                           (PMD_SHIFT + PMD_WIDE)
+#define PMD_SHIFT                           (EFI_PAGE_SHIFT + PTE_WIDE)
+#define PTE_SHIFT                           (EFI_PAGE_SHIFT)
+
+#define PGD_SIZE                            (1UL << PGD_SHIFT)
+#define PUD_SIZE                            (1UL << PUD_SHIFT)
+#define PMD_SIZE                            (1UL << PMD_SHIFT)
+
+#define PGD_MASK                            (~(PGD_SIZE-1))
+#define PUD_MASK                            (~(PUD_SIZE-1))
+#define PMD_MASK                            (~(PMD_SIZE-1))
+#define PAGE_MASK                           (~(EFI_PAGE_SIZE - 1))
+#define PFN_MASK                            (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \
+                                             (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
+
+typedef struct { UINTN PgdVal; } PGD;
+typedef struct { UINTN PudVal; } PUD;
+typedef struct { UINTN PmdVal; } PMD;
+typedef struct { UINTN PteVal; } PTE;
+/**
+  Gets the value of the page global directory table entry.
+
+  @param  x    Page global directory struct variables.
+
+  @retval   the value of the page global directory table entry.
+ **/
+#define PGD_VAL(x)                          ((x).PgdVal)
+/**
+  Gets the value of the page upper directory table entry.
+
+  @param  x    Page upper directory struct variables.
+
+  @retval  the value of the page upper directory table entry.
+ **/
+#define PUD_VAL(x)                          ((x).PudVal)
+/**
+  Gets the value of the page middle directory table entry.
+
+  @param  x    Page middle directory struct variables.
+
+  @retval  the value of the page middle directory table entry.
+ **/
+#define PMD_VAL(x)                          ((x).PmdVal)
+/**
+  Gets the value of the page table entry.
+
+  @param  x    Page table entry struct variables.
+
+  @retval  the value of the page table entry.
+ **/
+#define PTE_VAL(x)                          ((x).PteVal)
+
+#define PGD_TABLE_SIZE                      (ENTRYS_PER_PGD * sizeof(PGD))
+#define PUD_TABLE_SIZE                      (ENTRYS_PER_PUD * sizeof(PUD))
+#define PMD_TABLE_SIZE                      (ENTRYS_PER_PMD * sizeof(PMD))
+#define PTE_TABLE_SIZE                      (ENTRYS_PER_PTE * sizeof(PTE))
+/**
+  Gets the physical address of the record in the page table entry.
+
+  @param  x    Page table entry struct variables.
+
+  @retval  the value of the physical address.
+ **/
+#define GET_PAGE_ATTRIBUTES(x)              (UINTN) {(PTE_VAL(x) & ~PFN_MASK)}
+/**
+  Gets the virtual address of the next block of the specified virtual address
+  that is aligned with the size of the global page directory mapping.
+
+  @param  Address  Specifies the virtual address.
+  @param  End    The end address of the memory region.
+
+  @retval   the specified virtual address  of the next block.
+ **/
+#define PGD_ADDRESS_END(Address, End)                  \
+({                                                     \
+  UINTN Boundary = ((Address) + PGD_SIZE) & PGD_MASK;  \
+  (Boundary - 1 < (End) - 1)? Boundary: (End);         \
+})
+/**
+  Gets the virtual address of the next block of the specified virtual address
+  that is aligned with the size of the page upper directory mapping.
+
+  @param  Address  Specifies the virtual address.
+  @param  End    The end address of the memory region.
+
+  @retval   the specified virtual address  of the next block.
+ **/
+#define PUD_ADDRESS_END(Address, End)                  \
+({                                                     \
+  UINTN Boundary = ((Address) + PUD_SIZE) & PUD_MASK;  \
+  (Boundary - 1 < (End) - 1)? Boundary: (End);         \
+})
+/**
+  Gets the virtual address of the next block of the specified virtual address
+  that is aligned with the size of the page middle directory mapping.
+
+  @param  Address  Specifies the virtual address.
+  @param  End    The end address of the memory region.
+
+  @retval   the specified virtual address  of the next block.
+ **/
+#define PMD_ADDRESS_END(Address, End)                  \
+({                                                     \
+  UINTN Boundary = ((Address) + PMD_SIZE) & PMD_MASK;  \
+  (Boundary - 1 < (End) - 1)? Boundary: (End);         \
+})
+/**
+  Get Specifies the virtual address corresponding to the index of the page global directory table entry.
+
+  @param  Address  Specifies the virtual address.
+
+  @retval   the index of the page global directory table entry.
+ **/
+#define PGD_INDEX(Address)                  (((Address) >> PGD_SHIFT) & (ENTRYS_PER_PGD-1))
+/**
+  Get Specifies the virtual address corresponding to the index of the page upper directory table entry.
+
+  @param  Address  Specifies the virtual address.
+  @param  End    The end address of the memory region.
+
+  @retval   the index of the page upper directory table entry.
+ **/
+#define PUD_INDEX(Address)                  (((Address) >> PUD_SHIFT) & (ENTRYS_PER_PUD - 1))
+/**
+  Get Specifies the virtual address corresponding to the index of the page middle directory table entry.
+
+  @param  Address  Specifies the virtual address.
+
+  @retval   the index of the page middle directory table entry.
+ **/
+#define PMD_INDEX(Address)                  (((Address) >> PMD_SHIFT) & (ENTRYS_PER_PMD - 1))
+/**
+  Get Specifies the virtual address corresponding to the index of the page table entry.
+
+  @param  Address  Specifies the virtual address.
+
+  @retval   the index of the page table entry.
+ **/
+#define PTE_INDEX(Address)                  (((Address) >> EFI_PAGE_SHIFT) & (ENTRYS_PER_PTE - 1))
+
+/**
+  Calculates the value of the page table entry based on the specified virtual address and properties.
+
+  @param  Address  Specifies the virtual address.
+  @param  Attributes  Specifies the Attributes.
+
+  @retval    the value of the page table entry.
+ **/
+#define MAKE_PTE(Address, Attributes)       (PTE){((((Address) >> EFI_PAGE_SHIFT) << 12) | (Attributes))}
+/**
+  Get Global bit from Attributes
+
+  @param  Attributes  Specifies the Attributes.
+ * */
+#define GET_GLOBALBIT(Attributes)           ((Attributes & PAGE_GLOBAL) >> PAGE_GLOBAL_SHIFT)
+/**
+  Calculates the value of the Huge page table entry based on the specified virtual address and properties.
+
+  @param  Address  Specifies the virtual address.
+  @param  Attributes  Specifies the Attributes.
+
+  @retval    the value of the HUGE page table entry.
+ **/
+#define MAKE_HUGE_PTE(Address, Attributes)  (((((Address) >> PMD_SHIFT) << PMD_SHIFT) | \
+                                             ((Attributes) | (GET_GLOBALBIT(Attributes) << PAGE_HGLOBAL_SHIFT) | \
+                                             PAGE_HUGE)))
+
+ /**
+  Check whether the large page table entry is.
+
+  @param  Val The value of the page table entry.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+#define IS_HUGE_PAGE(Val)                   ((((Val) & PAGE_HUGE) == PAGE_HUGE) && \
+                                             (((Val) & PAGE_HGLOBAL) == PAGE_HGLOBAL))
+
+#define HUGE_PAGE_SIZE                      (PMD_SIZE)
+
+ /**
+  Check that the global page directory table entry is empty.
+
+  @param  pgd   the global page directory struct variables.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pgd_none (
+  IN PGD pgd
+  )
+{
+  return (PGD_VAL(pgd) == (UINTN)PcdGet64(PcdInvalidPud));
+}
+
+ /**
+  Check that the page upper directory table entry is empty.
+
+  @param  pud   Page upper directory struct variables.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pud_none (
+  IN PUD pud
+  )
+{
+  return (PUD_VAL(pud) == (UINTN)PcdGet64 (PcdInvalidPmd));
+}
+
+ /**
+  Check that the page middle directory table entry is empty.
+
+  @param  pmd   Page middle directory struct variables.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pmd_none (
+  IN PMD pmd
+  )
+{
+  return (PMD_VAL(pmd) == (UINTN)PcdGet64(PcdInvalidPte));
+}
+ /**
+  Check that the page  table entry is empty.
+
+  @param  pmd   Page table entry struct variables.
+
+  @retval    1   Is huge page table entry.
+  @retval    0   Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pte_none (
+  IN PTE pte
+  )
+{
+  return (!(PTE_VAL(pte) & (~PAGE_GLOBAL)));
+}
+#endif // PAGE_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
new file mode 100644
index 0000000000..aacbf81744
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
@@ -0,0 +1,57 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Tlb or TLB     - Translation Lookaside Buffer
+    - HGLOBAL     - Huge Global
+    - PFN       - Page Frame number
+    - EXEC       - Execute
+    - PLV       - Privilege Level
+    - RPLV       - Restricted Privilege Level
+    - SUC       - Strong-ordered UnCached
+    - CC       - Coherent Cached
+    - WUC       - Weak-ordered UnCached
+**/
+#ifndef PTE_H_
+#define PTE_H_
+/*Page table property definitions */
+#define  PAGE_VALID_SHIFT    0
+#define  PAGE_DIRTY_SHIFT    1
+#define  PAGE_PLV_SHIFT      2  /* 2~3, two bits */
+#define  CACHE_SHIFT         4  /* 4~5, two bits */
+#define  PAGE_GLOBAL_SHIFT   6
+#define  PAGE_HUGE_SHIFT     6  /* HUGE is a PMD bit */
+
+#define  PAGE_HGLOBAL_SHIFT  12 /* HGlobal is a PMD bit */
+#define  PAGE_PFN_SHIFT      12
+#define  PAGE_PFN_END_SHIFT  48
+#define  PAGE_NO_READ_SHIFT  61
+#define  PAGE_NO_EXEC_SHIFT  62
+#define  PAGE_RPLV_SHIFT     63
+
+/* Used by TLB hardware (placed in EntryLo*) */
+#define PAGE_VALID           ((UINTN)(1) << PAGE_VALID_SHIFT)
+#define PAGE_DIRTY           ((UINTN)(1) << PAGE_DIRTY_SHIFT)
+#define PAGE_PLV             ((UINTN)(3) << PAGE_PLV_SHIFT)
+#define PAGE_GLOBAL          ((UINTN)(1) << PAGE_GLOBAL_SHIFT)
+#define PAGE_HUGE            ((UINTN)(1) << PAGE_HUGE_SHIFT)
+#define PAGE_HGLOBAL         ((UINTN)(1) << PAGE_HGLOBAL_SHIFT)
+#define PAGE_NO_READ         ((UINTN)(1) << PAGE_NO_READ_SHIFT)
+#define PAGE_NO_EXEC         ((UINTN)(1) << PAGE_NO_EXEC_SHIFT)
+#define PAGE_RPLV            ((UINTN)(1) << PAGE_RPLV_SHIFT)
+#define CACHE_MASK           ((UINTN)(3) << CACHE_SHIFT)
+#define PFN_SHIFT            (EFI_PAGE_SHIFT - 12 + PAGE_PFN_SHIFT)
+
+#define PLV_KERNEL           0
+#define PLV_USER             3
+
+#define PAGE_USER            (PLV_USER << PAGE_PLV_SHIFT)
+#define PAGE_KERNEL          (PLV_KERN << PAGE_PLV_SHIFT)
+
+#define CACHE_SUC            (0 << CACHE_SHIFT) /* Strong-ordered UnCached */
+#define CACHE_CC             (1 << CACHE_SHIFT) /* Coherent Cached */
+#define CACHE_WUC            (2 << CACHE_SHIFT) /* Weak-ordered UnCached */
+#endif // PTE_H_
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 06/15] Platform/Loongson: Add StableTimerLib.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (4 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 05/15] Platform/Loongson: Add MmuLib xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 07/15] Platform/Loongson: Support PEI phase xianglai
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

This library provides a delay interface and a timing interface.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../Include/Library/StableTimer.h             |  59 +++++
 .../Library/StableTimerLib/Count.S            |  52 ++++
 .../Library/StableTimerLib/TimerLib.c         | 236 ++++++++++++++++++
 .../Library/StableTimerLib/TimerLib.inf       |  32 +++
 4 files changed, 379 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h
new file mode 100644
index 0000000000..93f5b66c34
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h
@@ -0,0 +1,59 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Csr    - Cpu Status Register
+    - Calc   - Calculation
+    - Freq   - frequency
+**/
+
+#ifndef STABLE_TIMER_H_
+#define STABLE_TIMER_H_
+#include "Library/Cpu.h"
+
+/**
+  Gets the timer count value.
+
+  @param[] VOID
+
+  @retval  timer count value.
+**/
+extern
+UINTN
+EFIAPI
+LoongArchReadTime (
+  VOID
+  );
+
+/**
+  Calculate the timer frequency.
+
+  @param[] VOID
+
+  @retval  Timer frequency.
+**/
+UINT32
+EFIAPI
+CalcConstFreq (
+  VOID
+  );
+
+/*
+  Reads data from the specified CPUCFG register.
+
+  @param[OUT]  Val   Pointer to the variable used to store the CPUCFG register value.
+  @param[IN]  reg    Specifies the register number of the CPUCFG to read the data.
+
+  @retval  none
+ */
+extern
+VOID
+LoongArchReadCpuCfg (
+  UINT64   *Val,
+  UINT64   reg
+  );
+
+#endif // STABLE_TIMER_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S
new file mode 100644
index 0000000000..4e0e718381
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S
@@ -0,0 +1,52 @@
+#------------------------------------------------------------------------------
+#
+# Count for LoongArch
+#
+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include "Library/Cpu.h"
+
+ASM_GLOBAL ASM_PFX(CpuSetIP)
+ASM_GLOBAL ASM_PFX(LoongArchReadTime)
+ASM_GLOBAL ASM_PFX(LoongArchReadCpuCfg)
+
+#
+# Set cpu interrupts
+# @param A0 The interrupt number
+#
+
+ASM_PFX(CpuSetIP):
+    csrrd   T0, LOONGARCH_CSR_ECFG
+    or      T0, T0, A0
+    csrwr   T0, LOONGARCH_CSR_ECFG
+    jirl    ZERO, RA, 0
+
+#
+#Gets the timer count value.
+#@param[] VOID
+#@retval  timer count value.
+#
+
+ASM_PFX(LoongArchReadTime):
+    rdtime.d   A0, ZERO
+    jirl    ZERO, RA, 0
+
+#
+#   Read Csr CPUCFG register.
+#   @param   A0 Pointer to the variable used to store the CPUCFG register value.
+#   @param   A1 Specifies the register number of the CPUCFG to read the data.
+#   @retval  none
+#
+
+ASM_PFX(LoongArchReadCpuCfg):
+    cpucfg T0, A1
+    stptr.d T0, A0, 0
+    jirl    ZERO, RA, 0
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c
new file mode 100644
index 0000000000..135fb22611
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c
@@ -0,0 +1,236 @@
+/** @file
+  Generic LoongArch implementation of TimerLib.h
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Freq - Frequency
+    - Csr  - Cpu Status Register
+    - calc - calculate
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/StableTimer.h"
+#include "Library/Cpu.h"
+
+UINT32 StableTimerFreq = 0;
+
+/**
+  Calculate the timer frequency.
+
+  @param[] VOID
+
+  @retval  Timer frequency.
+**/
+UINT32
+EFIAPI
+CalcConstFreq (
+  VOID
+  )
+{
+  UINT32 Result;
+  UINT32 BaseFreq;
+  UINT32 ClockMultiplier;
+  UINT32 ClockDivide;
+  UINT64 Val;
+
+  LoongArchReadCpuCfg (&Val, LOONGARCH_CPUCFG4);
+  BaseFreq = (UINT32)Val;
+  LoongArchReadCpuCfg (&Val, LOONGARCH_CPUCFG5);
+  Result = (UINT32)Val;
+  ClockMultiplier = Result & 0xffff;
+  ClockDivide = (Result >> 16) & 0xffff;
+
+  if ((!BaseFreq) || (!ClockMultiplier) || (!ClockDivide)) {
+    return 0;
+  } else {
+    return (BaseFreq * ClockMultiplier / ClockDivide);
+  }
+}
+/**
+  Get the timer frequency.
+
+  @param[] VOID
+
+  @retval  Timer frequency.
+**/
+UINT32
+EFIAPI
+GetFreq (
+  VOID
+  )
+{
+  if (StableTimerFreq) {
+  } else {
+    StableTimerFreq = CalcConstFreq ();
+  }
+
+  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
+  )
+{
+
+  UINTN Count;
+  UINTN Ticks;
+  UINTN Start;
+  UINTN End;
+
+  Count = GetFreq ();
+  Count = (Count * MicroSeconds) / 1000000;
+  Start = LoongArchReadTime ();
+  End = Start + Count;
+
+  do {
+    Ticks = LoongArchReadTime ();
+  } while (Ticks < End);
+
+  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
+  )
+{
+  UINT32  MicroSeconds;
+
+  if (NanoSeconds % 1000 == 0) {
+    MicroSeconds = NanoSeconds/1000;
+  } else {
+    MicroSeconds = NanoSeconds/1000 + 1;
+  }
+  MicroSecondDelay (MicroSeconds);
+
+  return NanoSeconds;
+}
+
+/**
+  Retrieves the current value of a 64-bit free running performance counter.
+
+  Retrieves the current value of a 64-bit free running performance counter. The
+  counter can either count up by 1 or count down by 1. If the physical
+  performance counter counts by a larger increment, then the counter values
+  must be translated. The properties of the counter can be retrieved from
+  GetPerformanceCounterProperties ().
+
+  @return The current value of the free running performance counter.
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+  VOID
+  )
+{
+  return LoongArchReadTime ();
+}
+/**
+  Retrieves the 64-bit frequency in Hz and the range of performance counter
+  values.
+
+  If StartValue is not NULL, then the value that the performance counter starts
+  with immediately after is it rolls over is returned in StartValue. If
+  EndValue is not NULL, then the value that the performance counter end with
+  immediately before it rolls over is returned in EndValue. The 64-bit
+  frequency of the performance counter in Hz is always returned. If StartValue
+  is less than EndValue, then the performance counter counts up. If StartValue
+  is greater than EndValue, then the performance counter counts down. For
+  example, a 64-bit free running counter that counts up would have a StartValue
+  of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+  that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+  @param  StartValue  The value the performance counter starts with when it
+                      rolls over.
+  @param  EndValue    The value that the performance 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 = BIT2;
+  }
+
+  if (EndValue != NULL) {
+    *EndValue = BIT48 - 1;
+  }
+
+  return GetFreq ();
+}
+
+/**
+  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;
+
+  Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+  //
+  //          Ticks
+  // Time = --------- x 1,000,000,000
+  //        Frequency
+  //
+  NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+  //
+  // 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);
+  NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+  return NanoSeconds;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
new file mode 100644
index 0000000000..86f243998b
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
@@ -0,0 +1,32 @@
+## @file
+#  Generic LoongArch implementation of TimerLib.h
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                       = 0x00010005
+  BASE_NAME                         = TimerLib
+  FILE_GUID                         = 740389C7-CC44-4A2F-88DC-89D97D312E7C
+  MODULE_TYPE                       = BASE
+  VERSION_STRING                    = 1.0
+  LIBRARY_CLASS                     = TimerLib
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  TimerLib.c
+  Count.S
+
+[Packages]
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  DebugLib
+  IoLib
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 07/15] Platform/Loongson: Support PEI phase.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (5 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 06/15] Platform/Loongson: Add StableTimerLib xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 08/15] Platform/Loongson: Add CPU DXE driver xianglai
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Platform PEI module for LoongArch platform initialization.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../Loongson/LoongArchQemuPkg/Loongson.dec    |  23 ++
 .../Loongson/LoongArchQemuPkg/Loongson.dsc    |  64 +++++
 .../Loongson/LoongArchQemuPkg/Loongson.fdf    |  51 ++++
 .../LoongArchQemuPkg/PlatformPei/Fv.c         |  58 ++++
 .../LoongArchQemuPkg/PlatformPei/MemDetect.c  | 104 +++++++
 .../LoongArchQemuPkg/PlatformPei/Platform.c   | 261 ++++++++++++++++++
 .../LoongArchQemuPkg/PlatformPei/Platform.h   |  86 ++++++
 .../PlatformPei/PlatformPei.inf               |  72 +++++
 8 files changed, 719 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
index 61f600b20d..aeae75a678 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
@@ -32,7 +32,30 @@
 [PcdsFixedAtBuild, PcdsDynamic]
   gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase|0x0|UINT64|0x00000000
   gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize|0x0|UINT32|0x00000001
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvBase|0x0|UINT64|0x00000003
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvSize|0x0|UINT32|0x00000004
+  gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase|0x0|UINT64|0x00000009
+  gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreePadding|256|UINT32|0x0000000a
+
   gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase|0|UINT64|0x0000000b
   gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize|0|UINT32|0x0000000c
+  gLoongArchQemuPkgTokenSpaceGuid.PcdUefiRamTop|0x0|UINT64|0x0000000d
+  gLoongArchQemuPkgTokenSpaceGuid.PcdRamRegionsBottom|0x0|UINT64|0x0000000e
   gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase|0x0|UINT64|0x0000000f
   gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize|0x0|UINT32|0x00000010
+
+## In the PcdsFixedAtBuild.LOONGARCH64 area, numbers start at 0x10000.
+[PcdsFixedAtBuild.LOONGARCH64]
+   gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00010000
+   gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00010001
+
+## In the PcdsDynamic area, numbers start at 0x20000.
+[PcdsDynamic]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize|0x40000000|UINT64|0x00020000
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgSelectorAddress|0x0|UINT64|0x00020001
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgDataAddress|0x0|UINT64|0x00020002
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir|0x0|UINT64|0x00020003
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd|0x0|UINT64|0x00020004
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud|0x0|UINT64|0x00020005
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd|0x0|UINT64|0x00020006
+  gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte|0x0|UINT64|0x00020007
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
index b506f70625..b78a7e3b49 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
@@ -56,16 +56,53 @@
 
 [LibraryClasses.common]
   PcdLib                           | MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  TimerLib                         | Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
   PrintLib                         | MdePkg/Library/BasePrintLib/BasePrintLib.inf
   BaseMemoryLib                    | MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
   BaseLib                          | MdePkg/Library/BaseLib/BaseLib.inf
+  PerformanceLib                   | MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
   PeCoffLib                        | MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+  CacheMaintenanceLib              | MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+  UefiDecompressLib                | MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
   PeCoffGetEntryPointLib           | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
   IoLib                            | MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
   SerialPortLib                    | Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
   DebugPrintErrorLevelLib          | MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+  FdtLib                           | EmbeddedPkg/Library/FdtLib/FdtLib.inf
   PeCoffExtraActionLib             | MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
   DebugAgentLib                    | MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+  PeiServicesLib                   | MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+
+[LibraryClasses.common.SEC]
+  ReportStatusCodeLib              | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+  HobLib                           | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+  MemoryAllocationLib              | MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+
+[LibraryClasses.common.PEI_CORE]
+  HobLib                           | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+  PeiServicesTablePointerLib       | Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+  MemoryAllocationLib              | MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+  PeiCoreEntryPoint                | MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf
+  ReportStatusCodeLib              | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+  OemHookStatusCodeLib             | MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+  PeCoffGetEntryPointLib           | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+  QemuFwCfgLib                     | Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+  MmuLib                           | Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
+
+[LibraryClasses.common.PEIM]
+  HobLib                           | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+  PeiServicesTablePointerLib       | Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+  MemoryAllocationLib              | MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+  PeimEntryPoint                   | MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+  ReportStatusCodeLib              | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+  OemHookStatusCodeLib             | MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+  PeCoffGetEntryPointLib           | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+  PeiResourcePublicationLib        | MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf
+  ExtractGuidedSectionLib          | MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf
+  PcdLib                           | MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+  QemuFwCfgS3Lib                   | OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
+  QemuFwCfgLib                     | Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+  MmuLib                           | Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
 
 ################################################################################
 #
@@ -111,8 +148,16 @@
   # ASSERT_BREAKPOINT_ENABLED  0x10
   # ASSERT_DEADLOOP_ENABLED    0x20
 
+#######################################################################################
   gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase                 | 0x10000
   gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize                 | 0x10000
+  gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase                    | 0x200000
+  #
+  # minimal memory for uefi bios should be 512M
+  # 0x00000000 - 0x10000000
+  # 0x90000000 - 0xA0000000
+  #
+  gLoongArchQemuPkgTokenSpaceGuid.PcdUefiRamTop                        | 0x10000000
 
 [Components]
 
@@ -120,3 +165,22 @@
   # SEC Phase modules
   #
   Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
+
+  #
+  # PEI Phase modules
+  #
+  MdeModulePkg/Core/Pei/PeiMain.inf
+  MdeModulePkg/Universal/PCD/Pei/Pcd.inf  {
+    <LibraryClasses>
+      PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  }
+  MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf
+  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
+    <LibraryClasses>
+      NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+  }
+
+  Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf {
+    <LibraryClasses>
+      PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+  }
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
index 9685795cda..8e257f2392 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
@@ -45,9 +45,60 @@ READ_LOCK_STATUS   = TRUE
 
 INF  Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
 
+#####################################################################################################
+[FV.PEIFV]
+FvNameGuid         = 6f856a84-de7d-4af9-93a3-342b4ecb46eb
+BlockSize          = $(BLOCK_SIZE)
+FvAlignment        = 16
+ERASE_POLARITY     = 1
+MEMORY_MAPPED      = TRUE
+STICKY_WRITE       = TRUE
+LOCK_CAP           = TRUE
+LOCK_STATUS        = TRUE
+READ_DISABLED_CAP  = TRUE
+READ_ENABLED_CAP   = TRUE
+READ_STATUS        = TRUE
+READ_LOCK_CAP      = TRUE
+READ_LOCK_STATUS   = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP  = TRUE
+WRITE_STATUS       = TRUE
+WRITE_LOCK_CAP     = TRUE
+WRITE_LOCK_STATUS  = TRUE
+
+APRIORI PEI {
+  INF  MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+}
+
+#
+#  PEI Phase modules
+#
+
+INF  MdeModulePkg/Core/Pei/PeiMain.inf
+INF  MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+INF  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+INF  Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
+
 #####################################################################################################
 [Rule.Common.SEC]
   FILE SEC = $(NAMED_GUID) {
     TE       TE Align = Auto   $(INF_OUTPUT)/$(MODULE_NAME).efi
     UI       STRING ="$(MODULE_NAME)" Optional
   }
+
+#####################################################################################################
+[Rule.Common.PEI_CORE]
+  FILE PEI_CORE = $(NAMED_GUID) {
+    TE       TE   Align=Auto    $(INF_OUTPUT)/$(MODULE_NAME).efi
+    UI       STRING ="$(MODULE_NAME)" Optional
+  }
+
+#####################################################################################################
+[Rule.Common.PEIM]
+  FILE PEIM = $(NAMED_GUID) {
+     PEI_DEPEX PEI_DEPEX Optional        $(INF_OUTPUT)/$(MODULE_NAME).depex
+     PE32      PE32   Align=Auto         $(INF_OUTPUT)/$(MODULE_NAME).efi
+     UI        STRING="$(MODULE_NAME)" Optional
+  }
+
+#####################################################################################################
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c
new file mode 100644
index 0000000000..06b2807d6c
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c
@@ -0,0 +1,58 @@
+/** @file
+  Build FV related hobs for platform.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiPei.h"
+#include "Platform.h"
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+
+/**
+  Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
+  and DXE know about them.
+
+  @retval EFI_SUCCESS   Platform PEI FVs were initialized successfully.
+**/
+EFI_STATUS
+PeiFvInitialization (
+  VOID
+  )
+{
+  DEBUG ((DEBUG_INFO, "Platform PEI Firmware Volume Initialization\n"));
+
+  //
+  // Create a memory allocation HOB for the PEI FV.
+  //
+  BuildMemoryAllocationHob (
+    PcdGet64 (PcdSecPeiTempRamBase),
+    PcdGet32 (PcdSecPeiTempRamSize),
+    EfiBootServicesData
+    );
+
+  //
+  // Let DXE know about the DXE FV
+  //
+  BuildFvHob (PcdGet64 (PcdFlashDxeFvBase), PcdGet32 (PcdFlashDxeFvSize));
+
+  //
+  // Let PEI know about the DXE FV so it can find the DXE Core
+  //
+  DEBUG ((DEBUG_INFO, "DXEFV base:%p size:%x\n", (VOID *) (UINTN)PcdGet64 (PcdFlashDxeFvBase),
+    PcdGet32 (PcdFlashDxeFvSize)));
+  PeiServicesInstallFvInfoPpi (
+    NULL,
+    (VOID *) (UINTN)PcdGet64 (PcdFlashDxeFvBase),
+    PcdGet32 (PcdFlashDxeFvSize),
+    NULL,
+    NULL
+    );
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c
new file mode 100644
index 0000000000..fad4cff8d8
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c
@@ -0,0 +1,104 @@
+/** @file
+  Memory Detection for Virtual Machines.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include "Platform.h"
+
+/**
+  Publish PEI core memory
+
+  @return EFI_SUCCESS     The PEIM initialized successfully.
+**/
+EFI_STATUS
+PublishPeiMemory (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINT64 Base;
+  UINT64      Size;
+  UINT64      RamTop;
+
+  //
+  // Determine the range of memory to use during PEI
+  //
+  Base = PcdGet64 (PcdSecPeiTempRamBase) + PcdGet32 (PcdSecPeiTempRamSize);
+  RamTop = PcdGet64 (PcdUefiRamTop);
+  Size = RamTop - Base;
+
+  //
+  // Publish this memory to the PEI Core
+  //
+  Status = PublishSystemMemory (Base, Size);
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG ((DEBUG_INFO, "Publish Memory Initialize done.\n"));
+  return Status;
+}
+
+/**
+  Peform Memory Detection
+  Publish system RAM and reserve memory regions
+**/
+VOID
+InitializeRamRegions (
+  VOID
+  )
+{
+  EFI_STATUS           Status;
+  FIRMWARE_CONFIG_ITEM FwCfgItem;
+  UINTN                FwCfgSize;
+  LOONGARCH_MEMMAP_ENTRY  MemoryMapEntry;
+  LOONGARCH_MEMMAP_ENTRY  *StartEntry;
+  LOONGARCH_MEMMAP_ENTRY  *pEntry;
+  UINTN                Processed;
+
+  Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status));
+    return ;
+  }
+  if (FwCfgSize % sizeof MemoryMapEntry != 0) {
+    DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize));
+    return ;
+  }
+
+  QemuFwCfgSelectItem (FwCfgItem);
+  StartEntry = AllocatePages  (EFI_SIZE_TO_PAGES (FwCfgSize));
+  QemuFwCfgReadBytes (FwCfgSize, StartEntry);
+  for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) {
+    pEntry = StartEntry + Processed;
+    if (pEntry->Length == 0) {
+      continue;
+    }
+
+    DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p  type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type));
+    if (pEntry->Type != EfiAcpiAddressRangeMemory) {
+      continue;
+    }
+
+    AddMemoryRangeHob ( pEntry->BaseAddr, pEntry->BaseAddr + pEntry->Length);
+  }
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c
new file mode 100644
index 0000000000..262e2750e4
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c
@@ -0,0 +1,261 @@
+/** @file
+  Platform PEI driver
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Mem - Memory
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/MmuLib.h>
+#include <Guid/FdtHob.h>
+#include <libfdt.h>
+#include <Ppi/MasterBootMode.h>
+
+#include "Platform.h"
+
+/* TODO */
+EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
+  { EfiReservedMemoryType,  0x004 },
+  { EfiRuntimeServicesData, 0x024 },
+  { EfiRuntimeServicesCode, 0x030 },
+  { EfiBootServicesCode,    0x180 },
+  { EfiBootServicesData,    0xF00 },
+  { EfiMaxMemoryType,       0x000 }
+};
+
+//
+// Module globals
+//
+CONST EFI_PEI_PPI_DESCRIPTOR  mPpiListBootMode = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiPeiMasterBootModePpiGuid,
+  NULL
+};
+
+/**
+  Create Reserved type memory range hand off block.
+
+  @param  MemoryBase    memory base address.
+  @param  MemoryLimit  memory length.
+
+  @return  VOID
+**/
+VOID
+AddReservedMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_MEMORY_RESERVED,
+    EFI_RESOURCE_ATTRIBUTE_PRESENT     |
+    EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+    EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+    EFI_RESOURCE_ATTRIBUTE_TESTED,
+    MemoryBase,
+    MemorySize
+    );
+}
+/**
+  Create system type  memory range hand off block.
+
+  @param  MemoryBase    memory base address.
+  @param  MemoryLimit  memory length.
+
+  @return  VOID
+**/
+VOID
+AddMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  )
+{
+  BuildResourceDescriptorHob (
+    EFI_RESOURCE_SYSTEM_MEMORY,
+    EFI_RESOURCE_ATTRIBUTE_PRESENT |
+    EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+    EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+    EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+    EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+    EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+    EFI_RESOURCE_ATTRIBUTE_TESTED,
+    MemoryBase,
+    MemorySize
+    );
+}
+
+/**
+  Create  memory range hand off block.
+
+  @param  MemoryBase    memory base address.
+  @param  MemoryLimit  memory length.
+
+  @return  VOID
+**/
+VOID
+AddMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  )
+{
+  AddMemoryBaseSizeHob (MemoryBase, (UINT64) (MemoryLimit - MemoryBase));
+}
+/**
+  Create  memory type information hand off block.
+
+  @param  VOID
+
+  @return  VOID
+**/
+VOID
+MemMapInitialization (
+  VOID
+  )
+{
+  DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
+  //
+  // Create Memory Type Information HOB
+  //
+  BuildGuidDataHob (
+    &gEfiMemoryTypeInformationGuid,
+    mDefaultMemoryTypeInformation,
+    sizeof (mDefaultMemoryTypeInformation)
+    );
+}
+
+/**
+  Misc Initialization.
+
+  @param  VOID
+
+  @return  VOID
+**/
+VOID
+MiscInitialization (
+  VOID
+  )
+{
+  DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
+  //
+  // Creat CPU HOBs.
+  //
+  BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize));
+}
+/**
+  add fdt hand off block.
+
+  @param  VOID
+
+  @return  VOID
+**/
+VOID
+AddFdtHob (VOID)
+{
+  VOID    *Base;
+  VOID    *NewBase;
+  UINTN   FdtSize;
+  UINTN   FdtPages;
+  UINT64  *FdtHobData;
+
+  Base = (VOID*)(UINTN)PcdGet64 (PcdDeviceTreeBase);
+  ASSERT (Base != NULL);
+
+  FdtSize = fdt_totalsize (Base) + PcdGet32 (PcdDeviceTreePadding);
+  FdtPages = EFI_SIZE_TO_PAGES (FdtSize);
+  NewBase = AllocatePages (FdtPages);
+  ASSERT (NewBase != NULL);
+  fdt_open_into (Base, NewBase, EFI_PAGES_TO_SIZE (FdtPages));
+
+  FdtHobData = BuildGuidHob (&gFdtHobGuid, sizeof *FdtHobData);
+  ASSERT (FdtHobData != NULL);
+  *FdtHobData = (UINTN)NewBase;
+}
+
+/**
+  Fetch the size of system memory from QEMU.
+
+  @param  VOID
+
+  @return  VOID
+**/
+VOID
+SystemMemorySizeInitialization (
+  VOID
+  )
+{
+  UINT64        RamSize;
+  RETURN_STATUS PcdStatus;
+
+  QemuFwCfgSelectItem (QemuFwCfgItemRamSize);
+  RamSize= QemuFwCfgRead64 ();
+  DEBUG ((DEBUG_INFO, "%a: QEMU reports %dM system memory\n", __FUNCTION__,
+    RamSize/1024/1024));
+
+  //
+  // If the fw_cfg key or fw_cfg entirely is unavailable, no change to PCD.
+  //
+  if (RamSize == 0) {
+    return;
+  }
+
+  //
+  // Otherwise, set RamSize to PCD.
+  //
+  PcdStatus =  PcdSet64S (PcdRamSize, RamSize);
+  ASSERT_RETURN_ERROR (PcdStatus);
+}
+
+/**
+  Perform Platform PEI initialization.
+
+  @param  FileHandle      Handle of the file being invoked.
+  @param  PeiServices     Describes the list of possible PEI Services.
+
+  @return EFI_SUCCESS     The PEIM initialized successfully.
+**/
+EFI_STATUS
+EFIAPI
+InitializePlatform (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS Status;
+
+  DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
+
+  Status = PeiServicesInstallPpi (&mPpiListBootMode);
+  ASSERT_EFI_ERROR (Status);
+
+  SystemMemorySizeInitialization ();
+  PublishPeiMemory ();
+  PeiFvInitialization ();
+  InitializeRamRegions ();
+  MemMapInitialization ();
+  MiscInitialization ();
+  AddFdtHob ();
+  ConfigureMmu ();
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h
new file mode 100644
index 0000000000..38d358b335
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h
@@ -0,0 +1,86 @@
+/** @file
+  Platform PEI module include file.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_H_
+#define PLATFORM_H_
+
+#include <IndustryStandard/Pci22.h>
+
+/**
+  Create system type  memory range hand off block.
+
+  @param  MemoryBase    memory base address.
+  @param  MemoryLimit  memory length.
+
+  @return  VOID
+**/
+VOID
+AddMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  );
+
+/**
+  Create  memory range hand off block.
+
+  @param  MemoryBase    memory base address.
+  @param  MemoryLimit  memory length.
+
+  @return  VOID
+**/
+VOID
+AddMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit
+  );
+
+/**
+  Create Reserved type memory range hand off block.
+
+  @param  MemoryBase    memory base address.
+  @param  MemoryLimit  memory length.
+
+  @return  VOID
+**/
+VOID
+AddReservedMemoryBaseSizeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  UINT64                      MemorySize
+  );
+/**
+  Publish PEI core memory
+
+  @return EFI_SUCCESS     The PEIM initialized successfully.
+**/
+EFI_STATUS
+PublishPeiMemory (
+  VOID
+  );
+/**
+  Publish system RAM and reserve memory regions
+
+  @return  VOID
+**/
+VOID
+InitializeRamRegions (
+  VOID
+  );
+
+/**
+  Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
+  and DXE know about them.
+
+  @retval EFI_SUCCESS   Platform PEI FVs were initialized successfully.
+**/
+EFI_STATUS
+PeiFvInitialization (
+  VOID
+  );
+
+#endif // PLATFORM_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
new file mode 100644
index 0000000000..417c5e586a
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
@@ -0,0 +1,72 @@
+## @file
+#  Platform PEI driver
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PlatformPei
+  FILE_GUID                      = 4c0e81e5-e8e3-4eef-b24b-19b686e9ab53
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializePlatform
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  Fv.c
+  MemDetect.c
+  Platform.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  OvmfPkg/OvmfPkg.dec
+
+[Ppis]
+  gEfiPeiMasterBootModePpiGuid
+
+[Guids]
+  gEfiMemoryTypeInformationGuid
+  gFdtHobGuid
+
+[LibraryClasses]
+  DebugLib
+  BaseMemoryLib
+  HobLib
+  IoLib
+  PeiResourcePublicationLib
+  PeiServicesLib
+  PeiServicesTablePointerLib
+  PeimEntryPoint
+  QemuFwCfgLib
+  PcdLib
+  TimerLib
+  MmuLib
+  MemoryAllocationLib
+
+[Pcd]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
+  gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreePadding
+
+[FixedPcd]
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvSize
+  gLoongArchQemuPkgTokenSpaceGuid.PcdRamRegionsBottom
+  gLoongArchQemuPkgTokenSpaceGuid.PcdUefiRamTop
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase
+  gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize
+  gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize
+  gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize
+
+[Depex]
+  TRUE
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 08/15] Platform/Loongson: Add CPU DXE driver.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (6 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 07/15] Platform/Loongson: Support PEI phase xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 09/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

The driver produces EFI_CPU_ARCH_PROTOCOL,
Initialize the exception entry address.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c  | 367 ++++++++++++++++++
 .../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h  | 199 ++++++++++
 .../Drivers/CpuDxe/CpuDxe.inf                 |  59 +++
 .../Drivers/CpuDxe/LoongArch64/Exception.c    | 335 ++++++++++++++++
 .../Drivers/CpuDxe/LoongArch64/Fpu.S          |  97 +++++
 .../Drivers/CpuDxe/LoongArch64/LoongArch.S    | 321 +++++++++++++++
 6 files changed, 1378 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S

diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c
new file mode 100644
index 0000000000..23f824d82b
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c
@@ -0,0 +1,367 @@
+/** @file
+  CPU DXE Module to produce CPU ARCH Protocol
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/IdleLoopEvent.h>
+#include <Uefi.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmuLib.h>
+#include "CpuDxe.h"
+
+BOOLEAN mInterruptState   = FALSE;
+
+/*
+  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
+  )
+{
+  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 ();
+
+  mInterruptState  = TRUE;
+  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 ();
+
+  mInterruptState = FALSE;
+  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 = mInterruptState;
+  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;
+}
+
+/**
+  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   Interrupt Type.
+  @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
+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
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  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                    EfiAttributes
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       LoongArchAttributes;
+  UINTN       RegionBaseAddress;
+  UINTN       RegionLength;
+  UINTN       RegionLoongArchAttributes;
+
+  if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
+    // Minimum granularity is SIZE_4KB (4KB on ARM)
+    DEBUG ((DEBUG_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_4KB\n",
+      BaseAddress,
+      Length,
+      EfiAttributes));
+
+    return EFI_UNSUPPORTED;
+  }
+  // Convert the 'Attribute' into LoongArch Attribute
+  LoongArchAttributes = EfiAttributeToLoongArchAttribute (EfiAttributes);
+
+  // Get the region starting from 'BaseAddress' and its 'Attribute'
+  RegionBaseAddress = BaseAddress;
+  Status = GetLoongArchMemoryRegion (RegionBaseAddress, BaseAddress + Length,
+             &RegionLength, &RegionLoongArchAttributes);
+
+  LoongArchSetMemoryAttributes (BaseAddress, Length, EfiAttributes);
+  // Data & Instruction Caches are flushed when we set new memory attributes.
+  // So, we only set the attributes if the new region is different.
+  if (EFI_ERROR (Status) || (RegionLoongArchAttributes != LoongArchAttributes) ||
+      ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
+  {
+    return LoongArchSetMemoryAttributes (BaseAddress, Length, EfiAttributes);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  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.
+
+  @param VOID
+**/
+VOID
+EFIAPI
+IdleLoopEventCallback (
+  IN EFI_EVENT                Event,
+  IN VOID                     *Context
+  )
+{
+  CpuSleep ();
+}
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE            CpuHandle = NULL;
+EFI_CPU_ARCH_PROTOCOL Cpu = {
+  CpuFlushCpuDataCache,
+  CpuEnableInterrupt,
+  CpuDisableInterrupt,
+  CpuGetInterruptState,
+  CpuInit,
+  CpuRegisterInterruptHandler,
+  CpuGetTimerValue,
+  CpuSetMemoryAttributes,
+  0,          // NumberOfTimers
+  4,          // DmaBufferAlignment
+};
+
+/**
+  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
+CpuDxeInitialize (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT    IdleLoopEvent;
+
+  InitializeExceptions (&Cpu);
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &CpuHandle,
+                  &gEfiCpuArchProtocolGuid, &Cpu,
+                  NULL
+                  );
+
+  //
+  // Setup a callback for idle events
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  IdleLoopEventCallback,
+                  NULL,
+                  &gIdleLoopEventGuid,
+                  &IdleLoopEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h
new file mode 100644
index 0000000000..43cb976aa2
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h
@@ -0,0 +1,199 @@
+/** @file
+  CPU DXE Module to produce CPU ARCH Protocol and CPU MP Protocol
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_DXE_H_
+#define CPU_DXE_H_
+
+#include <Protocol/Cpu.h>
+
+/**
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InteruptNum. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InteruptNum is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  InteruptNum    A number of the processor's current interrupt.
+  @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 InteruptNum was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InteruptNum was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InteruptNum is not supported.
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE             InteruptNum,
+  IN EFI_CPU_INTERRUPT_HANDLER      InterruptHandler
+  );
+
+/**
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InteruptNum. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InteruptNum is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  InteruptNum    A number of the processor's current interrupt.
+  @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 InteruptNum was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InteruptNum was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InteruptNum is not supported.
+**/
+EFI_STATUS
+RegisterDebuggerInterruptHandler (
+  IN EFI_EXCEPTION_TYPE             InteruptNum,
+  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
+  );
+
+/** Exception module initialization
+  This function sets the exception base address.
+
+  @param  Cpu   A pointer to the CPU architecture protocol structure.
+
+  @retval EFI_SUCCESS           Initialization succeeded
+  @retval EFI_NOT_FOUND          Could not Found resources.
+  @retval EFI_OUT_OF_RESOURCES   No enough resources.
+**/
+EFI_STATUS
+InitializeExceptions (
+  IN EFI_CPU_ARCH_PROTOCOL    *Cpu
+  );
+
+/** Common exception entry
+  Exception handling is the entry point for the C environment,
+  This function does different things depending on the exception type.
+
+  @param  SystemContext  The system context at the time of the exception.
+
+  @retval            VOID.
+**/
+VOID
+EFIAPI
+CommonExceptionEntry (
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext
+  );
+
+extern CHAR8 LoongArchException[], LoongArchExceptionEnd[];
+/** Set Exception Base Address
+
+  @param  addr Exception Base Address.
+
+  @retval      The Old Exception Base Address.
+**/
+extern
+UINT64
+SetEbase (
+  EFI_PHYSICAL_ADDRESS addr
+  );
+/*
+  Load the FPU with signalling NANS.  This bit pattern we're using has
+  the property that no matter whether considered as single or as double
+  precision represents signaling NANS.
+
+  @param  fcsr  The value to initialize FCSR0
+
+  @retval      The Old Exception Base Address.
+ */
+extern
+VOID
+InitFpu (
+  UINT32 fcsr
+  );
+
+/*
+  Read Csr EUEN register.
+
+  @param  CsrEuen Pointer to the variable used to store the EUEN register value
+
+  @retval  none
+ */
+extern
+VOID
+LoongArchReadqCsrEuen (
+  UINT64   *CsrEuen
+  );
+
+/*
+  Write Csr EUEN register.
+
+  @param   The value used to write to the EUEN register
+
+  @retval  none
+ */
+extern
+VOID
+LoongArchWriteqCsrEuen (
+  UINT64   CsrEuen
+  );
+
+/*
+  Enables  floating-point unit
+
+  @param  VOID
+
+  @retval  VOID
+ */
+extern
+VOID
+LoongArchEnableFpu (
+  VOID
+  );
+
+/*
+  Disable  floating-point unit
+
+  @param  VOID
+
+  @retval  VOID
+ */
+extern
+VOID
+LoongArchDisableFpu (
+  VOID
+  );
+
+#endif // CPU_DXE_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
new file mode 100644
index 0000000000..96aabfefb8
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
@@ -0,0 +1,59 @@
+## @file
+#  CPU driver installs CPU Architecture Protocol and CPU MP protocol.
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = CpuDxe
+  FILE_GUID                      = bf954921-25c1-48c0-9bfb-8d0cd7ee92da
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = CpuDxeInitialize
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources.Common]
+  CpuDxe.c
+  CpuDxe.h
+
+[Sources.LOONGARCH64]
+  LoongArch64/Exception.c
+  LoongArch64/LoongArch.S
+  LoongArch64/Fpu.S
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  CacheMaintenanceLib
+  CpuLib
+  DebugLib
+  DxeServicesTableLib
+  HobLib
+  PeCoffGetEntryPointLib
+  UefiDriverEntryPoint
+  UefiLib
+  MmuLib
+
+[Protocols]
+  gEfiCpuArchProtocolGuid
+  gEfiMpServiceProtocolGuid
+
+[Guids]
+  gEfiDebugImageInfoTableGuid
+  gIdleLoopEventGuid
+
+[Depex]
+ TRUE
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c
new file mode 100644
index 0000000000..793ae90e4f
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c
@@ -0,0 +1,335 @@
+/** @file
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - ESTAT     - Exception Status
+    - ECFG      - Exception Configure
+    - ERA       - Exception Return Address
+    - BADV      - Bad Virtual Address
+    - BADI      - Bad Instructions
+    - Epc or EPC or epc   - Exception Program Counter
+    - pc or PC or pc      - Program Counter
+    - CRMD      - Current Mode
+    - PRMD      - Previous Mode
+    - CsrEuen      - Cpu Status Register Extern Unit Enable
+    - fpu or fp or FP   - Float Point Unit
+    - LOONGARCH   - Loongson Arch
+    - Irq   - Interrupt ReQuest
+**/
+
+#include "Library/Cpu.h"
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include "CpuDxe.h"
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/UefiLib.h>
+#include <Guid/DebugImageInfoTable.h>
+
+EFI_EXCEPTION_CALLBACK  gInterruptHandler[MAX_LOONGARCH_INTERRUPT + 1];
+EFI_EXCEPTION_CALLBACK  gDebuggerExceptionHandlers[MAX_LOONGARCH_INTERRUPT + 1];
+
+/**
+  This function registers and enables the handler specified by InterruptHandler for a processor
+  interrupt or exception type specified by InteruptNum. If InterruptHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by InteruptNum is uninstalled.
+  The installed handler is called once for each processor interrupt or exception.
+
+  @param  InteruptNum    A number of the processor's current interrupt.
+  @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 InteruptNum was
+                                previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InteruptNum was not
+                                previously installed.
+  @retval EFI_UNSUPPORTED       The interrupt specified by InteruptNum is not supported.
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE             InteruptNum,
+  IN EFI_CPU_INTERRUPT_HANDLER      InterruptHandler
+  )
+{
+  if (InteruptNum > MAX_LOONGARCH_INTERRUPT) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if ((InterruptHandler != NULL)
+    && (gInterruptHandler[InteruptNum] != NULL))
+  {
+    return EFI_ALREADY_STARTED;
+  }
+
+  gInterruptHandler[InteruptNum] = InterruptHandler;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function calls the corresponding exception handler based on the exception type.
+
+  @param  SystemContext  The system context at the time of the exception.
+
+  @retval VOID
+**/
+STATIC VOID
+EFIAPI
+CommonInterruptHandler (
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext
+  )
+{
+  INT32 Pending;
+  INT32 InterruptNum;
+  /*Interrupt [13-0] NMI IPI TI PCOV hw IP10-IP2 soft IP1-IP0*/
+  Pending = ((SystemContext.SystemContextLoongArch64->ESTAT) &
+             (SystemContext.SystemContextLoongArch64->ECFG) & 0x1fff);
+  for (InterruptNum = 0; InterruptNum < MAX_LOONGARCH_INTERRUPT; InterruptNum++) {
+    if (Pending & (1 << InterruptNum)) {
+      if (gInterruptHandler[InterruptNum] != NULL) {
+        gInterruptHandler[InterruptNum] (InterruptNum, SystemContext);
+      } else {
+        DEBUG ((DEBUG_INFO, "Pending: 0x%0x, InterruptNum: 0x%0x\n", Pending, InterruptNum));
+      }
+    }
+  }
+}
+
+/**
+  Use the EFI Debug Image Table to lookup the FaultAddress and find which PE/COFF image
+  it came from. As long as the PE/COFF image contains a debug directory entry a
+  string can be returned. For ELF and Mach-O images the string points to the Mach-O or ELF
+  image. Microsoft tools contain a pointer to the PDB file that contains the debug information.
+
+  @param  FaultAddress         Address to find PE/COFF image for.
+  @param  ImageBase            Return load address of found image
+  @param  PeCoffSizeOfHeaders  Return the size of the PE/COFF header for the image that was found
+
+  @retval NULL                 FaultAddress not in a loaded PE/COFF image.
+  @retval                      Path and file name of PE/COFF image.
+**/
+CHAR8 *
+GetImageName (
+  IN  UINTN  FaultAddress,
+  OUT UINTN  *ImageBase,
+  OUT UINTN  *PeCoffSizeOfHeaders
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_DEBUG_IMAGE_INFO_TABLE_HEADER   *DebugTableHeader;
+  EFI_DEBUG_IMAGE_INFO                *DebugTable;
+  UINTN                               Entry;
+  CHAR8                               *Address;
+
+  Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugTableHeader);
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+
+  DebugTable = DebugTableHeader->EfiDebugImageInfoTable;
+  if (DebugTable == NULL) {
+    return NULL;
+  }
+
+  Address = (CHAR8 *)(UINTN)FaultAddress;
+  for (Entry = 0; Entry < DebugTableHeader->TableSize; Entry++, DebugTable++) {
+    if (DebugTable->NormalImage != NULL) {
+      if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) &&
+          (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {
+        if ((Address >= (CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase) &&
+            (Address <= ((CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase + DebugTable->NormalImage->LoadedImageProtocolInstance->ImageSize))) {
+          *ImageBase = (UINTN)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase;
+          *PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)*ImageBase);
+          return PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase);
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+/**
+  pass a file name string that contains the path, return file name.
+
+  @param  FullName   Path and file name
+
+  @retval            file name.
+**/
+STATIC
+CONST CHAR8 *
+BaseName (
+  IN  CONST CHAR8 *FullName
+  )
+{
+  CONST CHAR8 *Str;
+
+  Str = FullName + AsciiStrLen (FullName);
+
+  while (--Str > FullName) {
+    if (*Str == '/' || *Str == '\\') {
+      return Str + 1;
+    }
+  }
+  return Str;
+}
+
+/** Default Exception Handler Function
+  This function is called when an exception occurs that cannot be handled,
+  and this function prints the system context information when the interrupt occurred
+
+  @param  SystemContext  The system context at the time of the exception.
+
+  @retval            VOID.
+**/
+STATIC
+VOID
+EFIAPI
+DefaultHandler (
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext
+  )
+{
+  CHAR8  *ImageName;
+  UINTN  ImageBase;
+  UINTN  Epc;
+  UINTN  PeCoffSizeOfHeader;
+
+  DEBUG ((DEBUG_ERROR, "CRMD   0x%llx\n",  SystemContext.SystemContextLoongArch64->CRMD));
+  DEBUG ((DEBUG_ERROR, "PRMD   0x%llx\n",  SystemContext.SystemContextLoongArch64->PRMD));
+  DEBUG ((DEBUG_ERROR, "ECFG  0x%llx\n",  SystemContext.SystemContextLoongArch64->ECFG));
+  DEBUG ((DEBUG_ERROR, "ESTAT   0x%llx\n",  SystemContext.SystemContextLoongArch64->ESTAT));
+  DEBUG ((DEBUG_ERROR, "ERA    0x%llx\n",  SystemContext.SystemContextLoongArch64->ERA));
+  DEBUG ((DEBUG_ERROR, "BADV    0x%llx\n",  SystemContext.SystemContextLoongArch64->BADV));
+  DEBUG ((DEBUG_ERROR, "BADI 0x%llx\n",  SystemContext.SystemContextLoongArch64->BADI));
+
+  Epc = SystemContext.SystemContextLoongArch64->ERA;
+  ImageName = GetImageName (Epc, &ImageBase, &PeCoffSizeOfHeader);
+  if (ImageName != NULL) {
+    DEBUG ((DEBUG_ERROR, "PC 0x%012lx (0x%012lx+0x%08x) [ 0] %a\n",
+           Epc, ImageBase,
+           Epc - ImageBase, BaseName (ImageName)));
+  } else {
+    DEBUG ((DEBUG_ERROR, "PC 0x%012lx\n", Epc));
+  }
+
+  while (1);
+}
+
+/** Common exception entry
+  Exception handling is the entry point for the C environment,
+  This function does different things depending on the exception type.
+
+  @param  SystemContext  The system context at the time of the exception.
+
+  @retval            VOID.
+**/
+VOID
+EFIAPI
+CommonExceptionEntry (
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext
+  )
+{
+  INT32    ExceptionType;
+  UINT64   CsrEuen;
+  UINT64   FpuStatus;
+
+  ExceptionType = SystemContext.SystemContextLoongArch64->ESTAT & CSR_ESTAT_EXC;
+  ExceptionType = ExceptionType >> CSR_ESTAT_EXC_SHIFT;
+
+  LoongArchReadqCsrEuen (&CsrEuen);
+  FpuStatus = CsrEuen & CSR_EUEN_FPEN;
+  switch (ExceptionType) {
+    case EXC_INT:
+      /*
+       * handle interrupt exception
+       */
+      CommonInterruptHandler (SystemContext);
+      if (!FpuStatus) {
+        LoongArchReadqCsrEuen (&CsrEuen);
+        if (CsrEuen & CSR_EUEN_FPEN) {
+          /*
+           * Since Hw FP is enabled during interrupt handler,
+           * disable FP
+           */
+           CsrEuen &= ~CSR_EUEN_FPEN;
+           LoongArchWriteqCsrEuen (CsrEuen);
+        }
+      }
+      break;
+    case EXC_FPDIS:
+      /*
+       * Hardware FP disabled exception,
+       * Enable and init FP registers here
+       */
+      LoongArchEnableFpu ();
+      InitFpu(FPU_CSR_RN);
+      break;
+    default:
+      DefaultHandler(SystemContext);
+      break;
+  }
+}
+
+/** Exception module initialization
+  This function sets the exception base address.
+
+  @param  Cpu   A pointer to the CPU architecture protocol structure.
+
+  @retval EFI_SUCCESS           Initialization succeeded
+  @retval EFI_NOT_FOUND          Could not Found resources.
+  @retval EFI_OUT_OF_RESOURCES   No enough resources.
+**/
+EFI_STATUS
+InitializeExceptions (
+  IN EFI_CPU_ARCH_PROTOCOL    *Cpu
+  )
+{
+  EFI_STATUS           Status;
+  BOOLEAN              IrqEnabled;
+  EFI_PHYSICAL_ADDRESS Address;
+
+  ZeroMem (gInterruptHandler, sizeof (*gInterruptHandler));
+
+  //
+  // Disable interrupts
+  //
+  Cpu->GetInterruptState (Cpu, &IrqEnabled);
+  Cpu->DisableInterrupt (Cpu);
+
+  //
+  // EFI does not use the FIQ, but a debugger might so we must disable
+  // as we take over the exception vectors.
+  //
+  Status = gBS->AllocatePages (
+                 AllocateAnyPages,
+                 EfiRuntimeServicesData,
+                 1,
+                 &Address
+                 );
+  if (EFI_ERROR (Status)) {
+         return Status;
+  }
+
+  DEBUG ((DEBUG_INFO, "Set Exception Base Address\n"));
+  CopyMem ((char *)Address, LoongArchException, (LoongArchExceptionEnd - LoongArchException));
+  InvalidateInstructionCacheRange ((char *)Address, (LoongArchExceptionEnd - LoongArchException));
+
+  SetEbase (Address);
+  DEBUG ((DEBUG_INFO, "LoongArchException address: 0x%p\n", Address));
+  DEBUG ((DEBUG_INFO, "LoongArchExceptionEnd address: 0x%p\n", Address + (LoongArchExceptionEnd - LoongArchException)));
+
+  DEBUG ((DEBUG_INFO, "InitializeExceptions, IrqEnabled = %x\n", IrqEnabled));
+  if (IrqEnabled) {
+    //
+    // Restore interrupt state
+    //
+    Status = Cpu->EnableInterrupt (Cpu);
+  }
+  return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S
new file mode 100644
index 0000000000..79a20c66a2
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S
@@ -0,0 +1,97 @@
+#------------------------------------------------------------------------------
+#
+# Fpu for LoongArch
+#
+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#  @par Glossary:
+#    - CsrEuen   - Cpu Status Register Extern Unit Enable
+#    - FPEN      - FPU Enable
+#    - fpu or fp or FP   - Float Point Unit
+#-----------------------------------------------------------------------------
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+#include "Library/Cpu.h"
+#include "CpuDxe.h"
+
+ASM_GLOBAL ASM_PFX(InitFpu)
+ASM_GLOBAL ASM_PFX(LoongArchEnableFpu)
+ASM_GLOBAL ASM_PFX(LoongArchDisableFpu)
+
+#
+#  Load the FPU with signalling NANS.  This bit pattern we're using has
+#  the property that no matter whether considered as single or as double
+#  precision represents signaling NANS.
+#
+#  The value to initialize FCSR0 to comes in $A0.
+#
+
+ASM_PFX(InitFpu):
+  li.d    T1, CSR_EUEN_FPEN
+  csrxchg T1, T1, LOONGARCH_CSR_EUEN
+
+  movgr2fcsr      FCSR0, A0
+  li.d    T1, -1                          # SNaN
+  movgr2fr.d      $f0, T1
+  movgr2fr.d      $f1, T1
+  movgr2fr.d      $f2, T1
+  movgr2fr.d      $f3, T1
+  movgr2fr.d      $f4, T1
+  movgr2fr.d      $f5, T1
+  movgr2fr.d      $f6, T1
+  movgr2fr.d      $f7, T1
+  movgr2fr.d      $f8, T1
+  movgr2fr.d      $f9, T1
+  movgr2fr.d      $f10, T1
+  movgr2fr.d      $f11, T1
+  movgr2fr.d      $f12, T1
+  movgr2fr.d      $f13, T1
+  movgr2fr.d      $f14, T1
+  movgr2fr.d      $f15, T1
+  movgr2fr.d      $f16, T1
+  movgr2fr.d      $f17, T1
+  movgr2fr.d      $f18, T1
+  movgr2fr.d      $f19, T1
+  movgr2fr.d      $f20, T1
+  movgr2fr.d      $f21, T1
+  movgr2fr.d      $f22, T1
+  movgr2fr.d      $f23, T1
+  movgr2fr.d      $f24, T1
+  movgr2fr.d      $f25, T1
+  movgr2fr.d      $f26, T1
+  movgr2fr.d      $f27, T1
+  movgr2fr.d      $f28, T1
+  movgr2fr.d      $f29, T1
+  movgr2fr.d      $f30, T1
+  movgr2fr.d      $f31, T1
+
+  jirl ZERO, RA, 0
+
+#
+#  Enables  floating-point unit
+#  @param  VOID
+#  @retval  VOID
+#
+
+ASM_PFX(LoongArchEnableFpu):
+    li.d    T0, 1
+    li.d    T1, CSR_EUEN_FPEN_SHIFT
+    sll.d   T0, T0, T1
+    csrxchg T0, T0, LOONGARCH_CSR_EUEN
+    jirl    ZERO, RA,0
+
+#
+#  Disable  floating-point unit
+#  @param  VOID
+#  @retval  VOID
+#
+
+ASM_PFX(LoongArchDisableFpu):
+    li.d    T0, 1
+    li.d    T1, CSR_EUEN_FPEN_SHIFT
+    sll.d   T0, T0, T1
+    csrxchg ZERO, T0, LOONGARCH_CSR_EUEN
+    jirl    ZERO, RA,0
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S
new file mode 100644
index 0000000000..e463cf44f2
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S
@@ -0,0 +1,321 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch for LoongArch
+#
+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#  @par Glossary:
+#    - CsrEuen      - Cpu Status Register Extern Unit Enable
+#    - fpu    - Float Point Unit
+#    - LOONGARCH   - Loongson Arch
+#    - Ebase - Exception Base Address
+#-----------------------------------------------------------------------------
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include "Library/Cpu.h"
+#include "CpuDxe.h"
+
+#define RSIZE   8       /* 64 bit mode register size */
+#define RLOGSIZE 3
+
+ASM_GLOBAL ASM_PFX(Exception_handler)
+ASM_GLOBAL ASM_PFX(LoongArchException)
+ASM_GLOBAL ASM_PFX(SetEbase)
+ASM_GLOBAL ASM_PFX(LoongArchReadqCsrEuen)
+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrEuen)
+
+#
+#   Main exception handler. Not really a leaf routine but not a normal
+#   function either. Save away the entire cpu state end enter exception mode.
+#
+
+ASM_PFX(Exception_handler):
+    csrrd   SP, LOONGARCH_CSR_KS1
+
+    addi.d  T0, $r0, -0x10
+    and     SP, SP, T0
+    addi.d  SP, SP,  -((CSR_NUM + BASE_NUM + FP_BASE_NUM)  * RSIZE)
+
+    st.d   RA, SP, RA_NUM * RSIZE
+    st.d   GP, SP, GP_NUM * RSIZE
+    st.d   A0, SP, A0_NUM * RSIZE
+    st.d   A1, SP, A1_NUM * RSIZE
+    st.d   A2, SP, A2_NUM * RSIZE
+    st.d   A3, SP, A3_NUM * RSIZE
+    st.d   A4, SP, A4_NUM * RSIZE
+    st.d   A5, SP, A5_NUM * RSIZE
+    st.d   A6, SP, A6_NUM * RSIZE
+    st.d   A7, SP, A7_NUM * RSIZE
+    st.d   T1, SP, T1_NUM * RSIZE
+    st.d   T2, SP, T2_NUM * RSIZE
+    st.d   T3, SP, T3_NUM * RSIZE
+    st.d   T4, SP, T4_NUM * RSIZE
+    st.d   T5, SP, T5_NUM * RSIZE
+    st.d   T6, SP, T6_NUM * RSIZE
+    st.d   T7, SP, T7_NUM * RSIZE
+    st.d   T8, SP, T8_NUM * RSIZE
+    st.d   TP, SP, TP_NUM * RSIZE
+    st.d   FP, SP, FP_NUM * RSIZE
+    st.d   S0, SP, S0_NUM * RSIZE
+    st.d   S1, SP, S1_NUM * RSIZE
+    st.d   S2, SP, S2_NUM * RSIZE
+    st.d   S3, SP, S3_NUM * RSIZE
+    st.d   S4, SP, S4_NUM * RSIZE
+    st.d   S5, SP, S5_NUM * RSIZE
+    st.d   S6, SP, S6_NUM * RSIZE
+    st.d   S7, SP, S7_NUM * RSIZE
+    st.d   S8, SP, S8_NUM * RSIZE
+
+    #
+    #  save T0/SP from scratch registers on stack
+    #
+    csrrd  T0, LOONGARCH_CSR_KS0
+    st.d   T0, SP, T0_NUM * RSIZE
+    csrrd  T0, LOONGARCH_CSR_KS1
+    st.d   T0, SP, SP_NUM * RSIZE
+
+    csrrd   T0, LOONGARCH_CSR_CRMD
+    st.d    T0, SP, (LOONGARCH_CSR_CRMD + BASE_NUM)  * RSIZE
+    csrrd   T0, LOONGARCH_CSR_PRMD
+    st.d    T0, SP, (LOONGARCH_CSR_PRMD + BASE_NUM)  * RSIZE
+    csrrd   T0, LOONGARCH_CSR_ECFG
+    st.d    T0, SP, (LOONGARCH_CSR_ECFG + BASE_NUM) * RSIZE
+    csrrd   T0, LOONGARCH_CSR_ESTAT
+    st.d    T0, SP, (LOONGARCH_CSR_ESTAT + BASE_NUM)  * RSIZE
+    csrrd   T0, LOONGARCH_CSR_EPC
+    st.d    T0, SP, (LOONGARCH_CSR_EPC+ BASE_NUM)    * RSIZE
+    csrrd   T0, LOONGARCH_CSR_BADV
+    st.d    T0, SP, (LOONGARCH_CSR_BADV + BASE_NUM)  * RSIZE
+    csrrd   T0, LOONGARCH_CSR_BADI
+    st.d    T0, SP, (LOONGARCH_CSR_BADI + BASE_NUM)  * RSIZE
+    csrrd   T0, LOONGARCH_CSR_EUEN
+    st.d    T0, SP, (LOONGARCH_CSR_EUEN + BASE_NUM)  * RSIZE
+
+    #
+    #  Save FPU context
+    #
+    ori     T1, ZERO, CSR_EUEN_FPEN
+    and     T2, T0, T1
+    beqz    T2, 1f
+
+    fst.d   $f0,  SP, (FP0_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f1,  SP, (FP1_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f2,  SP, (FP2_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f3,  SP, (FP3_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f4,  SP, (FP4_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f5,  SP, (FP5_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f6,  SP, (FP6_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f7,  SP, (FP7_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f8,  SP, (FP8_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f9,  SP, (FP9_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f10, SP, (FP10_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f11, SP, (FP11_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f12, SP, (FP12_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f13, SP, (FP13_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f14, SP, (FP14_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f15, SP, (FP15_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f16, SP, (FP16_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f17, SP, (FP17_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f18, SP, (FP18_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f19, SP, (FP19_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f20, SP, (FP20_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f21, SP, (FP21_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f22, SP, (FP22_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f23, SP, (FP23_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f24, SP, (FP24_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f25, SP, (FP25_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f26, SP, (FP26_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f27, SP, (FP27_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f28, SP, (FP28_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f29, SP, (FP29_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f30, SP, (FP30_NUM + FP_BASE_INDEX) * RSIZE
+    fst.d   $f31, SP, (FP31_NUM + FP_BASE_INDEX) * RSIZE
+
+    movfcsr2gr      T3, FCSR0
+    st.d            T3, SP, (FCSR_NUM + FP_BASE_INDEX) * RSIZE
+    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, (FCC_NUM + FP_BASE_INDEX)  * RSIZE
+1:
+    or      A0, SP, ZERO
+    bl      CommonExceptionEntry
+    /*disable interrupt*/
+    li.d     T0, (1 << 2)
+    csrxchg ZERO, T0, LOONGARCH_CSR_CRMD
+
+    ld.d    T0, SP, (LOONGARCH_CSR_PRMD + BASE_NUM) * RSIZE
+    csrwr   T0, LOONGARCH_CSR_PRMD
+    ld.d    T0, SP, (LOONGARCH_CSR_ECFG + BASE_NUM) * RSIZE
+    csrwr   T0, LOONGARCH_CSR_ECFG
+    ld.d    T0, SP, (LOONGARCH_CSR_EPC + BASE_NUM) * RSIZE
+    csrwr   T0, LOONGARCH_CSR_EPC
+
+    ld.d    T0, SP, (LOONGARCH_CSR_EUEN + BASE_NUM) * RSIZE
+    ori     T1, ZERO, CSR_EUEN_FPEN
+    and     T2, T0, T1
+    beqz    T2, 2f
+
+    #
+    #  check previous FP state
+    #  restore FP contect if FP enabled
+    #
+    fld.d   $f0,  SP, (FP0_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f1,  SP, (FP1_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f2,  SP, (FP2_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f3,  SP, (FP3_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f4,  SP, (FP4_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f5,  SP, (FP5_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f6,  SP, (FP6_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f7,  SP, (FP7_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f8,  SP, (FP8_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f9,  SP, (FP9_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f10, SP, (FP10_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f11, SP, (FP11_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f12, SP, (FP12_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f13, SP, (FP13_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f14, SP, (FP14_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f15, SP, (FP15_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f16, SP, (FP16_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f17, SP, (FP17_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f18, SP, (FP18_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f19, SP, (FP19_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f20, SP, (FP20_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f21, SP, (FP21_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f22, SP, (FP22_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f23, SP, (FP23_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f24, SP, (FP24_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f25, SP, (FP25_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f26, SP, (FP26_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f27, SP, (FP27_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f28, SP, (FP28_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f29, SP, (FP29_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f30, SP, (FP30_NUM + FP_BASE_INDEX) * RSIZE
+    fld.d   $f31, SP, (FP31_NUM + FP_BASE_INDEX) * RSIZE
+
+    ld.d    T0, SP, (FCSR_NUM + FP_BASE_INDEX) * RSIZE
+    movgr2fcsr      FCSR0, T0
+    ld.d    T0, SP, (FCC_NUM + FP_BASE_INDEX) * 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
+2:
+    ld.d    RA, SP, RA_NUM * RSIZE
+    ld.d    GP, SP, GP_NUM * RSIZE
+    ld.d    A0, SP, A0_NUM * RSIZE
+    ld.d    A1, SP, A1_NUM * RSIZE
+    ld.d    A2, SP, A2_NUM * RSIZE
+    ld.d    A3, SP, A3_NUM * RSIZE
+    ld.d    A4, SP, A4_NUM * RSIZE
+    ld.d    A5, SP, A5_NUM * RSIZE
+    ld.d    A6, SP, A6_NUM * RSIZE
+    ld.d    A7, SP, A7_NUM * RSIZE
+    ld.d    T0, SP, T0_NUM * RSIZE
+    ld.d    T1, SP, T1_NUM * RSIZE
+    ld.d    T2, SP, T2_NUM * RSIZE
+    ld.d    T3, SP, T3_NUM * RSIZE
+    ld.d    T4, SP, T4_NUM * RSIZE
+    ld.d    T5, SP, T5_NUM * RSIZE
+    ld.d    T6, SP, T6_NUM * RSIZE
+    ld.d    T7, SP, T7_NUM * RSIZE
+    ld.d    T8, SP, T8_NUM * RSIZE
+    ld.d    TP, SP, TP_NUM * RSIZE
+    ld.d    FP, SP, FP_NUM * RSIZE
+    ld.d    S0, SP, S0_NUM * RSIZE
+    ld.d    S1, SP, S1_NUM * RSIZE
+    ld.d    S2, SP, S2_NUM * RSIZE
+    ld.d    S3, SP, S3_NUM * RSIZE
+    ld.d    S4, SP, S4_NUM * RSIZE
+    ld.d    S5, SP, S5_NUM * RSIZE
+    ld.d    S6, SP, S6_NUM * RSIZE
+    ld.d    S7, SP, S7_NUM * RSIZE
+    ld.d    S8, SP, S8_NUM * RSIZE
+
+    ld.d    SP, SP, SP_NUM * RSIZE
+    ertn
+
+#
+#   Exception trampoline copied down to RAM after initialization.
+#
+
+ASM_PFX(LoongArchException):
+    csrwr   T0, LOONGARCH_CSR_KS0
+    csrwr   SP, LOONGARCH_CSR_KS1
+    pcaddi   T0, 0
+    ld.d     T0, T0, 16
+    jirl    ZERO, T0, 0
+    nop
+1:
+    .quad  Exception_handler
+.globl  LoongArchExceptionEnd
+LoongArchExceptionEnd:
+
+#
+#   Set Exception Base Address.
+#
+
+ASM_PFX(SetEbase):
+    #
+    #  clear Vint cofigure
+    #  all exceptions share the same interrupt entry
+    #
+    csrrd   T0, LOONGARCH_CSR_ECFG
+    li.d    T1, ~0x70000
+    and     T0, T0, T1
+    csrwr   T0, LOONGARCH_CSR_ECFG
+
+    #  set ebase
+    csrwr   A0, LOONGARCH_CSR_EBASE
+    jirl    ZERO, RA, 0
+
+#
+#  Read Csr EUEN register.
+#  @param   A0 Pointer to the variable used to store the EUEN register value
+#  @retval  none
+#
+
+ASM_PFX(LoongArchReadqCsrEuen):
+    csrrd T0, LOONGARCH_CSR_EUEN
+    stptr.d T0, A0, 0
+    jirl    ZERO, RA,0
+
+#
+#  Write Csr EUEN register.
+#  @param  A0  The value used to write to the EUEN register
+#  @retval  none
+#
+
+ASM_PFX(LoongArchWriteqCsrEuen):
+    csrwr A0, LOONGARCH_CSR_EUEN
+    jirl    ZERO, RA,0
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 09/15] Platform/Loongson: Add PciCpuIoDxe driver.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (7 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 08/15] Platform/Loongson: Add CPU DXE driver xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 10/15] Platform/Loongson: Add timer Dxe driver xianglai
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Add PCI CpuIo protocol.there is no fix translation
offset between I/O port accesses and MMIO accesses.
Add PciCpuIo2Dxe driver to implement EFI_CPU_IO2_PROTOCOL
to add the translation for IO access.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c       | 538 ++++++++++++++++++
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h       | 207 +++++++
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf     |  44 ++
 3 files changed, 789 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
new file mode 100644
index 0000000000..25417ff101
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
@@ -0,0 +1,538 @@
+/** @file
+  Produces the CPU I/O 2 Protocol.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/CpuIo2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "PciCpuIo2Dxe.h"
+
+//
+// Handle for the CPU I/O 2 Protocol
+//
+STATIC EFI_HANDLE  mHandle = NULL;
+
+//
+// Lookup table for increment values based on transfer widths
+//
+STATIC CONST UINT8 mInStride[] = {
+  1, // EfiCpuIoWidthUint8
+  2, // EfiCpuIoWidthUint16
+  4, // EfiCpuIoWidthUint32
+  8, // EfiCpuIoWidthUint64
+  0, // EfiCpuIoWidthFifoUint8
+  0, // EfiCpuIoWidthFifoUint16
+  0, // EfiCpuIoWidthFifoUint32
+  0, // EfiCpuIoWidthFifoUint64
+  1, // EfiCpuIoWidthFillUint8
+  2, // EfiCpuIoWidthFillUint16
+  4, // EfiCpuIoWidthFillUint32
+  8  // EfiCpuIoWidthFillUint64
+};
+
+//
+// Lookup table for increment values based on transfer widths
+//
+STATIC CONST UINT8 mOutStride[] = {
+  1, // EfiCpuIoWidthUint8
+  2, // EfiCpuIoWidthUint16
+  4, // EfiCpuIoWidthUint32
+  8, // EfiCpuIoWidthUint64
+  1, // EfiCpuIoWidthFifoUint8
+  2, // EfiCpuIoWidthFifoUint16
+  4, // EfiCpuIoWidthFifoUint32
+  8, // EfiCpuIoWidthFifoUint64
+  0, // EfiCpuIoWidthFillUint8
+  0, // EfiCpuIoWidthFillUint16
+  0, // EfiCpuIoWidthFillUint32
+  0  // EfiCpuIoWidthFillUint64
+};
+
+/**
+  Check parameters to a CPU I/O 2 Protocol service request.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  @param[in] MmioOperation  TRUE for an MMIO operation, FALSE for I/O Port operation.
+  @param[in] Width          Signifies the width of the I/O or Memory operation.
+  @param[in] Address        The base address of the I/O operation.
+  @param[in] Count          The number of I/O operations to perform. The number of
+                            bytes moved is Width size * Count, starting at Address.
+  @param[in] Buffer         For read operations, the destination buffer to store the results.
+                            For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The parameters for this request pass the checks.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+CpuIoCheckParameter (
+  IN BOOLEAN                    MmioOperation,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  )
+{
+  UINT64  MaxCount;
+  UINT64  Limit;
+
+  //
+  // Check to see if Buffer is NULL
+  //
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check to see if Width is in the valid range
+  //
+  if ((UINT32)Width >= EfiCpuIoWidthMaximum) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // For FIFO type, the target address won't increase during the access,
+  // so treat Count as 1
+  //
+  if ((Width >= EfiCpuIoWidthFifoUint8)
+    && (Width <= EfiCpuIoWidthFifoUint64))
+  {
+    Count = 1;
+  }
+
+  //
+  // Check to see if Width is in the valid range for I/O Port operations
+  //
+  Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+  if ((!MmioOperation)
+    && (Width == EfiCpuIoWidthUint64))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check to see if Address is aligned
+  //
+  if ((Address & (UINT64) (mInStride[Width] - 1)) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check to see if any address associated with this transfer exceeds the maximum
+  // allowed address.  The maximum address implied by the parameters passed in is
+  // Address + Size * Count.  If the following condition is met, then the transfer
+  // is not supported.
+  //
+  //    Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
+  //
+  // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
+  // can also be the maximum integer value supported by the CPU, this range
+  // check must be adjusted to avoid all overflow conditions.
+  //
+  // The following form of the range check is equivalent but assumes that
+  // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
+  //
+  Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
+  if (Count == 0) {
+    if (Address > Limit) {
+      return EFI_UNSUPPORTED;
+    }
+  } else {
+    MaxCount = RShiftU64 (Limit, Width);
+    if (MaxCount < (Count - 1)) {
+      return EFI_UNSUPPORTED;
+    }
+    if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  //
+  // Check to see if Buffer is aligned
+  //
+  if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width])  - 1))) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Reads memory-mapped registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[out] Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceRead (
+  IN  EFI_CPU_IO2_PROTOCOL       *This,
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN  UINT64                     Address,
+  IN  UINTN                      Count,
+  OUT VOID                       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      InStride;
+  UINT8                      OutStride;
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
+  UINT8                      *Uint8Buffer;
+  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Select loop based on the width of the transfer
+  //
+  InStride = mInStride[Width];
+  OutStride = mOutStride[Width];
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+    if (OperationWidth == EfiCpuIoWidthUint8) {
+      *Uint8Buffer = MmioRead8 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {
+      *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {
+      *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint64) {
+      *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Writes memory-mapped registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceWrite (
+  IN EFI_CPU_IO2_PROTOCOL       *This,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      InStride;
+  UINT8                      OutStride;
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
+  UINT8                      *Uint8Buffer;
+
+  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Select loop based on the width of the transfer
+  //
+  InStride = mInStride[Width];
+  OutStride = mOutStride[Width];
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+    if (OperationWidth == EfiCpuIoWidthUint8) {
+      MmioWrite8 ((UINTN)Address, *Uint8Buffer);
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {
+      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {
+      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+    } else if (OperationWidth == EfiCpuIoWidthUint64) {
+      MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Reads I/O registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[out] Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceRead (
+  IN  EFI_CPU_IO2_PROTOCOL       *This,
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN  UINT64                     Address,
+  IN  UINTN                      Count,
+  OUT VOID                       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      InStride;
+  UINT8                      OutStride;
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
+  UINT8                      *Uint8Buffer;
+
+  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Address += PcdGet64 (PcdPciIoTranslation);
+
+  //
+  // Select loop based on the width of the transfer
+  //
+  InStride = mInStride[Width];
+  OutStride = mOutStride[Width];
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+    if (OperationWidth == EfiCpuIoWidthUint8) {
+      *Uint8Buffer = MmioRead8 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {
+      *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {
+      *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Write I/O registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceWrite (
+  IN EFI_CPU_IO2_PROTOCOL       *This,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      InStride;
+  UINT8                      OutStride;
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
+  UINT8                      *Uint8Buffer;
+
+  //
+  // Make sure the parameters are valid
+  //
+  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Address += PcdGet64 (PcdPciIoTranslation);
+
+  //
+  // Select loop based on the width of the transfer
+  //
+  InStride = mInStride[Width];
+  OutStride = mOutStride[Width];
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+  for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+    if (OperationWidth == EfiCpuIoWidthUint8) {
+      MmioWrite8 ((UINTN)Address, *Uint8Buffer);
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {
+      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {
+      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+//
+// CPU I/O 2 Protocol instance
+//
+STATIC EFI_CPU_IO2_PROTOCOL mCpuIo2 = {
+  {
+    CpuMemoryServiceRead,
+    CpuMemoryServiceWrite
+  },
+  {
+    CpuIoServiceRead,
+    CpuIoServiceWrite
+  }
+};
+
+/**
+  The user Entry Point for module CpuIo2Dxe. The user code starts with this function.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The entry point is executed successfully.
+  @retval other             Some error occurs when executing this entry point.
+**/
+EFI_STATUS
+EFIAPI
+PciCpuIo2Initialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mHandle,
+                  &gEfiCpuIo2ProtocolGuid, &mCpuIo2,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
new file mode 100644
index 0000000000..2489429df7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
@@ -0,0 +1,207 @@
+/** @file
+  Internal include file for the CPU I/O 2 Protocol.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PCI_CPU_IO2_DXE_H_
+#define PCI_CPU_IO2_DXE_H_
+
+#define MAX_IO_PORT_ADDRESS   0xFFFF
+
+/**
+  Reads memory-mapped registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[out] Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceRead (
+  IN  EFI_CPU_IO2_PROTOCOL       *This,
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN  UINT64                     Address,
+  IN  UINTN                      Count,
+  OUT VOID                       *Buffer
+  );
+
+/**
+  Writes memory-mapped registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceWrite (
+  IN EFI_CPU_IO2_PROTOCOL       *This,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  );
+
+/**
+  Reads I/O registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[out] Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceRead (
+  IN  EFI_CPU_IO2_PROTOCOL       *This,
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN  UINT64                     Address,
+  IN  UINTN                      Count,
+  OUT VOID                       *Buffer
+  );
+
+/**
+  Write I/O registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceWrite (
+  IN EFI_CPU_IO2_PROTOCOL       *This,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  );
+
+#endif // PCI_CPU_IO2_DXE_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
new file mode 100644
index 0000000000..a8a14cddd2
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
@@ -0,0 +1,44 @@
+## @file
+#  Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PciCpuIo2Dxe
+  FILE_GUID                      = 168D1A6E-F4A5-448A-9E95-795661BB3067
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PciCpuIo2Initialize
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  PciCpuIo2Dxe.c
+
+[Packages]
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  BaseLib
+  DebugLib
+  IoLib
+  PcdLib
+  UefiBootServicesTableLib
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
+
+[Protocols]
+  gEfiCpuIo2ProtocolGuid                         ## PRODUCES
+
+[Depex]
+  TRUE
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 10/15] Platform/Loongson: Add timer Dxe driver.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (8 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 09/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 11/15] Platform/Loongson: Add RealTime Clock lib xianglai
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

This driver produces Timer Architectural Protocol,
Registers a timer interrupt and initializes the timer.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../Drivers/StableTimerDxe/Timer.c            | 388 ++++++++++++++++++
 .../Drivers/StableTimerDxe/Timer.h            | 172 ++++++++
 .../Drivers/StableTimerDxe/TimerConfig.S      |  38 ++
 .../Drivers/StableTimerDxe/TimerDxe.inf       |  44 ++
 4 files changed, 642 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerConfig.S
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c
new file mode 100644
index 0000000000..e09da71272
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c
@@ -0,0 +1,388 @@
+/** @file
+  Timer Architectural Protocol as defined in the DXE CIS
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Protocol/Cpu.h>
+#include "Library/Cpu.h"
+#include <Library/DebugLib.h>
+#include <Library/StableTimer.h>
+#include "Timer.h"
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+//
+// The handle onto which the Timer Architectural Protocol will be installed
+//
+EFI_HANDLE            mTimerHandle = NULL;
+EFI_EVENT             EfiExitBootServicesEvent = (EFI_EVENT)NULL;
+
+//
+// The Timer Architectural Protocol that this driver produces
+//
+EFI_TIMER_ARCH_PROTOCOL   mTimer = {
+  TimerDriverRegisterHandler,
+  TimerDriverSetTimerPeriod,
+  TimerDriverGetTimerPeriod,
+  TimerDriverGenerateSoftInterrupt
+};
+
+//
+// Pointer to the CPU Architectural Protocol instance
+//
+EFI_CPU_ARCH_PROTOCOL     *mCpu;
+
+//
+// The notification function to call on every timer interrupt.
+// A bug in the compiler prevents us from initializing this here.
+//
+EFI_TIMER_NOTIFY mTimerNotifyFunction;
+
+//
+// The current period of the timer interrupt
+//
+volatile UINT64           mTimerPeriod = 0;
+volatile UINT64           mTimerTicks = 0;
+
+//
+// Const frequence in Hz
+//
+extern UINT32 StableTimerFreq;
+
+/**
+  Sets the counter value for timer.
+
+  @param Count    The 16-bit counter value to program into stable timer.
+
+  @retval VOID
+**/
+VOID
+SetPitCount (
+  IN UINT64  Count
+  )
+{
+  if (Count <= 4) {
+    return;
+  }
+
+  Count &= LOONGARCH_CSR_TMCFG_TIMEVAL;
+  Count |= LOONGARCH_CSR_TMCFG_EN | LOONGARCH_CSR_TMCFG_PERIOD;
+  LoongarchWriteqTmcfg (Count);
+}
+
+/**
+  Timer Interrupt Handler.
+
+  @param InterruptType    The type of interrupt that occurred
+  @param SystemContext    A pointer to the system context when the interrupt occurred
+
+  @retval VOID
+**/
+VOID
+EFIAPI
+TimerInterruptHandler (
+  IN EFI_EXCEPTION_TYPE   InterruptType,
+  IN EFI_SYSTEM_CONTEXT   SystemContext
+  )
+{
+  EFI_TPL OriginalTPL;
+
+  OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+  //
+  // Clear interrupt.
+  //
+  LoongarchWriteqTintclr (0x1);
+
+  if (mTimerNotifyFunction != NULL) {
+    //
+    // @bug : This does not handle missed timer interrupts
+    //
+    mTimerNotifyFunction (mTimerPeriod);
+  }
+
+  gBS->RestoreTPL (OriginalTPL);
+}
+
+/**
+  This function registers the handler NotifyFunction so it is called every time
+  the timer interrupt fires.  It also passes the amount of time since the last
+  handler call to the NotifyFunction.  If NotifyFunction is NULL, then the
+  handler is unregistered.  If the handler is registered, then EFI_SUCCESS is
+  returned.  If the CPU does not support registering a timer interrupt handler,
+  then EFI_UNSUPPORTED is returned.  If an attempt is made to register a handler
+  when a handler is already registered, then EFI_ALREADY_STARTED is returned.
+  If an attempt is made to unregister a handler when a handler is not registered,
+  then EFI_INVALID_PARAMETER is returned.  If an error occurs attempting to
+  register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR
+  is returned.
+
+  @param This             The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param NotifyFunction   The function to call when a timer interrupt fires.  This
+                          function executes at TPL_HIGH_LEVEL.  The DXE Core will
+                          register a handler for the timer interrupt, so it can know
+                          how much time has passed.  This information is used to
+                          signal timer based events.  NULL will unregister the handler.
+
+  @retval        EFI_SUCCESS            The timer handler was registered.
+  @retval        EFI_UNSUPPORTED        The platform does not support timer interrupts.
+  @retval        EFI_ALREADY_STARTED    NotifyFunction is not NULL, and a handler is already
+                                        registered.
+  @retval        EFI_INVALID_PARAMETER  NotifyFunction is NULL, and a handler was not
+                                        previously registered.
+  @retval        EFI_DEVICE_ERROR       The timer handler could not be registered.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverRegisterHandler (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN EFI_TIMER_NOTIFY         NotifyFunction
+  )
+{
+  //
+  // Check for invalid parameters
+  //
+  if ((NotifyFunction == NULL)
+    && (mTimerNotifyFunction == NULL))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((NotifyFunction != NULL)
+    && mTimerNotifyFunction != NULL)
+  {
+    return EFI_ALREADY_STARTED;
+  }
+
+  mTimerNotifyFunction = NotifyFunction;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function adjusts the period of timer interrupts to the value specified
+  by TimerPeriod.  If the timer period is updated, then the selected timer
+  period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned.  If
+  the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
+  If an error occurs while attempting to update the timer period, then the
+  timer hardware will be put back in its state prior to this call, and
+  EFI_DEVICE_ERROR is returned.  If TimerPeriod is 0, then the timer interrupt
+  is disabled.  This is not the same as disabling the CPU's interrupts.
+  Instead, it must either turn off the timer hardware, or it must adjust the
+  interrupt controller so that a CPU interrupt is not generated when the timer
+  interrupt fires.
+
+  @param This            The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param TimerPeriod     The rate to program the timer interrupt in 100 nS units.  If
+                         the timer hardware is not programmable, then EFI_UNSUPPORTED is
+                         returned.  If the timer is programmable, then the timer period
+                         will be rounded up to the nearest timer period that is supported
+                         by the timer hardware.  If TimerPeriod is set to 0, then the
+                         timer interrupts will be disabled.
+
+  @retval        EFI_SUCCESS       The timer period was changed.
+  @retval        EFI_UNSUPPORTED   The platform cannot change the period of the timer interrupt.
+  @retval        EFI_DEVICE_ERROR  The timer period could not be changed due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverSetTimerPeriod (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN UINT64                   TimerPeriod
+  )
+{
+  UINT64  TimerCount;
+
+  if (TimerPeriod == 0) {
+    //
+    // Disable timer interrupt for a TimerPeriod of 0
+    //
+    mCpu->DisableInterrupt (mCpu);
+  } else {
+
+    TimerCount = TimerPeriod * StableTimerFreq / 10000000ULL;
+
+    if (TimerCount >= BIT48) {
+      TimerCount = 0;
+    }
+
+    //
+    // Program the stable timer with the new count value
+    //
+    mTimerTicks = TimerCount;
+    SetPitCount (TimerCount);
+
+    //
+    // Enable timer interrupt
+    //
+    mCpu->EnableInterrupt (mCpu);
+  }
+
+  //
+  // Save the new timer period
+  //
+  mTimerPeriod = TimerPeriod;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function retrieves the period of timer interrupts in 100 ns units,
+  returns that value in TimerPeriod, and returns EFI_SUCCESS.  If TimerPeriod
+  is NULL, then EFI_INVALID_PARAMETER is returned.  If a TimerPeriod of 0 is
+  returned, then the timer is currently disabled.
+
+  @param This            The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param TimerPeriod     A pointer to the timer period to retrieve in 100 ns units.  If
+                         0 is returned, then the timer is currently disabled.
+
+  @retval EFI_SUCCESS            The timer period was returned in TimerPeriod.
+  @retval EFI_INVALID_PARAMETER  TimerPeriod is NULL.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGetTimerPeriod (
+  IN EFI_TIMER_ARCH_PROTOCOL   *This,
+  OUT UINT64                   *TimerPeriod
+  )
+{
+  if (TimerPeriod == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *TimerPeriod = mTimerPeriod;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Disable the timer
+  DXE Core will disable the timer after all the event handlers have run.
+
+  @param[in]  Event   The Event that is being processed
+  @param[in]  Context Event Context
+**/
+VOID
+EFIAPI
+ExitBootServicesEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  /*
+   * Disable timer interrupt when exiting boot service
+   */
+  LoongarchWriteqTmcfg (0);
+}
+
+/**
+  This function generates a soft timer interrupt. If the platform does not support soft
+  timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned.
+  If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler ()
+  service, then a soft timer interrupt will be generated. If the timer interrupt is
+  enabled when this service is called, then the registered handler will be invoked. The
+  registered handler should not be able to distinguish a hardware-generated timer
+  interrupt from a software-generated timer interrupt.
+
+  @param This              The EFI_TIMER_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS       The soft timer interrupt was generated.
+  @retval EFI_UNSUPPORTED   The platform does not support the generation of soft timer interrupts.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGenerateSoftInterrupt (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Initialize the Timer Architectural Protocol driver
+
+  @param ImageHandle     ImageHandle of the loaded driver
+  @param SystemTable     Pointer to the System Table
+
+  @retval EFI_SUCCESS            Timer Architectural Protocol created
+  @retval EFI_OUT_OF_RESOURCES   Not enough resources available to initialize driver.
+  @retval EFI_DEVICE_ERROR       A device error occurred attempting to initialize the driver.
+**/
+EFI_STATUS
+EFIAPI
+StableTimerDriverInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      TimerVector;
+
+  //
+  // Initialize the pointer to our notify function.
+  //
+  mTimerNotifyFunction = NULL;
+
+  //
+  // Make sure the Timer Architectural Protocol is not already installed in the system
+  //
+  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiTimerArchProtocolGuid);
+
+  //
+  // Find the CPU architectural protocol.
+  //
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &mCpu);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Force the timer to be disabled
+  //
+  Status = TimerDriverSetTimerPeriod (&mTimer, 0);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Calculate const frequence
+  //
+  StableTimerFreq = CalcConstFreq ();
+  DEBUG ((DEBUG_INFO, "===========Stable timer freq %d Hz=============\n", StableTimerFreq));
+
+  //
+  // Install interrupt handler for Stable Timer #0 (ISA IRQ0)
+  //
+  TimerVector = EXCEPT_LOONGARCH_INT_TIMER;
+  Status = mCpu->RegisterInterruptHandler (mCpu, TimerVector, TimerInterruptHandler);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Enable TI local timer interrupt
+  //
+  CpuSetIP (1 << 11);
+
+  //
+  // Force the timer to be enabled at its default period
+  //
+  Status = TimerDriverSetTimerPeriod (&mTimer, DEFAULT_TIMER_TICK_DURATION);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Install the Timer Architectural Protocol onto a new handle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mTimerHandle,
+                  &gEfiTimerArchProtocolGuid, &mTimer,
+                  NULL
+                  );
+
+  ASSERT_EFI_ERROR (Status);
+
+  // Register for an ExitBootServicesEvent
+  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL,
+                  &EfiExitBootServicesEvent);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h
new file mode 100644
index 0000000000..84036cab00
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h
@@ -0,0 +1,172 @@
+/** @file
+  Private data structures
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TIMER_H_
+#define TIMER_H_
+
+#include <Protocol/Timer.h>
+
+#define DEFAULT_TIMER_TICK_DURATION 100000 //10ms = 100000 100 ns units
+#define SR_IP7                      (1 << 15)
+//
+// Function Prototypes
+//
+extern UINT32 EFIAPI CpuGetCompare(VOID);
+extern VOID  EFIAPI CpuSetCompare(IN UINT32 val);
+extern VOID  EFIAPI CpuSetIP(IN UINT32 val);
+extern VOID  EFIAPI ClearC0Cause(IN UINT32 val);
+extern VOID  EFIAPI ClearC0Status(IN UINT32 val);
+/**
+  Initialize the Timer Architectural Protocol driver
+
+  @param ImageHandle     ImageHandle of the loaded driver
+  @param SystemTable     Pointer to the System Table
+
+  @retval EFI_SUCCESS            Timer Architectural Protocol created
+  @retval EFI_OUT_OF_RESOURCES   Not enough resources available to initialize driver.
+  @retval EFI_DEVICE_ERROR       A device error occurred attempting to initialize the driver.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+/**
+  This function adjusts the period of timer interrupts to the value specified
+  by TimerPeriod.  If the timer period is updated, then the selected timer
+  period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned.  If
+  the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
+  If an error occurs while attempting to update the timer period, then the
+  timer hardware will be put back in its state prior to this call, and
+  EFI_DEVICE_ERROR is returned.  If TimerPeriod is 0, then the timer interrupt
+  is disabled.  This is not the same as disabling the CPU's interrupts.
+  Instead, it must either turn off the timer hardware, or it must adjust the
+  interrupt controller so that a CPU interrupt is not generated when the timer
+  interrupt fires.
+
+  @param This            The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param NotifyFunction  The rate to program the timer interrupt in 100 nS units.  If
+                         the timer hardware is not programmable, then EFI_UNSUPPORTED is
+                         returned.  If the timer is programmable, then the timer period
+                         will be rounded up to the nearest timer period that is supported
+                         by the timer hardware.  If TimerPeriod is set to 0, then the
+                         timer interrupts will be disabled.
+
+  @retval        EFI_SUCCESS       The timer period was changed.
+  @retval        EFI_UNSUPPORTED   The platform cannot change the period of the timer interrupt.
+  @retval        EFI_DEVICE_ERROR  The timer period could not be changed due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverRegisterHandler (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN EFI_TIMER_NOTIFY         NotifyFunction
+  );
+
+/**
+  This function adjusts the period of timer interrupts to the value specified
+  by TimerPeriod.  If the timer period is updated, then the selected timer
+  period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned.  If
+  the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
+  If an error occurs while attempting to update the timer period, then the
+  timer hardware will be put back in its state prior to this call, and
+  EFI_DEVICE_ERROR is returned.  If TimerPeriod is 0, then the timer interrupt
+  is disabled.  This is not the same as disabling the CPU's interrupts.
+  Instead, it must either turn off the timer hardware, or it must adjust the
+  interrupt controller so that a CPU interrupt is not generated when the timer
+  interrupt fires.
+
+  @param This            The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param TimerPeriod     The rate to program the timer interrupt in 100 nS units.  If
+                         the timer hardware is not programmable, then EFI_UNSUPPORTED is
+                         returned.  If the timer is programmable, then the timer period
+                         will be rounded up to the nearest timer period that is supported
+                         by the timer hardware.  If TimerPeriod is set to 0, then the
+                         timer interrupts will be disabled.
+
+  @retval        EFI_SUCCESS       The timer period was changed.
+  @retval        EFI_UNSUPPORTED   The platform cannot change the period of the timer interrupt.
+  @retval        EFI_DEVICE_ERROR  The timer period could not be changed due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverSetTimerPeriod (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN UINT64                   TimerPeriod
+  );
+
+/**
+  This function retrieves the period of timer interrupts in 100 ns units,
+  returns that value in TimerPeriod, and returns EFI_SUCCESS.  If TimerPeriod
+  is NULL, then EFI_INVALID_PARAMETER is returned.  If a TimerPeriod of 0 is
+  returned, then the timer is currently disabled.
+
+  @param This            The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param TimerPeriod     A pointer to the timer period to retrieve in 100 ns units.  If
+                         0 is returned, then the timer is currently disabled.
+
+  @retval EFI_SUCCESS            The timer period was returned in TimerPeriod.
+  @retval EFI_INVALID_PARAMETER  TimerPeriod is NULL.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGetTimerPeriod (
+  IN EFI_TIMER_ARCH_PROTOCOL   *This,
+  OUT UINT64                   *TimerPeriod
+  );
+
+/**
+  This function generates a soft timer interrupt. If the platform does not support soft
+  timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned.
+  If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler()
+  service, then a soft timer interrupt will be generated. If the timer interrupt is
+  enabled when this service is called, then the registered handler will be invoked. The
+  registered handler should not be able to distinguish a hardware-generated timer
+  interrupt from a software-generated timer interrupt.
+
+  @param This              The EFI_TIMER_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS       The soft timer interrupt was generated.
+  @retval EFI_UNSUPPORTED   The platform does not support the generation of soft timer interrupts.
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGenerateSoftInterrupt (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This
+  );
+
+/**
+  Write Csr TMCFG register.
+
+  @param A0 The value used to write to the TMCFG register
+
+  @retval none
+**/
+extern
+VOID
+LoongarchWriteqTmcfg (
+  IN UINT64  Val
+  );
+
+/**
+  Write Csr TINTCLR register.
+
+  @param A0 The value used to write to the TINTCLR register
+
+  @retval none
+**/
+extern
+VOID
+LoongarchWriteqTintclr (
+  IN UINT64  Val
+  );
+
+#endif // TIMER_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerConfig.S b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerConfig.S
new file mode 100644
index 0000000000..2f364c193d
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerConfig.S
@@ -0,0 +1,38 @@
+#------------------------------------------------------------------------------
+#
+# Timer Cfg for LoongArch
+#
+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include "Library/Cpu.h"
+
+ASM_GLOBAL ASM_PFX(LoongarchWriteqTmcfg)
+ASM_GLOBAL ASM_PFX(LoongarchWriteqTintclr)
+
+#
+# Write Csr TMCFG register.
+# @param A0 The value used to write to the TMCFG register
+# @retval  none
+#
+
+ASM_PFX(LoongarchWriteqTmcfg):
+    csrwr   A0, LOONGARCH_CSR_TMCFG
+    jirl    ZERO, RA,0
+
+#
+# Write Csr TINTCLR register.
+# @param A0 The value used to write to the TINTCLR register
+# @retval  none
+#
+
+ASM_PFX(LoongarchWriteqTintclr):
+    csrwr   A0, LOONGARCH_CSR_TINTCLR
+    jirl    ZERO, RA,0
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
new file mode 100644
index 0000000000..d4a07c8759
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
@@ -0,0 +1,44 @@
+## @file
+#  Stable timer driver that provides Timer Arch protocol.
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = Timer
+  MODULE_UNI_FILE                = Timer.uni
+  FILE_GUID                      = AEBE2648-47A9-40FA-83FD-06AA88443BB2
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = StableTimerDriverInitialize
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  Timer.h
+  Timer.c
+  TimerConfig.S
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+  UefiBootServicesTableLib
+  BaseLib
+  DebugLib
+  UefiDriverEntryPoint
+  IoLib
+  TimerLib
+
+[Protocols]
+  gEfiCpuArchProtocolGuid       ## CONSUMES
+  gEfiTimerArchProtocolGuid     ## PRODUCES
+
+[depex]
+  TRUE
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 11/15] Platform/Loongson: Add RealTime Clock lib.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (9 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 10/15] Platform/Loongson: Add timer Dxe driver xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 12/15] Platform/Loongson: Add Platform Boot Manager Lib xianglai
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

This library provides interfaces such as
real-time clock initialization
to get time and setting time.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../LsRealTimeClockLib/LsRealTimeClock.h      |  40 +++
 .../LsRealTimeClockLib/LsRealTimeClockLib.c   | 335 ++++++++++++++++++
 .../LsRealTimeClockLib/LsRealTimeClockLib.inf |  44 +++
 3 files changed, 419 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h
new file mode 100644
index 0000000000..6567ec80db
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h
@@ -0,0 +1,40 @@
+/** @file
+  Implement EFI RealTimeClock runtime services via RTC Lib.
+
+  Copyright (c) 2022, Loongson Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef LS_REAL_TIME_CLOCK_H_
+#define LS_REAL_TIME_CLOCK_H_
+
+#define TOY_WRITE0_REG        0x24
+#define TOY_WRITE1_REG        0x28
+#define TOY_READ0_REG         0x2c
+#define TOY_READ1_REG         0x30
+#define RTC_CTRL_REG          0x40
+
+/* TOY Enable bits */
+#define RTC_ENABLE_BIT        (1UL << 13)
+#define TOY_ENABLE_BIT        (1UL << 11)
+#define OSC_ENABLE_BIT        (1UL << 8)
+
+/*
+ * shift bits and filed mask
+ */
+#define TOY_MON_MASK          0x3f
+#define TOY_DAY_MASK          0x1f
+#define TOY_HOUR_MASK         0x1f
+#define TOY_MIN_MASK          0x3f
+#define TOY_SEC_MASK          0x3f
+#define TOY_MSEC_MASK         0xf
+
+#define TOY_MON_SHIFT         26
+#define TOY_DAY_SHIFT         21
+#define TOY_HOUR_SHIFT        16
+#define TOY_MIN_SHIFT         10
+#define TOY_SEC_SHIFT         4
+
+#endif // LS_REAL_TIME_CLOCK_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c
new file mode 100644
index 0000000000..dc651ccaaf
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c
@@ -0,0 +1,335 @@
+/** @file
+  Implement EFI RealTimeClock runtime services via RTC Lib.
+
+  Copyright (c) 2022, Loongson Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/GlobalVariable.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/RealTimeClockLib.h>
+#include <Library/TimeBaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Protocol/RealTimeClock.h>
+#include "LsRealTimeClock.h"
+
+STATIC BOOLEAN                mInitialized = FALSE;
+STATIC EFI_EVENT              mRtcVirtualAddrChangeEvent;
+STATIC UINTN                  mRtcBase = 0x100d0100;
+/*
+  Enable Real-time clock.
+
+  @param VOID
+
+  @retval  VOID
+ */
+VOID
+InitRtc (
+  VOID
+  )
+{
+ UINTN  Val;
+
+  if (!mInitialized) {
+    /* enable rtc */
+    Val  = MmioRead32 (mRtcBase + RTC_CTRL_REG);
+    Val |= TOY_ENABLE_BIT | OSC_ENABLE_BIT;
+    MmioWrite32 (mRtcBase + RTC_CTRL_REG, Val);
+    mInitialized = TRUE;
+  }
+}
+
+/**
+  Returns the current time and date information, and the time-keeping capabilities
+  of the hardware platform.
+
+  @param  Time                   A pointer to storage to receive a snapshot of the current time.
+  @param  Capabilities           An optional pointer to a buffer to receive the real time clock
+                                 device's capabilities.
+
+  @retval EFI_SUCCESS            The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER  Time is NULL.
+  @retval EFI_DEVICE_ERROR       The time could not be retrieved due to hardware error.
+  @retval EFI_SECURITY_VIOLATION The time could not be retrieved due to an authentication failure.
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+  OUT EFI_TIME                *Time,
+  OUT EFI_TIME_CAPABILITIES   *Capabilities
+  )
+{
+  UINT32      Val;
+
+  // Ensure Time is a valid pointer
+  if (Time == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  InitRtc ();
+  Val = MmioRead32 (mRtcBase + TOY_READ1_REG);
+  Time->Year = Val + 1900;
+
+  Val = MmioRead32 (mRtcBase + TOY_READ0_REG);
+  Time->Month =  (Val >> TOY_MON_SHIFT) & TOY_MON_MASK;
+  Time->Day   =  (Val >> TOY_DAY_SHIFT) & TOY_DAY_MASK;
+  Time->Hour  =  (Val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK;
+  Time->Minute = (Val >> TOY_MIN_SHIFT) & TOY_MIN_MASK;
+  Time->Second = (Val >> TOY_SEC_SHIFT) & TOY_SEC_MASK;
+  Time->Nanosecond  = 0;
+  return EFI_SUCCESS;
+}
+
+/**
+  Sets the current local time and date information.
+
+  @param  Time                  A pointer to the current time.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware error.
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+  IN  EFI_TIME                *Time
+  )
+{
+  UINT32      Val;
+
+  // Initialize the hardware if not already done
+  InitRtc ();
+
+  Val = 0;
+  Val |= (Time->Second << TOY_SEC_SHIFT);
+  Val |= (Time->Minute << TOY_MIN_SHIFT);
+  Val |= (Time->Hour   << TOY_HOUR_SHIFT);
+  Val |= (Time->Day    << TOY_DAY_SHIFT);
+  Val |= (Time->Month  << TOY_MON_SHIFT);
+  MmioWrite32 (mRtcBase + TOY_WRITE0_REG, Val);
+
+  Val = Time->Year - 1900;
+  MmioWrite32 (mRtcBase + TOY_WRITE1_REG, Val);
+  return EFI_SUCCESS;
+}
+
+/**
+  Returns the current wakeup alarm clock setting.
+
+  @param  Enabled               Indicates if the alarm is currently enabled or disabled.
+  @param  Pending               Indicates if the alarm signal is pending and requires acknowledgement.
+  @param  Time                  The current alarm setting.
+
+  @retval EFI_SUCCESS           The alarm settings were returned.
+  @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be retrieved due to a hardware error.
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+  OUT BOOLEAN     *Enabled,
+  OUT BOOLEAN     *Pending,
+  OUT EFI_TIME    *Time
+  )
+{
+  // Not a required feature
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Sets the system wakeup alarm clock time.
+
+  @param  Enabled               Enable or disable the wakeup alarm.
+  @param  Time                  If Enable is TRUE, the time to set the wakeup alarm for.
+
+  @retval EFI_SUCCESS           If Enable is TRUE, then the wakeup alarm was enabled. If
+                                Enable is FALSE, then the wakeup alarm was disabled.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be set due to a hardware error.
+  @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+  IN BOOLEAN      Enabled,
+  OUT EFI_TIME    *Time
+  )
+{
+  // Not a required feature
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Fixup internal data so that EFI can be call in virtual mode.
+  Call the passed in Child Notify event and convert any pointers in
+  lib to virtual mode.
+
+  @param[in]    Event   The Event that is being processed
+  @param[in]    Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  //
+  // Only needed if you are going to support the OS calling RTC functions in virtual mode.
+  // You will need to call EfiConvertPointer (). To convert any stored physical addresses
+  // to virtual address. After the OS transitions to calling in virtual mode, all future
+  // runtime calls will be made in virtual mode.
+  //
+  EfiConvertPointer (0x0, (VOID**)&mRtcBase);
+  return;
+}
+
+/** Add the RTC controller address range to the memory map.
+
+  @param [in]  ImageHandle  The handle to the image.
+  @param [in]  RtcPageBase  Base address of the RTC controller.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+  @retval EFI_NOT_FOUND           Flash device not found.
+**/
+EFI_STATUS
+KvmtoolRtcMapMemory (
+  IN EFI_HANDLE               ImageHandle,
+  IN EFI_PHYSICAL_ADDRESS     RtcPageBase
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = gDS->AddMemorySpace (
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  RtcPageBase,
+                  EFI_PAGE_SIZE,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR, "Failed to add memory space. Status = %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Status = gDS->AllocateMemorySpace (
+                  EfiGcdAllocateAddress,
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  0,
+                  EFI_PAGE_SIZE,
+                  &RtcPageBase,
+                  ImageHandle,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Failed to allocate memory space. Status = %r\n",
+      Status
+      ));
+    gDS->RemoveMemorySpace (
+           RtcPageBase,
+           EFI_PAGE_SIZE
+           );
+    return Status;
+  }
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  RtcPageBase,
+                  EFI_PAGE_SIZE,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Failed to set memory attributes. Status = %r\n",
+      Status
+      ));
+
+    gDS->FreeMemorySpace (
+           RtcPageBase,
+           EFI_PAGE_SIZE
+           );
+
+    gDS->RemoveMemorySpace (
+           RtcPageBase,
+           EFI_PAGE_SIZE
+           );
+  }
+
+  return Status;
+}
+
+/**
+  This is the declaration of an EFI image entry point. This can be the entry point to an application
+  written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+  @param  ImageHandle           Handle that identifies the loaded image.
+  @param  SystemTable           System Table for this image.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+  EFI_HANDLE    Handle;
+
+  Status = KvmtoolRtcMapMemory (ImageHandle, (mRtcBase & ~EFI_PAGE_MASK));
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "Failed to map memory for loongson 7A RTC. Status = %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  // Setup the setters and getters
+  gRT->GetTime       = LibGetTime;
+  gRT->SetTime       = LibSetTime;
+
+  // Install the protocol
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEfiRealTimeClockArchProtocolGuid,  NULL,
+                  NULL
+                 );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Register for the virtual address change event
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  LibRtcVirtualNotifyEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &mRtcVirtualAddrChangeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf
new file mode 100644
index 0000000000..6f7bf467b9
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf
@@ -0,0 +1,44 @@
+## @file
+#
+#  Copyright (c) 2022, Loongson Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = LsRealTimeClockLib
+  FILE_GUID                      = 9793a3da-1869-4fdf-88b1-c6484341f50b
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = RealTimeClockLib
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  LsRealTimeClockLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+  IoLib
+  UefiLib
+  DebugLib
+  PcdLib
+  DxeServicesTableLib
+  UefiRuntimeLib
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+  gEfiRealTimeClockArchProtocolGuid             # PROTOCOL ALWAYS_PRODUCED
+
+[Depex]
+  TRUE
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 12/15] Platform/Loongson: Add Platform Boot Manager Lib.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (10 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 11/15] Platform/Loongson: Add RealTime Clock lib xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 13/15] Platform/Loongson: Add Reset System Lib xianglai
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

The Library provides Boot Manager interfaces.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../PlatformBootManagerLib/PlatformBm.c       | 742 ++++++++++++++++++
 .../PlatformBootManagerLib/PlatformBm.h       | 112 +++
 .../PlatformBootManagerLib.inf                |  75 ++
 .../PlatformBootManagerLib/QemuKernel.c       |  81 ++
 4 files changed, 1010 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c

diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c
new file mode 100644
index 0000000000..eb7f4241f0
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c
@@ -0,0 +1,742 @@
+/** @file
+  Implementation for PlatformBootManagerLib library class interfaces.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/Pci22.h>
+#include <Library/BootLogoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/QemuBootOrderLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "PlatformBm.h"
+
+STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
+    //
+    // VENDOR_DEVICE_PATH SerialDxe
+    //
+    {
+        { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
+        SERIAL_DXE_FILE_GUID
+    },
+
+    //
+    // UART_DEVICE_PATH Uart
+    //
+    {
+        { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
+    0,                                      // Reserved
+    FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
+    FixedPcdGet8 (PcdUartDefaultDataBits),  // DataBits
+    FixedPcdGet8 (PcdUartDefaultParity),    // Parity
+    FixedPcdGet8 (PcdUartDefaultStopBits)   // StopBits
+  },
+
+  //
+  // VENDOR_DEFINED_DEVICE_PATH TermType
+  //
+  {
+    {
+      MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
+      DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
+    }
+    //
+    // Guid to be filled in dynamically
+    //
+  },
+
+  //
+  // EFI_DEVICE_PATH_PROTOCOL End
+  //
+  {
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+  }
+};
+
+STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
+  //
+  // USB_CLASS_DEVICE_PATH Keyboard
+  //
+  {
+    {
+      MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
+      DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
+    },
+    0xFFFF, // VendorId: any
+    0xFFFF, // ProductId: any
+    3,      // DeviceClass: HID
+    1,      // DeviceSubClass: boot
+    1       // DeviceProtocol: keyboard
+  },
+
+  //
+  // EFI_DEVICE_PATH_PROTOCOL End
+  //
+  {
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+  }
+};
+
+/**
+  Locate all handles that carry the specified protocol, filter them with a
+  callback function, and pass each handle that passes the filter to another
+  callback.
+
+  @param[in] ProtocolGuid  The protocol to look for.
+
+  @param[in] Filter        The filter function to pass each handle to. If this
+                           parameter is NULL, then all handles are processed.
+
+  @param[in] Process       The callback function to pass each handle to that
+                           clears the filter.
+**/
+VOID
+FilterAndProcess (
+  IN EFI_GUID          *ProtocolGuid,
+  IN FILTER_FUNCTION   Filter         OPTIONAL,
+  IN CALLBACK_FUNCTION Process
+  )
+{
+  EFI_STATUS Status;
+  EFI_HANDLE *Handles;
+  UINTN      NoHandles;
+  UINTN      Idx;
+
+  Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,
+                  NULL /* SearchKey */, &NoHandles, &Handles);
+  if (EFI_ERROR (Status)) {
+    //
+    // This is not an error, just an informative condition.
+    //
+    DEBUG ((DEBUG_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,
+      Status));
+    return;
+  }
+
+  ASSERT (NoHandles > 0);
+  for (Idx = 0; Idx < NoHandles; ++Idx) {
+    CHAR16        *DevicePathText;
+    STATIC CHAR16 Fallback[] = L"<device path unavailable>";
+
+    //
+    // The ConvertDevicePathToText () function handles NULL input transparently.
+    //
+    DevicePathText = ConvertDevicePathToText (
+                       DevicePathFromHandle (Handles[Idx]),
+                       FALSE, // DisplayOnly
+                       FALSE  // AllowShortcuts
+                       );
+    if (DevicePathText == NULL) {
+      DevicePathText = Fallback;
+    }
+
+    if ((Filter == NULL)
+      || (Filter (Handles[Idx], DevicePathText)))
+    {
+      Process (Handles[Idx], DevicePathText);
+    }
+
+    if (DevicePathText != Fallback) {
+      FreePool (DevicePathText);
+    }
+  }
+  gBS->FreePool (Handles);
+}
+
+/**
+  This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
+
+  @param  Handle   The handle to check
+  @param  ReportText   A pointer to a string at the time of the error.
+
+  @retval    TURE     THe  handle corresponds to a PCI display device.
+  @retval    FALSE    THe  handle does not corresponds to a PCI display device.
+**/
+BOOLEAN
+EFIAPI
+IsPciDisplay (
+  IN EFI_HANDLE   Handle,
+  IN CONST CHAR16 *ReportText
+  )
+{
+  EFI_STATUS          Status;
+  EFI_PCI_IO_PROTOCOL *PciIo;
+  PCI_TYPE00          Pci;
+
+  Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
+                  (VOID**)&PciIo);
+  if (EFI_ERROR (Status)) {
+    //
+    // This is not an error worth reporting.
+    //
+    return FALSE;
+  }
+
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,
+                        sizeof Pci / sizeof (UINT32), &Pci);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
+    return FALSE;
+  }
+
+  return IS_PCI_DISPLAY (&Pci);
+}
+
+/**
+  This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
+  the matching driver to produce all first-level child handles.
+
+  @param  Handle   The handle to connect.
+  @param  ReportText   A pointer to a string at the time of the error.
+
+  @retval  VOID
+**/
+VOID
+EFIAPI
+Connect (
+  IN EFI_HANDLE   Handle,
+  IN CONST CHAR16 *ReportText
+  )
+{
+  EFI_STATUS Status;
+
+  Status = gBS->ConnectController (
+                  Handle, // ControllerHandle
+                  NULL,   // DriverImageHandle
+                  NULL,   // RemainingDevicePath -- produce all children
+                  FALSE   // Recursive
+                  );
+  DEBUG ((EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE, "%a: %s: %r\n",
+    __FUNCTION__, ReportText, Status));
+}
+
+/**
+  This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
+  handle, and adds it to ConOut and ErrOut.
+
+  @param  Handle   The handle to retrieves.
+  @param  ReportText   A pointer to a string at the time of the error.
+
+  @retval  VOID
+**/
+VOID
+EFIAPI
+AddOutput (
+  IN EFI_HANDLE   Handle,
+  IN CONST CHAR16 *ReportText
+  )
+{
+  EFI_STATUS               Status;
+  EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+  DevicePath = DevicePathFromHandle (Handle);
+  if (DevicePath == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: %s: handle %p: device path not found\n",
+      __FUNCTION__, ReportText, Handle));
+    return;
+  }
+
+  Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
+      ReportText, Status));
+    return;
+  }
+
+  Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
+      ReportText, Status));
+    return;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
+    ReportText));
+}
+/**
+  Register the boot option.
+
+  @param  FileGuid      File Guid.
+  @param  Description   Option descriptor.
+  @param  Attributes    Option  Attributes.
+
+  @retval  VOID
+**/
+VOID
+PlatformRegisterFvBootOption (
+  IN EFI_GUID                         *FileGuid,
+  IN CHAR16                           *Description,
+  IN UINT32                           Attributes
+  )
+{
+  EFI_STATUS                        Status;
+  INTN                              OptionIndex;
+  EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;
+  EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;
+  UINTN                             BootOptionCount;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+  EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;
+  EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
+
+  Status = gBS->HandleProtocol (
+                  gImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **) &LoadedImage
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+  DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
+  ASSERT (DevicePath != NULL);
+  DevicePath = AppendDevicePathNode (
+                 DevicePath,
+                 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+                 );
+  ASSERT (DevicePath != NULL);
+
+  Status = EfiBootManagerInitializeLoadOption (
+             &NewOption,
+             LoadOptionNumberUnassigned,
+             LoadOptionTypeBoot,
+             Attributes,
+             Description,
+             DevicePath,
+             NULL,
+             0
+             );
+  ASSERT_EFI_ERROR (Status);
+  FreePool (DevicePath);
+
+  BootOptions = EfiBootManagerGetLoadOptions (
+                  &BootOptionCount, LoadOptionTypeBoot
+                  );
+
+  OptionIndex = EfiBootManagerFindLoadOption (
+                  &NewOption, BootOptions, BootOptionCount
+                  );
+
+  if (OptionIndex == -1) {
+    Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
+    ASSERT_EFI_ERROR (Status);
+  }
+  EfiBootManagerFreeLoadOption (&NewOption);
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+/**
+  Remove all MemoryMapped (...)/FvFile (...) and Fv (...)/FvFile (...) boot options
+  whose device paths do not resolve exactly to an FvFile in the system.
+
+  This removes any boot options that point to binaries built into the firmware
+  and have become stale due to any of the following:
+  - FvMain's base address or size changed (historical),
+  - FvMain's FvNameGuid changed,
+  - the FILE_GUID of the pointed-to binary changed,
+  - the referenced binary is no longer built into the firmware.
+
+  EfiBootManagerFindLoadOption () used in PlatformRegisterFvBootOption () only
+  avoids exact duplicates.
+**/
+VOID
+RemoveStaleFvFileOptions (
+  VOID
+  )
+{
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+  UINTN                        BootOptionCount;
+  UINTN                        Index;
+
+  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
+                  LoadOptionTypeBoot);
+
+  for (Index = 0; Index < BootOptionCount; ++Index) {
+    EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
+    EFI_STATUS               Status;
+    EFI_HANDLE               FvHandle;
+
+    //
+    // If the device path starts with neither MemoryMapped (...) nor Fv (...),
+    // then keep the boot option.
+    //
+    Node1 = BootOptions[Index].FilePath;
+    if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH
+      && DevicePathSubType (Node1) == HW_MEMMAP_DP)
+      && !(DevicePathType (Node1) == MEDIA_DEVICE_PATH
+      && DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP))
+    {
+      continue;
+    }
+
+    //
+    // If the second device path node is not FvFile (...), then keep the boot
+    // option.
+    //
+    Node2 = NextDevicePathNode (Node1);
+    if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH)
+      || (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
+    {
+      continue;
+    }
+
+    //
+    // Locate the Firmware Volume2 protocol instance that is denoted by the
+    // boot option. If this lookup fails (i.e., the boot option references a
+    // firmware volume that doesn't exist), then we'll proceed to delete the
+    // boot option.
+    //
+    SearchNode = Node1;
+    Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
+                    &SearchNode, &FvHandle);
+
+    if (!EFI_ERROR (Status)) {
+      //
+      // The firmware volume was found; now let's see if it contains the FvFile
+      // identified by GUID.
+      //
+      EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol;
+      MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
+      UINTN                             BufferSize;
+      EFI_FV_FILETYPE                   FoundType;
+      EFI_FV_FILE_ATTRIBUTES            FileAttributes;
+      UINT32                            AuthenticationStatus;
+
+      Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
+                      (VOID **)&FvProtocol);
+      ASSERT_EFI_ERROR (Status);
+
+      FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
+      //
+      // Buffer==NULL means we request metadata only: BufferSize, FoundType,
+      // FileAttributes.
+      //
+      Status = FvProtocol->ReadFile (
+                             FvProtocol,
+                             &FvFileNode->FvFileName, // NameGuid
+                             NULL,                    // Buffer
+                             &BufferSize,
+                             &FoundType,
+                             &FileAttributes,
+                             &AuthenticationStatus
+                             );
+      if (!EFI_ERROR (Status)) {
+        //
+        // The FvFile was found. Keep the boot option.
+        //
+        continue;
+      }
+    }
+
+    //
+    // Delete the boot option.
+    //
+    Status = EfiBootManagerDeleteLoadOptionVariable (
+               BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+    DEBUG_CODE (
+      CHAR16 *DevicePathString;
+
+      DevicePathString = ConvertDevicePathToText (BootOptions[Index].FilePath,
+                           FALSE, FALSE);
+      DEBUG ((
+        EFI_ERROR (Status) ? EFI_D_WARN : DEBUG_VERBOSE,
+        "%a: removing stale Boot#%04x %s: %r\n",
+        __FUNCTION__,
+        (UINT32)BootOptions[Index].OptionNumber,
+        DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
+        Status
+        ));
+      if (DevicePathString != NULL) {
+        FreePool (DevicePathString);
+      }
+      );
+  }
+
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+/**
+  Register the boot option And Keys.
+
+  @param  VOID
+
+  @retval  VOID
+**/
+VOID
+PlatformRegisterOptionsAndKeys (
+  VOID
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_INPUT_KEY                Enter;
+  EFI_INPUT_KEY                F2;
+  EFI_INPUT_KEY                Esc;
+  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+  //
+  // Register ENTER as CONTINUE key
+  //
+  Enter.ScanCode    = SCAN_NULL;
+  Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+  Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Map F2 and ESC to Boot Manager Menu
+  //
+  F2.ScanCode     = SCAN_F2;
+  F2.UnicodeChar  = CHAR_NULL;
+  Esc.ScanCode    = SCAN_ESC;
+  Esc.UnicodeChar = CHAR_NULL;
+  Status = EfiBootManagerGetBootManagerMenu (&BootOption);
+  ASSERT_EFI_ERROR (Status);
+  Status = EfiBootManagerAddKeyOptionVariable (
+             NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
+             );
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+  Status = EfiBootManagerAddKeyOptionVariable (
+             NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
+             );
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+}
+
+//
+// BDS Platform Functions
+//
+/**
+  Do the platform init, can be customized by OEM/IBV
+  Possible things that can be done in PlatformBootManagerBeforeConsole:
+  > Update console variable: 1. include hot-plug devices;
+  >                          2. Clear ConIn and add SOL for AMT
+  > Register new Driver#### or Boot####
+  > Register new Key####: e.g.: F12
+  > Signal ReadyToLock event
+  > Authentication action: 1. connect Auth devices;
+  >                        2. Identify auto logon user.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+  VOID
+  )
+{
+  RETURN_STATUS PcdStatus;
+
+  //
+  // Signal EndOfDxe PI Event
+  //
+  EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+
+  //
+  // Dispatch deferred images after EndOfDxe event.
+  //
+  EfiBootManagerDispatchDeferredImages ();
+
+  //
+  // Locate the PCI root bridges and make the PCI bus driver connect each,
+  // non-recursively. This will produce a number of child handles with PciIo on
+  // them.
+  //
+  FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
+
+  //
+  // Signal the ACPI platform driver that it can download QEMU ACPI tables.
+  //
+  EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
+
+  //
+  // Find all display class PCI devices (using the handles from the previous
+  // step), and connect them non-recursively. This should produce a number of
+  // child handles with GOPs on them.
+  //
+  FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
+
+  //
+  // Now add the device path of all handles with GOP on them to ConOut and
+  // ErrOut.
+  //
+  FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
+
+  //
+  // Add the hardcoded short-form USB keyboard device path to ConIn.
+  //
+  EfiBootManagerUpdateConsoleVariable (ConIn,
+    (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
+
+  //
+  // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
+  //
+  CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
+  EfiBootManagerUpdateConsoleVariable (ConIn,
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+  EfiBootManagerUpdateConsoleVariable (ConOut,
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+  EfiBootManagerUpdateConsoleVariable (ErrOut,
+    (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+
+  //
+  // Set the front page timeout from the QEMU configuration.
+  //
+  PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,
+                GetFrontPageTimeoutFromQemu ());
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  //
+  // Register platform-specific boot options and keyboard shortcuts.
+  //
+  PlatformRegisterOptionsAndKeys ();
+}
+
+/**
+  Do the platform specific action after the console is ready
+  Possible things that can be done in PlatformBootManagerAfterConsole:
+  > Console post action:
+    > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
+    > Signal console ready platform customized event
+  > Run diagnostics like memory testing
+  > Connect certain devices
+  > Dispatch aditional option roms
+  > Special boot: e.g.: USB boot, enter UI
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+  VOID
+  )
+{
+  //
+  // Show the splash screen.
+  //
+  BootLogoEnableLogo ();
+
+  //
+  // Connect the rest of the devices.
+  //
+  EfiBootManagerConnectAll ();
+
+  //
+  // Process QEMU's -kernel command line option. Note that the kernel booted
+  // this way should receive ACPI tables, which is why we connect all devices
+  // first (see above) -- PCI enumeration blocks ACPI table installation, if
+  // there is a PCI host.
+  //
+  TryRunningQemuKernel ();
+
+  //
+  // Enumerate all possible boot options, then filter and reorder them based on
+  // the QEMU configuration.
+  //
+  EfiBootManagerRefreshAllBootOption ();
+
+  //
+  // Register UEFI Shell
+  //
+  PlatformRegisterFvBootOption (
+    &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+    );
+
+  RemoveStaleFvFileOptions ();
+  SetBootOrderFromQemu ();
+}
+
+/**
+  This function is called each second during the boot manager waits the
+  timeout.
+
+  @param TimeoutRemain  The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+  IN UINT16          TimeoutRemain
+  )
+{
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
+  UINT16                              Timeout;
+
+  Timeout = PcdGet16 (PcdPlatformBootTimeOut);
+
+  Black.Raw = 0x00000000;
+  White.Raw = 0x00FFFFFF;
+
+  BootLogoUpdateProgress (
+    White.Pixel,
+    Black.Pixel,
+    L"Start boot option",
+    White.Pixel,
+    (Timeout - TimeoutRemain) * 100 / Timeout,
+    0
+    );
+}
+
+/**
+  The function is called when no boot option could be launched,
+  including platform recovery options and options pointing to applications
+  built into firmware volumes.
+
+  If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+  VOID
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_INPUT_KEY                Key;
+  EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+  UINTN                        Index;
+
+  //
+  // BootManagerMenu doesn't contain the correct information when return status
+  // is EFI_NOT_FOUND.
+  //
+  Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+  //
+  // Normally BdsDxe does not print anything to the system console, but this is
+  // a last resort -- the end-user will likely not see any DEBUG messages
+  // logged in this situation.
+  //
+  // AsciiPrint () will NULL-check gST->ConOut internally. We check gST->ConIn
+  // here to see if it makes sense to request and wait for a keypress.
+  //
+  if (gST->ConIn != NULL) {
+    AsciiPrint (
+      "%a: No bootable option or device was found.\n"
+      "%a: Press any key to enter the Boot Manager Menu.\n",
+      gEfiCallerBaseName,
+      gEfiCallerBaseName
+      );
+    Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+    ASSERT_EFI_ERROR (Status);
+    ASSERT (Index == 0);
+
+    //
+    // Drain any queued keys.
+    //
+    while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
+      //
+      // just throw away Key
+      //
+    }
+  }
+
+  for (;;) {
+    EfiBootManagerBoot (&BootManagerMenu);
+  }
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h
new file mode 100644
index 0000000000..f20c78252f
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h
@@ -0,0 +1,112 @@
+/** @file
+  Head file for BDS Platform specific code
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_BM_H_
+#define PLATFORM_BM_H_
+
+#include <Library/DevicePathLib.h>
+
+#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
+
+#define SERIAL_DXE_FILE_GUID { \
+          0xD3987D4B, 0x971A, 0x435F, \
+          { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
+          }
+
+#define ALIGN_UP(addr, align) \
+    ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1))
+
+#pragma pack (1)
+typedef struct {
+  VENDOR_DEVICE_PATH         SerialDxe;
+  UART_DEVICE_PATH           Uart;
+  VENDOR_DEFINED_DEVICE_PATH TermType;
+  EFI_DEVICE_PATH_PROTOCOL   End;
+} PLATFORM_SERIAL_CONSOLE;
+#pragma pack ()
+
+#pragma pack (1)
+typedef struct {
+  USB_CLASS_DEVICE_PATH    Keyboard;
+  EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_USB_KEYBOARD;
+#pragma pack ()
+
+/**
+  Check if the handle satisfies a particular condition.
+
+  @param[in] Handle      The handle to check.
+  @param[in] ReportText  A caller-allocated string passed in for reporting
+                         purposes. It must never be NULL.
+
+  @retval TRUE   The condition is satisfied.
+  @retval FALSE  Otherwise. This includes the case when the condition could not
+                 be fully evaluated due to an error.
+**/
+typedef
+BOOLEAN
+(EFIAPI *FILTER_FUNCTION) (
+  IN EFI_HANDLE   Handle,
+  IN CONST CHAR16 *ReportText
+  );
+
+/**
+  Process a handle.
+
+  @param[in] Handle      The handle to process.
+  @param[in] ReportText  A caller-allocated string passed in for reporting
+                         purposes. It must never be NULL.
+**/
+typedef
+VOID
+(EFIAPI *CALLBACK_FUNCTION)  (
+  IN EFI_HANDLE   Handle,
+  IN CONST CHAR16 *ReportText
+  );
+
+/**
+ * execute from kernel entry point.
+ *
+ * @param[in] Argc  The count of args.
+ * @param[in] Argv  The pointer to args array.
+ * @param[in] Bpi   The pointer to bootparaminterface struct.
+ * @param[in] Vec   The fourth args for kernel.
+ ***/
+typedef
+VOID
+(EFIAPI *EFI_KERNEL_ENTRY_POINT) (
+  IN UINTN  Argc,
+  IN VOID   *Argv,
+  IN VOID   *Bpi,
+  IN VOID   *Vec
+  );
+
+/**
+  Download the kernel, the initial ramdisk, and the kernel command line from
+  QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
+  image files, and load and start the kernel from it.
+
+  The kernel will be instructed via its command line to load the initrd from
+  the same Simple FileSystem.
+
+  @retval EFI_NOT_FOUND         Kernel image was not found.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
+  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.
+
+  @return                       Error codes from any of the underlying
+                                functions. On success, the function doesn't
+                                return.
+**/
+EFI_STATUS
+EFIAPI
+TryRunningQemuKernel (
+  VOID
+  );
+
+#endif // PLATFORM_BM_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
new file mode 100644
index 0000000000..0ea6fea5c5
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -0,0 +1,75 @@
+## @file
+#  Implementation for PlatformBootManagerLib library class interfaces.
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PlatformBootManagerLib
+  FILE_GUID                      = 469184E8-FADA-41E4-8823-012CA19B40D4
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PlatformBootManagerLib|DXE_DRIVER
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  PlatformBm.c
+  QemuKernel.c
+
+[Packages]
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+  ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  BootLogoLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  PcdLib
+  PrintLib
+  QemuBootOrderLib
+  QemuLoadImageLib
+  QemuFwCfgLib
+  UefiBootManagerLib
+  UefiBootServicesTableLib
+  UefiLib
+  UefiRuntimeServicesTableLib
+
+[FixedPcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
+  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
+
+[Guids]
+  gEfiFileInfoGuid
+  gEfiFileSystemInfoGuid
+  gEfiFileSystemVolumeLabelInfoIdGuid
+  gEfiEndOfDxeEventGroupGuid
+  gRootBridgesConnectedEventGroupGuid
+  gUefiShellFileGuid
+  gEfiLoongsonBootparamsTableGuid                               ## SOMETIMES_PRODUCES ## SystemTable
+  gEfiTtyTermGuid
+
+[Protocols]
+  gEfiDevicePathProtocolGuid
+  gEfiFirmwareVolume2ProtocolGuid
+  gEfiGraphicsOutputProtocolGuid
+  gEfiLoadedImageProtocolGuid
+  gEfiPciRootBridgeIoProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c
new file mode 100644
index 0000000000..386003a8d7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c
@@ -0,0 +1,81 @@
+/** @file
+  Try to run Linux kernel.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - mem     - Memory
+    - Bpi    - Boot Parameter Interface
+    - FwCfg    - FirmWare Configure
+**/
+
+#include <Library/QemuLoadImageLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+/**
+  Download the kernel, the initial ramdisk, and the kernel command line from
+  QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
+  image files, and load and start the kernel from it.
+
+  The kernel will be instructed via its command line to load the initrd from
+  the same Simple FileSystem.
+
+  @retval EFI_NOT_FOUND         Kernel image was not found.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
+  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.
+
+  @return                       Error codes from any of the underlying
+                                functions. On success, the function doesn't
+                                return.
+**/
+EFI_STATUS
+TryRunningQemuKernel (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  KernelImageHandle;
+
+  Status = QemuLoadKernelImage (&KernelImageHandle);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Signal the EFI_EVENT_GROUP_READY_TO_BOOT event.
+  //
+  EfiSignalEventReadyToBoot ();
+
+  REPORT_STATUS_CODE (
+    EFI_PROGRESS_CODE,
+    (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)
+    );
+
+  //
+  // Start the image.
+  //
+  Status = QemuStartKernelImage (&KernelImageHandle);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: QemuStartKernelImage(): %r\n",
+      __FUNCTION__,
+      Status
+      ));
+  }
+
+  QemuUnloadKernelImage (KernelImageHandle);
+
+  return Status;
+}
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 13/15] Platform/Loongson: Add Reset System Lib.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (11 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 12/15] Platform/Loongson: Add Platform Boot Manager Lib xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 14/15] Platform/Loongson: Support Dxe xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 15/15] Platform/Loongson: Add Readme xianglai
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

This library provides interfaces related to restart and shutdown.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../BaseResetSystemAcpiGed.c                  | 146 ++++++++++
 .../BaseResetSystemAcpiGedLib.inf             |  37 +++
 .../DxeResetSystemAcpiGed.c                   | 257 ++++++++++++++++++
 .../DxeResetSystemAcpiGedLib.inf              |  41 +++
 .../ResetSystemAcpiLib/ResetSystemAcpiGed.c   | 128 +++++++++
 .../ResetSystemAcpiLib/ResetSystemAcpiGed.h   |  23 ++
 6 files changed, 632 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h

diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c
new file mode 100644
index 0000000000..0df629ffcd
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c
@@ -0,0 +1,146 @@
+/** @file
+  Base ResetSystem library implementation.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include "ResetSystemAcpiGed.h"
+#include <Library/QemuFwCfgLib.h>
+
+/**
+  Get configuration item data by the firmware configuration file name.
+
+  @param[in]  Name - Name of file to look up.
+
+  @return    VOID*       The Pointer of Value of Firmware Configuration item read.
+**/
+VOID *
+GetFwCfgData(
+CONST CHAR8           *Name
+)
+{
+  FIRMWARE_CONFIG_ITEM FwCfgItem;
+  EFI_STATUS           Status;
+  UINTN                FwCfgSize;
+  VOID                 *Data;
+
+  Status = QemuFwCfgFindFile (Name, &FwCfgItem, &FwCfgSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a %d read  %s error Status %d \n", __func__, __LINE__, Name, Status));
+    return NULL;
+  }
+
+  Data = AllocatePool (FwCfgSize);
+  if (Data == NULL) {
+    return NULL;
+  }
+
+  QemuFwCfgSelectItem (FwCfgItem);
+  QemuFwCfgReadBytes (FwCfgSize, Data);
+
+  return Data;
+}
+
+/**
+  Find the power manager related info from ACPI table
+
+  @retval RETURN_SUCCESS     Successfully find out all the required information.
+  @retval RETURN_NOT_FOUND   Failed to find the required info.
+**/
+STATIC EFI_STATUS
+GetPowerManagerByParseAcpiInfo (VOID)
+{
+  EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE    *Fadt = NULL;
+  EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp = NULL;
+  EFI_ACPI_DESCRIPTION_HEADER                  *Xsdt = NULL;
+  EFI_ACPI_DESCRIPTION_HEADER                  *Rsdt = NULL;
+  VOID                                         *AcpiTables = NULL;
+  UINT32                                       *Entry32 = NULL;
+  UINTN                                         Entry32Num;
+  UINT32                                       *Signature = NULL;
+  UINTN                                         Idx;
+
+  Rsdp = GetFwCfgData ("etc/acpi/rsdp");
+  if (Rsdp == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a %d read etc/acpi/rsdp error \n", __func__, __LINE__));
+    return RETURN_NOT_FOUND;
+  }
+
+  AcpiTables = GetFwCfgData ("etc/acpi/tables");
+  if (AcpiTables == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a %d read etc/acpi/tables error \n", __func__, __LINE__));
+    FreePool (Rsdp);
+    return RETURN_NOT_FOUND;
+  }
+
+  Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)AcpiTables +  Rsdp->RsdtAddress);
+  Entry32    = (UINT32 *)(Rsdt + 1);
+  Entry32Num = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
+  for (Idx = 0; Idx < Entry32Num; Idx++) {
+    Signature = (UINT32 *)((UINTN)Entry32[Idx] + (UINTN)AcpiTables);
+    if (*Signature == EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+      Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;
+      DEBUG ((DEBUG_INFO, "Found Fadt in Rsdt\n"));
+      goto Done;
+    }
+  }
+
+  Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)AcpiTables +  Rsdp->XsdtAddress);
+  Entry32    = (UINT32 *)(Xsdt + 1);
+  Entry32Num = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
+  for (Idx = 0; Idx < Entry32Num; Idx++) {
+    Signature = (UINT32 *)((UINTN)Entry32[Idx] + (UINTN)AcpiTables);
+    if (*Signature == EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+      Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;
+      DEBUG ((DEBUG_INFO, "Found Fadt in Xsdt\n"));
+      goto Done;
+    }
+  }
+
+  FreePool (Rsdp);
+  FreePool (AcpiTables);
+  DEBUG ((DEBUG_ERROR, " Fadt Not Found\n"));
+  return RETURN_NOT_FOUND;
+
+Done:
+  mPowerManager.ResetRegAddr        = Fadt->ResetReg.Address;
+  mPowerManager.ResetValue          = Fadt->ResetValue;
+  mPowerManager.SleepControlRegAddr = Fadt->SleepControlReg.Address;
+  mPowerManager.SleepStatusRegAddr  = Fadt->SleepStatusReg.Address;
+
+  FreePool (Rsdp);
+  FreePool (AcpiTables);
+  return RETURN_SUCCESS;
+}
+
+/**
+  The constructor function to initialize mPowerManager.
+
+  @retval EFI_SUCCESS   initialize mPowerManager success.
+  @retval RETURN_NOT_FOUND   Failed to initialize mPowerManager.
+**/
+EFI_STATUS
+ResetSystemLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GetPowerManagerByParseAcpiInfo ();
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a:%d\n",  __FUNCTION__, __LINE__));
+  }
+
+  ASSERT (mPowerManager.SleepControlRegAddr);
+  ASSERT (mPowerManager.SleepStatusRegAddr);
+  ASSERT (mPowerManager.ResetRegAddr);
+  return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
new file mode 100644
index 0000000000..120dd7dcff
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
@@ -0,0 +1,37 @@
+## @file
+#  Base library instance for ResetSystem library class for loongarhch
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 1.29
+  BASE_NAME                      = ResetSystemLib
+  FILE_GUID                      = 3d6faf60-804a-4ca9-a36a-1a92416919d0
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = ResetSystemLib|SEC PEI_CORE PEIM DXE_CORE
+  CONSTRUCTOR                    = ResetSystemLibConstructor
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  BaseResetSystemAcpiGed.c
+  ResetSystemAcpiGed.c
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  QemuFwCfgLib
+  MemoryAllocationLib
+  IoLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c
new file mode 100644
index 0000000000..ef48946ae4
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c
@@ -0,0 +1,257 @@
+/** @file
+  Dxe ResetSystem library implementation.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeLib.h> // EfiConvertPointer()
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "ResetSystemAcpiGed.h"
+#include <Library/UefiLib.h>
+
+/**
+  Modifies the attributes to Runtime type for a page size memory region.
+
+  @param  BaseAddress            Specified start address
+
+  @retval EFI_SUCCESS           The attributes were set for the memory region.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
+                                resource range specified by BaseAddress and Length.
+  @retval EFI_UNSUPPORTED       The bit mask of attributes is not support for the memory resource
+                                range specified by BaseAddress and Length.
+  @retval EFI_ACCESS_DEFINED    The attributes for the memory resource range specified by
+                                BaseAddress and Length cannot be modified.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
+                                the memory resource range.
+  @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
+                                not available yet.
+**/
+EFI_STATUS
+SetMemoryAttributesRunTime (
+  UINTN Address
+  )
+{
+  EFI_STATUS  Status;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  Descriptor;
+
+  Address &= ~EFI_PAGE_MASK;
+
+  Status = gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a: GetMemorySpaceDescriptor failed\n", __FUNCTION__));
+    return Status;
+  }
+
+  if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+    Status = gDS->AddMemorySpace (
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  Address,
+                  EFI_PAGE_SIZE,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_INFO, "%a: AddMemorySpace failed\n", __FUNCTION__));
+      return Status;
+    }
+
+    Status = gDS->SetMemorySpaceAttributes (
+                  Address,
+                  EFI_PAGE_SIZE,
+                  EFI_MEMORY_RUNTIME
+                  );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_INFO, "%a:%d SetMemorySpaceAttributes failed\n", __FUNCTION__, __LINE__));
+      return Status;
+    }
+  } else if (!(Descriptor.Attributes & EFI_MEMORY_RUNTIME)) {
+    Status = gDS->SetMemorySpaceAttributes (
+                  Address,
+                  EFI_PAGE_SIZE,
+                  Descriptor.Attributes | EFI_MEMORY_RUNTIME
+                  );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_INFO, "%a:%d SetMemorySpaceAttributes failed\n", __FUNCTION__, __LINE__));
+      return Status;
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Find the power manager related info from ACPI table
+
+  @retval RETURN_SUCCESS     Successfully find out all the required information.
+  @retval RETURN_NOT_FOUND   Failed to find the required info.
+**/
+STATIC EFI_STATUS
+GetPowerManagerByParseAcpiInfo (
+  VOID
+)
+{
+  EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE    *Fadt = NULL;
+  EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp = NULL;
+  EFI_ACPI_DESCRIPTION_HEADER                  *Xsdt = NULL;
+  EFI_ACPI_DESCRIPTION_HEADER                  *Rsdt = NULL;
+  UINT32                                       *Entry32 = NULL;
+  UINTN                                         Entry32Num;
+  UINT32                                       *Signature = NULL;
+  UINTN                                         Idx;
+  EFI_STATUS           Status;
+
+  Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **)&Rsdp);
+  if (EFI_ERROR (Status)) {
+    Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **)&Rsdp);
+  }
+
+  if (EFI_ERROR (Status) || (Rsdp == NULL)) {
+    DEBUG ((DEBUG_ERROR, "EFI_ERROR or Rsdp == NULL\n"));
+    return RETURN_NOT_FOUND;
+  }
+
+  Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress;
+  Entry32    = (UINT32 *)(UINTN)(Rsdt + 1);
+  Entry32Num = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
+  for (Idx = 0; Idx < Entry32Num; Idx++) {
+    Signature = (UINT32 *)(UINTN)Entry32[Idx];
+    if (*Signature == EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+      Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;
+      DEBUG ((DEBUG_INFO, "Found Fadt in Rsdt\n"));
+      goto Done;
+    }
+  }
+
+  Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)Rsdp->XsdtAddress;
+  Entry32    = (UINT32 *)(Xsdt + 1);
+  Entry32Num = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
+  for (Idx = 0; Idx < Entry32Num; Idx++) {
+    Signature = (UINT32 *)(UINTN)Entry32[Idx];
+    if (*Signature == EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+      Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;
+      DEBUG ((DEBUG_INFO, "Found Fadt in Xsdt\n"));
+      goto Done;
+    }
+  }
+
+  DEBUG ((DEBUG_ERROR, " Fadt Not Found\n"));
+  return RETURN_NOT_FOUND;
+
+Done:
+  mPowerManager.ResetRegAddr        = Fadt->ResetReg.Address;
+  mPowerManager.ResetValue          = Fadt->ResetValue;
+  mPowerManager.SleepControlRegAddr = Fadt->SleepControlReg.Address;
+  mPowerManager.SleepStatusRegAddr  = Fadt->SleepStatusReg.Address;
+  return RETURN_SUCCESS;
+}
+
+/**
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+  event. It converts a pointer to a new virtual address.
+
+  @param[in] Event        Event whose notification function is being invoked.
+  @param[in] Context      Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+ResetSystemLibAddressChangeEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EfiConvertPointer (0, (VOID **)&mPowerManager.SleepControlRegAddr);
+  EfiConvertPointer (0, (VOID **)&mPowerManager.SleepStatusRegAddr);
+  EfiConvertPointer (0, (VOID **)&mPowerManager.ResetRegAddr);
+}
+
+/**
+  Notification function of ACPI Table change.
+
+  This is a notification function registered on ACPI Table change event.
+  It saves the Century address stored in ACPI FADT table.
+
+  @param  Event        Event whose notification function is being invoked.
+  @param  Context      Pointer to the notification function's context.
+**/
+STATIC VOID
+AcpiNotificationEvent (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  EFI_STATUS                       Status;
+
+  Status = GetPowerManagerByParseAcpiInfo ();
+  if (EFI_ERROR (Status)) {
+    return ;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: sleepControl %llx\n", __FUNCTION__, mPowerManager.SleepControlRegAddr));
+  ASSERT (mPowerManager.SleepControlRegAddr);
+  Status =  SetMemoryAttributesRunTime (mPowerManager.SleepControlRegAddr);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a:%d\n",  __FUNCTION__, __LINE__));
+    return ;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: sleepStatus %llx\n", __FUNCTION__, mPowerManager.SleepStatusRegAddr));
+  ASSERT (mPowerManager.SleepStatusRegAddr);
+  Status =  SetMemoryAttributesRunTime (mPowerManager.SleepStatusRegAddr);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a:%d\n",  __FUNCTION__, __LINE__));
+    return ;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: ResetReg %llx\n", __FUNCTION__, mPowerManager.ResetRegAddr));
+  ASSERT (mPowerManager.ResetRegAddr);
+  Status =  SetMemoryAttributesRunTime (mPowerManager.ResetRegAddr);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a:%d\n",  __FUNCTION__, __LINE__));
+  }
+  return ;
+}
+
+/**
+  The constructor function to Register ACPI Table change event and Address Change Event.
+
+  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+ResetSystemLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   Event;
+  EFI_EVENT   ResetSystemVirtualNotifyEvent;
+
+  Status = gBS->CreateEventEx (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    AcpiNotificationEvent,
+                    NULL,
+                    &gEfiAcpiTableGuid,
+                    &Event
+                    );
+
+  //
+  // Register SetVirtualAddressMap () notify function
+  //
+  Status = gBS->CreateEvent (
+                  EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+                  TPL_NOTIFY,
+                  ResetSystemLibAddressChangeEvent,
+                  NULL,
+                  &ResetSystemVirtualNotifyEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
new file mode 100644
index 0000000000..48c7ea2dc3
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
@@ -0,0 +1,41 @@
+## @file
+#  DXE library instance for ResetSystem library class for loongarch.
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 1.29
+  BASE_NAME                      = ResetSystemLib
+  FILE_GUID                      = 3d6faf60-804a-4ca9-a36a-1a92416919d0
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = ResetSystemLib|DXE_DRIVER DXE_RUNTIME_DRIVER SMM_CORE DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION
+  CONSTRUCTOR                    = ResetSystemLibConstructor
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  DxeResetSystemAcpiGed.c
+  ResetSystemAcpiGed.c
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  DxeServicesTableLib
+  IoLib
+  UefiLib
+
+[Guids]
+  gEfiAcpi10TableGuid                           ## PRODUCES           ## SystemTable
+  gEfiAcpiTableGuid                             ## PRODUCES           ## SystemTable
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c
new file mode 100644
index 0000000000..d15cc70b4b
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c
@@ -0,0 +1,128 @@
+/** @file
+  ResetSystem library implementation.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <PiPei.h>
+#include <Library/BaseLib.h>        // CpuDeadLoop()
+#include <Library/DebugLib.h>
+#include <Library/ResetSystemLib.h> // ResetCold()
+#include <Library/IoLib.h>
+#include "ResetSystemAcpiGed.h"
+
+POWER_MANAGER mPowerManager;
+
+/**
+  Calling this function causes a system-wide reset. This sets
+  all circuitry within the system to its initial state. This type of reset
+  is asynchronous to system operation and operates without regard to
+  cycle boundaries.
+
+  System reset should not return, if it returns, it means the system does
+  not support cold reset.
+**/
+STATIC VOID
+AcpiGedReset (
+  VOID
+  )
+{
+  MmioWrite8 (
+    (UINTN)mPowerManager.ResetRegAddr,
+    mPowerManager.ResetValue
+    );
+
+  CpuDeadLoop ();
+}
+
+/**
+  This function causes the system to enter a power state equivalent
+    to the ACPI S5 states.
+
+ * */
+STATIC VOID
+AcpiGedShutdown (
+  VOID
+  )
+{
+  MmioWrite8 (
+    (UINTN)mPowerManager.SleepControlRegAddr,
+    (1 << 5) /* enable bit */ |
+    (5 << 2) /* typ == S5  */
+    );
+
+  CpuDeadLoop ();
+}
+
+/**
+  This function causes a system-wide reset (cold reset), in which
+  all circuitry within the system returns to its initial state. This type of
+  reset is asynchronous to system operation and operates without regard to
+  cycle boundaries.
+
+  If this function returns, it means that the system does not support cold
+  reset.
+**/
+VOID EFIAPI
+ResetCold (
+  VOID
+  )
+{
+  AcpiGedReset ();
+}
+
+/**
+  This function causes a system-wide initialization (warm reset), in which all
+  processors are set to their initial state. Pending cycles are not corrupted.
+
+  If this function returns, it means that the system does not support warm
+  reset.
+**/
+VOID EFIAPI
+ResetWarm (
+  VOID
+  )
+{
+  AcpiGedReset ();
+}
+
+/**
+  This function causes a systemwide reset. The exact type of the reset is
+  defined by the EFI_GUID that follows the Null-terminated Unicode string passed
+  into ResetData. If the platform does not recognize the EFI_GUID in ResetData
+  the platform must pick a supported reset type to perform.The platform may
+  optionally log the parameters from any non-normal reset that occurs.
+
+  @param[in]  DataSize   The size, in bytes, of ResetData.
+  @param[in]  ResetData  The data buffer starts with a Null-terminated string,
+                         followed by the EFI_GUID.
+**/
+VOID
+EFIAPI
+ResetPlatformSpecific (
+  IN UINTN  DataSize,
+  IN VOID   *ResetData
+  )
+{
+  AcpiGedReset ();
+}
+
+/**
+  This function causes the system to enter a power state equivalent
+  to the ACPI G2/S5 or G3 states.
+
+  If this function returns, it means that the system does not support shut down
+  reset.
+**/
+VOID EFIAPI
+ResetShutdown (
+  VOID
+  )
+{
+  AcpiGedShutdown ();
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h
new file mode 100644
index 0000000000..e504e870f9
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h
@@ -0,0 +1,23 @@
+/** @file
+  ResetSystem lib head file.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef RESET_SYSTEM_ACPI_GED_H_
+#define RESET_SYSTEM_ACPI_GED_H_
+
+#include <Base.h>
+
+typedef struct {
+  UINT64  SleepControlRegAddr;
+  UINT64  SleepStatusRegAddr;
+  UINT64  ResetRegAddr;
+  UINT8   ResetValue;
+} POWER_MANAGER;
+
+extern POWER_MANAGER mPowerManager;
+#endif // RESET_SYSTEM_ACPI_GED_H_
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 14/15] Platform/Loongson: Support Dxe
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (12 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 13/15] Platform/Loongson: Add Reset System Lib xianglai
@ 2022-11-11  8:25 ` xianglai
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 15/15] Platform/Loongson: Add Readme xianglai
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Support Dxe for LoogArch.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../Loongson/LoongArchQemuPkg/Loongson.dec    |  13 +
 .../Loongson/LoongArchQemuPkg/Loongson.dsc    | 421 ++++++++++++++++++
 .../Loongson/LoongArchQemuPkg/Loongson.fdf    | 245 ++++++++++
 .../LoongArchQemuPkg/Loongson.fdf.inc         |  42 ++
 4 files changed, 721 insertions(+)

diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
index aeae75a678..54a50738ec 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
@@ -27,13 +27,21 @@
 
 [Guids]
   gLoongArchQemuPkgTokenSpaceGuid  = { 0x0e0383ce, 0x0151, 0x4d01, { 0x80, 0x0e, 0x3f, 0xef, 0x8b, 0x27, 0x6d, 0x52 } }
+  gEfiLoongsonBootparamsTableGuid  = { 0x4660f721, 0x2ec5, 0x416a, { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } }
+
+[Protocols]
 
 ## In the PcdsFixedAtBuild and PcdsDynamic areas, numbers start at 0x0.
 [PcdsFixedAtBuild, PcdsDynamic]
   gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase|0x0|UINT64|0x00000000
   gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize|0x0|UINT32|0x00000001
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvOffset|0x0|UINT64|0x00000002
   gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvBase|0x0|UINT64|0x00000003
   gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvSize|0x0|UINT32|0x00000004
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecModuleBase|0x0|UINT64|0x00000005
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecModuleSize|0x0|UINT32|0x00000006
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashEventLogBase|0x0|UINT64|0x00000007
+  gLoongArchQemuPkgTokenSpaceGuid.PcdFlashEventLogSize|0x0|UINT32|0x00000008
   gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase|0x0|UINT64|0x00000009
   gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreePadding|256|UINT32|0x0000000a
 
@@ -48,6 +56,8 @@
 [PcdsFixedAtBuild.LOONGARCH64]
    gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00010000
    gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00010001
+   gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceSpaceStartAddress|0x10000000|UINT32|0x00010002
+   gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceSpaceLength|0x80000000|UINT32|0x00010003
 
 ## In the PcdsDynamic area, numbers start at 0x20000.
 [PcdsDynamic]
@@ -59,3 +69,6 @@
   gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud|0x0|UINT64|0x00020005
   gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd|0x0|UINT64|0x00020006
   gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte|0x0|UINT64|0x00020007
+
+## In the PcdsFeatureFlag area, numbers start at 0x30000.
+[PcdsFeatureFlag]
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
index b78a7e3b49..6f71280c4d 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
@@ -24,6 +24,25 @@
   FLASH_DEFINITION               = Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
   TTY_TERMINAL                   = FALSE
 
+  #
+  # Defines for default states.  These can be changed on the command line.
+  # -D FLAG=VALUE
+  DEFINE TTY_TERMINAL            = FALSE
+  DEFINE SECURE_BOOT_ENABLE      = FALSE
+  DEFINE TPM2_ENABLE             = FALSE
+  DEFINE TPM2_CONFIG_ENABLE      = FALSE
+
+  #
+  # Network definition
+  #
+  DEFINE NETWORK_IP6_ENABLE              = FALSE
+  DEFINE NETWORK_HTTP_BOOT_ENABLE        = FALSE
+  DEFINE NETWORK_SNP_ENABLE              = FALSE
+  DEFINE NETWORK_TLS_ENABLE              = FALSE
+  DEFINE NETWORK_ALLOW_HTTP_CONNECTIONS  = TRUE
+  DEFINE NETWORK_ISCSI_ENABLE            = FALSE
+
+!include NetworkPkg/NetworkDefines.dsc.inc
 ############################################################################
 #
 # Defines for default states.  These can be changed on the command line.
@@ -37,6 +56,8 @@
   #
   GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
 
+!include NetworkPkg/NetworkBuildOptions.dsc.inc
+
 [BuildOptions.LOONGARCH64.EDKII.SEC]
   *_*_*_CC_FLAGS                 =
 
@@ -46,6 +67,14 @@
 [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
   GCC:*_*_LOONGARCH64_DLINK_FLAGS = -z common-page-size=0x10000
 
+################################################################################
+#
+# SKU Identification section - list of all SKU IDs supported by this Platform.
+#
+################################################################################
+[SkuIds]
+  0|DEFAULT
+
 ################################################################################
 #
 # Library Class section - list of all Library Classes needed by this Platform.
@@ -59,19 +88,93 @@
   TimerLib                         | Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
   PrintLib                         | MdePkg/Library/BasePrintLib/BasePrintLib.inf
   BaseMemoryLib                    | MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+
+  # Networking Requirements
+!include NetworkPkg/NetworkLibs.dsc.inc
+!if $(NETWORK_TLS_ENABLE) == TRUE
+  TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf
+!endif
+
   BaseLib                          | MdePkg/Library/BaseLib/BaseLib.inf
+  SafeIntLib                       | MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
+  TimeBaseLib                      | EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
+  BmpSupportLib                    | MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
+  SynchronizationLib               | MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
+  CpuLib                           | MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
   PerformanceLib                   | MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
   PeCoffLib                        | MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
   CacheMaintenanceLib              | MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
   UefiDecompressLib                | MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
+  UefiHiiServicesLib               | MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+  HiiLib                           | MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+  CapsuleLib                       | MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+  DxeServicesLib                   | MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+  DxeServicesTableLib              | MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
   PeCoffGetEntryPointLib           | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+  PciLib                           | MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf
+  PciExpressLib                    | OvmfPkg/Library/BaseCachingPciExpressLib/BaseCachingPciExpressLib.inf
+  PciCapLib                        | OvmfPkg/Library/BasePciCapLib/BasePciCapLib.inf
+  PciCapPciSegmentLib              | OvmfPkg/Library/BasePciCapPciSegmentLib/BasePciCapPciSegmentLib.inf
+  PciCapPciIoLib                   | OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.inf
+  DxeHardwareInfoLib               | OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
   IoLib                            | MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
   SerialPortLib                    | Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
+  EfiResetSystemLib                | Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
+  ResetSystemLib                   | Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
+
+  UefiLib                          | MdePkg/Library/UefiLib/UefiLib.inf
+  UefiBootServicesTableLib         | MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+  UefiRuntimeServicesTableLib      | MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+  UefiDriverEntryPoint             | MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+  UefiApplicationEntryPoint        | MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+  DevicePathLib                    | MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.inf
+  FileHandleLib                    | MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+  SecurityManagementLib            | MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
+  UefiUsbLib                       | MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
+  SerializeVariablesLib            | OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf
+  CustomizedDisplayLib             | MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
   DebugPrintErrorLevelLib          | MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+  TpmMeasurementLib                | MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+  AuthVariableLib                  | MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
+  VarCheckLib                      | MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
+  VariablePolicyLib                | MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
+  VariablePolicyHelperLib          | MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
+  SortLib                          | MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
   FdtLib                           | EmbeddedPkg/Library/FdtLib/FdtLib.inf
+  PciPcdProducerLib                | OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+  PciSegmentLib                    | MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+  PciHostBridgeLib                 | OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
+  PciHostBridgeUtilityLib          | OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
+  MmuLib                           | Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
+  FileExplorerLib                  | MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+
+!if $(HTTP_BOOT_ENABLE) == TRUE
+  HttpLib                          | MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.inf
+!endif
+  UefiBootManagerLib               | MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
+  OrderedCollectionLib             | MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
+  ReportStatusCodeLib              | MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+
+  PeCoffGetEntryPointLib           | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
   PeCoffExtraActionLib             | MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
   DebugAgentLib                    | MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+  CpuExceptionHandlerLib           | MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
+
+  PlatformBootManagerLib           | Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+  BootLogoLib                      | MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
+  QemuBootOrderLib                 | OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf
+  QemuFwCfgSimpleParserLib         | OvmfPkg/Library/QemuFwCfgSimpleParserLib/QemuFwCfgSimpleParserLib.inf
+  QemuLoadImageLib                 | OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
+
+  #
+  # Virtio Support
+  #
+  VirtioLib                        | OvmfPkg/Library/VirtioLib/VirtioLib.inf
+  FrameBufferBltLib                | MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
+  QemuFwCfgLib                     | OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.inf
+  DebugLib                         | MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
   PeiServicesLib                   | MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+  VariableFlashInfoLib             | MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf
 
 [LibraryClasses.common.SEC]
   ReportStatusCodeLib              | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
@@ -104,17 +207,88 @@
   QemuFwCfgLib                     | Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
   MmuLib                           | Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
 
+[LibraryClasses.common.DXE_CORE]
+  HobLib                           | MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
+  DxeCoreEntryPoint                | MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf
+  MemoryAllocationLib              | MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
+  ReportStatusCodeLib              | MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+  PcdLib                           | MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  HobLib                           | MdePkg/Library/DxeHobLib/DxeHobLib.inf
+  DxeCoreEntryPoint                | MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf
+  MemoryAllocationLib              | MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+  ReportStatusCodeLib              | MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
+  UefiRuntimeLib                   | MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+  ExtractGuidedSectionLib          | MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf
+  QemuFwCfgS3Lib                   | OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+  RealTimeClockLib                 | Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf
+  VariablePolicyLib                | MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
+  QemuFwCfgLib                     | Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+  EfiResetSystemLib                | Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
+  ResetSystemLib                   | Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
+!if $(TARGET) != RELEASE
+  DebugLib                         | MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDebugLibSerialPort.inf
+!endif
+
+[LibraryClasses.common.UEFI_DRIVER]
+  PcdLib                           | MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  HobLib                           | MdePkg/Library/DxeHobLib/DxeHobLib.inf
+  DxeCoreEntryPoint                | MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf
+  MemoryAllocationLib              | MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+  ReportStatusCodeLib              | MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+  UefiScsiLib                      | MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
+  ExtractGuidedSectionLib          | MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf
+  QemuFwCfgLib                     | OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+  PcdLib                           | MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  HobLib                           | MdePkg/Library/DxeHobLib/DxeHobLib.inf
+  MemoryAllocationLib              | MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+  ReportStatusCodeLib              | MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+  UefiScsiLib                      | MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
+  CpuExceptionHandlerLib           | UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+  ExtractGuidedSectionLib          | MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+  QemuFwCfgS3Lib                   | OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+  QemuFwCfgLib                     | OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.inf
+
+[LibraryClasses.common.UEFI_APPLICATION]
+  PcdLib                           | MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  HobLib                           | MdePkg/Library/DxeHobLib/DxeHobLib.inf
+  MemoryAllocationLib              | MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+  ExtractGuidedSectionLib          | MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+
 ################################################################################
 #
 # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
 #
 ################################################################################
+[PcdsFeatureFlag]
+   gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport               | FALSE
+#  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial               | TRUE
+#  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory               | TRUE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress        | TRUE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport                   | TRUE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport                   | FALSE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport         | FALSE
+  gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation            | TRUE
+  gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation           | TRUE
 [PcdsFixedAtBuild]
 ## BaseLib ##
   gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength               | 1000000
   gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength                 | 1000000
   gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength                  | 1000000
+  gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout                          | 10000000
 
+  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize               | 1
+  gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange | FALSE
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler              | 0x10
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize                    | 0x2000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize       | 0x8000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress                     | 0x0
+  gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize                        | 48
+  gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize                            | 32
+  gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask             | 0x07
   gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel                     | 0x8000004F
   # DEBUG_INIT      0x00000001  // Initialization
   # DEBUG_WARN      0x00000002  // Warnings
@@ -158,6 +332,60 @@
   # 0x90000000 - 0xA0000000
   #
   gLoongArchQemuPkgTokenSpaceGuid.PcdUefiRamTop                        | 0x10000000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions           | 0x06
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile                | { 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }
+
+  #
+  # Network Pcds
+  #
+!include NetworkPkg/NetworkPcds.dsc.inc
+################################################################################
+#
+# Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+[PcdsDynamicDefault]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase         | 0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64       | 0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64       | 0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase       | 0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64     | 0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved         | 0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration           | FALSE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution          | 800
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution            | 600
+  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut                      | 2
+
+  # Set video resolution for text setup.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution     | 640
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution       | 480
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion                      | 0x0300
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosDocRev                       | 0x0
+
+  gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize                           | 0x40000000
+
+  ## If TRUE, OvmfPkg/AcpiPlatformDxe will not wait for PCI
+  #  enumeration to complete before installing ACPI tables.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration           |TRUE
+  gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation                         |0x0
+  # set PcdPciExpressBaseAddress to MAX_UINT64, which signifies that this
+  # PCD and PcdPciDisableBusEnumeration above have not been assigned yet
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress                    |0xFFFFFFFFFFFFFFFF
+
+  #
+  # IPv4 and IPv6 PXE Boot support.
+  #
+  gEfiNetworkPkgTokenSpaceGuid.PcdIPv4PXESupport                       | 0x01
+  gEfiNetworkPkgTokenSpaceGuid.PcdIPv6PXESupport                       | 0x01
+
+  #
+  # SMBIOS entry point version
+  #
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0300
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosDocRev|0x0
+  gUefiOvmfPkgTokenSpaceGuid.PcdQemuSmbiosValidated|TRUE
 
 [Components]
 
@@ -184,3 +412,196 @@
     <LibraryClasses>
       PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
   }
+
+  #
+  # DXE Phase modules
+  #
+  MdeModulePkg/Core/Dxe/DxeMain.inf {
+    <LibraryClasses>
+      NULL                             | MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+      DevicePathLib                    | MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+      ExtractGuidedSectionLib          | MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+  }
+
+  MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
+  MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
+  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf  {
+   <LibraryClasses>
+      PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  }
+
+  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+  Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
+  MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+  MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+  MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+  Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
+  MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+  MdeModulePkg/Universal/Metronome/Metronome.inf
+  EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+
+  #
+  # Variable
+  #
+
+  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
+    <LibraryClasses>
+      PlatformFvbLib|OvmfPkg/Library/EmuVariableFvbLib/EmuVariableFvbLib.inf
+  }
+  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
+    <LibraryClasses>
+      NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+      BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+  }
+
+  #
+  # Platform Driver
+  #
+  OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
+  OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
+  OvmfPkg/VirtioRngDxe/VirtioRng.inf
+
+  #
+  # File system
+  #
+  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+  MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+  MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+  FatPkg/EnhancedFatDxe/Fat.inf
+  MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
+  OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf
+
+  #
+  #BDS
+  #
+  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf {
+    <LibraryClasses>
+      DevicePathLib                    | MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+      PcdLib                           | MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  }
+  MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+  MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+  MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+  MdeModulePkg/Logo/LogoDxe.inf
+  MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+  MdeModulePkg/Application/UiApp/UiApp.inf {
+    <LibraryClasses>
+      NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
+      NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
+      NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
+  }
+
+  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf {
+    <LibraryClasses>
+      NULL|OvmfPkg/Library/BlobVerifierLibNull/BlobVerifierLibNull.inf
+  }
+
+  #
+  # Network Support
+  #
+#!include NetworkPkg/NetworkComponents.dsc.inc
+
+#  NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf {
+#    <LibraryClasses>
+#      NULL|OvmfPkg/Library/PxeBcPcdProducerLib/PxeBcPcdProducerLib.inf
+#  }
+
+!if $(NETWORK_TLS_ENABLE) == TRUE
+  NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf {
+    <LibraryClasses>
+      NULL|OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf
+  }
+!endif
+  OvmfPkg/VirtioNetDxe/VirtioNet.inf
+
+  #
+  # IDE/SCSI
+  #
+  OvmfPkg/SataControllerDxe/SataControllerDxe.inf
+  MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
+  MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
+  MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+  MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+  #
+  # SMBIOS Support
+  #
+  MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf {
+    <LibraryClasses>
+      NULL                             | OvmfPkg/Library/SmbiosVersionLib/DetectSmbiosVersionLib.inf
+  }
+  OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
+
+  #
+  # PCI
+  #
+  Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
+  EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf
+  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+  OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
+  OvmfPkg/Virtio10Dxe/Virtio10.inf
+
+  #
+  # Console
+  #
+  MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+  MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+  MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+  MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
+  MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+  MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf {
+    <LibraryClasses>
+      PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  }
+
+  #
+  # Video
+  #
+  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
+  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
+  OvmfPkg/PlatformDxe/Platform.inf
+
+  #
+  # Usb Support
+  #
+  MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf
+  MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
+  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
+  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
+  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+
+  #
+  # ACPI Support
+  #
+  MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
+  MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
+  OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
+
+  #
+  #app
+  #
+  ShellPkg/Application/Shell/Shell.inf {
+    <LibraryClasses>
+      ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
+      NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf
+      NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf
+      NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf
+      NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf
+      NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
+      NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
+      NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf
+      HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
+      ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+      FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+      SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+      PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+      BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
+<PcdsFixedAtBuild>
+      gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
+      gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+      gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
+  }
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
index 8e257f2392..34bcdf0d9c 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
@@ -22,6 +22,14 @@ $(SECFV_OFFSET)|$(SECFV_SIZE)
 gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase|gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
 FV = SECFV
 
+$(PEIFV_OFFSET)|$(PEIFV_SIZE)
+gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase|gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize
+FV = PEIFV
+
+$(DXEFV_OFFSET)|$(DXEFV_SIZE)
+gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvBase|gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvSize
+FV = FVMAIN_COMPACT
+
 #####################################################################################################
 [FV.SECFV]
 FvNameGuid         = 587d4265-5e71-41da-9c35-4258551f1e22
@@ -79,6 +87,181 @@ INF  MdeModulePkg/Universal/PCD/Pei/Pcd.inf
 INF  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
 INF  Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
 
+#####################################################################################################
+[FV.DXEFV]
+FvNameGuid         = 5d19a5b3-130f-459b-a292-9270a9e6bc62
+BlockSize          = $(BLOCK_SIZE)
+FvAlignment        = 16
+ERASE_POLARITY     = 1
+MEMORY_MAPPED      = TRUE
+STICKY_WRITE       = TRUE
+LOCK_CAP           = TRUE
+LOCK_STATUS        = TRUE
+READ_DISABLED_CAP  = TRUE
+READ_ENABLED_CAP   = TRUE
+READ_STATUS        = TRUE
+READ_LOCK_CAP      = TRUE
+READ_LOCK_STATUS   = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP  = TRUE
+WRITE_STATUS       = TRUE
+WRITE_LOCK_CAP     = TRUE
+WRITE_LOCK_STATUS  = TRUE
+
+APRIORI DXE {
+  INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+  INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+}
+
+#
+# DXE Phase modules
+#
+INF  MdeModulePkg/Core/Dxe/DxeMain.inf
+
+INF  MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
+INF  MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
+INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+INF  Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
+INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+INF  Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
+INF  MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+INF  MdeModulePkg/Universal/Metronome/Metronome.inf
+INF  MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+INF  MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+INF  EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+INF  MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+
+#
+# Variable
+#
+INF  OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
+INF  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+#
+# PCI
+#
+INF  Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
+INF  EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf
+INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+INF  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+INF  OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
+INF  OvmfPkg/Virtio10Dxe/Virtio10.inf
+
+#
+# Platform Driver
+#
+INF  OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
+INF  OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
+INF  OvmfPkg/VirtioRngDxe/VirtioRng.inf
+INF  OvmfPkg/VirtioNetDxe/VirtioNet.inf
+
+#
+# Console
+#
+INF  MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+INF  MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+INF  MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+INF  MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
+INF  MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+INF  MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+
+#
+#Video
+#
+INF  OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
+INF  OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
+INF  OvmfPkg/PlatformDxe/Platform.inf
+
+#
+# IDE
+#
+INF  OvmfPkg/SataControllerDxe/SataControllerDxe.inf
+INF  MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
+INF  MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
+INF  MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+INF  MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+#
+# Usb Support
+#
+INF  MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf
+INF  MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
+INF  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
+INF  MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+INF  MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
+INF  MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+
+#
+#BDS
+#
+INF  MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+INF  MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+INF  MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+INF  MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+INF  MdeModulePkg/Logo/LogoDxe.inf
+INF  MdeModulePkg/Application/UiApp/UiApp.inf
+INF  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
+
+#
+#Smbios
+#
+INF  MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
+INF  OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
+
+#
+#Acpi
+#
+INF  MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
+INF  MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
+INF  OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
+
+#
+# Network modules
+#!include NetworkPkg/Network.fdf.inc
+
+#
+# File system
+#
+INF  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+INF  MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+INF  MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+INF  FatPkg/EnhancedFatDxe/Fat.inf
+INF  MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
+INF  OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf
+
+#
+#Boot OS
+#
+INF ShellPkg/Application/Shell/Shell.inf
+
+#####################################################################################################
+[FV.FVMAIN_COMPACT]
+FvNameGuid         = af8c3fe8-9ce8-4548-884a-e3f4dd91f040
+FvAlignment        = 16
+ERASE_POLARITY     = 1
+MEMORY_MAPPED      = TRUE
+STICKY_WRITE       = TRUE
+LOCK_CAP           = TRUE
+LOCK_STATUS        = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP  = TRUE
+WRITE_STATUS       = TRUE
+WRITE_LOCK_CAP     = TRUE
+WRITE_LOCK_STATUS  = TRUE
+READ_DISABLED_CAP  = TRUE
+READ_ENABLED_CAP   = TRUE
+READ_STATUS        = TRUE
+READ_LOCK_CAP      = TRUE
+READ_LOCK_STATUS   = TRUE
+
+FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 {
+   SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE {
+     SECTION FV_IMAGE = DXEFV
+   }
+ }
+
 #####################################################################################################
 [Rule.Common.SEC]
   FILE SEC = $(NAMED_GUID) {
@@ -102,3 +285,65 @@ INF  Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
   }
 
 #####################################################################################################
+[Rule.Common.DXE_CORE]
+  FILE DXE_CORE = $(NAMED_GUID) {
+    PE32     PE32           $(INF_OUTPUT)/$(MODULE_NAME).efi
+    UI       STRING="$(MODULE_NAME)" Optional
+  }
+
+#####################################################################################################
+[Rule.Common.DXE_DRIVER]
+  FILE DRIVER = $(NAMED_GUID) {
+    DXE_DEPEX    DXE_DEPEX Optional      $(INF_OUTPUT)/$(MODULE_NAME).depex
+    PE32         PE32                    $(INF_OUTPUT)/$(MODULE_NAME).efi
+    UI       STRING="$(MODULE_NAME)" Optional
+    RAW          ACPI  Optional            |.acpi
+    RAW          ASL   Optional            |.aml
+  }
+
+#####################################################################################################
+[Rule.Common.DXE_RUNTIME_DRIVER]
+  FILE DRIVER = $(NAMED_GUID) {
+    DXE_DEPEX    DXE_DEPEX     Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+    PE32         PE32                   $(INF_OUTPUT)/$(MODULE_NAME).efi
+    UI           STRING="$(MODULE_NAME)" Optional
+  }
+
+#####################################################################################################
+[Rule.Common.UEFI_DRIVER]
+  FILE DRIVER = $(NAMED_GUID) {
+    DXE_DEPEX    DXE_DEPEX Optional  $(INF_OUTPUT)/$(MODULE_NAME).depex
+    PE32     PE32                    $(INF_OUTPUT)/$(MODULE_NAME).efi
+    UI       STRING="$(MODULE_NAME)" Optional
+  }
+
+#####################################################################################################
+[Rule.Common.UEFI_DRIVER.BINARY]
+  FILE DRIVER = $(NAMED_GUID) {
+    DXE_DEPEX DXE_DEPEX Optional      |.depex
+    PE32      PE32                    |.efi
+    UI        STRING="$(MODULE_NAME)" Optional
+    VERSION   STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+  }
+
+#####################################################################################################
+[Rule.Common.UEFI_APPLICATION]
+  FILE APPLICATION = $(NAMED_GUID) {
+    PE32     PE32                    $(INF_OUTPUT)/$(MODULE_NAME).efi
+    UI       STRING="$(MODULE_NAME)" Optional
+  }
+
+#####################################################################################################
+[Rule.Common.UEFI_APPLICATION.BINARY]
+  FILE APPLICATION = $(NAMED_GUID) {
+    PE32      PE32                    |.efi
+    UI        STRING="$(MODULE_NAME)" Optional
+    VERSION   STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+  }
+
+#####################################################################################################
+[Rule.Common.USER_DEFINED.ACPITABLE]
+  FILE FREEFORM = $(NAMED_GUID) {
+    RAW ACPI               |.acpi
+    RAW ASL                |.aml
+  }
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
index 6f17909748..3530f90c67 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
@@ -19,3 +19,45 @@ DEFINE FD_SIZE                    = 0x400000
 #Set Sec base address and size in flash
 DEFINE SECFV_OFFSET               = 0x00000000
 DEFINE SECFV_SIZE                 = 0x00010000
+
+#Set Pei base address and size in flash
+DEFINE PEIFV_OFFSET               = 0x00010000
+DEFINE PEIFV_SIZE                 = 0x00040000
+
+#Set Dxe base address and size in flash
+DEFINE DXEFV_OFFSET               = 0x00050000
+DEFINE DXEFV_SIZE                 = 0x00350000
+
+#Set Var base address and size in flash
+DEFINE VARIABLE_OFFSET            = 0x003a0000
+DEFINE VAR_ALL_SIZE               = 0x60000
+
+############################################################################
+#Set Var Flash layout
+DEFINE VARIABLE_SIZE              = 0x00010000
+DEFINE VAR_ALL_BLOCKS             = 0x60
+
+DEFINE RESERVE1_OFFSET            = $(VARIABLE_OFFSET) + $(VARIABLE_SIZE)
+DEFINE RESERVE1_SIZE              = 0xB000
+
+DEFINE RESERVE2_OFFSET            = $(RESERVE1_OFFSET) + $(RESERVE1_SIZE)
+DEFINE RESERVE2_SIZE              = 0x14000
+
+DEFINE SPARE_OFFSET               = $(RESERVE2_OFFSET) + $(RESERVE2_SIZE)
+DEFINE SPARE_SIZE                 = 0x20000
+
+DEFINE FWTWORKING_OFFSET          = $(SPARE_OFFSET) + $(SPARE_SIZE)
+DEFINE FWTWORKING_SIZE            = 0x8000
+
+DEFINE EVENT_LOG_OFFSET           = $(FWTWORKING_OFFSET) + $(FWTWORKING_SIZE)
+DEFINE EVENT_LOG_SIZE             = 0x8000
+
+# Set Variable
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 = 0
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize = $(VARIABLE_SIZE)
+
+# Set FtwSpare
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize = $(SPARE_SIZE)
+
+# Set FtwWorking
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize = $(FWTWORKING_SIZE)
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 15/15] Platform/Loongson: Add Readme.
  2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
                   ` (13 preceding siblings ...)
  2022-11-11  8:25 ` [edk2-platforms][PATCH V5 14/15] Platform/Loongson: Support Dxe xianglai
@ 2022-11-11  8:25 ` xianglai
  14 siblings, 0 replies; 18+ messages in thread
From: xianglai @ 2022-11-11  8:25 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Add Readme for LoogArch and Modify the Readme in the root directory.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 Platform/Loongson/LoongArchQemuPkg/Readme.md | 60 ++++++++++++++++++++
 Readme.md                                    |  9 +++
 2 files changed, 69 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Readme.md

diff --git a/Platform/Loongson/LoongArchQemuPkg/Readme.md b/Platform/Loongson/LoongArchQemuPkg/Readme.md
new file mode 100644
index 0000000000..7b11905f14
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Readme.md
@@ -0,0 +1,60 @@
+# Introduction
+
+  This document provides the guideline to build UEFI firmware for Qemu of LoongArch.
+
+  LoongArch is the general processor architecture of Loongson.
+
+  We can get the latest LoongArch documents or LoongArch tools at https://github.com/loongson/.
+
+# How to build (X86 Linux Environment)
+
+  1. Install LoongArch cross-tools on X86 machines.
+    Download cross-tools from https://github.com/loongson/build-tools ,Then config cross-tools env.
+    For Example:
+
+    $ wget https://github.com/loongson/build-tools/releases/download/2022.09.06/loongarch64-clfs-6.3-cross-tools-gcc-glibc.tar.xz
+    $ tar -vxf loongarch64-clfs-6.3-cross-tools-gcc-glibc.tar.xz  -C /opt
+    $ export PATH=/opt/cross-tools/bin:$PATH
+
+    Note: Please obtain the latest cross-compilation tools from https://github.com/loongson/build-tools .
+
+  2. Follow edk2-platforms/Readme.md to obtaining source code,And config build env.
+    For Example:
+
+    $ export WORKSPACE=/work/git/tianocore
+    $ mkdir -p $WORKSPACE
+    $ cd $WORKSPACE
+    $ git clone https://github.com/tianocore/edk2.git
+    $ git submodule update --init
+    $ git clone https://github.com/tianocore/edk2-platforms.git
+    $ git submodule update --init
+    $ git clone https://github.com/tianocore/edk2-non-osi.git
+    $ export PACKAGES_PATH=$PWD/edk2:$PWD/edk2-platforms:$PWD/edk2-non-osi
+
+  3. Config  cross compiler prefix.
+    For Example:
+
+    $ export GCC5_LOONGARCH64_PREFIX=loongarch64-unknown-linux-gnu-
+
+  4.Set up the build environment And  build BaseTool.
+    For Example:
+
+    $. edk2/edksetup.sh
+    $make -C edk2/BaseTools
+
+  5.Build  platform.
+    For Exmaple:
+
+    $build --buildtarget=DEBUG --tagname=GCC5 --arch=LOONGARCH64  --platform=Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
+
+  After a successful build, the resulting images can be found in `Build/{Platform Name}/{TARGET}_{TOOL_CHAIN_TAG}/FV/QEMU_EFI.fd`.
+
+  A compile script is provided here:
+
+    #!/bin/bash
+    export WORKSPACE=/work/git/tianocore
+    export PACKAGES_PATH=$WORKSPACE/edk2:$WORKSPACE/edk2-platforms
+    export GCC5_LOONGARCH64_PREFIX=loongarch64-unknown-linux-gnu-
+    . edk2/edksetup.sh
+    make -C edk2/BaseTools
+    build --buildtarget=DEBUG --tagname=GCC5 --arch=LOONGARCH64  --platform=Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
diff --git a/Readme.md b/Readme.md
index 62876b4b7d..93e4dc5255 100644
--- a/Readme.md
+++ b/Readme.md
@@ -57,6 +57,7 @@ IA32                | i?86-linux-gnu-* _or_ x86_64-linux-gnu-
 IPF                 | ia64-linux-gnu
 X64                 | x86_64-linux-gnu-
 RISCV64             | riscv64-unknown-elf-
+LOONGARCH64         | loongarch64-unknown-linux-
 
 \* i386, i486, i586 or i686
 
@@ -71,6 +72,11 @@ RISC-V open source community provides GCC toolchains for
 [riscv64-unknown-elf](https://github.com/riscv/riscv-gnu-toolchain)
 compiled to run on x86 Linux.
 
+### GCC for LoongArch
+Loonson open source community provides GCC toolchains for
+[loongarch64-unknown-elf](https://github.com/loongson/build-tools)
+compiled to run on x86 Linux
+
 ### clang
 Clang does not require separate cross compilers, but it does need a
 target-specific binutils. These are included with any prepackaged GCC toolchain
@@ -257,6 +263,9 @@ For more information, see the
 ##### Minnowboard Max/Turbot based on Intel Valleyview2 SoC
 * [Minnowboard Max](Platform/Intel/Vlv2TbltDevicePkg)
 
+## Loongson
+* [LoongArchQemu](Platform/Loongson/LoongArchQemuPkg)
+
 ## Marvell
 * [Armada 70x0](Platform/Marvell/Armada70x0Db)
 * [Armada 80x0](Platform/Marvell/Armada80x0Db)
-- 
2.31.1


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

* [edk2-platforms][PATCH V5 09/15] Platform/Loongson: Add PciCpuIoDxe driver.
  2022-11-11  9:12 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
@ 2022-11-11  9:12 ` xianglai
  2022-11-11  9:46   ` Chao Li
  0 siblings, 1 reply; 18+ messages in thread
From: xianglai @ 2022-11-11  9:12 UTC (permalink / raw)
  To: devel; +Cc: Bibo Mao, Chao Li, Leif Lindholm, Liming Gao, Michael D Kinney

Add PCI CpuIo protocol.there is no fix translation
offset between I/O port accesses and MMIO accesses.
Add PciCpuIo2Dxe driver to implement EFI_CPU_IO2_PROTOCOL
to add the translation for IO access.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Chao Li <lichao@loongson.cn>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c       | 538 ++++++++++++++++++
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h       | 207 +++++++
 .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf     |  44 ++
 3 files changed, 789 insertions(+)
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
 create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf

diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
new file mode 100644
index 0000000000..25417ff101
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
@@ -0,0 +1,538 @@
+/** @file
+  Produces the CPU I/O 2 Protocol.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/CpuIo2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "PciCpuIo2Dxe.h"
+
+//
+// Handle for the CPU I/O 2 Protocol
+//
+STATIC EFI_HANDLE  mHandle = NULL;
+
+//
+// Lookup table for increment values based on transfer widths
+//
+STATIC CONST UINT8 mInStride[] = {
+  1, // EfiCpuIoWidthUint8
+  2, // EfiCpuIoWidthUint16
+  4, // EfiCpuIoWidthUint32
+  8, // EfiCpuIoWidthUint64
+  0, // EfiCpuIoWidthFifoUint8
+  0, // EfiCpuIoWidthFifoUint16
+  0, // EfiCpuIoWidthFifoUint32
+  0, // EfiCpuIoWidthFifoUint64
+  1, // EfiCpuIoWidthFillUint8
+  2, // EfiCpuIoWidthFillUint16
+  4, // EfiCpuIoWidthFillUint32
+  8  // EfiCpuIoWidthFillUint64
+};
+
+//
+// Lookup table for increment values based on transfer widths
+//
+STATIC CONST UINT8 mOutStride[] = {
+  1, // EfiCpuIoWidthUint8
+  2, // EfiCpuIoWidthUint16
+  4, // EfiCpuIoWidthUint32
+  8, // EfiCpuIoWidthUint64
+  1, // EfiCpuIoWidthFifoUint8
+  2, // EfiCpuIoWidthFifoUint16
+  4, // EfiCpuIoWidthFifoUint32
+  8, // EfiCpuIoWidthFifoUint64
+  0, // EfiCpuIoWidthFillUint8
+  0, // EfiCpuIoWidthFillUint16
+  0, // EfiCpuIoWidthFillUint32
+  0  // EfiCpuIoWidthFillUint64
+};
+
+/**
+  Check parameters to a CPU I/O 2 Protocol service request.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  @param[in] MmioOperation  TRUE for an MMIO operation, FALSE for I/O Port operation.
+  @param[in] Width          Signifies the width of the I/O or Memory operation.
+  @param[in] Address        The base address of the I/O operation.
+  @param[in] Count          The number of I/O operations to perform. The number of
+                            bytes moved is Width size * Count, starting at Address.
+  @param[in] Buffer         For read operations, the destination buffer to store the results.
+                            For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The parameters for this request pass the checks.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+CpuIoCheckParameter (
+  IN BOOLEAN                    MmioOperation,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  )
+{
+  UINT64  MaxCount;
+  UINT64  Limit;
+
+  //
+  // Check to see if Buffer is NULL
+  //
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check to see if Width is in the valid range
+  //
+  if ((UINT32)Width >= EfiCpuIoWidthMaximum) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // For FIFO type, the target address won't increase during the access,
+  // so treat Count as 1
+  //
+  if ((Width >= EfiCpuIoWidthFifoUint8)
+    && (Width <= EfiCpuIoWidthFifoUint64))
+  {
+    Count = 1;
+  }
+
+  //
+  // Check to see if Width is in the valid range for I/O Port operations
+  //
+  Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+  if ((!MmioOperation)
+    && (Width == EfiCpuIoWidthUint64))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check to see if Address is aligned
+  //
+  if ((Address & (UINT64) (mInStride[Width] - 1)) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check to see if any address associated with this transfer exceeds the maximum
+  // allowed address.  The maximum address implied by the parameters passed in is
+  // Address + Size * Count.  If the following condition is met, then the transfer
+  // is not supported.
+  //
+  //    Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
+  //
+  // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
+  // can also be the maximum integer value supported by the CPU, this range
+  // check must be adjusted to avoid all overflow conditions.
+  //
+  // The following form of the range check is equivalent but assumes that
+  // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
+  //
+  Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
+  if (Count == 0) {
+    if (Address > Limit) {
+      return EFI_UNSUPPORTED;
+    }
+  } else {
+    MaxCount = RShiftU64 (Limit, Width);
+    if (MaxCount < (Count - 1)) {
+      return EFI_UNSUPPORTED;
+    }
+    if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  //
+  // Check to see if Buffer is aligned
+  //
+  if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width])  - 1))) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Reads memory-mapped registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[out] Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceRead (
+  IN  EFI_CPU_IO2_PROTOCOL       *This,
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN  UINT64                     Address,
+  IN  UINTN                      Count,
+  OUT VOID                       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      InStride;
+  UINT8                      OutStride;
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
+  UINT8                      *Uint8Buffer;
+  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Select loop based on the width of the transfer
+  //
+  InStride = mInStride[Width];
+  OutStride = mOutStride[Width];
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+    if (OperationWidth == EfiCpuIoWidthUint8) {
+      *Uint8Buffer = MmioRead8 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {
+      *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {
+      *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint64) {
+      *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Writes memory-mapped registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceWrite (
+  IN EFI_CPU_IO2_PROTOCOL       *This,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      InStride;
+  UINT8                      OutStride;
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
+  UINT8                      *Uint8Buffer;
+
+  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Select loop based on the width of the transfer
+  //
+  InStride = mInStride[Width];
+  OutStride = mOutStride[Width];
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+    if (OperationWidth == EfiCpuIoWidthUint8) {
+      MmioWrite8 ((UINTN)Address, *Uint8Buffer);
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {
+      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {
+      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+    } else if (OperationWidth == EfiCpuIoWidthUint64) {
+      MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Reads I/O registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[out] Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceRead (
+  IN  EFI_CPU_IO2_PROTOCOL       *This,
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN  UINT64                     Address,
+  IN  UINTN                      Count,
+  OUT VOID                       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      InStride;
+  UINT8                      OutStride;
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
+  UINT8                      *Uint8Buffer;
+
+  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Address += PcdGet64 (PcdPciIoTranslation);
+
+  //
+  // Select loop based on the width of the transfer
+  //
+  InStride = mInStride[Width];
+  OutStride = mOutStride[Width];
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+    if (OperationWidth == EfiCpuIoWidthUint8) {
+      *Uint8Buffer = MmioRead8 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {
+      *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {
+      *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Write I/O registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceWrite (
+  IN EFI_CPU_IO2_PROTOCOL       *This,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      InStride;
+  UINT8                      OutStride;
+  EFI_CPU_IO_PROTOCOL_WIDTH  OperationWidth;
+  UINT8                      *Uint8Buffer;
+
+  //
+  // Make sure the parameters are valid
+  //
+  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Address += PcdGet64 (PcdPciIoTranslation);
+
+  //
+  // Select loop based on the width of the transfer
+  //
+  InStride = mInStride[Width];
+  OutStride = mOutStride[Width];
+  OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+  for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+    if (OperationWidth == EfiCpuIoWidthUint8) {
+      MmioWrite8 ((UINTN)Address, *Uint8Buffer);
+    } else if (OperationWidth == EfiCpuIoWidthUint16) {
+      MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+    } else if (OperationWidth == EfiCpuIoWidthUint32) {
+      MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+//
+// CPU I/O 2 Protocol instance
+//
+STATIC EFI_CPU_IO2_PROTOCOL mCpuIo2 = {
+  {
+    CpuMemoryServiceRead,
+    CpuMemoryServiceWrite
+  },
+  {
+    CpuIoServiceRead,
+    CpuIoServiceWrite
+  }
+};
+
+/**
+  The user Entry Point for module CpuIo2Dxe. The user code starts with this function.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The entry point is executed successfully.
+  @retval other             Some error occurs when executing this entry point.
+**/
+EFI_STATUS
+EFIAPI
+PciCpuIo2Initialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mHandle,
+                  &gEfiCpuIo2ProtocolGuid, &mCpuIo2,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
new file mode 100644
index 0000000000..2489429df7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
@@ -0,0 +1,207 @@
+/** @file
+  Internal include file for the CPU I/O 2 Protocol.
+
+  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PCI_CPU_IO2_DXE_H_
+#define PCI_CPU_IO2_DXE_H_
+
+#define MAX_IO_PORT_ADDRESS   0xFFFF
+
+/**
+  Reads memory-mapped registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[out] Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceRead (
+  IN  EFI_CPU_IO2_PROTOCOL       *This,
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN  UINT64                     Address,
+  IN  UINTN                      Count,
+  OUT VOID                       *Buffer
+  );
+
+/**
+  Writes memory-mapped registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceWrite (
+  IN EFI_CPU_IO2_PROTOCOL       *This,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  );
+
+/**
+  Reads I/O registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[out] Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceRead (
+  IN  EFI_CPU_IO2_PROTOCOL       *This,
+  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN  UINT64                     Address,
+  IN  UINTN                      Count,
+  OUT VOID                       *Buffer
+  );
+
+/**
+  Write I/O registers.
+
+  The I/O operations are carried out exactly as requested. The caller is responsible
+  for satisfying any alignment and I/O width restrictions that a PI System on a
+  platform might require. For example on some platforms, width requests of
+  EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+  be handled by the driver.
+
+  If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+  or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+  each of the Count operations that is performed.
+
+  If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+  EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times on the same Address.
+
+  If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+  EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+  incremented for each of the Count operations that is performed. The read or
+  write operation is performed Count times from the first element of Buffer.
+
+  @param[in]  This     A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+  @param[in]  Width    Signifies the width of the I/O or Memory operation.
+  @param[in]  Address  The base address of the I/O operation.
+  @param[in]  Count    The number of I/O operations to perform. The number of
+                       bytes moved is Width size * Count, starting at Address.
+  @param[in]  Buffer   For read operations, the destination buffer to store the results.
+                       For write operations, the source buffer from which to write data.
+
+  @retval EFI_SUCCESS            The data was read from or written to the PI system.
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this PI system.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
+  @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width,
+                                 and Count is not valid for this PI system.
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceWrite (
+  IN EFI_CPU_IO2_PROTOCOL       *This,
+  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
+  IN UINT64                     Address,
+  IN UINTN                      Count,
+  IN VOID                       *Buffer
+  );
+
+#endif // PCI_CPU_IO2_DXE_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
new file mode 100644
index 0000000000..a8a14cddd2
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
@@ -0,0 +1,44 @@
+## @file
+#  Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
+#
+#  Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PciCpuIo2Dxe
+  FILE_GUID                      = 168D1A6E-F4A5-448A-9E95-795661BB3067
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PciCpuIo2Initialize
+
+#
+#  VALID_ARCHITECTURES           = LOONGARCH64
+#
+
+[Sources]
+  PciCpuIo2Dxe.c
+
+[Packages]
+  Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  BaseLib
+  DebugLib
+  IoLib
+  PcdLib
+  UefiBootServicesTableLib
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
+
+[Protocols]
+  gEfiCpuIo2ProtocolGuid                         ## PRODUCES
+
+[Depex]
+  TRUE
-- 
2.31.1



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

* Re: [edk2-platforms][PATCH V5 09/15] Platform/Loongson: Add PciCpuIoDxe driver.
  2022-11-11  9:12 ` [edk2-platforms][PATCH V5 09/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
@ 2022-11-11  9:46   ` Chao Li
  0 siblings, 0 replies; 18+ messages in thread
From: Chao Li @ 2022-11-11  9:46 UTC (permalink / raw)
  To: xianglai li
  Cc: devel@edk2.groups.io, Bibo Mao, Leif Lindholm, Liming Gao,
	Michael D Kinney

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

Reviewed-by: Chao Li <lichao@loongson.cn>

Thanks,
Chao
--------

On 11月 11 2022, at 5:12 下午, xianglai li <lixianglai@loongson.cn> wrote:
> Add PCI CpuIo protocol.there is no fix translation
>
> offset between I/O port accesses and MMIO accesses.
> Add PciCpuIo2Dxe driver to implement EFI_CPU_IO2_PROTOCOL
> to add the translation for IO access.
>
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054
>
>
> Cc: Bibo Mao <maobibo@loongson.cn>
> Cc: Chao Li <lichao@loongson.cn>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Signed-off-by: xianglai li <lixianglai@loongson.cn>
> ---
> .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c | 538 ++++++++++++++++++
> .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h | 207 +++++++
> .../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf | 44 ++
> 3 files changed, 789 insertions(+)
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
>
>
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
> new file mode 100644
> index 0000000000..25417ff101
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
> @@ -0,0 +1,538 @@
> +/** @file
> + Produces the CPU I/O 2 Protocol.
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiDxe.h>
> +
> +#include <Protocol/CpuIo2.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include "PciCpuIo2Dxe.h"
> +
> +//
> +// Handle for the CPU I/O 2 Protocol
> +//
> +STATIC EFI_HANDLE mHandle = NULL;
> +
> +//
> +// Lookup table for increment values based on transfer widths
> +//
> +STATIC CONST UINT8 mInStride[] = {
> + 1, // EfiCpuIoWidthUint8
> + 2, // EfiCpuIoWidthUint16
> + 4, // EfiCpuIoWidthUint32
> + 8, // EfiCpuIoWidthUint64
> + 0, // EfiCpuIoWidthFifoUint8
> + 0, // EfiCpuIoWidthFifoUint16
> + 0, // EfiCpuIoWidthFifoUint32
> + 0, // EfiCpuIoWidthFifoUint64
> + 1, // EfiCpuIoWidthFillUint8
> + 2, // EfiCpuIoWidthFillUint16
> + 4, // EfiCpuIoWidthFillUint32
> + 8 // EfiCpuIoWidthFillUint64
> +};
> +
> +//
> +// Lookup table for increment values based on transfer widths
> +//
> +STATIC CONST UINT8 mOutStride[] = {
> + 1, // EfiCpuIoWidthUint8
> + 2, // EfiCpuIoWidthUint16
> + 4, // EfiCpuIoWidthUint32
> + 8, // EfiCpuIoWidthUint64
> + 1, // EfiCpuIoWidthFifoUint8
> + 2, // EfiCpuIoWidthFifoUint16
> + 4, // EfiCpuIoWidthFifoUint32
> + 8, // EfiCpuIoWidthFifoUint64
> + 0, // EfiCpuIoWidthFillUint8
> + 0, // EfiCpuIoWidthFillUint16
> + 0, // EfiCpuIoWidthFillUint32
> + 0 // EfiCpuIoWidthFillUint64
> +};
> +
> +/**
> + Check parameters to a CPU I/O 2 Protocol service request.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[in] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The parameters for this request pass the checks.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +CpuIoCheckParameter (
> + IN BOOLEAN MmioOperation,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + IN VOID *Buffer
> + )
> +{
> + UINT64 MaxCount;
> + UINT64 Limit;
> +
> + //
> + // Check to see if Buffer is NULL
> + //
> + if (Buffer == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Check to see if Width is in the valid range
> + //
> + if ((UINT32)Width >= EfiCpuIoWidthMaximum) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // For FIFO type, the target address won't increase during the access,
> + // so treat Count as 1
> + //
> + if ((Width >= EfiCpuIoWidthFifoUint8)
> + && (Width <= EfiCpuIoWidthFifoUint64))
> + {
> + Count = 1;
> + }
> +
> + //
> + // Check to see if Width is in the valid range for I/O Port operations
> + //
> + Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
> + if ((!MmioOperation)
> + && (Width == EfiCpuIoWidthUint64))
> + {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Check to see if Address is aligned
> + //
> + if ((Address & (UINT64) (mInStride[Width] - 1)) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Check to see if any address associated with this transfer exceeds the maximum
> + // allowed address. The maximum address implied by the parameters passed in is
> + // Address + Size * Count. If the following condition is met, then the transfer
> + // is not supported.
> + //
> + // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
> + //
> + // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
> + // can also be the maximum integer value supported by the CPU, this range
> + // check must be adjusted to avoid all overflow conditions.
> + //
> + // The following form of the range check is equivalent but assumes that
> + // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
> + //
> + Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
> + if (Count == 0) {
> + if (Address > Limit) {
> + return EFI_UNSUPPORTED;
> + }
> + } else {
> + MaxCount = RShiftU64 (Limit, Width);
> + if (MaxCount < (Count - 1)) {
> + return EFI_UNSUPPORTED;
> + }
> + if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
> + return EFI_UNSUPPORTED;
> + }
> + }
> +
> + //
> + // Check to see if Buffer is aligned
> + //
> + if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Reads memory-mapped registers.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
> + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
> + each of the Count operations that is performed.
> +
> + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
> + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times on the same Address.
> +
> + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
> + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times from the first element of Buffer.
> +
> + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[out] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The data was read from or written to the PI system.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +CpuMemoryServiceRead (
> + IN EFI_CPU_IO2_PROTOCOL *This,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + OUT VOID *Buffer
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 InStride;
> + UINT8 OutStride;
> + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
> + UINT8 *Uint8Buffer;
> + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Select loop based on the width of the transfer
> + //
> + InStride = mInStride[Width];
> + OutStride = mOutStride[Width];
> + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
> + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
> + if (OperationWidth == EfiCpuIoWidthUint8) {
> + *Uint8Buffer = MmioRead8 ((UINTN)Address);
> + } else if (OperationWidth == EfiCpuIoWidthUint16) {
> + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
> + } else if (OperationWidth == EfiCpuIoWidthUint32) {
> + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
> + } else if (OperationWidth == EfiCpuIoWidthUint64) {
> + *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
> + }
> + }
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Writes memory-mapped registers.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
> + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
> + each of the Count operations that is performed.
> +
> + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
> + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times on the same Address.
> +
> + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
> + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times from the first element of Buffer.
> +
> + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[in] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The data was read from or written to the PI system.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +CpuMemoryServiceWrite (
> + IN EFI_CPU_IO2_PROTOCOL *This,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + IN VOID *Buffer
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 InStride;
> + UINT8 OutStride;
> + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
> + UINT8 *Uint8Buffer;
> +
> + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Select loop based on the width of the transfer
> + //
> + InStride = mInStride[Width];
> + OutStride = mOutStride[Width];
> + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
> + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
> + if (OperationWidth == EfiCpuIoWidthUint8) {
> + MmioWrite8 ((UINTN)Address, *Uint8Buffer);
> + } else if (OperationWidth == EfiCpuIoWidthUint16) {
> + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
> + } else if (OperationWidth == EfiCpuIoWidthUint32) {
> + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
> + } else if (OperationWidth == EfiCpuIoWidthUint64) {
> + MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
> + }
> + }
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Reads I/O registers.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
> + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
> + each of the Count operations that is performed.
> +
> + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
> + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times on the same Address.
> +
> + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
> + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times from the first element of Buffer.
> +
> + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[out] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The data was read from or written to the PI system.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +CpuIoServiceRead (
> + IN EFI_CPU_IO2_PROTOCOL *This,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + OUT VOID *Buffer
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 InStride;
> + UINT8 OutStride;
> + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
> + UINT8 *Uint8Buffer;
> +
> + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Address += PcdGet64 (PcdPciIoTranslation);
> +
> + //
> + // Select loop based on the width of the transfer
> + //
> + InStride = mInStride[Width];
> + OutStride = mOutStride[Width];
> + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
> +
> + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
> + if (OperationWidth == EfiCpuIoWidthUint8) {
> + *Uint8Buffer = MmioRead8 ((UINTN)Address);
> + } else if (OperationWidth == EfiCpuIoWidthUint16) {
> + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
> + } else if (OperationWidth == EfiCpuIoWidthUint32) {
> + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
> + }
> + }
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Write I/O registers.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
> + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
> + each of the Count operations that is performed.
> +
> + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
> + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times on the same Address.
> +
> + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
> + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times from the first element of Buffer.
> +
> + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[in] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The data was read from or written to the PI system.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +CpuIoServiceWrite (
> + IN EFI_CPU_IO2_PROTOCOL *This,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + IN VOID *Buffer
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 InStride;
> + UINT8 OutStride;
> + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
> + UINT8 *Uint8Buffer;
> +
> + //
> + // Make sure the parameters are valid
> + //
> + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Address += PcdGet64 (PcdPciIoTranslation);
> +
> + //
> + // Select loop based on the width of the transfer
> + //
> + InStride = mInStride[Width];
> + OutStride = mOutStride[Width];
> + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
> +
> + for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
> + if (OperationWidth == EfiCpuIoWidthUint8) {
> + MmioWrite8 ((UINTN)Address, *Uint8Buffer);
> + } else if (OperationWidth == EfiCpuIoWidthUint16) {
> + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
> + } else if (OperationWidth == EfiCpuIoWidthUint32) {
> + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
> + }
> + }
> + return EFI_SUCCESS;
> +}
> +
> +//
> +// CPU I/O 2 Protocol instance
> +//
> +STATIC EFI_CPU_IO2_PROTOCOL mCpuIo2 = {
> + {
> + CpuMemoryServiceRead,
> + CpuMemoryServiceWrite
> + },
> + {
> + CpuIoServiceRead,
> + CpuIoServiceWrite
> + }
> +};
> +
> +/**
> + The user Entry Point for module CpuIo2Dxe. The user code starts with this function.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval EFI_SUCCESS The entry point is executed successfully.
> + @retval other Some error occurs when executing this entry point.
> +**/
> +EFI_STATUS
> +EFIAPI
> +PciCpuIo2Initialize (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> +
> + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &mHandle,
> + &gEfiCpuIo2ProtocolGuid, &mCpuIo2,
> + NULL
> + );
> + ASSERT_EFI_ERROR (Status);
> + return Status;
> +}
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
> new file mode 100644
> index 0000000000..2489429df7
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
> @@ -0,0 +1,207 @@
> +/** @file
> + Internal include file for the CPU I/O 2 Protocol.
> +
> + Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef PCI_CPU_IO2_DXE_H_
> +#define PCI_CPU_IO2_DXE_H_
> +
> +#define MAX_IO_PORT_ADDRESS 0xFFFF
> +
> +/**
> + Reads memory-mapped registers.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
> + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
> + each of the Count operations that is performed.
> +
> + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
> + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times on the same Address.
> +
> + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
> + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times from the first element of Buffer.
> +
> + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[out] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The data was read from or written to the PI system.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +CpuMemoryServiceRead (
> + IN EFI_CPU_IO2_PROTOCOL *This,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + OUT VOID *Buffer
> + );
> +
> +/**
> + Writes memory-mapped registers.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
> + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
> + each of the Count operations that is performed.
> +
> + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
> + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times on the same Address.
> +
> + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
> + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times from the first element of Buffer.
> +
> + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[in] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The data was read from or written to the PI system.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +CpuMemoryServiceWrite (
> + IN EFI_CPU_IO2_PROTOCOL *This,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + IN VOID *Buffer
> + );
> +
> +/**
> + Reads I/O registers.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
> + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
> + each of the Count operations that is performed.
> +
> + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
> + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times on the same Address.
> +
> + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
> + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times from the first element of Buffer.
> +
> + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[out] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The data was read from or written to the PI system.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +CpuIoServiceRead (
> + IN EFI_CPU_IO2_PROTOCOL *This,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + OUT VOID *Buffer
> + );
> +
> +/**
> + Write I/O registers.
> +
> + The I/O operations are carried out exactly as requested. The caller is responsible
> + for satisfying any alignment and I/O width restrictions that a PI System on a
> + platform might require. For example on some platforms, width requests of
> + EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
> + be handled by the driver.
> +
> + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
> + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
> + each of the Count operations that is performed.
> +
> + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
> + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times on the same Address.
> +
> + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
> + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
> + incremented for each of the Count operations that is performed. The read or
> + write operation is performed Count times from the first element of Buffer.
> +
> + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
> + @param[in] Width Signifies the width of the I/O or Memory operation.
> + @param[in] Address The base address of the I/O operation.
> + @param[in] Count The number of I/O operations to perform. The number of
> + bytes moved is Width size * Count, starting at Address.
> + @param[in] Buffer For read operations, the destination buffer to store the results.
> + For write operations, the source buffer from which to write data.
> +
> + @retval EFI_SUCCESS The data was read from or written to the PI system.
> + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
> + @retval EFI_INVALID_PARAMETER Buffer is NULL.
> + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
> + @retval EFI_UNSUPPORTED The address range specified by Address, Width,
> + and Count is not valid for this PI system.
> +**/
> +EFI_STATUS
> +EFIAPI
> +CpuIoServiceWrite (
> + IN EFI_CPU_IO2_PROTOCOL *This,
> + IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
> + IN UINT64 Address,
> + IN UINTN Count,
> + IN VOID *Buffer
> + );
> +
> +#endif // PCI_CPU_IO2_DXE_H_
> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
> new file mode 100644
> index 0000000000..a8a14cddd2
> --- /dev/null
> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
> @@ -0,0 +1,44 @@
> +## @file
> +# Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
> +#
> +# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = PciCpuIo2Dxe
> + FILE_GUID = 168D1A6E-F4A5-448A-9E95-795661BB3067
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = PciCpuIo2Initialize
> +
> +#
> +# VALID_ARCHITECTURES = LOONGARCH64
> +#
> +
> +[Sources]
> + PciCpuIo2Dxe.c
> +
> +[Packages]
> + Platform/Loongson/LoongArchQemuPkg/Loongson.dec
> + MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> + UefiDriverEntryPoint
> + BaseLib
> + DebugLib
> + IoLib
> + PcdLib
> + UefiBootServicesTableLib
> +
> +[Pcd]
> + gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
> +
> +[Protocols]
> + gEfiCpuIo2ProtocolGuid ## PRODUCES
> +
> +[Depex]
> + TRUE
> --
> 2.31.1

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

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

end of thread, other threads:[~2022-11-11  9:46 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-11  8:25 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 01/15] Platform/Loongson: Add Serial Port library xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 02/15] Platform/Loongson: Support SEC xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 03/15] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 04/15] Platform/Loongson: Add QemuFwCfgLib xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 05/15] Platform/Loongson: Add MmuLib xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 06/15] Platform/Loongson: Add StableTimerLib xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 07/15] Platform/Loongson: Support PEI phase xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 08/15] Platform/Loongson: Add CPU DXE driver xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 09/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 10/15] Platform/Loongson: Add timer Dxe driver xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 11/15] Platform/Loongson: Add RealTime Clock lib xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 12/15] Platform/Loongson: Add Platform Boot Manager Lib xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 13/15] Platform/Loongson: Add Reset System Lib xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 14/15] Platform/Loongson: Support Dxe xianglai
2022-11-11  8:25 ` [edk2-platforms][PATCH V5 15/15] Platform/Loongson: Add Readme xianglai
  -- strict thread matches above, loose matches on Subject: below --
2022-11-11  9:12 [edk2-platforms][PATCH V5 00/15] Platform: Add Loongson support xianglai
2022-11-11  9:12 ` [edk2-platforms][PATCH V5 09/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
2022-11-11  9:46   ` Chao Li

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