* [edk2-devel] [PATCH v3 01/39] MdePkg: Add the header file named Csr.h for LoongArch64
[not found] <20231117095742.3605778-1-lichao@loongs>
@ 2023-11-17 9:58 ` Chao Li
2023-11-17 9:58 ` [edk2-devel] [PATCH v3 02/39] MdePkg: Add LoongArch64 FPU function set into BaseCpuLib Chao Li
` (39 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:58 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu
Adding Csr.h for LoongArch64, it is use for accessing the CSR registers.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
---
MdePkg/Include/Register/LoongArch64/Csr.h | 263 ++++++++++++++++++++++
1 file changed, 263 insertions(+)
create mode 100644 MdePkg/Include/Register/LoongArch64/Csr.h
diff --git a/MdePkg/Include/Register/LoongArch64/Csr.h b/MdePkg/Include/Register/LoongArch64/Csr.h
new file mode 100644
index 0000000000..96ea0cc8a8
--- /dev/null
+++ b/MdePkg/Include/Register/LoongArch64/Csr.h
@@ -0,0 +1,263 @@
+/** @file
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - EXC - Exception
+ - CSR - CPU Status Register
+**/
+
+#ifndef LOONGARCH_CSR_H_
+#define LOONGARCH_CSR_H_
+
+#include <Base.h>
+
+//
+// CSR register numbers
+//
+
+//
+// Basic CSR registers
+//
+#define LOONGARCH_CSR_CRMD 0x0
+#define LOONGARCH_CSR_PRMD 0x1
+#define LOONGARCH_CSR_EUEN 0x2
+#define CSR_EUEN_LBTEN_SHIFT 3
+#define CSR_EUEN_LBTEN (0x1ULL << CSR_EUEN_LBTEN_SHIFT)
+#define CSR_EUEN_LASXEN_SHIFT 2
+#define CSR_EUEN_LASXEN (0x1ULL << CSR_EUEN_LASXEN_SHIFT)
+#define CSR_EUEN_LSXEN_SHIFT 1
+#define CSR_EUEN_LSXEN (0x1ULL << CSR_EUEN_LSXEN_SHIFT)
+#define CSR_EUEN_FPEN_SHIFT 0
+#define CSR_EUEN_FPEN (0x1ULL << CSR_EUEN_FPEN_SHIFT)
+#define LOONGARCH_CSR_MISC 0x3
+#define LOONGARCH_CSR_ECFG 0x4
+
+#define LOONGARCH_CSR_ESTAT 0x5
+#define CSR_ESTAT_ESUBCODE_SHIFT 22
+#define CSR_ESTAT_ESUBCODE_WIDTH 9
+#define CSR_ESTAT_ESUBCODE (0x1ffULL << CSR_ESTAT_ESUBCODE_SHIFT)
+#define CSR_ESTAT_EXC_SHIFT 16
+#define CSR_ESTAT_EXC_WIDTH 6
+#define CSR_ESTAT_EXC (0x3FULL << CSR_ESTAT_EXC_SHIFT)
+#define CSR_ESTAT_IS_SHIFT 0
+#define CSR_ESTAT_IS_WIDTH 15
+#define CSR_ESTAT_IS (0x7FFFULL << CSR_ESTAT_IS_SHIFT)
+
+#define LOONGARCH_CSR_ERA 0x6
+#define LOONGARCH_CSR_BADV 0x7
+#define LOONGARCH_CSR_BADI 0x8
+#define LOONGARCH_CSR_EBASE 0xC // Exception entry base address
+
+//
+// TLB related CSR registers
+//
+#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_ASID 0x18 // ASID
+#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_PGD 0x1B // Page table base
+#define LOONGARCH_CSR_PWCTL0 0x1C // PWCtl0
+#define LOONGARCH_CSR_PWCTL1 0x1D // PWCtl1
+#define LOONGARCH_CSR_STLBPGSIZE 0x1E
+#define LOONGARCH_CSR_RVACFG 0x1F
+
+///
+/// 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
+
+//
+// Config CSR registers
+//
+#define LOONGARCH_CSR_CPUNUM 0x20 // CPU core number
+#define LOONGARCH_CSR_PRCFG1 0x21 // Config1
+#define LOONGARCH_CSR_PRCFG2 0x22 // Config2
+#define LOONGARCH_CSR_PRCFG3 0x23 // Config3
+
+//
+// Kscratch registers
+//
+#define LOONGARCH_CSR_KS0 0x30
+#define LOONGARCH_CSR_KS1 0x31
+#define LOONGARCH_CSR_KS2 0x32
+#define LOONGARCH_CSR_KS3 0x33
+#define LOONGARCH_CSR_KS4 0x34
+#define LOONGARCH_CSR_KS5 0x35
+#define LOONGARCH_CSR_KS6 0x36
+#define LOONGARCH_CSR_KS7 0x37
+#define LOONGARCH_CSR_KS8 0x38
+
+//
+// Stable timer registers
+//
+#define LOONGARCH_CSR_TMID 0x40 // Timer ID
+#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 // TLB refill exception entry
+#define LOONGARCH_CSR_TLBRBADV 0x89 // TLB refill badvaddr
+#define LOONGARCH_CSR_TLBRERA 0x8a // TLB refill ERA
+#define LOONGARCH_CSR_TLBRSAVE 0x8b // KScratch for TLB refill exception
+#define LOONGARCH_CSR_TLBRELO0 0x8c // TLB refill entrylo0
+#define LOONGARCH_CSR_TLBRELO1 0x8d // TLB refill entrylo1
+#define LOONGARCH_CSR_TLBREHI 0x8e // TLB refill entryhi
+
+//
+// Direct map windows registers
+//
+#define LOONGARCH_CSR_DMWIN0 0x180 // 64 direct map win0: MEM & IF
+#define LOONGARCH_CSR_DMWIN1 0x181 // 64 direct map win1: MEM & IF
+#define LOONGARCH_CSR_DMWIN2 0x182 // 64 direct map win2: MEM
+#define LOONGARCH_CSR_DMWIN3 0x183 // 64 direct map win3: MEM
+//
+// CSR register numbers end
+//
+
+//
+// IOCSR register numbers
+//
+#define LOONGARCH_IOCSR_FEATURES 0x8
+#define IOCSRF_TEMP (1ULL << 0)
+#define IOCSRF_NODECNT (1ULL << 1)
+#define IOCSRF_MSI (1ULL << 2)
+#define IOCSRF_EXTIOI (1ULL << 3)
+#define IOCSRF_CSRIPI (1ULL << 4)
+#define IOCSRF_FREQCSR (1ULL << 5)
+#define IOCSRF_FREQSCALE (1ULL << 6)
+#define IOCSRF_DVFSV1 (1ULL << 7)
+#define IOCSRF_EXTIOI_DECODE (1ULL << 9)
+#define IOCSRF_FLATMODE (1ULL << 10)
+#define IOCSRF_VM (1ULL << 11)
+
+#define LOONGARCH_IOCSR_VENDOR 0x10
+
+#define LOONGARCH_IOCSR_CPUNAME 0x20
+
+#define LOONGARCH_IOCSR_NODECNT 0x408
+
+#define LOONGARCH_IOCSR_MISC_FUNC 0x420
+#define IOCSR_MISC_FUNC_TIMER_RESET (1ULL << 21)
+#define IOCSR_MISC_FUNC_EXT_IOI_EN (1ULL << 48)
+
+#define LOONGARCH_IOCSR_CPUTEMP 0x428
+
+//
+// PerCore CSR, only accessable by local cores
+//
+#define LOONGARCH_IOCSR_IPI_STATUS 0x1000
+#define LOONGARCH_IOCSR_IPI_EN 0x1004
+#define LOONGARCH_IOCSR_IPI_SET 0x1008
+#define LOONGARCH_IOCSR_IPI_CLEAR 0x100c
+#define LOONGARCH_IOCSR_MBUF0 0x1020
+#define LOONGARCH_IOCSR_MBUF1 0x1028
+#define LOONGARCH_IOCSR_MBUF2 0x1030
+#define LOONGARCH_IOCSR_MBUF3 0x1038
+
+#define LOONGARCH_IOCSR_IPI_SEND 0x1040
+#define IOCSR_IPI_SEND_IP_SHIFT 0
+#define IOCSR_IPI_SEND_CPU_SHIFT 16
+#define IOCSR_IPI_SEND_BLOCKING (1ULL << 31)
+
+#define LOONGARCH_IOCSR_MBUF_SEND 0x1048
+#define IOCSR_MBUF_SEND_BLOCKING (1ULL << 31)
+#define IOCSR_MBUF_SEND_BOX_SHIFT 2
+#define IOCSR_MBUF_SEND_BOX_LO(box) (box << 1)
+#define IOCSR_MBUF_SEND_BOX_HI(box) ((box << 1) + 1)
+#define IOCSR_MBUF_SEND_CPU_SHIFT 16
+#define IOCSR_MBUF_SEND_BUF_SHIFT 32
+#define IOCSR_MBUF_SEND_H32_MASK 0xFFFFFFFF00000000ULL
+
+#define LOONGARCH_IOCSR_ANY_SEND 0x1158
+#define IOCSR_ANY_SEND_BLOCKING (1ULL << 31)
+#define IOCSR_ANY_SEND_CPU_SHIFT 16
+#define IOCSR_ANY_SEND_MASK_SHIFT 27
+#define IOCSR_ANY_SEND_BUF_SHIFT 32
+#define IOCSR_ANY_SEND_H32_MASK 0xFFFFFFFF00000000ULL
+
+//
+// Register offset and bit definition for CSR access
+//
+#define LOONGARCH_IOCSR_TIMER_CFG 0x1060
+#define LOONGARCH_IOCSR_TIMER_TICK 0x1070
+#define IOCSR_TIMER_CFG_RESERVED BIT63
+#define IOCSR_TIMER_CFG_PERIODIC BIT62
+#define IOCSR_TIMER_CFG_EN BIT61
+#define IOCSR_TIMER_MASK 0x0FFFFFFFFFFFFULL
+#define IOCSR_TIMER_INITVAL_RST (0xFFFFULL << 48)
+//
+// IOCSR register numbers end
+//
+
+//
+// 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
+
+#define DEFAULT_PAGE_SIZE 0x0c
+#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 0x0
+#define CSR_TLBREHI_PS 0x3f
+
+#endif
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111354): https://edk2.groups.io/g/devel/message/111354
Mute This Topic: https://groups.io/mt/102644740/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 02/39] MdePkg: Add LoongArch64 FPU function set into BaseCpuLib
[not found] <20231117095742.3605778-1-lichao@loongs>
2023-11-17 9:58 ` [edk2-devel] [PATCH v3 01/39] MdePkg: Add the header file named Csr.h for LoongArch64 Chao Li
@ 2023-11-17 9:58 ` Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 03/39] MdePkg: Add LoongArch64 exception function set into BaseLib Chao Li
` (38 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:58 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu
Adding InitializeFloatingPointUnits, EnableFloatingPointUnits and
DisableFloatingPointUnits functions for LoongArch64.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
---
MdePkg/Include/Library/CpuLib.h | 37 +++++++++++---
MdePkg/Library/BaseCpuLib/BaseCpuLib.inf | 7 ++-
.../Library/BaseCpuLib/LoongArch/DisableFpu.S | 17 +++++++
.../Library/BaseCpuLib/LoongArch/EnableFpu.S | 17 +++++++
.../BaseCpuLib/LoongArch/InitializeFpu.S | 51 +++++++++++++++++++
5 files changed, 121 insertions(+), 8 deletions(-)
create mode 100644 MdePkg/Library/BaseCpuLib/LoongArch/DisableFpu.S
create mode 100644 MdePkg/Library/BaseCpuLib/LoongArch/EnableFpu.S
create mode 100644 MdePkg/Library/BaseCpuLib/LoongArch/InitializeFpu.S
diff --git a/MdePkg/Include/Library/CpuLib.h b/MdePkg/Include/Library/CpuLib.h
index 3f29937dc7..42da55ca69 100644
--- a/MdePkg/Include/Library/CpuLib.h
+++ b/MdePkg/Include/Library/CpuLib.h
@@ -8,6 +8,7 @@
As a result, these services could not be defined in the Base Library.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -41,14 +42,14 @@ CpuFlushTlb (
VOID
);
-#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
-
/**
+ Initialize the CPU floating point units.
+
Initializes floating point units for requirement of UEFI specification.
- This function initializes floating-point control word to 0x027F (all exceptions
- masked,double-precision, round-to-nearest) and multimedia-extensions control word
- (if supported) to 0x1F80 (all exceptions masked, round-to-nearest, flush to zero
- for masked underflow).
+ For IA32 and X64, this function initializes floating-point control word to 0x027F
+ (all exceptions masked,double-precision, round-to-nearest) and multimedia-extensions
+ control word (if supported) to 0x1F80 (all exceptions masked, round-to-nearest,
+ flush to zero for masked underflow).
**/
VOID
EFIAPI
@@ -56,6 +57,30 @@ InitializeFloatingPointUnits (
VOID
);
+/**
+ Enable the CPU floating point units.
+
+ Enable the CPU floating point units.
+**/
+VOID
+EFIAPI
+EnableFloatingPointUnits (
+ VOID
+ );
+
+/**
+ Disable the CPU floating point units.
+
+ Disable the CPU floating point units.
+**/
+VOID
+EFIAPI
+DisableFloatingPointUnits (
+ VOID
+ );
+
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
+
/**
Determine if the standard CPU signature is "AuthenticAMD".
@retval TRUE The CPU signature matches.
diff --git a/MdePkg/Library/BaseCpuLib/BaseCpuLib.inf b/MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
index 9a162afe6d..89f6272f11 100644
--- a/MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
+++ b/MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
@@ -65,8 +65,11 @@
RiscV/Cpu.S
[Sources.LOONGARCH64]
- LoongArch/CpuFlushTlb.S | GCC
- LoongArch/CpuSleep.S | GCC
+ LoongArch/CpuFlushTlb.S | GCC
+ LoongArch/CpuSleep.S | GCC
+ LoongArch/InitializeFpu.S | GCC
+ LoongArch/EnableFpu.S | GCC
+ LoongArch/DisableFpu.S | GCC
[Packages]
MdePkg/MdePkg.dec
diff --git a/MdePkg/Library/BaseCpuLib/LoongArch/DisableFpu.S b/MdePkg/Library/BaseCpuLib/LoongArch/DisableFpu.S
new file mode 100644
index 0000000000..6cb253a416
--- /dev/null
+++ b/MdePkg/Library/BaseCpuLib/LoongArch/DisableFpu.S
@@ -0,0 +1,17 @@
+#------------------------------------------------------------------------------
+#
+# DisableFloatingPointUnits() for LoongArch64
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(DisableFloatingPointUnits)
+
+ASM_PFX(DisableFloatingPointUnits):
+ li.w $t0, 0x1
+ csrxchg $zero, $t0, 0x2
+
+ jirl $zero, $ra, 0
+ .end
diff --git a/MdePkg/Library/BaseCpuLib/LoongArch/EnableFpu.S b/MdePkg/Library/BaseCpuLib/LoongArch/EnableFpu.S
new file mode 100644
index 0000000000..27d8243a59
--- /dev/null
+++ b/MdePkg/Library/BaseCpuLib/LoongArch/EnableFpu.S
@@ -0,0 +1,17 @@
+#------------------------------------------------------------------------------
+#
+# EnableFloatingPointUnits() for LoongArch64
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(EnableFloatingPointUnits)
+
+ASM_PFX(EnableFloatingPointUnits):
+ li.w $t0, 0x1
+ csrxchg $t0, $t0, 0x2
+
+ jirl $zero, $ra, 0
+ .end
diff --git a/MdePkg/Library/BaseCpuLib/LoongArch/InitializeFpu.S b/MdePkg/Library/BaseCpuLib/LoongArch/InitializeFpu.S
new file mode 100644
index 0000000000..1b9d01c2c1
--- /dev/null
+++ b/MdePkg/Library/BaseCpuLib/LoongArch/InitializeFpu.S
@@ -0,0 +1,51 @@
+#------------------------------------------------------------------------------
+#
+# InitializeFloatingPointUnits() for LoongArch64
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(InitializeFloatingPointUnits)
+
+ASM_PFX(InitializeFloatingPointUnits):
+ li.d $t0, 0x0 // RNE mode
+ movgr2fcsr $r0, $t0
+ 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
+ .end
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111355): https://edk2.groups.io/g/devel/message/111355
Mute This Topic: https://groups.io/mt/102644742/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 03/39] MdePkg: Add LoongArch64 exception function set into BaseLib
[not found] <20231117095742.3605778-1-lichao@loongs>
2023-11-17 9:58 ` [edk2-devel] [PATCH v3 01/39] MdePkg: Add the header file named Csr.h for LoongArch64 Chao Li
2023-11-17 9:58 ` [edk2-devel] [PATCH v3 02/39] MdePkg: Add LoongArch64 FPU function set into BaseCpuLib Chao Li
@ 2023-11-17 9:59 ` Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 04/39] MdePkg: Add LoongArch64 local interrupt " Chao Li
` (37 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:59 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu
Adding SetExceptionBaseAddress and SetTlbRebaseAddress functions
for LoongArch64.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
---
MdePkg/Include/Library/BaseLib.h | 20 +++++++++
MdePkg/Library/BaseLib/BaseLib.inf | 1 +
.../BaseLib/LoongArch64/ExceptionBase.S | 41 +++++++++++++++++++
3 files changed, 62 insertions(+)
create mode 100644 MdePkg/Library/BaseLib/LoongArch64/ExceptionBase.S
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 5d7067ee85..a9a69c734c 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -229,6 +229,26 @@ typedef struct {
#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8
+/*
+ * Set the exception base address for LoongArch.
+ *
+ * @param ExceptionBaseAddress The exception base address, must be aligned greater than or qeual to 4K .
+ */
+VOID
+SetExceptionBaseAddress (
+ IN UINT64
+ );
+
+/*
+ * Set the TlbRebase address for LoongArch.
+ *
+ * @param TlbRebaseAddress The TlbRebase address, must be aligned greater than or qeual to 4K .
+ */
+VOID
+SetTlbRebaseAddress (
+ IN UINT64
+ );
+
#endif // defined (MDE_CPU_LOONGARCH64)
//
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index 03c7b02e82..a18fe5efb4 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -419,6 +419,7 @@
LoongArch64/CpuPause.S | GCC
LoongArch64/SetJumpLongJump.S | GCC
LoongArch64/SwitchStack.S | GCC
+ LoongArch64/ExceptionBase.S | GCC
[Packages]
MdePkg/MdePkg.dec
diff --git a/MdePkg/Library/BaseLib/LoongArch64/ExceptionBase.S b/MdePkg/Library/BaseLib/LoongArch64/ExceptionBase.S
new file mode 100644
index 0000000000..36c6ca7ca8
--- /dev/null
+++ b/MdePkg/Library/BaseLib/LoongArch64/ExceptionBase.S
@@ -0,0 +1,41 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch set exception base address operations
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#include <Base.h>
+#include <Register/LoongArch64/Csr.h>
+
+ASM_GLOBAL ASM_PFX(SetExceptionBaseAddress)
+ASM_GLOBAL ASM_PFX(SetTlbRebaseAddress)
+
+#/**
+# Set the exception base address for LoongArch.
+#
+# @param ExceptionBaseAddress The exception base address, must be aligned greater than or qeual to 4K .
+#**/
+ASM_PFX(SetExceptionBaseAddress):
+ csrrd $t0, LOONGARCH_CSR_ECFG
+ li.d $t1, ~(BIT16 | BIT17 | BIT18)
+ and $t0, $t0, $t1
+ csrwr $t0, LOONGARCH_CSR_ECFG
+
+ move $t0, $a0
+ csrwr $t0, LOONGARCH_CSR_EBASE
+ jirl $zero, $ra, 0
+
+#/**
+# Set the TlbRebase address for LoongArch.
+#
+# @param TlbRebaseAddress The TlbRebase address, must be aligned greater than or qeual to 4K .
+#**/
+ASM_PFX(SetTlbRebaseAddress):
+ move $t0, $a0
+ csrwr $t0, LOONGARCH_CSR_TLBREBASE
+ jirl $zero, $ra, 0
+.end
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111356): https://edk2.groups.io/g/devel/message/111356
Mute This Topic: https://groups.io/mt/102644745/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 04/39] MdePkg: Add LoongArch64 local interrupt function set into BaseLib
[not found] <20231117095742.3605778-1-lichao@loongs>
` (2 preceding siblings ...)
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 03/39] MdePkg: Add LoongArch64 exception function set into BaseLib Chao Li
@ 2023-11-17 9:59 ` Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 05/39] MdePkg: Add LoongArch Cpucfg function Chao Li
` (36 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:59 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu
Adding LoongArch local interrupt function set, which is used to control
the opening or closing of the local interrupt when the global interrupt
is enabled.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
---
MdePkg/Include/Library/BaseLib.h | 20 +++++++++++++++++
.../BaseLib/LoongArch64/DisableInterrupts.S | 22 ++++++++++++++-----
.../BaseLib/LoongArch64/EnableInterrupts.S | 22 ++++++++++++++-----
3 files changed, 54 insertions(+), 10 deletions(-)
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index a9a69c734c..93a014cd49 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -249,6 +249,26 @@ SetTlbRebaseAddress (
IN UINT64
);
+/**
+ Enables local CPU interrupts.
+
+ @param Needs to enable local interrupt bit.
+**/
+VOID
+EnableLocalInterrupts (
+ IN UINT16
+ );
+
+/**
+ Disables local CPU interrupts.
+
+ @param Needs to disable local interrupt bit.
+**/
+VOID
+DisableLocalInterrupts (
+ IN UINT16
+ );
+
#endif // defined (MDE_CPU_LOONGARCH64)
//
diff --git a/MdePkg/Library/BaseLib/LoongArch64/DisableInterrupts.S b/MdePkg/Library/BaseLib/LoongArch64/DisableInterrupts.S
index 0f228339af..5de10e9e7a 100644
--- a/MdePkg/Library/BaseLib/LoongArch64/DisableInterrupts.S
+++ b/MdePkg/Library/BaseLib/LoongArch64/DisableInterrupts.S
@@ -1,21 +1,33 @@
#------------------------------------------------------------------------------
#
-# LoongArch interrupt disable
+# LoongArch interrupt disable operations
#
-# Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#------------------------------------------------------------------------------
+#include <Base.h>
+#include <Register/LoongArch64/Csr.h>
+
+ASM_GLOBAL ASM_PFX(DisableLocalInterrupts)
ASM_GLOBAL ASM_PFX(DisableInterrupts)
#/**
-# Disables CPU interrupts.
+# Disables local CPU interrupts.
+#
+# @param Needs to disable local interrupt bit.
#**/
+ASM_PFX(DisableLocalInterrupts):
+ csrxchg $zero, $a0, LOONGARCH_CSR_ECFG
+ jirl $zero, $ra, 0
+#/**
+# Disables global CPU interrupts.
+#**/
ASM_PFX(DisableInterrupts):
- li.w $t0, 0x4
- csrxchg $zero, $t0, 0x0
+ li.w $t0, BIT2
+ csrxchg $zero, $t0, LOONGARCH_CSR_CRMD
jirl $zero, $ra, 0
.end
diff --git a/MdePkg/Library/BaseLib/LoongArch64/EnableInterrupts.S b/MdePkg/Library/BaseLib/LoongArch64/EnableInterrupts.S
index 3c34fb2cdd..73adcd7b0c 100644
--- a/MdePkg/Library/BaseLib/LoongArch64/EnableInterrupts.S
+++ b/MdePkg/Library/BaseLib/LoongArch64/EnableInterrupts.S
@@ -1,21 +1,33 @@
#------------------------------------------------------------------------------
#
-# LoongArch interrupt enable
+# LoongArch interrupt enable operations
#
-# Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#------------------------------------------------------------------------------
+#include <Base.h>
+#include <Register/LoongArch64/Csr.h>
+
+ASM_GLOBAL ASM_PFX(EnableLocalInterrupts)
ASM_GLOBAL ASM_PFX(EnableInterrupts)
#/**
-# Enables CPU interrupts.
+# Enables local CPU interrupts.
+#
+# @param Needs to enable local interrupt bit.
#**/
+ASM_PFX(EnableLocalInterrupts):
+ csrxchg $a0, $a0, LOONGARCH_CSR_ECFG
+ jirl $zero, $ra, 0
+#/**
+# Enables global CPU interrupts.
+#**/
ASM_PFX(EnableInterrupts):
- li.w $t0, 0x4
- csrxchg $t0, $t0, 0x0
+ li.w $t0, BIT2
+ csrxchg $t0, $t0, LOONGARCH_CSR_CRMD
jirl $zero, $ra, 0
.end
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111357): https://edk2.groups.io/g/devel/message/111357
Mute This Topic: https://groups.io/mt/102644748/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 05/39] MdePkg: Add LoongArch Cpucfg function
[not found] <20231117095742.3605778-1-lichao@loongs>
` (3 preceding siblings ...)
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 04/39] MdePkg: Add LoongArch64 local interrupt " Chao Li
@ 2023-11-17 9:59 ` Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 06/39] MdePkg: Add read stable counter operation for LoongArch Chao Li
` (35 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:59 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu
Add LoongArch AsmCpucfg function and Cpucfg definitions.
Also added Include/Register/LoongArch64/Cpucfg.h to IgnoreFiles of
EccCheck.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
---
MdePkg/Include/Library/BaseLib.h | 12 +
MdePkg/Include/Register/LoongArch64/Cpucfg.h | 565 +++++++++++++++++++
MdePkg/Library/BaseLib/BaseLib.inf | 1 +
MdePkg/Library/BaseLib/LoongArch64/Cpucfg.S | 26 +
MdePkg/MdePkg.ci.yaml | 3 +-
5 files changed, 606 insertions(+), 1 deletion(-)
create mode 100644 MdePkg/Include/Register/LoongArch64/Cpucfg.h
create mode 100644 MdePkg/Library/BaseLib/LoongArch64/Cpucfg.S
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 93a014cd49..3adf4d0042 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -269,6 +269,18 @@ DisableLocalInterrupts (
IN UINT16
);
+/**
+ Read CPUCFG register.
+
+ @param Index Specifies the register number of the CPUCFG to read the data.
+ @param Data A pointer to the variable used to store the CPUCFG register value.
+**/
+VOID
+AsmCpucfg (
+ IN UINT32 Index,
+ OUT UINT32 *Data
+ );
+
#endif // defined (MDE_CPU_LOONGARCH64)
//
diff --git a/MdePkg/Include/Register/LoongArch64/Cpucfg.h b/MdePkg/Include/Register/LoongArch64/Cpucfg.h
new file mode 100644
index 0000000000..841885dc70
--- /dev/null
+++ b/MdePkg/Include/Register/LoongArch64/Cpucfg.h
@@ -0,0 +1,565 @@
+/** @file
+ CPUCFG definitions.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef CPUCFG_H_
+#define CPUCFG_H_
+
+/**
+ CPUCFG REG0 Information
+
+ @code
+ CPUCFG_REG0_INFO_DATA
+ **/
+#define CPUCFG_REG0_INFO 0x0
+
+/**
+ CPUCFG REG0 Information returned data.
+ #CPUCFG_REG0_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 31:0] Processor Identity.
+ ///
+ UINT32 PRID : 32;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_REG0_INFO_DATA;
+
+/**
+ CPUCFG REG1 Information
+
+ @code
+ CPUCFG_REG1_INFO_DATA
+ **/
+#define CPUCFG_REG1_INFO 0x1
+
+/**
+ CPUCFG REG1 Information returned data.
+ #CPUCFG_REG1_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 1:0] Architecture:
+ /// 2'b00 indicates the implementation of simplified LoongAarch32;
+ /// 2'b01 indicates the implementation of LoongAarch32;
+ /// 2'b10 indicates the implementation of LoongAarch64;
+ /// 2'b11 reserved;
+ ///
+ UINT32 ARCH : 2;
+ ///
+ /// [Bit 2] Paging mapping mode. A value of 1 indicates the processor MMU supports
+ /// page mapping mode.
+ ///
+ UINT32 PGMMU : 1;
+ ///
+ /// [Bit 3] A value of 1 indicates the processor supports the IOCSR instruction.
+ ///
+ UINT32 IOCSR : 1;
+ ///
+ /// [Bit 11:4] Physical address bits. The supported physical address bits PALEN value
+ /// minus 1.
+ ///
+ UINT32 PALEN : 8;
+ ///
+ /// [Bit 19:12] Virtual address bits. The supported virtual address bits VALEN value
+ /// minus 1.
+ ///
+ UINT32 VALEN : 8;
+ ///
+ /// [Bit 20] Non-aligned Memory Access. A value of 1 indicates the processor supports
+ /// non-aligned memory access.
+ ///
+ UINT32 UAL : 1;
+ ///
+ /// [Bit 21] Page Read Inhibit. A value of 1 indicates the processor supports page
+ /// attribute of "Read Inhibit".
+ ///
+ UINT32 RI : 1;
+ ///
+ /// [Bit 22] Page Execution Protection. A value of 1 indicates the processor supports
+ /// page attribute of "Execution Protection".
+ ///
+ UINT32 EP : 1;
+ ///
+ /// [Bit 23] A value of 1 indicates the processor supports for page attributes of RPLV.
+ ///
+ UINT32 RPLV : 1;
+ ///
+ /// [Bit 24] Huge Page. A value of 1 indicates the processor supports page attribute
+ /// of huge page.
+ ///
+ UINT32 HP : 1;
+ ///
+ /// [Bit 25] A value of 1 indicates that the string of processor product information
+ /// is recorded at address 0 of the IOCSR access space.
+ ///
+ UINT32 IOCSR_BRD : 1;
+ ///
+ /// [Bit 26] A value of 1 indicates that the external interrupt uses the message
+ /// interrupt mode, otherwise it is the level interrupt line mode.
+ ///
+ UINT32 MSG_INT : 1;
+ ///
+ /// [Bit 31:27] Reserved.
+ ///
+ UINT32 Reserved : 5;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_REG1_INFO_DATA;
+
+/**
+ CPUCFG REG2 Information
+
+ @code
+ CPUCFG_REG2_INFO_DATA
+ **/
+#define CPUCFG_REG2_INFO 0x2
+
+/**
+ CPUCFG REG2 Information returned data.
+ #CPUCFG_REG2_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 0] Basic Floating-Point. A value of 1 indicates the processor supports basic
+ /// floating-point instructions.
+ ///
+ UINT32 FP : 1;
+ ///
+ /// [Bit 1] Sigle-Precision. A value of 1 indicates the processor supports sigle-precision
+ /// floating-point numbers.
+ ///
+ UINT32 FP_SP : 1;
+ ///
+ /// [Bit 2] Double-Precision. A value of 1 indicates the processor supports double-precision
+ /// floating-point numbers.
+ ///
+ UINT32 FP_DP : 1;
+ ///
+ /// [Bit 5:3] The version number of the floating-point arithmetic standard. 1 is the initial
+ /// version number, indicating that it is compatible with the IEEE 754-2008 standard.
+ ///
+ UINT32 FP_ver : 3;
+ ///
+ /// [Bit 6] 128-bit Vector Extension. A value of 1 indicates the processor supports 128-bit
+ /// vector extension.
+ ///
+ UINT32 LSX : 1;
+ ///
+ /// [Bit 7] 256-bit Vector Extension. A value of 1 indicates the processor supports 256-bit
+ /// vector extension.
+ ///
+ UINT32 LASX : 1;
+ ///
+ /// [Bit 8] Complex Vector Operation Instructions. A value of 1 indicates the processor supports
+ /// complex vector operation instructions.
+ ///
+ UINT32 COMPLEX : 1;
+ ///
+ /// [Bit 9] Encryption And Decryption Vector Instructions. A value of 1 indicates the processor
+ /// supports encryption and decryption vector instructions.
+ ///
+ UINT32 CRYPTO : 1;
+ ///
+ /// [Bit 10] Virtualization Expansion. A value of 1 indicates the processor supports
+ /// virtualization expansion.
+ ///
+ UINT32 LVZ : 1;
+ ///
+ /// [Bit 13:11] The version number of the virtualization hardware acceleration specification.
+ /// 1 is the initial version number.
+ ///
+ UINT32 LVZ_ver : 3;
+ ///
+ /// [Bit 14] Constant Frequency Counter And Timer. A value of 1 indicates the processor supports
+ /// constant frequency counter and timer.
+ ///
+ UINT32 LLFTP : 1;
+ ///
+ /// [Bit 17:15] Constant frequency counter and timer version number. 1 is the initial version.
+ ///
+ UINT32 LLTP_ver : 3;
+ ///
+ /// [Bit 18] X86 Binary Translation Extension. A value of 1 indicates the processor supports
+ /// X86 binary translation extension.
+ ///
+ UINT32 LBT_X86 : 1;
+ ///
+ /// [Bit 19] ARM Binary Translation Extension. A value of 1 indicates the processor supports
+ /// ARM binary translation extension.
+ ///
+ UINT32 LBT_ARM : 1;
+ ///
+ /// [Bit 20] MIPS Binary Translation Extension. A value of 1 indicates the processor supports
+ /// MIPS binary translation extension.
+ ///
+ UINT32 LBT_MIPS : 1;
+ ///
+ /// [Bit 21] Software Page Table Walking Instruction. A value of 1 indicates the processor
+ /// supports software page table walking instruction.
+ ///
+ UINT32 LSPW : 1;
+ ///
+ /// [Bit 22] Atomic Memory Access Instruction. A value of 1 indicates the processor supports
+ /// AM* atomic memory access instruction.
+ ///
+ UINT32 LAM : 1;
+ ///
+ /// [Bit 31:23] Reserved.
+ ///
+ UINT32 Reserved : 9;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_REG2_INFO_DATA;
+
+/**
+ CPUCFG REG3 Information
+
+ @code
+ CPUCFG_REG3_INFO_DATA
+ **/
+#define CPUCFG_REG3_INFO 0x3
+
+/**
+ CPUCFG REG3 Information returned data.
+ #CPUCFG_REG3_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 0] Hardware Cache Coherent DMA. A value of 1 indicates the processor supports
+ /// hardware cache coherent DMA.
+ ///
+ UINT32 CCDMA : 1;
+ ///
+ /// [Bit 1] Store Fill Buffer. A value of 1 indicates the processor supports store fill
+ /// buffer (SFB).
+ ///
+ UINT32 SFB : 1;
+ ///
+ /// [Bit 2] Uncache Accelerate. A value of 1 indicates the processor supports uncache
+ /// accelerate.
+ ///
+ UINT32 UCACC : 1;
+ ///
+ /// [Bit 3] A value of 1 indicates the processor supports LL instruction to fetch exclusive
+ /// block function.
+ ///
+ UINT32 LLEXC : 1;
+ ///
+ /// [Bit 4] A value of 1 indicates the processor supports random delay function after SC
+ /// instruction.
+ ///
+ UINT32 SCDLY : 1;
+ ///
+ /// [Bit 5] A value of 1 indicates the processor supports LL automatic with dbar function.
+ ///
+ UINT32 LLDBAR : 1;
+ ///
+ /// [Bit 6] A value of 1 indicates the processor supports the hardware maintains the
+ /// consistency between ITLB and TLB.
+ ///
+ UINT32 ITLBT : 1;
+ ///
+ /// [Bit 7] A value of 1 indicates the processor supports the hardware maintains the data
+ /// consistency between ICache and DCache in one processor core.
+ ///
+ UINT32 ICACHET : 1;
+ ///
+ /// [Bit 10:8] The maximum number of directory levels supported by the page walk instruction.
+ ///
+ UINT32 SPW_LVL : 3;
+ ///
+ /// [Bit 11] A value of 1 indicates the processor supports the page walk instruction fills
+ /// the TLB in half when it encounters a large page.
+ ///
+ UINT32 SPW_HP_HF : 1;
+ ///
+ /// [Bit 12] Virtual Address Range. A value of 1 indicates the processor supports the software
+ /// configuration can be used to shorten the virtual address range.
+ ///
+ UINT32 RVA : 1;
+ ///
+ /// [Bit 16:13] The maximum configurable virtual address is shortened by -1.
+ ///
+ UINT32 RVAMAX_1 : 4;
+ ///
+ /// [Bit 31:17] Reserved.
+ ///
+ UINT32 Reserved : 15;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_REG3_INFO_DATA;
+
+/**
+ CPUCFG REG4 Information
+
+ @code
+ CPUCFG_REG4_INFO_DATA
+ **/
+#define CPUCFG_REG4_INFO 0x4
+
+/**
+ CPUCFG REG4 Information returned data.
+ #CPUCFG_REG4_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 31:0] Constant frequency timer and the crystal frequency corresponding to the clock
+ /// used by the timer.
+ ///
+ UINT32 CC_FREQ : 32;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_REG4_INFO_DATA;
+
+/**
+ CPUCFG REG5 Information
+
+ @code
+ CPUCFG_REG5_INFO_DATA
+ **/
+#define CPUCFG_REG5_INFO 0x5
+
+/**
+ CPUCFG REG5 Information returned data.
+ #CPUCFG_REG5_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 15:0] Constant frequency timer and the corresponding multiplication factor of the
+ /// clock used by the timer.
+ ///
+ UINT32 CC_MUL : 16;
+ ///
+ /// [Bit 31:16] Constant frequency timer and the division coefficient corresponding to the
+ /// clock used by the timer
+ ///
+ UINT32 CC_DIV : 16;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_REG5_INFO_DATA;
+
+/**
+ CPUCFG REG6 Information
+
+ @code
+ CPUCFG_REG6_INFO_DATA
+ **/
+#define CPUCFG_REG6_INFO 0x6
+
+/**
+ CPUCFG REG6 Information returned data.
+ #CPUCFG_REG6_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 0] Performance Counter. A value of 1 indicates the processor supports performance
+ /// counter.
+ ///
+ UINT32 PMP : 1;
+ ///
+ /// [Bit 3:1] In the performance monitor, the architecture defines the version number of the
+ /// event, and 1 is the initial version
+ ///
+ UINT32 PMVER : 3;
+ ///
+ /// [Bit 7:4] Number of performance monitors minus 1.
+ ///
+ UINT32 PMNUM : 4;
+ ///
+ /// [Bit 13:8] Number of bits of a performance monitor minus 1.
+ ///
+ UINT32 PMBITS : 6;
+ ///
+ /// [Bit 14] A value of 1 indicates the processor supports reading performance counter in user mode.
+ ///
+ UINT32 UPM : 1;
+ ///
+ /// [Bit 31:15] Reserved.
+ ///
+ UINT32 Reserved : 17;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_REG6_INFO_DATA;
+
+/**
+ CPUCFG REG16 Information
+
+ @code
+ CPUCFG_REG16_INFO_DATA
+ **/
+#define CPUCFG_REG16_INFO 0x10
+
+/**
+ CPUCFG REG16 Information returned data.
+ #CPUCFG_REG16_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 0] A value of 1 indicates the processor has a first-level instruction cache
+ /// or a first-level unified cache
+ ///
+ UINT32 L1_IU_Present : 1;
+ ///
+ /// [Bit 1] A value of 1 indicates that the cache shown by L1 IU_Present is the
+ /// unified cache.
+ ///
+ UINT32 L1_IU_Unify : 1;
+ ///
+ /// [Bit 2] A value of 1 indicates the processor has a first-level data cache.
+ ///
+ UINT32 L1_D_Present : 1;
+ ///
+ /// [Bit 3] A value of 1 indicates the processor has a second-level instruction cache
+ /// or a second-level unified cache.
+ ///
+ UINT32 L2_IU_Present : 1;
+ ///
+ /// [Bit 4] A value of 1 indicates that the cache shown by L2 IU_Present is the
+ /// unified cache.
+ ///
+ UINT32 L2_IU_Unify : 1;
+ ///
+ /// [Bit 5] A value of 1 indicates that the cache shown by L2 IU_Present is private
+ /// to each core.
+ ///
+ UINT32 L2_IU_Private : 1;
+ ///
+ /// [Bit 6] A value of 1 indicates that the cache shown by L2 IU_Present has an inclusive
+ /// relationship to the lower levels (L1).
+ ///
+ UINT32 L2_IU_Inclusive : 1;
+ ///
+ /// [Bit 7] A value of 1 indicates the processor has a second-level data cache.
+ ///
+ UINT32 L2_D_Present : 1;
+ ///
+ /// [Bit 8] A value of 1 indicates that the second-level data cache is private to each core.
+ ///
+ UINT32 L2_D_Private : 1;
+ ///
+ /// [Bit 9] A value of 1 indicates that the second-level data cache has a containment
+ /// relationship to the lower level (L1).
+ ///
+ UINT32 L2_D_Inclusive : 1;
+ ///
+ /// [Bit 10] A value of 1 indicates the processor has a three-level instruction cache
+ /// or a second-level unified Cache.
+ ///
+ UINT32 L3_IU_Present : 1;
+ ///
+ /// [Bit 11] A value of 1 indicates that the cache shown by L3 IU_Present is the
+ /// unified cache.
+ ///
+ UINT32 L3_IU_Unify : 1;
+ ///
+ /// [Bit 12] A value of 1 indicates that the cache shown by L3 IU_Present is private
+ /// to each core.
+ ///
+ UINT32 L3_IU_Private : 1;
+ ///
+ /// [Bit 13] A value of 1 indicates that the cache shown by L3 IU_Present has an inclusive
+ /// relationship to the lower levels (L1 and L2).
+ ///
+ UINT32 L3_IU_Inclusive : 1;
+ ///
+ /// [Bit 14] A value of 1 indicates the processor has a three-level data cache.
+ ///
+ UINT32 L3_D_Present : 1;
+ ///
+ /// [Bit 15] A value of 1 indicates that the three-level data cache is private to each core.
+ ///
+ UINT32 L3_D_Private : 1;
+ ///
+ /// [Bit 16] A value of 1 indicates that the three-level data cache has a containment
+ /// relationship to the lower level (L1 and L2).
+ ///
+ UINT32 L3_D_Inclusive : 1;
+ ///
+ /// [Bit 31:17] Reserved.
+ ///
+ UINT32 Reserved : 15;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_REG16_INFO_DATA;
+
+/**
+ CPUCFG REG17, REG18, REG19 and REG20 Information
+
+ @code
+ CPUCFG_CACHE_INFO_DATA
+ **/
+#define CPUCFG_REG17_INFO 0x11 /// L1 unified cache.
+#define CPUCFG_REG18_INFO 0x12 /// L1 data cache.
+#define CPUCFG_REG19_INFO 0x13 /// L2 unified cache.
+#define CPUCFG_REG20_INFO 0x14 /// L3 unified cache.
+
+/**
+ CPUCFG CACHE Information returned data.
+ #CPUCFG_REG17_INFO
+ #CPUCFG_REG18_INFO
+ #CPUCFG_REG19_INFO
+ #CPUCFG_REG20_INFO
+ **/
+typedef union {
+ struct {
+ ///
+ /// [Bit 15:0] Number of channels minus 1.
+ ///
+ UINT32 Way_1 : 16;
+ ///
+ /// [Bit 23:16] Log2 (number of cache rows per channel).
+ ///
+ UINT32 Index_log2 : 8;
+ ///
+ /// [Bit 30:24] Log2 (cache row bytes).
+ ///
+ UINT32 Linesize_log2 : 7;
+ ///
+ /// [Bit 31] Reserved.
+ ///
+ UINT32 Reserved : 1;
+ } Bits;
+ ///
+ /// All bit fields as a 32-bit value
+ ///
+ UINT32 Uint32;
+} CPUCFG_CACHE_INFO_DATA;
+#endif
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index a18fe5efb4..a427aa9359 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -420,6 +420,7 @@
LoongArch64/SetJumpLongJump.S | GCC
LoongArch64/SwitchStack.S | GCC
LoongArch64/ExceptionBase.S | GCC
+ LoongArch64/Cpucfg.S | GCC
[Packages]
MdePkg/MdePkg.dec
diff --git a/MdePkg/Library/BaseLib/LoongArch64/Cpucfg.S b/MdePkg/Library/BaseLib/LoongArch64/Cpucfg.S
new file mode 100644
index 0000000000..7ed49146b4
--- /dev/null
+++ b/MdePkg/Library/BaseLib/LoongArch64/Cpucfg.S
@@ -0,0 +1,26 @@
+#------------------------------------------------------------------------------
+#
+# AsmCpucfg for LoongArch
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+ASM_GLOBAL ASM_PFX(AsmCpucfg)
+
+#/**
+# Read CPUCFG register.
+#
+# @param a0 Specifies the register number of the CPUCFG to read the data.
+# @param a1 Pointer to the variable used to store the CPUCFG register value.
+#
+#**/
+
+ASM_PFX(AsmCpucfg):
+ cpucfg $t0, $a0
+ stptr.d $t0, $a1, 0
+
+ jirl $zero, $ra, 0
+ .end
diff --git a/MdePkg/MdePkg.ci.yaml b/MdePkg/MdePkg.ci.yaml
index 1d3d8327b1..f2d81af080 100644
--- a/MdePkg/MdePkg.ci.yaml
+++ b/MdePkg/MdePkg.ci.yaml
@@ -80,7 +80,8 @@
"Include/Register/Amd/SmramSaveStateMap.h",
"Test/UnitTest/Library/DevicePathLib/TestDevicePathLib.c",
"Test/UnitTest/Library/DevicePathLib/TestDevicePathLib.h",
- "Test/UnitTest/Library/DevicePathLib/TestDevicePathStringConversions.c"
+ "Test/UnitTest/Library/DevicePathLib/TestDevicePathStringConversions.c",
+ "Include/Register/LoongArch64/Cpucfg.h"
]
},
## options defined ci/Plugin/CompilerPlugin
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111358): https://edk2.groups.io/g/devel/message/111358
Mute This Topic: https://groups.io/mt/102644749/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 06/39] MdePkg: Add read stable counter operation for LoongArch
[not found] <20231117095742.3605778-1-lichao@loongs>
` (4 preceding siblings ...)
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 05/39] MdePkg: Add LoongArch Cpucfg function Chao Li
@ 2023-11-17 9:59 ` Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 07/39] MdePkg: Add CSR " Chao Li
` (34 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:59 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu
Add LoongArch gets stable counter ASM function.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
---
MdePkg/Include/Library/BaseLib.h | 12 ++++++++++
MdePkg/Library/BaseLib/BaseLib.inf | 1 +
.../BaseLib/LoongArch64/ReadStableCounter.S | 24 +++++++++++++++++++
3 files changed, 37 insertions(+)
create mode 100644 MdePkg/Library/BaseLib/LoongArch64/ReadStableCounter.S
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 3adf4d0042..55d53c75a0 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -281,6 +281,18 @@ AsmCpucfg (
OUT UINT32 *Data
);
+/**
+ Gets the timer count value.
+
+ @param[] VOID
+ @retval timer count value.
+
+**/
+UINTN
+AsmReadStableCounter (
+ VOID
+ );
+
#endif // defined (MDE_CPU_LOONGARCH64)
//
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index a427aa9359..aaf221822b 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -421,6 +421,7 @@
LoongArch64/SwitchStack.S | GCC
LoongArch64/ExceptionBase.S | GCC
LoongArch64/Cpucfg.S | GCC
+ LoongArch64/ReadStableCounter.S | GCC
[Packages]
MdePkg/MdePkg.dec
diff --git a/MdePkg/Library/BaseLib/LoongArch64/ReadStableCounter.S b/MdePkg/Library/BaseLib/LoongArch64/ReadStableCounter.S
new file mode 100644
index 0000000000..59c877211d
--- /dev/null
+++ b/MdePkg/Library/BaseLib/LoongArch64/ReadStableCounter.S
@@ -0,0 +1,24 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch Read Stable Counter
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+ASM_GLOBAL ASM_PFX(AsmReadStableCounter)
+
+#/**
+# Gets the timer count value.
+#
+# @param[] VOID
+# @retval timer count value.
+#
+#**/
+
+ASM_PFX(AsmReadStableCounter):
+ rdtime.d $a0, $zero
+ jirl $zero, $ra, 0
+ .end
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111359): https://edk2.groups.io/g/devel/message/111359
Mute This Topic: https://groups.io/mt/102644751/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 07/39] MdePkg: Add CSR operation for LoongArch
[not found] <20231117095742.3605778-1-lichao@loongs>
` (5 preceding siblings ...)
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 06/39] MdePkg: Add read stable counter operation for LoongArch Chao Li
@ 2023-11-17 9:59 ` Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 08/39] MdePkg: Add IOCSR " Chao Li
` (33 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:59 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Bibo Mao
Add CsrRead, CsrWrite and CsrXChg functions for LoongArch, and use them
to operate the CSR register of LoongArch architecture.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
---
MdePkg/Include/Library/BaseLib.h | 45 +++
MdePkg/Library/BaseLib/BaseLib.inf | 2 +
MdePkg/Library/BaseLib/LoongArch64/AsmCsr.S | 422 ++++++++++++++++++++
MdePkg/Library/BaseLib/LoongArch64/Csr.c | 81 ++++
4 files changed, 550 insertions(+)
create mode 100644 MdePkg/Library/BaseLib/LoongArch64/AsmCsr.S
create mode 100644 MdePkg/Library/BaseLib/LoongArch64/Csr.c
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 55d53c75a0..234f3065c2 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -293,6 +293,51 @@ AsmReadStableCounter (
VOID
);
+/**
+ CSR read operation.
+
+ @param[in] Select CSR read instruction select values.
+
+ @return The return value of csrrd instruction, return -1 means no CSR instruction
+ is found.
+**/
+UINTN
+CsrRead (
+ IN UINT16 Select
+ );
+
+/**
+ CSR write operation.
+
+ @param[in] Select CSR write instruction select values.
+ @param[in] Value The csrwr will write the value.
+
+ @return The return value of csrwr instruction, that is, store the old value of
+ the register, return -1 means no CSR instruction is found.
+**/
+UINTN
+CsrWrite (
+ IN UINT16 Select,
+ IN UINTN Value
+ );
+
+/**
+ CSR exchange operation.
+
+ @param[in] Select CSR exchange instruction select values.
+ @param[in] Value The csrxchg will write the value.
+ @param[in] Mask The csrxchg mask value.
+
+ @return The return value of csrxchg instruction, that is, store the old value of
+ the register, return -1 means no CSR instruction is found.
+**/
+UINTN
+CsrXChg (
+ IN UINT16 Select,
+ IN UINTN Value,
+ IN UINTN Mask
+ );
+
#endif // defined (MDE_CPU_LOONGARCH64)
//
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index aaf221822b..74a323c798 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -409,7 +409,9 @@
[Sources.LOONGARCH64]
Math64.c
Unaligned.c
+ LoongArch64/Csr.c
LoongArch64/InternalSwitchStack.c
+ LoongArch64/AsmCsr.S | GCC
LoongArch64/GetInterruptState.S | GCC
LoongArch64/EnableInterrupts.S | GCC
LoongArch64/DisableInterrupts.S | GCC
diff --git a/MdePkg/Library/BaseLib/LoongArch64/AsmCsr.S b/MdePkg/Library/BaseLib/LoongArch64/AsmCsr.S
new file mode 100644
index 0000000000..25dd060ede
--- /dev/null
+++ b/MdePkg/Library/BaseLib/LoongArch64/AsmCsr.S
@@ -0,0 +1,422 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch ASM CSR operation functions
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#include <Register/LoongArch64/Csr.h>
+
+ASM_GLOBAL ASM_PFX (AsmCsrRead)
+ASM_GLOBAL ASM_PFX (AsmCsrWrite)
+ASM_GLOBAL ASM_PFX (AsmCsrXChg)
+
+.macro AsmCsrRd Sel
+ csrrd $a0, \Sel
+ jirl $zero, $ra, 0
+.endm
+
+.macro AsmCsrWr Sel
+ csrwr $a0, \Sel
+ jirl $zero, $ra, 0
+.endm
+
+.macro AsmCsrXChange Sel
+ csrxchg $a0, $a1, \Sel
+ jirl $zero, $ra, 0
+.endm
+
+ASM_PFX(AsmCsrRead):
+ blt $a0, $zero, ReadSelNumErr
+ li.w $t0, LOONGARCH_CSR_EBASE
+ bltu $t0, $a0, TlbCsrRd
+
+BasicCsrRd:
+ la.pcrel $t0, BasicCsrRead
+ alsl.d $t0, $a0, $t0, 3
+ jirl $zero, $t0, 0
+
+TlbCsrRd:
+ li.w $t0, LOONGARCH_CSR_TLBIDX
+ bltu $a0, $t0, ReadSelNumErr
+ li.w $t0, LOONGARCH_CSR_RVACFG
+ bltu $t0, $a0, CfgCsrRd
+ la.pcrel $t0, TlbCsrRead
+ addi.w $t1, $a0, -LOONGARCH_CSR_TLBIDX
+ alsl.d $t0, $t1, $t0, 3
+ jirl $zero, $t0, 0
+
+CfgCsrRd:
+ li.w $t0, LOONGARCH_CSR_CPUNUM
+ bltu $a0, $t0, ReadSelNumErr
+ li.w $t0, LOONGARCH_CSR_PRCFG3
+ bltu $t0, $a0, KcsCsrRd
+ la.pcrel $t0, CfgCsrRead
+ addi.w $t1, $a0, -LOONGARCH_CSR_CPUNUM
+ alsl.d $t0, $t1, $t0, 3
+ jirl $zero, $t0, 0
+
+KcsCsrRd:
+ li.w $t0, LOONGARCH_CSR_KS0
+ bltu $a0, $t0, ReadSelNumErr
+ li.w $t0, LOONGARCH_CSR_KS8
+ bltu $t0, $a0, StableTimerCsrRd
+ la.pcrel $t0, KcsCsrRead
+ addi.w $t1, $a0, -LOONGARCH_CSR_KS0
+ alsl.d $t0, $t1, $t0, 3
+ jirl $zero, $t0, 0
+
+StableTimerCsrRd:
+ li.w $t0, LOONGARCH_CSR_TMID
+ bltu $a0, $t0, ReadSelNumErr
+ li.w $t0, LOONGARCH_CSR_TINTCLR
+ bltu $t0, $a0, TlbRefillCsrRd
+ la.pcrel $t0, StableTimerCsrRead
+ addi.w $t1, $a0, -LOONGARCH_CSR_TMID
+ alsl.d $t0, $t1, $t0, 3
+ jirl $zero, $t0, 0
+
+TlbRefillCsrRd:
+ li.w $t0, LOONGARCH_CSR_TLBREBASE
+ bltu $a0, $t0, ReadSelNumErr
+ li.w $t0, LOONGARCH_CSR_TLBREHI
+ bltu $t0, $a0, DirMapCsrRd
+ la.pcrel $t0, TlbRefillCsrRead
+ addi.w $t1, $a0, -LOONGARCH_CSR_TLBREBASE
+ alsl.d $t0, $t1, $t0, 3
+ jirl $zero, $t0, 0
+
+DirMapCsrRd:
+ li.w $t0, LOONGARCH_CSR_DMWIN0
+ bltu $a0, $t0, ReadSelNumErr
+ li.w $t0, LOONGARCH_CSR_DMWIN3
+ bltu $t0, $a0, ReadSelNumErr
+ la.pcrel $t0, DirMapCsrRead
+ addi.w $t1, $a0, -LOONGARCH_CSR_DMWIN0
+ alsl.d $t0, $t1, $t0, 3
+ jirl $zero, $t0, 0
+
+ReadSelNumErr:
+ addi.d $a0, $zero, -1
+ jirl $zero, $ra, 0
+
+BasicCsrRead:
+ CsrSel = LOONGARCH_CSR_CRMD
+ .rept LOONGARCH_CSR_EBASE - LOONGARCH_CSR_CRMD + 1
+ AsmCsrRd CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+TlbCsrRead:
+ CsrSel = LOONGARCH_CSR_TLBIDX
+ .rept LOONGARCH_CSR_RVACFG - LOONGARCH_CSR_TLBIDX + 1
+ AsmCsrRd CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+CfgCsrRead:
+ CsrSel = LOONGARCH_CSR_CPUNUM
+ .rept LOONGARCH_CSR_PRCFG3 - LOONGARCH_CSR_CPUNUM + 1
+ AsmCsrRd CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+KcsCsrRead:
+ CsrSel = LOONGARCH_CSR_KS0
+ .rept LOONGARCH_CSR_KS8 - LOONGARCH_CSR_KS0 + 1
+ AsmCsrRd CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+StableTimerCsrRead:
+ CsrSel = LOONGARCH_CSR_TMID
+ .rept LOONGARCH_CSR_TINTCLR - LOONGARCH_CSR_TMID + 1
+ AsmCsrRd CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+TlbRefillCsrRead:
+ CsrSel = LOONGARCH_CSR_TLBREBASE
+ .rept LOONGARCH_CSR_TLBREHI - LOONGARCH_CSR_TLBREBASE + 1
+ AsmCsrRd CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+DirMapCsrRead:
+ CsrSel = LOONGARCH_CSR_DMWIN0
+ .rept LOONGARCH_CSR_DMWIN3 - LOONGARCH_CSR_DMWIN0 + 1
+ AsmCsrRd CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+ASM_PFX(AsmCsrWrite):
+ blt $a0, $zero, WriteSelNumErr
+ li.w $t0, LOONGARCH_CSR_EBASE
+ bltu $t0, $a0, TlbCsrWr
+
+BasicCsrWr:
+ la.pcrel $t0, BasicCsrWrite
+ alsl.d $t0, $a0, $t0, 3
+ move $a0, $a1
+ jirl $zero, $t0, 0
+
+TlbCsrWr:
+ li.w $t0, LOONGARCH_CSR_TLBIDX
+ bltu $a0, $t0, WriteSelNumErr
+ li.w $t0, LOONGARCH_CSR_RVACFG
+ bltu $t0, $a0, CfgCsrWr
+ la.pcrel $t0, TlbCsrWrite
+ addi.w $t1, $a0, -LOONGARCH_CSR_TLBIDX
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ jirl $zero, $t0, 0
+
+CfgCsrWr:
+ li.w $t0, LOONGARCH_CSR_CPUNUM
+ bltu $a0, $t0, WriteSelNumErr
+ li.w $t0, LOONGARCH_CSR_PRCFG3
+ bltu $t0, $a0, KcsCsrWr
+ la.pcrel $t0, CfgCsrWrite
+ addi.w $t1, $a0, -LOONGARCH_CSR_CPUNUM
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ jirl $zero, $t0, 0
+
+KcsCsrWr:
+ li.w $t0, LOONGARCH_CSR_KS0
+ bltu $a0, $t0, WriteSelNumErr
+ li.w $t0, LOONGARCH_CSR_KS8
+ bltu $t0, $a0, StableTimerCsrWr
+ la.pcrel $t0, KcsCsrWrite
+ addi.w $t1, $a0, -LOONGARCH_CSR_KS0
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ jirl $zero, $t0, 0
+
+StableTimerCsrWr:
+ li.w $t0, LOONGARCH_CSR_TMID
+ bltu $a0, $t0, WriteSelNumErr
+ li.w $t0, LOONGARCH_CSR_TINTCLR
+ bltu $t0, $a0, TlbRefillCsrWr
+ la.pcrel $t0, StableTimerCsrWrite
+ addi.w $t1, $a0, -LOONGARCH_CSR_TMID
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ jirl $zero, $t0, 0
+
+TlbRefillCsrWr:
+ li.w $t0, LOONGARCH_CSR_TLBREBASE
+ bltu $a0, $t0, WriteSelNumErr
+ li.w $t0, LOONGARCH_CSR_TLBREHI
+ bltu $t0, $a0, DirMapCsrWr
+ la.pcrel $t0, TlbRefillCsrWrite
+ addi.w $t1, $a0, -LOONGARCH_CSR_TLBREBASE
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ jirl $zero, $t0, 0
+
+DirMapCsrWr:
+ li.w $t0, LOONGARCH_CSR_DMWIN0
+ bltu $a0, $t0, WriteSelNumErr
+ li.w $t0, LOONGARCH_CSR_DMWIN3
+ bltu $t0, $a0, WriteSelNumErr
+ la.pcrel $t0, DirMapCsrWrite
+ addi.w $t1, $a0, -LOONGARCH_CSR_DMWIN0
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ jirl $zero, $t0, 0
+
+WriteSelNumErr:
+ addi.d $a0, $zero, -1
+ jirl $zero, $ra, 0
+
+BasicCsrWrite:
+ CsrSel = LOONGARCH_CSR_CRMD
+ .rept LOONGARCH_CSR_EBASE - LOONGARCH_CSR_CRMD + 1
+ AsmCsrWr CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+TlbCsrWrite:
+ CsrSel = LOONGARCH_CSR_TLBIDX
+ .rept LOONGARCH_CSR_RVACFG - LOONGARCH_CSR_TLBIDX + 1
+ AsmCsrWr CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+CfgCsrWrite:
+ CsrSel = LOONGARCH_CSR_CPUNUM
+ .rept LOONGARCH_CSR_PRCFG3 - LOONGARCH_CSR_CPUNUM + 1
+ AsmCsrWr CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+KcsCsrWrite:
+ CsrSel = LOONGARCH_CSR_KS0
+ .rept LOONGARCH_CSR_KS8 - LOONGARCH_CSR_KS0 + 1
+ AsmCsrWr CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+StableTimerCsrWrite:
+ CsrSel = LOONGARCH_CSR_TMID
+ .rept LOONGARCH_CSR_TINTCLR - LOONGARCH_CSR_TMID + 1
+ AsmCsrWr CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+TlbRefillCsrWrite:
+ CsrSel = LOONGARCH_CSR_TLBREBASE
+ .rept LOONGARCH_CSR_TLBREHI - LOONGARCH_CSR_TLBREBASE + 1
+ AsmCsrWr CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+DirMapCsrWrite:
+ CsrSel = LOONGARCH_CSR_DMWIN0
+ .rept LOONGARCH_CSR_DMWIN3 - LOONGARCH_CSR_DMWIN0 + 1
+ AsmCsrWr CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+
+ASM_PFX(AsmCsrXChg):
+ blt $a0, $zero, XchgSelNumErr
+ li.w $t0, LOONGARCH_CSR_EBASE
+ bltu $t0, $a0, TlbCsrXchg
+
+BasicCsrXchg:
+ la.pcrel $t0, BasicCsrXchange
+ alsl.d $t0, $a0, $t0, 3
+ move $a0, $a1
+ move $a1, $a2
+ jirl $zero, $t0, 0
+
+TlbCsrXchg:
+ li.w $t0, LOONGARCH_CSR_TLBIDX
+ bltu $a0, $t0, XchgSelNumErr
+ li.w $t0, LOONGARCH_CSR_RVACFG
+ bltu $t0, $a0, CfgCsrXchg
+ la.pcrel $t0, TlbCsrXchange
+ addi.w $t1, $a0, -LOONGARCH_CSR_TLBIDX
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ move $a1, $a2
+ jirl $zero, $t0, 0
+
+CfgCsrXchg:
+ li.w $t0, LOONGARCH_CSR_CPUNUM
+ bltu $a0, $t0, XchgSelNumErr
+ li.w $t0, LOONGARCH_CSR_PRCFG3
+ bltu $t0, $a0, KcsCsrXchg
+ la.pcrel $t0, CfgCsrXchange
+ addi.w $t1, $a0, -LOONGARCH_CSR_CPUNUM
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ move $a1, $a2
+ jirl $zero, $t0, 0
+
+KcsCsrXchg:
+ li.w $t0, LOONGARCH_CSR_KS0
+ bltu $a0, $t0, XchgSelNumErr
+ li.w $t0, LOONGARCH_CSR_KS8
+ bltu $t0, $a0, StableTimerCsrXchg
+ la.pcrel $t0, KcsCsrXchange
+ addi.w $t1, $a0, -LOONGARCH_CSR_KS0
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ move $a1, $a2
+ jirl $zero, $t0, 0
+
+StableTimerCsrXchg:
+ li.w $t0, LOONGARCH_CSR_TMID
+ bltu $a0, $t0, XchgSelNumErr
+ li.w $t0, LOONGARCH_CSR_TINTCLR
+ bltu $t0, $a0, TlbRefillCsrXchg
+ la.pcrel $t0, StableTimerCsrXchange
+ addi.w $t1, $a0, -LOONGARCH_CSR_TMID
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ move $a1, $a2
+ jirl $zero, $t0, 0
+
+TlbRefillCsrXchg:
+ li.w $t0, LOONGARCH_CSR_TLBREBASE
+ bltu $a0, $t0, XchgSelNumErr
+ li.w $t0, LOONGARCH_CSR_TLBREHI
+ bltu $t0, $a0, DirMapCsrXchg
+ la.pcrel $t0, TlbRefillCsrXchange
+ addi.w $t1, $a0, -LOONGARCH_CSR_TLBREBASE
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ move $a1, $a2
+ jirl $zero, $t0, 0
+
+DirMapCsrXchg:
+ li.w $t0, LOONGARCH_CSR_DMWIN0
+ bltu $a0, $t0, XchgSelNumErr
+ li.w $t0, LOONGARCH_CSR_DMWIN3
+ bltu $t0, $a0, XchgSelNumErr
+ la.pcrel $t0, DirMapCsrXchange
+ addi.w $t1, $a0, -LOONGARCH_CSR_DMWIN0
+ alsl.d $t0, $t1, $t0, 3
+ move $a0, $a1
+ move $a1, $a2
+ jirl $zero, $t0, 0
+
+XchgSelNumErr:
+ addi.d $a0, $zero, -1
+ jirl $zero, $ra, 0
+
+BasicCsrXchange:
+ CsrSel = LOONGARCH_CSR_CRMD
+ .rept LOONGARCH_CSR_EBASE - LOONGARCH_CSR_CRMD + 1
+ AsmCsrXChange CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+TlbCsrXchange:
+ CsrSel = LOONGARCH_CSR_TLBIDX
+ .rept LOONGARCH_CSR_RVACFG - LOONGARCH_CSR_TLBIDX + 1
+ AsmCsrXChange CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+CfgCsrXchange:
+ CsrSel = LOONGARCH_CSR_CPUNUM
+ .rept LOONGARCH_CSR_PRCFG3 - LOONGARCH_CSR_CPUNUM + 1
+ AsmCsrXChange CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+KcsCsrXchange:
+ CsrSel = LOONGARCH_CSR_KS0
+ .rept LOONGARCH_CSR_KS8 - LOONGARCH_CSR_KS0 + 1
+ AsmCsrXChange CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+StableTimerCsrXchange:
+ CsrSel = LOONGARCH_CSR_TMID
+ .rept LOONGARCH_CSR_TINTCLR - LOONGARCH_CSR_TMID + 1
+ AsmCsrXChange CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+TlbRefillCsrXchange:
+ CsrSel = LOONGARCH_CSR_TLBREBASE
+ .rept LOONGARCH_CSR_TLBREHI - LOONGARCH_CSR_TLBREBASE + 1
+ AsmCsrXChange CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+
+DirMapCsrXchange:
+ CsrSel = LOONGARCH_CSR_DMWIN0
+ .rept LOONGARCH_CSR_DMWIN3 - LOONGARCH_CSR_DMWIN0 + 1
+ AsmCsrXChange CsrSel
+ CsrSel = CsrSel + 1
+ .endr
+.end
diff --git a/MdePkg/Library/BaseLib/LoongArch64/Csr.c b/MdePkg/Library/BaseLib/LoongArch64/Csr.c
new file mode 100644
index 0000000000..d51f30aacc
--- /dev/null
+++ b/MdePkg/Library/BaseLib/LoongArch64/Csr.c
@@ -0,0 +1,81 @@
+/** @file
+ LoongArch CSR operation functions.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+UINTN
+AsmCsrRead (
+ IN UINT16 Select
+ );
+
+UINTN
+AsmCsrWrite (
+ IN UINT16 Select,
+ IN UINTN Value
+ );
+
+UINTN
+AsmCsrXChg (
+ IN UINT16 Select,
+ IN UINTN Value,
+ IN UINTN Mask
+ );
+
+/**
+ CSR read operation.
+
+ @param[in] Select CSR read instruction select values.
+
+ @return The return value of csrrd instruction, return -1 means Select is out of support.
+**/
+UINTN
+EFIAPI
+CsrRead (
+ IN UINT16 Select
+ )
+{
+ return AsmCsrRead (Select);
+}
+
+/**
+ CSR write operation.
+
+ @param[in] Select CSR write instruction select values.
+ @param[in, out] Value The csrwr will write the value.
+
+ @return The return value of csrwr instruction, that is, store the old value of
+ the register, return -1 means Select is out of support.
+**/
+UINTN
+EFIAPI
+CsrWrite (
+ IN UINT16 Select,
+ IN OUT UINTN Value
+ )
+{
+ return AsmCsrWrite (Select, Value);
+}
+
+/**
+ CSR exchange operation.
+
+ @param[in] Select CSR exchange instruction select values.
+ @param[in, out] Value The csrxchg will write the value.
+ @param[in] Mask The csrxchg mask value.
+
+ @return The return value of csrxchg instruction, that is, store the old value of
+ the register, return -1 means Select is out of support.
+**/
+UINTN
+EFIAPI
+CsrXChg (
+ IN UINT16 Select,
+ IN OUT UINTN Value,
+ IN UINTN Mask
+ )
+{
+ return AsmCsrXChg (Select, Value, Mask);
+}
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111360): https://edk2.groups.io/g/devel/message/111360
Mute This Topic: https://groups.io/mt/102644752/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 08/39] MdePkg: Add IOCSR operation for LoongArch
[not found] <20231117095742.3605778-1-lichao@loongs>
` (6 preceding siblings ...)
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 07/39] MdePkg: Add CSR " Chao Li
@ 2023-11-17 9:59 ` Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg Chao Li
` (32 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:59 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu
Add IoCsrRead8, IoCsrRead16, IoCsrRead32, IoCsrRead64, IoCsrWrite8,
IoCsrWrite16, IoCsrWrite32, IoCsrWrite64 to operate the IOCSR registers
of LoongArch architecture.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
---
MdePkg/Include/Library/BaseLib.h | 112 +++++++++++++++++++
MdePkg/Library/BaseLib/BaseLib.inf | 1 +
MdePkg/Library/BaseLib/LoongArch64/IoCsr.S | 120 +++++++++++++++++++++
3 files changed, 233 insertions(+)
create mode 100644 MdePkg/Library/BaseLib/LoongArch64/IoCsr.S
diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 234f3065c2..88ee6e9d51 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -338,6 +338,118 @@ CsrXChg (
IN UINTN Mask
);
+/**
+ IO CSR read byte operation.
+
+ @param[in] Select IO CSR read instruction select values.
+
+ @return The return value of iocsrrd.b instruction.
+
+**/
+UINT8
+IoCsrRead8 (
+ IN UINTN Select
+ );
+
+/**
+ IO CSR read half word operation.
+
+ @param[in] Select IO CSR read instruction select values.
+
+ @return The return value of iocsrrd.h instruction.
+
+**/
+UINT16
+IoCsrRead16 (
+ IN UINTN Select
+ );
+
+/**
+ IO CSR read word operation.
+
+ @param[in] Select IO CSR read instruction select values.
+
+ @return The return value of iocsrrd.w instruction.
+
+**/
+UINT32
+IoCsrRead32 (
+ IN UINTN Select
+ );
+
+/**
+ IO CSR read double word operation. Only for LoongArch64.
+
+ @param[in] Select IO CSR read instruction select values.
+
+ @return The return value of iocsrrd.d instruction.
+
+**/
+UINT64
+IoCsrRead64 (
+ IN UINTN Select
+ );
+
+/**
+ IO CSR write byte operation.
+
+ @param[in] Select IO CSR write instruction select values.
+ @param[in] Value The iocsrwr.b will write the value.
+
+ @return VOID.
+
+**/
+VOID
+IoCsrWrite8 (
+ IN UINTN Select,
+ IN UINT8 Value
+ );
+
+/**
+ IO CSR write half word operation.
+
+ @param[in] Select IO CSR write instruction select values.
+ @param[in] Value The iocsrwr.h will write the value.
+
+ @return VOID.
+
+**/
+VOID
+IoCsrWrite16 (
+ IN UINTN Select,
+ IN UINT16 Value
+ );
+
+/**
+ IO CSR write word operation.
+
+ @param[in] Select IO CSR write instruction select values.
+ @param[in] Value The iocsrwr.w will write the value.
+
+ @return VOID.
+
+**/
+VOID
+IoCsrWrite32 (
+ IN UINTN Select,
+ IN UINT32 Value
+ );
+
+/**
+ IO CSR write double word operation. Only for LoongArch64.
+
+ @param[in] Select IO CSR write instruction select values.
+ @param[in] Value The iocsrwr.d will write the value.
+
+ @return VOID.
+
+**/
+VOID
+IoCsrWrite64 (
+ IN UINTN Select,
+ IN UINT64 Value
+ );
+
#endif // defined (MDE_CPU_LOONGARCH64)
//
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index 74a323c798..e72724c1c1 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -412,6 +412,7 @@
LoongArch64/Csr.c
LoongArch64/InternalSwitchStack.c
LoongArch64/AsmCsr.S | GCC
+ LoongArch64/IoCsr.S | GCC
LoongArch64/GetInterruptState.S | GCC
LoongArch64/EnableInterrupts.S | GCC
LoongArch64/DisableInterrupts.S | GCC
diff --git a/MdePkg/Library/BaseLib/LoongArch64/IoCsr.S b/MdePkg/Library/BaseLib/LoongArch64/IoCsr.S
new file mode 100644
index 0000000000..4c0009b93a
--- /dev/null
+++ b/MdePkg/Library/BaseLib/LoongArch64/IoCsr.S
@@ -0,0 +1,120 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch ASM IO CSR operation functions
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+ASM_GLOBAL ASM_PFX (IoCsrRead8)
+ASM_GLOBAL ASM_PFX (IoCsrRead16)
+ASM_GLOBAL ASM_PFX (IoCsrRead32)
+ASM_GLOBAL ASM_PFX (IoCsrRead64)
+
+ASM_GLOBAL ASM_PFX (IoCsrWrite8)
+ASM_GLOBAL ASM_PFX (IoCsrWrite16)
+ASM_GLOBAL ASM_PFX (IoCsrWrite32)
+ASM_GLOBAL ASM_PFX (IoCsrWrite64)
+
+#/**
+# IO CSR read byte operation.
+#
+# @param[in] Select IO CSR read instruction select values.
+#
+# @return The return value of iocsrrd.b instruction.
+#
+#**/
+ASM_PFX (IoCsrRead8):
+ iocsrrd.b $a0, $a0
+ jirl $zero, $ra, 0
+
+#/**
+# IO CSR read half word operation.
+#
+# @param[in] Select IO CSR read instruction select values.
+#
+# @return The return value of iocsrrd.h instruction.
+#
+#**/
+ASM_PFX (IoCsrRead16):
+ iocsrrd.h $a0, $a0
+ jirl $zero, $ra, 0
+
+#/**
+# IO CSR read word operation.
+#
+# @param[in] Select IO CSR read instruction select values.
+#
+# @return The return value of iocsrrd.w instruction.
+#
+#**/
+ASM_PFX (IoCsrRead32):
+ iocsrrd.w $a0, $a0
+ jirl $zero, $ra, 0
+
+#/**
+# IO CSR read double word operation. Only for LoongArch64.
+#
+# @param[in] Select IO CSR read instruction select values.
+#
+# @return The return value of iocsrrd.d instruction.
+#
+#**/
+ASM_PFX (IoCsrRead64):
+ iocsrrd.d $a0, $a0
+ jirl $zero, $ra, 0
+
+#/**
+# IO CSR write byte operation.
+#
+# @param[in] Select IO CSR write instruction select values.
+# @param[in] Value The iocsrwr.b will write the value.
+#
+# @return VOID.
+#
+#**/
+ASM_PFX (IoCsrWrite8):
+ iocsrwr.b $a1, $a0
+ jirl $zero, $ra, 0
+
+#/**
+# IO CSR write half word operation.
+#
+# @param[in] Select IO CSR write instruction select values.
+# @param[in] Value The iocsrwr.h will write the value.
+#
+# @return VOID.
+#
+#**/
+ASM_PFX (IoCsrWrite16):
+ iocsrwr.h $a1, $a0
+ jirl $zero, $ra, 0
+
+#/**
+# IO CSR write word operation.
+#
+# @param[in] Select IO CSR write instruction select values.
+# @param[in] Value The iocsrwr.w will write the value.
+#
+# @return VOID.
+#
+#**/
+ASM_PFX (IoCsrWrite32):
+ iocsrwr.w $a1, $a0
+ jirl $zero, $ra, 0
+
+#/**
+# IO CSR write double word operation. Only for LoongArch64.
+#
+# @param[in] Select IO CSR write instruction select values.
+# @param[in] Value The iocsrwr.d will write the value.
+#
+# @return VOID.
+#
+#**/
+ASM_PFX (IoCsrWrite64):
+ iocsrwr.d $a1, $a0
+ jirl $zero, $ra, 0
+ .end
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111361): https://edk2.groups.io/g/devel/message/111361
Mute This Topic: https://groups.io/mt/102644753/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (7 preceding siblings ...)
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 08/39] MdePkg: Add IOCSR " Chao Li
@ 2023-11-17 9:59 ` Chao Li
2023-11-17 11:35 ` Leif Lindholm
2023-11-21 14:37 ` Laszlo Ersek
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 10/39] MdePkg: Add method of LoongArch64 to PeiServicesTablePointerLibReg Chao Li
` (31 subsequent siblings)
40 siblings, 2 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:59 UTC (permalink / raw)
To: devel
Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Laszlo Ersek, Sunil V L
Since some ARCH or platform not require execute code on memory during
PEI phase, some values may transferred via CPU registers.
Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
table pointer depend by a CPU register, this library can accommodate lot
of platforms who not require execte code on memory during PEI phase.
Adding PeiServiceTablePointerLibReg to allows setting and getting the
PEI service table pointer via CPU registers, and the library can
accommodate many platforms that do not need to execute code on memory
during the PEI phase.
The idea of this library is derived from
ArmPkg/Library/PeiServicesTablePointerLib/
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
.../Library/PeiServicesTablePointerLib.h | 37 +++++++-
.../PeiServicesTablePointer.c | 86 +++++++++++++++++++
.../PeiServicesTablePointerLib.uni | 20 +++++
.../PeiServicesTablePointerLibReg.inf | 40 +++++++++
MdePkg/MdePkg.dsc | 1 +
5 files changed, 180 insertions(+), 4 deletions(-)
create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
diff --git a/MdePkg/Include/Library/PeiServicesTablePointerLib.h b/MdePkg/Include/Library/PeiServicesTablePointerLib.h
index 61635eff00..f5c764cb13 100644
--- a/MdePkg/Include/Library/PeiServicesTablePointerLib.h
+++ b/MdePkg/Include/Library/PeiServicesTablePointerLib.h
@@ -52,10 +52,11 @@ SetPeiServicesTablePointer (
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.
+ For Itanium, ARM and LoongArch 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, ARM and
+ LoongArch CPUs.
**/
VOID
@@ -64,4 +65,32 @@ MigratePeiServicesTablePointer (
VOID
);
+/**
+ Retrieves the cached value of the PEI Services Table pointer from a CPU register.
+
+ 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.
+
+ @return The pointer to PeiServices.
+**/
+CONST EFI_PEI_SERVICES **
+EFIAPI
+GetPeiServicesTablePointerFromRegister (
+ VOID
+ );
+
+/**
+ Set the pointer PEI Service Table to a CPU register.
+
+ Caches the pointer to the PEI Services Table specified by PeiServicesTablePointer
+ in a platform specific manner.
+
+ @param PeiServicesTablePointer The address of PeiServices.
+**/
+VOID
+EFIAPI
+SetPeiServicesTablePointerToRegester (
+ IN UINTN PeiServicesTablePointer
+ );
#endif
diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
new file mode 100644
index 0000000000..0227f98871
--- /dev/null
+++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
@@ -0,0 +1,86 @@
+/** @file
+ PEI Services Table Pointer Library For Reigseter Mechanism.
+
+ This library is used for PEIM which does executed from flash device directly but
+ executed in memory.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
+ Copyright (c) 2023 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>
+
+/**
+ 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
+ )
+{
+ ASSERT (PeiServicesTablePointer != NULL);
+ SetPeiServicesTablePointerToRegester ((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
+ )
+{
+ CONST EFI_PEI_SERVICES **PeiServices;
+
+ PeiServices = GetPeiServicesTablePointerFromRegister ();
+ ASSERT (PeiServices != NULL);
+ return PeiServices;
+}
+
+/**
+ 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, ARM and LoongArch 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, ARM and
+ LoongArch CPUs.
+
+**/
+VOID
+EFIAPI
+MigratePeiServicesTablePointer (
+ VOID
+ )
+{
+ return;
+}
diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
new file mode 100644
index 0000000000..937cf857d9
--- /dev/null
+++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Instance of PEI Services Table Pointer Library using CPU register for the table pointer.
+//
+// PEI Services Table Pointer Library implementation that retrieves a pointer to the
+// PEI Services Table from a CPU register. Applies to modules that execute from
+// read-only memory.
+//
+// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+// Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
+// Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of PEI Services Table Pointer Library using CPU register for the table pointer"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The PEI Services Table Pointer Library implementation that retrieves a pointer to the PEI Services Table from a CPU register. Applies to modules that execute from read-only memory."
+
diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
new file mode 100644
index 0000000000..22499e22ad
--- /dev/null
+++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
@@ -0,0 +1,40 @@
+## @file
+# Instance of PEI Services Table Pointer Library using CPU register for the table pointer.
+#
+# PEI Services Table Pointer Library implementation that retrieves a pointer to the
+# PEI Services Table from a CPU register. Applies to modules that execute from
+# read-only memory.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiServicesTablePointerLib
+ MODULE_UNI_FILE = PeiServicesTablePointerLib.uni
+ FILE_GUID = 619950D1-7C5F-EA1B-D6DD-2FF7B0A4A2B7
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PeiServicesTablePointerLib|PEIM PEI_CORE SEC
+
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64 RISCV64 LOONGARCH64
+#
+
+[Sources]
+ PeiServicesTablePointer.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+
+[Pcd]
+
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index 3abd1a1e23..2e9a3d4b4c 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -103,6 +103,7 @@
MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf
MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+ MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
MdePkg/Library/PeiSmbusLibSmbus2Ppi/PeiSmbusLibSmbus2Ppi.inf
MdePkg/Library/PeiPciLibPciCfg2/PeiPciLibPciCfg2.inf
MdePkg/Library/PeiPciSegmentLibPciCfg2/PeiPciSegmentLibPciCfg2.inf
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111362): https://edk2.groups.io/g/devel/message/111362
Mute This Topic: https://groups.io/mt/102644754/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 10/39] MdePkg: Add method of LoongArch64 to PeiServicesTablePointerLibReg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (8 preceding siblings ...)
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg Chao Li
@ 2023-11-17 9:59 ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library Chao Li
` (30 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 9:59 UTC (permalink / raw)
To: devel
Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Laszlo Ersek
LoongArch uses the reigster LOONGARCH_CSR_KS0 in the PEI stage to set
and get the PEI service table pointer. Add this method to
PeiServiceTablePointerLibReg.
This is a code first phase, I will update the PI specification next.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
.../LoongArch64/PeiServicesTablePointerReg.c | 47 +++++++++++++++++++
.../PeiServicesTablePointerLibReg.inf | 3 ++
2 files changed, 50 insertions(+)
create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/LoongArch64/PeiServicesTablePointerReg.c
diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/LoongArch64/PeiServicesTablePointerReg.c b/MdePkg/Library/PeiServicesTablePointerLibReg/LoongArch64/PeiServicesTablePointerReg.c
new file mode 100644
index 0000000000..368c907992
--- /dev/null
+++ b/MdePkg/Library/PeiServicesTablePointerLibReg/LoongArch64/PeiServicesTablePointerReg.c
@@ -0,0 +1,47 @@
+/** @file
+ PEI Services Table Pointer Library For LoongArch.
+
+ Used Register Mechanism.
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Register/LoongArch64/Csr.h>
+
+/**
+ Set the pointer PEI Service Table to a CPU register.
+
+ Caches the pointer to the PEI Services Table specified by PeiServicesTablePointer
+ in a platform specific manner.
+
+ @param PeiServicesTablePointer The address of PeiServices.
+**/
+VOID
+EFIAPI
+SetPeiServicesTablePointerToRegester (
+ IN UINTN PeiServicesTablePointer
+ )
+{
+ CsrWrite (LOONGARCH_CSR_KS0, (UINTN)PeiServicesTablePointer);
+}
+
+/**
+ Retrieves the cached value of the PEI Services Table pointer from a CPU register.
+
+ 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.
+
+ @return The pointer to PeiServices.
+**/
+CONST EFI_PEI_SERVICES **
+EFIAPI
+GetPeiServicesTablePointerFromRegister (
+ VOID
+ )
+{
+ return (CONST EFI_PEI_SERVICES **)(CsrRead (LOONGARCH_CSR_KS0));
+}
diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
index 22499e22ad..b26a970b12 100644
--- a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
+++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
@@ -30,6 +30,9 @@
[Sources]
PeiServicesTablePointer.c
+[Sources.LOONGARCH64]
+ LoongArch64/PeiServicesTablePointerReg.c
+
[Packages]
MdePkg/MdePkg.dec
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111363): https://edk2.groups.io/g/devel/message/111363
Mute This Topic: https://groups.io/mt/102644762/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library
[not found] <20231117095742.3605778-1-lichao@loongs>
` (9 preceding siblings ...)
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 10/39] MdePkg: Add method of LoongArch64 to PeiServicesTablePointerLibReg Chao Li
@ 2023-11-17 10:00 ` Chao Li
2023-11-22 16:12 ` Laszlo Ersek
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 12/39] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
` (29 subsequent siblings)
40 siblings, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:00 UTC (permalink / raw)
To: devel; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
Add the LoongArch64 CPU Timer library, using CPUCFG 0x4 and 0x5 for
Stable Counter frequency.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
.../BaseLoongArch64CpuTimerLib.inf | 30 +++
.../BaseLoongArch64CpuTimerLib.uni | 15 ++
.../BaseLoongArch64CpuTimerLib/CpuTimerLib.c | 226 ++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
4 files changed, 274 insertions(+)
create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
new file mode 100644
index 0000000000..c00c215aec
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
@@ -0,0 +1,30 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides base timer support using CPUCFG 0x4 and 0x5 stable counter frequency.
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseLoongArch64CpuTimerLib
+ FILE_GUID = 740389C7-CC44-4A2F-88DC-89D97D312E7C
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseLoongArch64CpuTimerLib.uni
+
+[Sources.common]
+ CpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
new file mode 100644
index 0000000000..72d38ec679
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides base timer support using CPUCFG 0x4 and 0x5 stable counter frequency.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "LOONGARCH CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUCFG 0x4 and 0x5 stable counter frequency."
diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..349b881cbc
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,226 @@
+/** @file
+ CPUCFG 0x4 and 0x5 for Stable Counter frequency instance of Timer Library.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Register/LoongArch64/Cpucfg.h>
+
+/**
+ Calculate clock frequency using CPUCFG 0x4 and 0x5 registers.
+
+ @param VOID.
+
+ @return The frequency in Hz.
+
+**/
+UINT32
+EFIAPI
+CalcConstFreq (
+ VOID
+ )
+{
+ UINT32 BaseFreq;
+ UINT32 ClockMultiplier;
+ UINT32 ClockDivide;
+ CPUCFG_REG4_INFO_DATA CCFreq;
+ CPUCFG_REG5_INFO_DATA CpucfgReg5Data;
+ UINT32 StableTimerFreq;
+
+ //
+ // Get the the crystal frequency corresponding to the constant
+ // frequency timer and the clock used by the timer.
+ //
+ AsmCpucfg (CPUCFG_REG4_INFO, &CCFreq.Uint32);
+
+ //
+ // Get the multiplication factor and frequency division factor
+ // corresponding to the constant frequency timer and the clock
+ // used by the timer.
+ //
+ AsmCpucfg (CPUCFG_REG5_INFO, &CpucfgReg5Data.Uint32);
+
+ BaseFreq = CCFreq.Bits.CC_FREQ;
+ ClockMultiplier = CpucfgReg5Data.Bits.CC_MUL & 0xFFFFULL;
+ ClockDivide = CpucfgReg5Data.Bits.CC_DIV & 0xFFFFULL;
+
+ if (!BaseFreq || !ClockMultiplier || !ClockDivide) {
+ DEBUG ((DEBUG_ERROR, "LoongArch Stable Timer is not available in the CPU, hence this library cannot be used.\n"));
+ StableTimerFreq = 0;
+ ASSERT (0);
+ } else {
+ StableTimerFreq = (BaseFreq * ClockMultiplier / ClockDivide);
+ }
+
+ 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, Ticks, Start, End;
+
+ Count = (CalcConstFreq () * MicroSeconds) / 1000000;
+ Start = AsmReadStableCounter ();
+ End = Start + Count;
+
+ do {
+ Ticks = AsmReadStableCounter ();
+ } 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 AsmReadStableCounter ();
+}
+
+/**
+ 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 CalcConstFreq ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ 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/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 074fd77461..8e34a9cd6b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -205,5 +205,8 @@
UefiCpuPkg/CpuTimerDxeRiscV64/CpuTimerDxeRiscV64.inf
UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
+[Components.LOONGARCH64]
+ UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
+
[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111364): https://edk2.groups.io/g/devel/message/111364
Mute This Topic: https://groups.io/mt/102644766/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 12/39] UefiCpuPkg: Add CPU exception library for LoongArch
[not found] <20231117095742.3605778-1-lichao@loongs>
` (10 preceding siblings ...)
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library Chao Li
@ 2023-11-17 10:00 ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
` (28 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:00 UTC (permalink / raw)
To: devel; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann, Baoqi Zhang
Added a new library named LoongArch64CpuExceptionHandlerLib, and
modified the way LoongArch exceptions are expressed.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
---
MdePkg/Include/Protocol/DebugSupport.h | 76 +++--
.../DxeCpuExceptionHandlerLib.inf | 45 +++
.../DxeCpuExceptionHandlerLib.uni | 15 +
.../DxeExceptionLib.c | 202 +++++++++++
.../ExceptionCommon.c | 170 ++++++++++
.../ExceptionCommon.h | 111 ++++++
.../LoongArch64/ArchExceptionHandler.c | 214 ++++++++++++
.../LoongArch64/ExceptionHandlerAsm.S | 320 ++++++++++++++++++
.../SecPeiCpuExceptionHandlerLib.inf | 45 +++
.../SecPeiCpuExceptionHandlerLib.uni | 15 +
.../SecPeiExceptionLib.c | 90 +++++
UefiCpuPkg/UefiCpuPkg.dec | 6 +
UefiCpuPkg/UefiCpuPkg.dsc | 2 +
13 files changed, 1279 insertions(+), 32 deletions(-)
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeExceptionLib.c
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.c
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.h
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ArchExceptionHandler.c
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ExceptionHandlerAsm.S
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiExceptionLib.c
diff --git a/MdePkg/Include/Protocol/DebugSupport.h b/MdePkg/Include/Protocol/DebugSupport.h
index 9742663619..ccdddd4828 100644
--- a/MdePkg/Include/Protocol/DebugSupport.h
+++ b/MdePkg/Include/Protocol/DebugSupport.h
@@ -680,33 +680,45 @@ typedef struct {
UINT32 STVAL;
} EFI_SYSTEM_CONTEXT_RISCV64;
-//
-// LoongArch processor exception types.
-//
-#define EXCEPT_LOONGARCH_INT 0
-#define EXCEPT_LOONGARCH_PIL 1
-#define EXCEPT_LOONGARCH_PIS 2
-#define EXCEPT_LOONGARCH_PIF 3
-#define EXCEPT_LOONGARCH_PME 4
-#define EXCEPT_LOONGARCH_PNR 5
-#define EXCEPT_LOONGARCH_PNX 6
-#define EXCEPT_LOONGARCH_PPI 7
-#define EXCEPT_LOONGARCH_ADE 8
-#define EXCEPT_LOONGARCH_ALE 9
-#define EXCEPT_LOONGARCH_BCE 10
-#define EXCEPT_LOONGARCH_SYS 11
-#define EXCEPT_LOONGARCH_BRK 12
-#define EXCEPT_LOONGARCH_INE 13
-#define EXCEPT_LOONGARCH_IPE 14
-#define EXCEPT_LOONGARCH_FPD 15
-#define EXCEPT_LOONGARCH_SXD 16
-#define EXCEPT_LOONGARCH_ASXD 17
-#define EXCEPT_LOONGARCH_FPE 18
-#define EXCEPT_LOONGARCH_TBR 64 // For code only, there is no such type in the ISA spec, the TLB refill is defined for an independent exception.
-
-//
-// LoongArch processor Interrupt types.
-//
+///
+/// LoongArch processor exception types.
+///
+#define EXCEPT_LOONGARCH_ECODE_SHIFT 16
+#define EXCEPT_LOONGARCH_INT (0 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PIL (1 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PIS (2 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PIF (3 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PME (4 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PNR (5 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PNX (6 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_PPI (7 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_ADE (8 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_ALE (9 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_BCE (10 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_SYS (11 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_BRK (12 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_INE (13 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_IPE (14 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_FPD (15 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_SXD (16 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_ASXD (17 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_FPE (18 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_WPE (19 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_BTD (20 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_BTE (21 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_GSPR (22 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_HVC (23 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+#define EXCEPT_LOONGARCH_GCXC (24 << EXCEPT_LOONGARCH_ECODE_SHIFT)
+
+///
+/// For coding convenience, define the maximum valid
+/// LoongArch exception.
+///
+#define MAX_LOONGARCH_EXCEPTION 64
+
+///
+/// LoongArch processor Interrupt types.
+///
#define EXCEPT_LOONGARCH_INT_SIP0 0
#define EXCEPT_LOONGARCH_INT_SIP1 1
#define EXCEPT_LOONGARCH_INT_IP0 2
@@ -721,11 +733,11 @@ typedef struct {
#define EXCEPT_LOONGARCH_INT_TIMER 11
#define EXCEPT_LOONGARCH_INT_IPI 12
-//
-// For coding convenience, define the maximum valid
-// LoongArch interrupt.
-//
-#define MAX_LOONGARCH_INTERRUPT 14
+///
+/// For coding convenience, define the maximum valid
+/// LoongArch interrupt.
+///
+#define MAX_LOONGARCH_INTERRUPT 16
typedef struct {
UINT64 R0;
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
new file mode 100644
index 0000000000..fa38218464
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -0,0 +1,45 @@
+## @file
+# LoongArch exception library instance for DXE modules.
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuExceptionHandlerLib
+ MODULE_UNI_FILE = DxeCpuExceptionHandlerLib.uni
+ FILE_GUID = 23C5D29F-F54B-091B-BD94-027576ED09FA
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_CORE DXE_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources.LoongArch64]
+ LoongArch64/ArchExceptionHandler.c
+ LoongArch64/ExceptionHandlerAsm.S | GCC
+
+[Sources.common]
+ ExceptionCommon.h
+ ExceptionCommon.c
+ DxeExceptionLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ CpuLib
+ BaseLib
+ SerialPortLib
+ PrintLib
+ PeCoffGetEntryPointLib
+ SynchronizationLib
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni
new file mode 100644
index 0000000000..d884387da3
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// CPU Exception Handler library instance for DXE modules.
+//
+// CPU Exception Handler library instance for DXE modules.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Exception Handler library instance for DXE modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Exception Handler library instance for DXE modules."
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeExceptionLib.c b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeExceptionLib.c
new file mode 100644
index 0000000000..f274f82c51
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeExceptionLib.c
@@ -0,0 +1,202 @@
+/** @file DxeExceptionLib.c
+
+ LoongArch exception library implemenation for DXE modules.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include <Protocol/DebugSupport.h>
+
+#include "ExceptionCommon.h"
+
+EFI_EXCEPTION_CALLBACK ExternalInterruptHandler[MAX_LOONGARCH_INTERRUPT + 1] = { 0 };
+EFI_EXCEPTION_CALLBACK ExceptionHandler[MAX_LOONGARCH_EXCEPTION + 1] = { 0 };
+
+/**
+ Registers a function to be called from the processor interrupt or exception handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ EFI_EXCEPTION_TYPE ExceptionType;
+
+ ExceptionType = InterruptType & CSR_ESTAT_EXC;
+
+ if (ExceptionType != 0) {
+ //
+ // Exception
+ //
+ if (ExceptionType > EXCEPT_LOONGARCH_FPE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ExceptionType >>= EXCEPT_LOONGARCH_ECODE_SHIFT;
+
+ if ((InterruptHandler == NULL) && (ExceptionHandler[InterruptType] == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((InterruptHandler != NULL) && (ExceptionHandler[ExceptionType] != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ ExceptionHandler[ExceptionType] = InterruptHandler;
+ } else {
+ //
+ // Interrupt
+ //
+ if (InterruptType > MAX_LOONGARCH_INTERRUPT) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((InterruptHandler == NULL) && (ExternalInterruptHandler[InterruptType] == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((InterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ ExternalInterruptHandler[InterruptType] = InterruptHandler;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Common exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_EXCEPTION_TYPE InterruptType;
+
+ if (ExceptionType == EXCEPT_LOONGARCH_INT) {
+ //
+ // Interrupt
+ //
+ InterruptType = GetInterruptType (SystemContext);
+ if (InterruptType == 0xFF) {
+ ExceptionType = InterruptType;
+ } else {
+ if ((ExternalInterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) {
+ ExternalInterruptHandler[InterruptType](InterruptType, SystemContext);
+ return;
+ }
+ }
+ } else if (ExceptionType == EXCEPT_LOONGARCH_FPD) {
+ EnableFloatingPointUnits ();
+ InitializeFloatingPointUnits ();
+ return;
+ } else {
+ //
+ // Exception
+ //
+ ExceptionType >>= EXCEPT_LOONGARCH_ECODE_SHIFT;
+ if ((ExceptionHandler != NULL) && (ExceptionHandler[ExceptionType] != NULL)) {
+ ExceptionHandler[ExceptionType](ExceptionType, SystemContext);
+ return;
+ }
+ }
+
+ //
+ // Only the TLB refill exception use the same entry point as normal exceptions.
+ //
+ if (CsrRead (LOONGARCH_CSR_TLBRERA) & 0x1) {
+ ExceptionType = mExceptionKnownNameNum - 1; // Use only to dump the exception context.
+ }
+
+ DefaultExceptionHandler (ExceptionType, SystemContext);
+}
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Setup separate stacks for certain exception handlers.
+ If the input Buffer and BufferSize are both NULL, use global variable if possible.
+
+ @param[in] Buffer Point to buffer used to separate exception stack.
+ @param[in, out] BufferSize On input, it indicates the byte size of Buffer.
+ If the size is not enough, the return status will
+ be EFI_BUFFER_TOO_SMALL, and output BufferSize
+ will be the size it needs.
+
+ @retval EFI_SUCCESS The stacks are assigned successfully.
+ @retval EFI_UNSUPPORTED This function is not supported.
+ @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.
+**/
+EFI_STATUS
+EFIAPI
+InitializeSeparateExceptionStacks (
+ IN VOID *Buffer,
+ IN OUT UINTN *BufferSize
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.c b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.c
new file mode 100644
index 0000000000..aa58a4128a
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.c
@@ -0,0 +1,170 @@
+/** @file DxeExceptionLib.c
+
+ CPU Exception Handler Library common functions.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include "ExceptionCommon.h"
+
+CONST CHAR8 mExceptionReservedStr[] = "Reserved";
+CONST CHAR8 *mExceptionNameStr[] = {
+ "#INT - Interrupt(CSR.ECFG.VS=0)",
+ "#PIL - Page invalid exception for Load option",
+ "#PIS - Page invalid exception for Store operation",
+ "#PIF - Page invalid exception for Fetch operation",
+ "#PME - Page modification exception",
+ "#PNR - Page non-readable exception",
+ "#PNX - Page non-executable exception",
+ "#PPI - Page privilege level illegal exception",
+ "#ADE - Address error exception",
+ "#ALE - Address alignment fault exception",
+ "#BCE - Bound check exception",
+ "#SYS - System call exception",
+ "#BRK - Beeakpoint exception",
+ "#INE - Instruction non-defined exception",
+ "#IPE - Instruction privilege error exception",
+ "#FPD - Floating-point instruction disable exception",
+ "#SXD - 128-bit vector (SIMD instructions) expansion instruction disable exception",
+ "#ASXD - 256-bit vector (Advanced SIMD instructions) expansion instruction disable exception",
+ "#FPE - Floating-Point error exception",
+ "#WPE - WatchPoint Exception for Fetch watchpoint or Memory load/store watchpoint",
+ "#BTD - Binary Translation expansion instruction Disable exception",
+ "#BTE - Binary Translation related exceptions",
+ "#GSPR - Guest Sensitive Privileged Resource exception",
+ "#HVC - HyperVisor Call exception",
+ "#GCXC - Guest CSR Software/Hardware Change exception",
+ "#TBR - TLB refill exception" // !!! NOTICE: Because the TLB refill exception is not instructed in ECODE, so the TLB refill exception must be the last one!
+};
+
+INTN mExceptionKnownNameNum = (sizeof (mExceptionNameStr) / sizeof (CHAR8 *));
+
+/**
+ Get ASCII format string exception name by exception type.
+
+ @param ExceptionType Exception type.
+
+ @return ASCII format string exception name.
+
+**/
+CONST CHAR8 *
+GetExceptionNameStr (
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ if ((UINTN)ExceptionType < mExceptionKnownNameNum) {
+ return mExceptionNameStr[ExceptionType];
+ } else {
+ return mExceptionReservedStr;
+ }
+}
+
+/**
+ Prints a message to the serial port.
+
+ @param Format Format string for the message to print.
+ @param ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+InternalPrintMessage (
+ IN CONST CHAR8 *Format,
+ ...
+ )
+{
+ CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
+ VA_LIST Marker;
+
+ //
+ // Convert the message to an ASCII String
+ //
+ VA_START (Marker, Format);
+ AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+ VA_END (Marker);
+
+ //
+ // Send the print string to a Serial Port
+ //
+ SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
+}
+
+/**
+ Find and display image base address and return image base and its entry point.
+
+ @param CurrentEra Current instruction pointer.
+
+**/
+VOID
+DumpModuleImageInfo (
+ IN UINTN CurrentEra
+ )
+{
+ EFI_STATUS Status;
+ UINTN Pe32Data;
+ VOID *PdbPointer;
+ VOID *EntryPoint;
+
+ Pe32Data = PeCoffSearchImageBase (CurrentEra);
+ if (Pe32Data == 0) {
+ InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
+ } else {
+ //
+ // Find Image Base entry point
+ //
+ Status = PeCoffLoaderGetEntryPoint ((VOID *)Pe32Data, &EntryPoint);
+ if (EFI_ERROR (Status)) {
+ EntryPoint = NULL;
+ }
+
+ InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentEra);
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)Pe32Data);
+ if (PdbPointer != NULL) {
+ InternalPrintMessage ("%a", PdbPointer);
+ } else {
+ InternalPrintMessage ("(No PDB) ");
+ }
+
+ InternalPrintMessage (
+ " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
+ (VOID *)Pe32Data,
+ EntryPoint
+ );
+ }
+}
+
+/**
+ Default exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+DefaultExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Initialize the serial port before dumping.
+ //
+ SerialPortInitialize ();
+ //
+ // Display ExceptionType, CPU information and Image information
+ //
+ DumpImageAndCpuContent (ExceptionType, SystemContext);
+
+ //
+ // Enter a dead loop.
+ //
+ CpuDeadLoop ();
+}
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.h b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.h
new file mode 100644
index 0000000000..b19144b196
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/ExceptionCommon.h
@@ -0,0 +1,111 @@
+/** @file DxeExceptionLib.h
+
+ Common header file for CPU Exception Handler Library.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef EXCEPTION_COMMON_H_
+#define EXCEPTION_COMMON_H_
+
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100
+
+extern INTN mExceptionKnownNameNum;
+
+/**
+ Get ASCII format string exception name by exception type.
+
+ @param[in] ExceptionType Exception type.
+
+ @return ASCII format string exception name.
+
+**/
+CONST CHAR8 *
+GetExceptionNameStr (
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ Prints a message to the serial port.
+
+ @param[in] Format Format string for the message to print.
+ @param[in] ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+InternalPrintMessage (
+ IN CONST CHAR8 *Format,
+ ...
+ );
+
+/**
+ Find and display image base address and return image base and its entry point.
+
+ @param[in] CurrentEip Current instruction pointer.
+
+**/
+VOID
+DumpModuleImageInfo (
+ IN UINTN CurrentEip
+ );
+
+/**
+ Default exception handler.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+DefaultExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Display CPU information.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+DumpImageAndCpuContent (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Get exception types
+
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+ @return Exception type.
+
+**/
+EFI_EXCEPTION_TYPE
+EFIAPI
+GetExceptionType (
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Get Common interrupt types
+
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+ @return Interrupt type.
+
+**/
+EFI_EXCEPTION_TYPE
+EFIAPI
+GetInterruptType (
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+#endif
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ArchExceptionHandler.c b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ArchExceptionHandler.c
new file mode 100644
index 0000000000..2b2f75aad0
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ArchExceptionHandler.c
@@ -0,0 +1,214 @@
+/** @file ArchExceptionHandler.c
+
+ LoongArch64 CPU Exception Handler.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/CpuLib.h>
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include "ExceptionCommon.h"
+
+/**
+ Get Exception Type
+
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+ @return LoongArch64 exception type.
+
+**/
+EFI_EXCEPTION_TYPE
+EFIAPI
+GetExceptionType (
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_EXCEPTION_TYPE ExceptionType;
+
+ ExceptionType = (SystemContext.SystemContextLoongArch64->ESTAT & CSR_ESTAT_EXC);
+ return ExceptionType;
+}
+
+/**
+ Get Interrupt Type
+
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+ @return LoongArch64 intrrupt type.
+
+**/
+EFI_EXCEPTION_TYPE
+EFIAPI
+GetInterruptType (
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_EXCEPTION_TYPE InterruptType;
+
+ for (InterruptType = 0; InterruptType <= EXCEPT_LOONGARCH_INT_IPI; InterruptType++) {
+ if (SystemContext.SystemContextLoongArch64->ESTAT & (1 << InterruptType)) {
+ //
+ // 0 - EXCEPT_LOONGARCH_INT_SIP0
+ // 1 - EXCEPT_LOONGARCH_INT_SIP1
+ // 2 - EXCEPT_LOONGARCH_INT_IP0
+ // 3 - EXCEPT_LOONGARCH_INT_IP1
+ // 4 - EXCEPT_LOONGARCH_INT_IP2
+ // 5 - EXCEPT_LOONGARCH_INT_IP3
+ // 6 - EXCEPT_LOONGARCH_INT_IP4
+ // 7 - EXCEPT_LOONGARCH_INT_IP5
+ // 8 - EXCEPT_LOONGARCH_INT_IP6
+ // 9 - EXCEPT_LOONGARCH_INT_IP7
+ // 10 - EXCEPT_LOONGARCH_INT_PMC
+ // 11 - EXCEPT_LOONGARCH_INT_TIMER
+ // 12 - EXCEPT_LOONGARCH_INT_IPI
+ // Greater than EXCEPT_LOONGARCH_INI_IPI is currently invalid.
+ //
+ return InterruptType;
+ }
+ }
+
+ //
+ // Invalid IRQ
+ //
+ return 0xFF;
+}
+
+/**
+ Display CPU information.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+DumpCpuContext (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ InternalPrintMessage (
+ "\n!!!! LoongArch64 Exception Type - %02x(%a) !!!!\n",
+ ExceptionType,
+ GetExceptionNameStr (ExceptionType)
+ );
+
+ //
+ // Dump TLB refill ERA and BADV
+ //
+ if (ExceptionType == (mExceptionKnownNameNum - 1)) {
+ InternalPrintMessage ("TLB refill ERA 0x%llx\n", (CsrRead (LOONGARCH_CSR_TLBRERA) & (~0x3ULL)));
+ InternalPrintMessage ("TLB refill BADV 0x%llx\n", CsrRead (LOONGARCH_CSR_TLBRBADV));
+ }
+
+ //
+ // Dump the general registers
+ //
+ InternalPrintMessage (
+ "Zero - 0x%016lx, RA - 0x%016lx, TP - 0x%016lx, SP - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->R0,
+ SystemContext.SystemContextLoongArch64->R1,
+ SystemContext.SystemContextLoongArch64->R2,
+ SystemContext.SystemContextLoongArch64->R3
+ );
+ InternalPrintMessage (
+ " A0 - 0x%016lx, A1 - 0x%016lx, A2 - 0x%016lx, A3 - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->R4,
+ SystemContext.SystemContextLoongArch64->R5,
+ SystemContext.SystemContextLoongArch64->R6,
+ SystemContext.SystemContextLoongArch64->R7
+ );
+ InternalPrintMessage (
+ " A4 - 0x%016lx, A5 - 0x%016lx, A6 - 0x%016lx, A7 - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->R8,
+ SystemContext.SystemContextLoongArch64->R9,
+ SystemContext.SystemContextLoongArch64->R10,
+ SystemContext.SystemContextLoongArch64->R11
+ );
+ InternalPrintMessage (
+ " T0 - 0x%016lx, T1 - 0x%016lx, T2 - 0x%016lx, T3 - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->R12,
+ SystemContext.SystemContextLoongArch64->R13,
+ SystemContext.SystemContextLoongArch64->R14,
+ SystemContext.SystemContextLoongArch64->R15
+ );
+ InternalPrintMessage (
+ " T4 - 0x%016lx, T5 - 0x%016lx, T6 - 0x%016lx, T7 - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->R16,
+ SystemContext.SystemContextLoongArch64->R17,
+ SystemContext.SystemContextLoongArch64->R18,
+ SystemContext.SystemContextLoongArch64->R19
+ );
+ InternalPrintMessage (
+ " T8 - 0x%016lx, R21 - 0x%016lx, FP - 0x%016lx, S0 - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->R20,
+ SystemContext.SystemContextLoongArch64->R21,
+ SystemContext.SystemContextLoongArch64->R22,
+ SystemContext.SystemContextLoongArch64->R23
+ );
+ InternalPrintMessage (
+ " S1 - 0x%016lx, S2 - 0x%016lx, S3 - 0x%016lx, S4 - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->R24,
+ SystemContext.SystemContextLoongArch64->R25,
+ SystemContext.SystemContextLoongArch64->R26,
+ SystemContext.SystemContextLoongArch64->R27
+ );
+ InternalPrintMessage (
+ " S5 - 0x%016lx, S6 - 0x%016lx, S7 - 0x%016lx, S8 - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->R28,
+ SystemContext.SystemContextLoongArch64->R29,
+ SystemContext.SystemContextLoongArch64->R30,
+ SystemContext.SystemContextLoongArch64->R31
+ );
+ InternalPrintMessage ("\n");
+
+ //
+ // Dump the CSR registers
+ //
+ InternalPrintMessage (
+ "CRMD - 0x%016lx, PRMD - 0x%016lx, EUEN - 0x%016lx, MISC - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->CRMD,
+ SystemContext.SystemContextLoongArch64->PRMD,
+ SystemContext.SystemContextLoongArch64->EUEN,
+ SystemContext.SystemContextLoongArch64->MISC
+ );
+ InternalPrintMessage (
+ "ECFG - 0x%016lx, ESTAT - 0x%016lx, ERA - 0x%016lx, BADV - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->ECFG,
+ SystemContext.SystemContextLoongArch64->ESTAT,
+ SystemContext.SystemContextLoongArch64->ERA,
+ SystemContext.SystemContextLoongArch64->BADV
+ );
+ InternalPrintMessage (
+ "BADI - 0x%016lx\n",
+ SystemContext.SystemContextLoongArch64->BADI
+ );
+}
+
+/**
+ Display CPU information.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+DumpImageAndCpuContent (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ DumpCpuContext (ExceptionType, SystemContext);
+
+ if (ExceptionType == (mExceptionKnownNameNum - 1)) {
+ //
+ // Dump TLB refill image info
+ //
+ DumpModuleImageInfo ((CsrRead (LOONGARCH_CSR_TLBRERA) & (~0x3ULL)));
+ } else {
+ DumpModuleImageInfo (SystemContext.SystemContextLoongArch64->ERA);
+ }
+}
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ExceptionHandlerAsm.S b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ExceptionHandlerAsm.S
new file mode 100644
index 0000000000..88a5f696a7
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/LoongArch64/ExceptionHandlerAsm.S
@@ -0,0 +1,320 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch64 ASM exception handler
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#include <Library/CpuLib.h>
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#define RSIZE 8 // 64 bit mode register size
+#define GP_REG_CONTEXT_SIZE 32 * RSIZE // General-purpose registers size
+#define FP_REG_CONTEXT_SIZE 34 * RSIZE // Floating-point registers size
+#define CSR_REG_CONTEXT_SIZE 9 * RSIZE // CSR registers size
+
+ASM_GLOBAL ASM_PFX(ExceptionEntry)
+ASM_GLOBAL ASM_PFX(ExceptionEntryStart)
+ASM_GLOBAL ASM_PFX(ExceptionEntryEnd)
+
+ASM_PFX(ExceptionEntry):
+ move $s0, $a0
+ bl GetExceptionType // Exception type stored in register a0
+ move $a1, $s0 // SystemContxt
+ bl CommonExceptionHandler
+
+PopContext:
+ //
+ // Not sure if interrupts are turned on during the exception handler, anyway disable interrupts here.
+ // It will be turned on when the instruction 'ertn' is executed.
+ //
+ bl DisableInterrupts
+
+ bl GetExceptionType // Get current exception type, and stored in register a0
+
+ // Check whether the FPE is changed during interrupt handler, if ture restore it.
+ ld.d $t1, $sp, (LOONGARCH_CSR_EUEN * RSIZE + GP_REG_CONTEXT_SIZE)
+ csrrd $t0, LOONGARCH_CSR_EUEN // Current EUEN
+ andi $t0, $t0, CSR_EUEN_FPEN
+ andi $t1, $t1, CSR_EUEN_FPEN
+ li.d $t2, EXCEPT_LOONGARCH_INT
+ bne $a0, $t2, PopRegs
+ beq $t0, $t1, PopRegs
+ beqz $t1, CloseFP
+ bl EnableFloatingPointUnits
+ b PopRegs
+
+CloseFP:
+ bl DisableFloatingPointUnits
+
+PopRegs:
+ //
+ // Pop CSR reigsters
+ //
+ addi.d $sp, $sp, GP_REG_CONTEXT_SIZE
+
+ ld.d $t0, $sp, LOONGARCH_CSR_CRMD * RSIZE
+ csrwr $t0, LOONGARCH_CSR_CRMD
+ ld.d $t0, $sp, LOONGARCH_CSR_PRMD * RSIZE
+ csrwr $t0, LOONGARCH_CSR_PRMD
+ ld.d $t0, $sp, LOONGARCH_CSR_ECFG * RSIZE
+ csrwr $t0, LOONGARCH_CSR_ECFG
+ ld.d $t0, $sp, LOONGARCH_CSR_ERA * RSIZE
+ csrwr $t0, LOONGARCH_CSR_ERA
+
+ addi.d $sp, $sp, CSR_REG_CONTEXT_SIZE // Fource change the stack pointer befor pop the FP registers.
+
+ beqz $t1, PopGP // If the FPE not set, only pop the GP registers.
+
+ //
+ // Pop FP registers
+ //
+ fld.d $fa0, $sp, 0 * RSIZE
+ fld.d $fa1, $sp, 1 * RSIZE
+ fld.d $fa2, $sp, 2 * RSIZE
+ fld.d $fa3, $sp, 3 * RSIZE
+ fld.d $fa4, $sp, 4 * RSIZE
+ fld.d $fa5, $sp, 5 * RSIZE
+ fld.d $fa6, $sp, 6 * RSIZE
+ fld.d $fa7, $sp, 7 * RSIZE
+ fld.d $ft0, $sp, 8 * RSIZE
+ fld.d $ft1, $sp, 9 * RSIZE
+ fld.d $ft2, $sp, 10 * RSIZE
+ fld.d $ft3, $sp, 11 * RSIZE
+ fld.d $ft4, $sp, 12 * RSIZE
+ fld.d $ft5, $sp, 13 * RSIZE
+ fld.d $ft6, $sp, 14 * RSIZE
+ fld.d $ft7, $sp, 15 * RSIZE
+ fld.d $ft8, $sp, 16 * RSIZE
+ fld.d $ft9, $sp, 17 * RSIZE
+ fld.d $ft10, $sp, 18 * RSIZE
+ fld.d $ft11, $sp, 19 * RSIZE
+ fld.d $ft12, $sp, 20 * RSIZE
+ fld.d $ft13, $sp, 21 * RSIZE
+ fld.d $ft14, $sp, 22 * RSIZE
+ fld.d $ft15, $sp, 23 * RSIZE
+ fld.d $fs0, $sp, 24 * RSIZE
+ fld.d $fs1, $sp, 25 * RSIZE
+ fld.d $fs2, $sp, 26 * RSIZE
+ fld.d $fs3, $sp, 27 * RSIZE
+ fld.d $fs4, $sp, 28 * RSIZE
+ fld.d $fs5, $sp, 29 * RSIZE
+ fld.d $fs6, $sp, 30 * RSIZE
+ fld.d $fs7, $sp, 31 * RSIZE
+
+ ld.d $t0, $sp, 32 * RSIZE
+ movgr2fcsr $r0, $t0 // Pop the fcsr0 register.
+
+ //
+ // Pop the fcc0-fcc7 registers.
+ //
+ ld.d $t0, $sp, 33 * RSIZE
+ bstrpick.d $t1, $t0, 7, 0
+ movgr2cf $fcc0, $t1
+ bstrpick.d $t1, $t0, 15, 8
+ movgr2cf $fcc1, $t1
+ bstrpick.d $t1, $t0, 23, 16
+ movgr2cf $fcc2, $t1
+ bstrpick.d $t1, $t0, 31, 24
+ movgr2cf $fcc3, $t1
+ bstrpick.d $t1, $t0, 39, 32
+ movgr2cf $fcc4, $t1
+ bstrpick.d $t1, $t0, 47, 40
+ movgr2cf $fcc5, $t1
+ bstrpick.d $t1, $t0, 55, 48
+ movgr2cf $fcc6, $t1
+ bstrpick.d $t1, $t0, 63, 56
+ movgr2cf $fcc7, $t1
+
+PopGP:
+ //
+ // Pop GP registers
+ //
+ addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
+ ld.d $ra, $sp, 1 * RSIZE
+ ld.d $tp, $sp, 2 * RSIZE
+ ld.d $a0, $sp, 4 * RSIZE
+ ld.d $a1, $sp, 5 * RSIZE
+ ld.d $a2, $sp, 6 * RSIZE
+ ld.d $a3, $sp, 7 * RSIZE
+ ld.d $a4, $sp, 8 * RSIZE
+ ld.d $a5, $sp, 9 * RSIZE
+ ld.d $a6, $sp, 10 * RSIZE
+ ld.d $a7, $sp, 11 * RSIZE
+ ld.d $t0, $sp, 12 * RSIZE
+ ld.d $t1, $sp, 13 * RSIZE
+ ld.d $t2, $sp, 14 * RSIZE
+ ld.d $t3, $sp, 15 * RSIZE
+ ld.d $t4, $sp, 16 * RSIZE
+ ld.d $t5, $sp, 17 * RSIZE
+ ld.d $t6, $sp, 18 * RSIZE
+ ld.d $t7, $sp, 19 * RSIZE
+ ld.d $t8, $sp, 20 * RSIZE
+ ld.d $r21, $sp, 21 * RSIZE
+ ld.d $fp, $sp, 22 * RSIZE
+ ld.d $s0, $sp, 23 * RSIZE
+ ld.d $s1, $sp, 24 * RSIZE
+ ld.d $s2, $sp, 25 * RSIZE
+ ld.d $s3, $sp, 26 * RSIZE
+ ld.d $s4, $sp, 27 * RSIZE
+ ld.d $s5, $sp, 28 * RSIZE
+ ld.d $s6, $sp, 29 * RSIZE
+ ld.d $s7, $sp, 30 * RSIZE
+ ld.d $s8, $sp, 31 * RSIZE
+ ld.d $sp, $sp, 3 * RSIZE
+
+ ertn // Returen from exception.
+//
+// End of ExceptionEntry
+//
+
+ASM_PFX(ExceptionEntryStart):
+ //
+ // Store the old stack pointer in preparation for pushing the exception context onto the new stack.
+ //
+ csrwr $sp, LOONGARCH_CSR_KS0
+
+ csrrd $sp, LOONGARCH_CSR_KS0
+
+ //
+ // Push GP registers
+ //
+ addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + FP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
+ st.d $zero, $sp, 0 * RSIZE
+ st.d $ra, $sp, 1 * RSIZE
+ st.d $tp, $sp, 2 * RSIZE
+ st.d $a0, $sp, 4 * RSIZE
+ st.d $a1, $sp, 5 * RSIZE
+ st.d $a2, $sp, 6 * RSIZE
+ st.d $a3, $sp, 7 * RSIZE
+ st.d $a4, $sp, 8 * RSIZE
+ st.d $a5, $sp, 9 * RSIZE
+ st.d $a6, $sp, 10 * RSIZE
+ st.d $a7, $sp, 11 * RSIZE
+ st.d $t0, $sp, 12 * RSIZE
+ st.d $t1, $sp, 13 * RSIZE
+ st.d $t2, $sp, 14 * RSIZE
+ st.d $t3, $sp, 15 * RSIZE
+ st.d $t4, $sp, 16 * RSIZE
+ st.d $t5, $sp, 17 * RSIZE
+ st.d $t6, $sp, 18 * RSIZE
+ st.d $t7, $sp, 19 * RSIZE
+ st.d $t8, $sp, 20 * RSIZE
+ st.d $r21, $sp, 21 * RSIZE
+ st.d $fp, $sp, 22 * RSIZE
+ st.d $s0, $sp, 23 * RSIZE
+ st.d $s1, $sp, 24 * RSIZE
+ st.d $s2, $sp, 25 * RSIZE
+ st.d $s3, $sp, 26 * RSIZE
+ st.d $s4, $sp, 27 * RSIZE
+ st.d $s5, $sp, 28 * RSIZE
+ st.d $s6, $sp, 29 * RSIZE
+ st.d $s7, $sp, 30 * RSIZE
+ st.d $s8, $sp, 31 * RSIZE
+ csrrd $t0, LOONGARCH_CSR_KS0 // Read the old stack pointer.
+ st.d $t0, $sp, 3 * RSIZE
+
+ //
+ // Push CSR registers
+ //
+ addi.d $sp, $sp, GP_REG_CONTEXT_SIZE
+
+ csrrd $t0, LOONGARCH_CSR_CRMD
+ st.d $t0, $sp, LOONGARCH_CSR_CRMD * RSIZE
+ csrrd $t0, LOONGARCH_CSR_PRMD
+ st.d $t0, $sp, LOONGARCH_CSR_PRMD * RSIZE
+ csrrd $t0, LOONGARCH_CSR_EUEN
+ st.d $t0, $sp, LOONGARCH_CSR_EUEN * RSIZE
+ csrrd $t0, LOONGARCH_CSR_MISC
+ st.d $t0, $sp, LOONGARCH_CSR_MISC * RSIZE
+ csrrd $t0, LOONGARCH_CSR_ECFG
+ st.d $t0, $sp, LOONGARCH_CSR_ECFG * RSIZE
+ csrrd $t0, LOONGARCH_CSR_ESTAT
+ st.d $t0, $sp, LOONGARCH_CSR_ESTAT * RSIZE
+ csrrd $t0, LOONGARCH_CSR_ERA
+ st.d $t0, $sp, LOONGARCH_CSR_ERA * RSIZE
+ csrrd $t0, LOONGARCH_CSR_BADV
+ st.d $t0, $sp, LOONGARCH_CSR_BADV * RSIZE
+ csrrd $t0, LOONGARCH_CSR_BADI
+ st.d $t0, $sp, LOONGARCH_CSR_BADI * RSIZE
+
+ //
+ // Push FP registers
+ //
+ addi.d $sp, $sp, CSR_REG_CONTEXT_SIZE
+
+ csrrd $t0, LOONGARCH_CSR_EUEN
+ andi $t0, $t0, CSR_EUEN_FPEN
+ beqz $t0, PushRegDone
+
+ fst.d $fa0, $sp, 0 * RSIZE
+ fst.d $fa1, $sp, 1 * RSIZE
+ fst.d $fa2, $sp, 2 * RSIZE
+ fst.d $fa3, $sp, 3 * RSIZE
+ fst.d $fa4, $sp, 4 * RSIZE
+ fst.d $fa5, $sp, 5 * RSIZE
+ fst.d $fa6, $sp, 6 * RSIZE
+ fst.d $fa7, $sp, 7 * RSIZE
+ fst.d $ft0, $sp, 8 * RSIZE
+ fst.d $ft1, $sp, 9 * RSIZE
+ fst.d $ft2, $sp, 10 * RSIZE
+ fst.d $ft3, $sp, 11 * RSIZE
+ fst.d $ft4, $sp, 12 * RSIZE
+ fst.d $ft5, $sp, 13 * RSIZE
+ fst.d $ft6, $sp, 14 * RSIZE
+ fst.d $ft7, $sp, 15 * RSIZE
+ fst.d $ft8, $sp, 16 * RSIZE
+ fst.d $ft9, $sp, 17 * RSIZE
+ fst.d $ft10, $sp, 18 * RSIZE
+ fst.d $ft11, $sp, 19 * RSIZE
+ fst.d $ft12, $sp, 20 * RSIZE
+ fst.d $ft13, $sp, 21 * RSIZE
+ fst.d $ft14, $sp, 22 * RSIZE
+ fst.d $ft15, $sp, 23 * RSIZE
+ fst.d $fs0, $sp, 24 * RSIZE
+ fst.d $fs1, $sp, 25 * RSIZE
+ fst.d $fs2, $sp, 26 * RSIZE
+ fst.d $fs3, $sp, 27 * RSIZE
+ fst.d $fs4, $sp, 28 * RSIZE
+ fst.d $fs5, $sp, 29 * RSIZE
+ fst.d $fs6, $sp, 30 * RSIZE
+ fst.d $fs7, $sp, 31 * RSIZE
+
+ movfcsr2gr $t3, $r0
+ st.d $t3, $sp, 32 * RSIZE // Push the FCSR0 register.
+
+ //
+ // Push the fcc0-fcc7 registers.
+ //
+ movcf2gr $t3, $fcc0
+ or $t2, $t3, $zero
+ movcf2gr $t3, $fcc1
+ bstrins.d $t2, $t3, 0xf, 0x8
+ movcf2gr $t3, $fcc2
+ bstrins.d $t2, $t3, 0x17, 0x10
+ movcf2gr $t3, $fcc3
+ bstrins.d $t2, $t3, 0x1f, 0x18
+ movcf2gr $t3, $fcc4
+ bstrins.d $t2, $t3, 0x27, 0x20
+ movcf2gr $t3, $fcc5
+ bstrins.d $t2, $t3, 0x2f, 0x28
+ movcf2gr $t3, $fcc6
+ bstrins.d $t2, $t3, 0x37, 0x30
+ movcf2gr $t3, $fcc7
+ bstrins.d $t2, $t3, 0x3f, 0x38
+ st.d $t2, $sp, 33 * RSIZE
+ //
+ // Push exception context down
+ //
+
+PushRegDone:
+ addi.d $sp, $sp, -(GP_REG_CONTEXT_SIZE + CSR_REG_CONTEXT_SIZE)
+ move $a0, $sp
+ la.abs $ra, ExceptionEntry
+ jirl $zero, $ra, 0
+ASM_PFX(ExceptionEntryEnd):
+.end
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
new file mode 100644
index 0000000000..456354ff04
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -0,0 +1,45 @@
+## @file
+# LoongArch exception library instance for PEI and SEC modules.
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecPeiCpuExceptionHandlerLib
+ MODULE_UNI_FILE = SecPeiCpuExceptionHandlerLib.uni
+ FILE_GUID = 0D69E6CD-1423-F118-C4EF-7AA439BC3E3B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuExceptionHandlerLib|SEC PEI_CORE PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources.LoongArch64]
+ LoongArch64/ArchExceptionHandler.c
+ LoongArch64/ExceptionHandlerAsm.S | GCC
+
+[Sources.common]
+ ExceptionCommon.h
+ ExceptionCommon.c
+ SecPeiExceptionLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ CpuLib
+ BaseLib
+ SerialPortLib
+ PrintLib
+ PeCoffGetEntryPointLib
+ SynchronizationLib
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni
new file mode 100644
index 0000000000..81fd606278
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// CPU Exception Handler library instance for SEC/PEI modules.
+//
+// CPU Exception Handler library instance for SEC/PEI modules.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Exception Handler library instance for SEC/PEI modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Exception Handler library instance for SEC/PEI modules."
diff --git a/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiExceptionLib.c b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiExceptionLib.c
new file mode 100644
index 0000000000..c140450d5b
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiExceptionLib.c
@@ -0,0 +1,90 @@
+/** @file SecPeiExceptionLib.c
+
+ LoongArch exception library implemenation for PEI and SEC modules.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include <Protocol/DebugSupport.h>
+
+#include "ExceptionCommon.h"
+
+/**
+ Registers a function to be called from the processor interrupt or exception handler.
+
+ Always return EFI_UNSUPPORTED in the SEC exception initialization module.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Common exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // APs may wake up by IPI IRQ during the SEC or PEI phase, clear the IPI interrupt and return.
+ //
+ if (GetInterruptType (SystemContext) == EXCEPT_LOONGARCH_INT_IPI) {
+ DisableLocalInterrupts (1 << EXCEPT_LOONGARCH_INT_IPI);
+ IoCsrWrite32 (LOONGARCH_IOCSR_IPI_CLEAR, IoCsrRead32 (LOONGARCH_IOCSR_IPI_STATUS));
+ return;
+ } else {
+ ExceptionType >>= EXCEPT_LOONGARCH_ECODE_SHIFT;
+ DefaultExceptionHandler (ExceptionType, SystemContext);
+ }
+}
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Always return EFI_SUCCESS in the SEC exception initialization module.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 0b5431dbf7..154b1d06fe 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -3,6 +3,7 @@
#
# Copyright (c) 2007 - 2023, Intel Corporation. All rights reserved.<BR>
# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -404,6 +405,11 @@
# 10 - 57bit mode.
gUefiCpuPkgTokenSpaceGuid.PcdCpuRiscVMmuMaxSatpMode|10|UINT32|0x60000021
+[PcdsFixedAtBuild.LoongArch64, PcdsPatchableInModule.LoongArch64, PcdsDynamic.LoongArch64, PcdsDynamicEx.LoongArch64]
+ ## Contains the pointer to a CPU exception vector base address.
+ # @Prompt The pointer to a CPU exception vector base address.
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress|0x0|UINT64|0x62640000
+
[PcdsDynamic, PcdsDynamicEx]
## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA.
# @Prompt The pointer to a CPU S3 data buffer.
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 8e34a9cd6b..872f20fc36 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -207,6 +207,8 @@
[Components.LOONGARCH64]
UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
+ UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+ UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111365): https://edk2.groups.io/g/devel/message/111365
Mute This Topic: https://groups.io/mt/102644767/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (11 preceding siblings ...)
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 12/39] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
@ 2023-11-17 10:00 ` Chao Li
2023-11-17 20:18 ` Andrei Warkentin
2023-11-30 0:59 ` Ni, Ray
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 14/39] UefiCpuPkg: Add LoongArch64CpuMmuLib " Chao Li
` (27 subsequent siblings)
40 siblings, 2 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:00 UTC (permalink / raw)
To: devel
Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Andrei Warkentin
Add a new header file CpuMmuLib.h, whitch is referenced from
ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
LoongArch64 is added, and more architectures can be accommodated in the
future.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Andrei Warkentin <andrei.warkentin@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
UefiCpuPkg/Include/Library/CpuMmuLib.h | 155 +++++++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 4 +
2 files changed, 159 insertions(+)
create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h b/UefiCpuPkg/Include/Library/CpuMmuLib.h
new file mode 100644
index 0000000000..23b2fe34ac
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
@@ -0,0 +1,155 @@
+/** @file
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_MMU_LIB_H_
+#define CPU_MMU_LIB_H_
+
+#include <Uefi/UefiBaseType.h>
+
+#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;
+
+/**
+ Converts EFI Attributes to corresponding architecture Attributes.
+
+ @param[in] EfiAttributes Efi Attributes.
+
+ @retval Corresponding architecture attributes.
+**/
+UINTN
+EfiAttributeConverse (
+ 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
+GetMemoryRegionAttribute (
+ 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.
+ @param[in] AttributeMask Mask of memory attributes to take into account.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+**/
+EFI_STATUS
+SetMemoryRegionAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length,
+ IN UINTN Attributes,
+ IN UINT64 AttributeMask
+ );
+
+/**
+ 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
+SetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ );
+
+/**
+ Clears the non-executable Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to clear the Attributes.
+ @param[in] Length The length of the memory region to clear the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was clear successfully
+**/
+EFI_STATUS
+EFIAPI
+ClearMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Sets the read-only 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
+EFIAPI
+SetMemoryRegionReadOnly (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Clears the read-only Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to clear the Attributes.
+ @param[in] Length The length of the memory region to clear the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was clear successfully
+**/
+EFI_STATUS
+EFIAPI
+ClearMemoryRegionReadOnly (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Create a page table and initialize the memory management unit(MMU).
+
+ @param[in] MemoryTable A pointer to a memory ragion table.
+ @param[out] TranslationTableBase A pointer to a translation table base address.
+ @param[out] TranslationTableSize A pointer to a translation table base size.
+
+ @retval EFI_SUCCESS Configure MMU successfully.
+ EFI_INVALID_PARAMETER MemoryTable is NULL.
+ EFI_UNSUPPORTED Out of memory space or size not aligned.
+**/
+EFI_STATUS
+EFIAPI
+ConfigureMemoryManagementUint (
+ IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
+ OUT VOID **TranslationTableBase OPTIONAL,
+ OUT UINTN *TranslationTableSize OPTIONAL
+ );
+
+#endif // CPU_MMU_LIB_H_
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 154b1d06fe..150beae981 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -62,6 +62,10 @@
## @libraryclass Provides function for manipulating x86 paging structures.
CpuPageTableLib|Include/Library/CpuPageTableLib.h
+[LibraryClasses.LoongArch64]
+ ## @libraryclass Provides macros and functions for the memory management unit.
+ CpuMmuLib|Include/Library/CpuMmuLib.h
+
## @libraryclass Provides functions for manipulating smram savestate registers.
MmSaveStateLib|Include/Library/MmSaveStateLib.h
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111366): https://edk2.groups.io/g/devel/message/111366
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 14/39] UefiCpuPkg: Add LoongArch64CpuMmuLib to UefiCpuPkg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (12 preceding siblings ...)
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
@ 2023-11-17 10:00 ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 15/39] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
` (26 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:00 UTC (permalink / raw)
To: devel
Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann, Baoqi Zhang,
Dongyan Qian, Xianglai Li, Bibo Mao
Add a new library LoongArch64CpuMmuLib. It provides two-stage MMU library
instances, PEI and DXE.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
Co-authored-by: Dongyan Qian <qiandongyan@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
.../LoongArch64CpuMmuLib/CommonMmuLib.c | 965 ++++++++++++++++++
.../LoongArch64CpuMmuLib/CommonMmuLib.h | 43 +
.../LoongArch64CpuMmuLib/DxeCpuMmuLib.inf | 37 +
.../LoongArch64CpuMmuLib/DxeCpuMmuLib.uni | 14 +
.../LoongArch64CpuMmuLib/CommonMmuLib.c | 964 +++++++++++++++++
.../LoongArch64CpuMmuLib/CommonMmuLib.h | 43 +
.../LoongArch64CpuMmuLib/DxeCpuMmuLib.inf | 37 +
.../LoongArch64CpuMmuLib/DxeCpuMmuLib.uni | 14 +
.../LoongArch64CpuMmuLib/Page.h | 279 +++++
.../LoongArch64CpuMmuLib/PeiCpuMmuLib.c | 165 +++
.../LoongArch64CpuMmuLib/PeiCpuMmuLib.inf | 44 +
.../LoongArch64CpuMmuLib/PeiCpuMmuLib.uni | 14 +
.../LoongArch64CpuMmuLib/Tlb.h | 48 +
.../LoongArch64CpuMmuLib/TlbOperation.S | 44 +
.../Library/LoongArch64CpuMmuLib/Page.h | 279 +++++
.../LoongArch64CpuMmuLib/PeiCpuMmuLib.c | 165 +++
.../LoongArch64CpuMmuLib/PeiCpuMmuLib.inf | 44 +
.../LoongArch64CpuMmuLib/PeiCpuMmuLib.uni | 14 +
UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h | 48 +
.../LoongArch64CpuMmuLib/TlbOperation.S | 44 +
UefiCpuPkg/UefiCpuPkg.dsc | 2 +
21 files changed, 3307 insertions(+)
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
new file mode 100644
index 0000000000..bd5c7e55b6
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
@@ -0,0 +1,965 @@
+/** @file
+
+ CPU Memory Map Unit Handler Library common functions.
+
+ Copyright (c) 2023 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/CpuMmuLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include "Tlb.h"
+#include "Page.h"
+
+BOOLEAN mMmuInited = FALSE;
+#define SWAP_PAGE_DIR CsrRead(LOONGARCH_CSR_PGDL)
+
+/**
+ 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 || (SWAP_PAGE_DIR != 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.
+
+ @return 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 *)(SWAP_PAGE_DIR) + 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;
+
+ 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;
+
+ 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;
+
+ 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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+**/
+EFI_STATUS
+PudAlloc (
+ IN PGD *Pgd
+ )
+{
+ PUD *Pud;
+
+ Pud = (PUD *)AllocatePages (1);
+ if (Pud == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)INVALID_PAGE);
+
+ SetPgd (Pgd, 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 *)INVALID_PAGE);
+
+ SetPud (Pud, 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.
+**/
+EFI_STATUS
+PteAlloc (
+ IN PMD *Pmd
+ )
+{
+ PTE *Pte;
+
+ Pte = (PTE *)AllocatePages (1);
+ if (!Pte) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
+
+ SetPmd (Pmd, 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.
+ @param Address The corresponding virtual address of the page table entry.
+
+ @retval A pointer to the page upper directory entry. Return NULL, if
+ allocate the memory buffer is fail.
+**/
+PUD *
+PudAllocGet (
+ IN PGD *Pgd,
+ IN UINTN Address
+ )
+{
+ EFI_STATUS Status;
+
+ if (PGD_IS_EMPTY (*Pgd)) {
+ Status = PudAlloc (Pgd);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ }
+
+ return 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.
+ @param Address The corresponding virtual address of the page table entry.
+
+ @retval A pointer to the page middle directory entry. Return NULL, if
+ allocate the memory buffer is fail.
+**/
+PMD *
+PmdAllocGet (
+ IN PUD *Pud,
+ IN UINTN Address
+ )
+{
+ EFI_STATUS Status;
+
+ if (PUD_IS_EMPTY (*Pud)) {
+ Status = PmdAlloc (Pud);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ }
+
+ return PmdOffset (Pud, Address);
+}
+
+/**
+ 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.
+ @param Address The corresponding virtual address of the page table entry.
+
+ @retval A pointer to the page table entry. Return NULL, if allocate
+ the memory buffer is fail.
+**/
+PTE *
+PteAllocGet (
+ IN PMD *Pmd,
+ IN UINTN Address
+ )
+{
+ EFI_STATUS Status;
+
+ if (PMD_IS_EMPTY (*Pmd)) {
+ Status = PteAlloc (Pmd);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ }
+
+ return 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_IS_EMPTY (*Pgd)) {
+ return NULL;
+ }
+
+ Pud = PudOffset (Pgd, Address);
+
+ if (PUD_IS_EMPTY (*Pud)) {
+ return NULL;
+ }
+
+ Pmd = PmdOffset (Pud, Address);
+ if (PMD_IS_EMPTY (*Pmd)) {
+ return NULL;
+ }
+
+ if (IS_HUGE_PAGE (Pmd->PmdVal)) {
+ return ((PTE *)Pmd);
+ }
+
+ return PteOffset (Pmd, Address);
+}
+
+/**
+ Gets the Attributes of Huge Page.
+
+ @param Pmd A pointer to the page middle directory.
+
+ @retval Value of Attributes.
+**/
+UINTN
+GetHugePageAttributes (
+ IN PMD *Pmd
+ )
+{
+ UINTN Attributes;
+ UINTN GlobalFlag;
+ UINTN HugeVal;
+
+ HugeVal = PMD_VAL (*Pmd);
+ Attributes = HugeVal & (~HUGEP_PAGE_MASK);
+ GlobalFlag = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT;
+ Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT);
+ Attributes |= GlobalFlag;
+ return Attributes;
+}
+
+/**
+ 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;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a %d Address %p End %p Attributes %llx\n",
+ __func__,
+ __LINE__,
+ Address,
+ End,
+ Attributes
+ ));
+
+ do {
+ UpDate = FALSE;
+ PteVal = MAKE_PTE (Address, Attributes);
+
+ if ((!PTE_IS_EMPTY (*Pte)) &&
+ (PTE_VAL (*Pte) != PTE_VAL (PteVal)))
+ {
+ UpDate = TRUE;
+ }
+
+ SetPte (Pte, PteVal);
+ if (UpDate) {
+ InvalidTlb (Address);
+ }
+ } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert Huge Page to Page.
+
+ @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
+ConvertHugePageToPage (
+ IN PMD *Pmd,
+ IN UINTN Address,
+ IN UINTN End,
+ IN UINTN Attributes
+ )
+{
+ UINTN OldAttributes;
+ UINTN HugePageEnd;
+ UINTN HugePageStart;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if ((PMD_IS_EMPTY (*Pmd)) ||
+ (!IS_HUGE_PAGE (Pmd->PmdVal)))
+ {
+ Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
+ } else {
+ OldAttributes = GetHugePageAttributes (Pmd);
+ if (Attributes == OldAttributes) {
+ return Status;
+ }
+
+ SetPmd (Pmd, (PTE *)(INVALID_PAGE));
+ HugePageStart = Address & PMD_MASK;
+ HugePageEnd = HugePageStart + HUGE_PAGE_SIZE;
+ ASSERT (HugePageEnd >= End);
+
+ if (Address > HugePageStart) {
+ Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes);
+ }
+
+ Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
+
+ if (End < HugePageEnd) {
+ Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ 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;
+ UINTN Next;
+ PTE PteVal;
+ BOOLEAN UpDate;
+
+ 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_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal)))
+ {
+ UpDate = FALSE;
+ PteVal = MAKE_HUGE_PTE (Address, Attributes);
+
+ if ((!PMD_IS_EMPTY (*Pmd)) &&
+ (PMD_VAL (*Pmd) != PTE_VAL (PteVal)))
+ {
+ UpDate = TRUE;
+ }
+
+ SetPmd (Pmd, (PTE *)PteVal.PteVal);
+ if (UpDate) {
+ InvalidTlb (Address);
+ }
+ } else {
+ ConvertHugePageToPage (Pmd, Address, Next, Attributes);
+ }
+ } while (Pmd++, Address = Next, Address != End);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 (EFI_ERROR (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;
+ EFI_STATUS Err;
+
+ Address = Start;
+
+ /* Get PGD(PTE PMD PUD PGD) in PageTables */
+ Pgd = PgdOffset (Address);
+ do {
+ Next = PGD_ADDRESS_END (Address, End);
+ /* Get Next Align Page to Map */
+ 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
+ );
+}
+
+/**
+ Convert EFI Attributes to Loongarch Attributes.
+
+ @param[in] EfiAttributes Efi Attributes.
+
+ @retval Corresponding architecture attributes.
+**/
+UINTN
+EfiAttributeConverse (
+ IN UINTN EfiAttributes
+ )
+{
+ UINTN LoongArchAttributes;
+
+ LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | 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) ||
+ ((EfiAttributes & EFI_MEMORY_WP) != 0))
+ {
+ LoongArchAttributes &= ~PAGE_DIRTY;
+ }
+
+ if ((EfiAttributes & EFI_MEMORY_RP) != 0) {
+ LoongArchAttributes |= PAGE_NO_READ;
+ }
+
+ // 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
+GetMemoryRegionAttribute (
+ IN UINTN BaseAddress,
+ IN UINTN EndAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ )
+{
+ PTE *Pte;
+ UINTN Attributes;
+ UINTN AttributesTmp;
+ UINTN MaxAddress;
+
+ if (!MmuIsInit ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
+ Pte = GetPteAddress (BaseAddress);
+
+ 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.
+ @param[in] AttributeMask Mask of memory attributes to take into account.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+**/
+EFI_STATUS
+SetMemoryRegionAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length,
+ IN UINTN Attributes,
+ IN UINT64 AttributeMask
+ )
+{
+ if (!MmuIsInit ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Attributes = EfiAttributeConverse (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
+SetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ )
+{
+ if (MmuIsInit ()) {
+ Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
+ SetMemoryRegionAttributes (BaseAddress, Length, EFI_MEMORY_XP, 0x0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check to see if mmu successfully initializes and saves the result.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval RETURN_SUCCESS Initialization succeeded.
+**/
+RETURN_STATUS
+EFIAPI
+MmuInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ if (SWAP_PAGE_DIR != 0) {
+ mMmuInited = TRUE;
+ }
+
+ return RETURN_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
new file mode 100644
index 0000000000..aa96f5143c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
@@ -0,0 +1,43 @@
+/** @file
+
+ Copyright (c) 2023 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/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
new file mode 100644
index 0000000000..d153354dd2
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
@@ -0,0 +1,37 @@
+## @file
+# CPU Memory Map Unit DXE phase driver.
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuMmuLib
+ MODULE_UNI_FILE = DxeCpuMmuLib.uni
+ FILE_GUID = DA8F0232-FB14-42F0-922C-63104D2C70BE
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuMmuLib | DXE_DRIVER
+ CONSTRUCTOR = MmuInitialize
+
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources]
+ TlbOperation.S | GCC
+ CommonMmuLib.c
+ Tlb.h
+ Page.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ PcdLib
+ DebugLib
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
new file mode 100644
index 0000000000..2e841d714c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CPU Memory Manager Unit library instance for DXE modules.
+//
+// CPU Memory Manager Unit library instance for DXE modules.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for DXE modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for DXE modules."
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
new file mode 100644
index 0000000000..f5e632a237
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
@@ -0,0 +1,964 @@
+/** @file
+
+ CPU Memory Map Unit Handler Library common functions.
+
+ Copyright (c) 2023 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/CpuMmuLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include "Tlb.h"
+#include "Page.h"
+
+BOOLEAN mMmuInited = FALSE;
+#define SWAP_PAGE_DIR CsrRead(LOONGARCH_CSR_PGDL)
+
+/**
+ 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 || (SWAP_PAGE_DIR != 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.
+
+ @return 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 *)(SWAP_PAGE_DIR) + 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;
+
+ 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;
+
+ 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;
+
+ 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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+
+**/
+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.
+**/
+EFI_STATUS
+PudAlloc (
+ IN PGD *Pgd
+ )
+{
+ PUD *Pud;
+
+ Pud = (PUD *)AllocatePages (1);
+ if (Pud == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)INVALID_PAGE);
+
+ SetPgd (Pgd, 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 *)INVALID_PAGE);
+
+ SetPud (Pud, 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.
+**/
+EFI_STATUS
+PteAlloc (
+ IN PMD *Pmd
+ )
+{
+ PTE *Pte;
+
+ Pte = (PTE *)AllocatePages (1);
+ if (!Pte) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
+
+ SetPmd (Pmd, 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.
+ @param Address The corresponding virtual address of the page table entry.
+
+ @retval A pointer to the page upper directory entry. Return NULL, if
+ allocate the memory buffer is fail.
+**/
+PUD *
+PudAllocGet (
+ IN PGD *Pgd,
+ IN UINTN Address
+ )
+{
+ EFI_STATUS Status;
+
+ if (PGD_IS_EMPTY (*Pgd)) {
+ Status = PudAlloc (Pgd);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ }
+
+ return 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.
+ @param Address The corresponding virtual address of the page table entry.
+
+ @retval A pointer to the page middle directory entry. Return NULL, if
+ allocate the memory buffer is fail.
+**/
+PMD *
+PmdAllocGet (
+ IN PUD *Pud,
+ IN UINTN Address
+ )
+{
+ EFI_STATUS Status;
+
+ if (PUD_IS_EMPTY (*Pud)) {
+ Status = PmdAlloc (Pud);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ }
+
+ return PmdOffset (Pud, Address);
+}
+
+/**
+ 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.
+ @param Address The corresponding virtual address of the page table entry.
+
+ @retval A pointer to the page table entry. Return NULL, if allocate
+ the memory buffer is fail.
+**/
+PTE *
+PteAllocGet (
+ IN PMD *Pmd,
+ IN UINTN Address
+ )
+{
+ EFI_STATUS Status;
+
+ if (PMD_IS_EMPTY (*Pmd)) {
+ Status = PteAlloc (Pmd);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ }
+
+ return 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_IS_EMPTY (*Pgd)) {
+ return NULL;
+ }
+
+ Pud = PudOffset (Pgd, Address);
+
+ if (PUD_IS_EMPTY (*Pud)) {
+ return NULL;
+ }
+
+ Pmd = PmdOffset (Pud, Address);
+ if (PMD_IS_EMPTY (*Pmd)) {
+ return NULL;
+ }
+
+ if (IS_HUGE_PAGE (Pmd->PmdVal)) {
+ return ((PTE *)Pmd);
+ }
+
+ return PteOffset (Pmd, Address);
+}
+
+/**
+ Gets the Attributes of Huge Page.
+
+ @param Pmd A pointer to the page middle directory.
+
+ @retval Value of Attributes.
+**/
+UINTN
+GetHugePageAttributes (
+ IN PMD *Pmd
+ )
+{
+ UINTN Attributes;
+ UINTN GlobalFlag;
+ UINTN HugeVal;
+
+ HugeVal = PMD_VAL (*Pmd);
+ Attributes = HugeVal & (~HUGEP_PAGE_MASK);
+ GlobalFlag = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT;
+ Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT);
+ Attributes |= GlobalFlag;
+ return Attributes;
+}
+
+/**
+ 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;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a %d Address %p End %p Attributes %llx\n",
+ __func__,
+ __LINE__,
+ Address,
+ End,
+ Attributes
+ ));
+
+ do {
+ UpDate = FALSE;
+ PteVal = MAKE_PTE (Address, Attributes);
+
+ if ((!PTE_IS_EMPTY (*Pte)) &&
+ (PTE_VAL (*Pte) != PTE_VAL (PteVal)))
+ {
+ UpDate = TRUE;
+ }
+
+ SetPte (Pte, PteVal);
+ if (UpDate) {
+ InvalidTlb (Address);
+ }
+ } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert Huge Page to Page.
+
+ @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
+ConvertHugePageToPage (
+ IN PMD *Pmd,
+ IN UINTN Address,
+ IN UINTN End,
+ IN UINTN Attributes
+ )
+{
+ UINTN OldAttributes;
+ UINTN HugePageEnd;
+ UINTN HugePageStart;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if ((PMD_IS_EMPTY (*Pmd)) ||
+ (!IS_HUGE_PAGE (Pmd->PmdVal)))
+ {
+ Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
+ } else {
+ OldAttributes = GetHugePageAttributes (Pmd);
+ if (Attributes == OldAttributes) {
+ return Status;
+ }
+
+ SetPmd (Pmd, (PTE *)(INVALID_PAGE));
+ HugePageStart = Address & PMD_MASK;
+ HugePageEnd = HugePageStart + HUGE_PAGE_SIZE;
+ ASSERT (HugePageEnd >= End);
+
+ if (Address > HugePageStart) {
+ Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes);
+ }
+
+ Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
+
+ if (End < HugePageEnd) {
+ Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ 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;
+ UINTN Next;
+ PTE PteVal;
+ BOOLEAN UpDate;
+
+ 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_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal)))
+ {
+ UpDate = FALSE;
+ PteVal = MAKE_HUGE_PTE (Address, Attributes);
+
+ if ((!PMD_IS_EMPTY (*Pmd)) &&
+ (PMD_VAL (*Pmd) != PTE_VAL (PteVal)))
+ {
+ UpDate = TRUE;
+ }
+
+ SetPmd (Pmd, (PTE *)PteVal.PteVal);
+ if (UpDate) {
+ InvalidTlb (Address);
+ }
+ } else {
+ ConvertHugePageToPage (Pmd, Address, Next, Attributes);
+ }
+ } while (Pmd++, Address = Next, Address != End);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 (EFI_ERROR (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;
+ EFI_STATUS Err;
+
+ Address = Start;
+
+ /* Get PGD(PTE PMD PUD PGD) in PageTables */
+ Pgd = PgdOffset (Address);
+ do {
+ Next = PGD_ADDRESS_END (Address, End);
+ /* Get Next Align Page to Map */
+ 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
+ );
+}
+
+/**
+ Convert EFI Attributes to Loongarch Attributes.
+
+ @param[in] EfiAttributes Efi Attributes.
+
+ @retval Corresponding architecture attributes.
+**/
+UINTN
+EfiAttributeConverse (
+ IN UINTN EfiAttributes
+ )
+{
+ UINTN LoongArchAttributes;
+
+ LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | 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) ||
+ ((EfiAttributes & EFI_MEMORY_WP) != 0))
+ {
+ LoongArchAttributes &= ~PAGE_DIRTY;
+ }
+
+ if ((EfiAttributes & EFI_MEMORY_RP) != 0) {
+ LoongArchAttributes |= PAGE_NO_READ;
+ }
+
+ // 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
+GetMemoryRegionAttribute (
+ IN UINTN BaseAddress,
+ IN UINTN EndAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ )
+{
+ PTE *Pte;
+ UINTN Attributes;
+ UINTN AttributesTmp;
+ UINTN MaxAddress;
+
+ if (!MmuIsInit ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
+ Pte = GetPteAddress (BaseAddress);
+
+ 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
+SetMemoryRegionAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length,
+ IN UINTN Attributes,
+ IN UINT64 AttributeMask
+ )
+{
+ if (!MmuIsInit ()) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Attributes = EfiAttributeConverse (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
+SetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ )
+{
+ if (MmuIsInit ()) {
+ Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
+ SetMemoryRegionAttributes (BaseAddress, Length, EFI_MEMORY_XP, 0x0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check to see if mmu successfully initializes and saves the result.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval RETURN_SUCCESS Initialization succeeded.
+**/
+RETURN_STATUS
+EFIAPI
+MmuInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ if (SWAP_PAGE_DIR != 0) {
+ mMmuInited = TRUE;
+ }
+
+ return RETURN_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
new file mode 100644
index 0000000000..aa96f5143c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
@@ -0,0 +1,43 @@
+/** @file
+
+ Copyright (c) 2023 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/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
new file mode 100644
index 0000000000..d153354dd2
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
@@ -0,0 +1,37 @@
+## @file
+# CPU Memory Map Unit DXE phase driver.
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuMmuLib
+ MODULE_UNI_FILE = DxeCpuMmuLib.uni
+ FILE_GUID = DA8F0232-FB14-42F0-922C-63104D2C70BE
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuMmuLib | DXE_DRIVER
+ CONSTRUCTOR = MmuInitialize
+
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources]
+ TlbOperation.S | GCC
+ CommonMmuLib.c
+ Tlb.h
+ Page.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ PcdLib
+ DebugLib
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
new file mode 100644
index 0000000000..2e841d714c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CPU Memory Manager Unit library instance for DXE modules.
+//
+// CPU Memory Manager Unit library instance for DXE modules.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for DXE modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for DXE modules."
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
new file mode 100644
index 0000000000..ad8f751ad7
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
@@ -0,0 +1,279 @@
+/** @file
+
+ Copyright (c) 2023 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_
+
+#include <Library/CpuMmuLib.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))
+
+#define HUGEP_PAGE_MASK (~(((UINTN)(1) << (PMD_SHIFT)) - 1) & \
+ (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
+
+#define INVALID_PAGE 0
+
+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) (PTE){(((((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 The page table is invalid.
+ @retval 0 The page table is valid.
+**/
+#define PGD_IS_EMPTY(Val) (PGD_VAL(Val) == INVALID_PAGE)
+
+/**
+ Check that the page upper directory table entry is empty.
+
+ @param pud Page upper directory struct variables.
+
+ @retval 1 The page table is invalid.
+ @retval 0 The page table is valid.
+**/
+#define PUD_IS_EMPTY(Val) (PUD_VAL(Val) == INVALID_PAGE)
+
+/**
+ Check that the page middle directory table entry is empty.
+
+ @param pmd Page middle directory struct variables.
+
+ @retval 1 The page table is invalid.
+ @retval 0 The page table is valid.
+**/
+#define PMD_IS_EMPTY(Val) (PMD_VAL(Val) == INVALID_PAGE)
+
+/**
+ Check that the page the page table entry is empty.
+
+ @param pte Page table entry struct variables.
+
+ @retval 1 The page table is invalid.
+ @retval 0 The page table is valid.
+**/
+#define PTE_IS_EMPTY(Val) (!(PTE_VAL(Val) & (~PAGE_VALID)))
+#endif // PAGE_H_
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
new file mode 100644
index 0000000000..42a424b84d
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
@@ -0,0 +1,165 @@
+/** @file
+ CPU Memory Map Unit PEI phase driver.
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - 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/CpuMmuLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/CpuMmuLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include "Page.h"
+#include "Tlb.h"
+#include "CommonMmuLib.h"
+
+/**
+ Create a page table and initialize the memory management unit(MMU).
+
+ @param[in] MemoryTable A pointer to a memory ragion table.
+ @param[out] TranslationTableBase A pointer to a translation table base address.
+ @param[out] TranslationTableSize A pointer to a translation table base size.
+
+ @retval EFI_SUCCESS Configure MMU successfully.
+ EFI_INVALID_PARAMETER MemoryTable is NULL.
+ EFI_UNSUPPORTED Out of memory space or size not aligned.
+**/
+EFI_STATUS
+EFIAPI
+ConfigureMemoryManagementUint (
+ IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
+ OUT VOID **TranslationTableBase OPTIONAL,
+ OUT UINTN *TranslationTableSize OPTIONAL
+ )
+{
+ PGD *SwapperPageDir;
+ UINTN PgdShift;
+ UINTN PgdWide;
+ UINTN PudShift;
+ UINTN PudWide;
+ UINTN PmdShift;
+ UINTN PmdWide;
+ UINTN PteShift;
+ UINTN PteWide;
+ UINTN Length;
+ UINTN TlbReEntry;
+ UINTN TlbReEntryOffset;
+ RETURN_STATUS Status;
+
+ SwapperPageDir = NULL;
+ PgdShift = PGD_SHIFT;
+ PgdWide = PGD_WIDE;
+ PudShift = PUD_SHIFT;
+ PudWide = PUD_WIDE;
+ PmdShift = PMD_SHIFT;
+ PmdWide = PMD_WIDE;
+ PteShift = PTE_SHIFT;
+ PteWide = PTE_WIDE;
+
+ if (MemoryTable == NULL) {
+ ASSERT (MemoryTable != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ ZeroMem (SwapperPageDir, PGD_TABLE_SIZE);
+
+ if (SwapperPageDir == NULL) {
+ goto FreeTranslationTable;
+ }
+
+ CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir);
+
+ while (MemoryTable->Length != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n",
+ __func__,
+ __LINE__,
+ MemoryTable->VirtualBase,
+ (MemoryTable->Length + MemoryTable->VirtualBase),
+ MemoryTable->Attributes
+ ));
+
+ Status = FillTranslationTable (MemoryTable);
+ if (EFI_ERROR (Status)) {
+ goto FreeTranslationTable;
+ }
+
+ MemoryTable++;
+ }
+
+ //
+ // TLB Re-entry address at the end of exception vector, a vector is up to 512 bytes,
+ // so the starting address is: total exception vector size + total interrupt vector size + base.
+ // The total size of TLB handler and exception vector size and interrupt vector size should not
+ // be lager than 64KB.
+ //
+ Length = (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart;
+ TlbReEntryOffset = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512;
+ TlbReEntry = PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryOffset;
+ if ((TlbReEntryOffset + Length) > SIZE_64KB) {
+ goto FreeTranslationTable;
+ }
+
+ //
+ // Make sure TLB refill exception base address alignment is greater than or equal to 4KB and valid
+ //
+ if (TlbReEntry & (SIZE_4KB - 1)) {
+ goto FreeTranslationTable;
+ }
+
+ CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%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
+ ));
+
+ //
+ // Set the address of TLB refill exception handler
+ //
+ SetTlbRebaseAddress ((UINTN)TlbReEntry);
+
+ //
+ // Set page size
+ //
+ CsrXChg (LOONGARCH_CSR_TLBIDX, (DEFAULT_PAGE_SIZE << CSR_TLBIDX_SIZE), CSR_TLBIDX_SIZE_MASK);
+ CsrWrite (LOONGARCH_CSR_STLBPGSIZE, DEFAULT_PAGE_SIZE);
+ CsrXChg (LOONGARCH_CSR_TLBREHI, (DEFAULT_PAGE_SIZE << CSR_TLBREHI_PS_SHIFT), CSR_TLBREHI_PS);
+
+ CsrWrite (LOONGARCH_CSR_PWCTL0, (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25));
+ CsrWrite (LOONGARCH_CSR_PWCTL1, (PgdShift | PgdWide << 6));
+
+ DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
+
+ return EFI_SUCCESS;
+
+FreeTranslationTable:
+ if (SwapperPageDir != NULL) {
+ FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ }
+
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
new file mode 100644
index 0000000000..e746c3b1a7
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
@@ -0,0 +1,44 @@
+## @file
+# CPU Memory Map Unit PEI phase driver.
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuMmuLib
+ MODULE_UNI_FILE = PeiCpuMmuLib.uni
+ FILE_GUID = F67EB983-AC2A-7550-AB69-3BC51A1C895B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuMmuLib | SEC PEIM
+
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources]
+ TlbOperation.S | GCC
+ PeiCpuMmuLib.c
+ CommonMmuLib.c
+ CommonMmuLib.h
+ Tlb.h
+ Page.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[PCD]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
+
+[LibraryClasses]
+ MemoryAllocationLib
+ CacheMaintenanceLib
+ PcdLib
+ DebugLib
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
new file mode 100644
index 0000000000..331500543c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CPU Memory Manager Unit library instance for PEI modules.
+//
+// CPU Memory Manager Unit library instance for PEI modules.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for PEI modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for PEI modules."
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
new file mode 100644
index 0000000000..5d3f80fe34
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
@@ -0,0 +1,48 @@
+/** @file
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TLB_H_
+#define TLB_H_
+
+/**
+ Invalid corresponding TLB entries are based on the address given
+
+ @param Address The address corresponding to the invalid page table entry
+
+ @retval none
+**/
+VOID
+InvalidTlb (
+ UINTN Address
+ );
+
+/**
+ TLB refill handler start.
+
+ @param none
+
+ @retval none
+**/
+VOID
+HandleTlbRefillStart (
+ VOID
+ );
+
+/**
+ TLB refill handler end.
+
+ @param none
+
+ @retval none
+**/
+VOID
+HandleTlbRefillEnd (
+ VOID
+ );
+
+#endif // TLB_H_
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
new file mode 100644
index 0000000000..e446f0839c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
@@ -0,0 +1,44 @@
+#------------------------------------------------------------------------------
+#
+# TLB operation functions
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-----------------------------------------------------------------------------
+
+#include <Register/LoongArch64/Csr.h>
+
+ASM_GLOBAL ASM_PFX(HandleTlbRefillStart)
+ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd)
+ASM_GLOBAL ASM_PFX(InvalidTlb)
+
+#
+# Refill the page table.
+# @param VOID
+# @retval VOID
+#
+ASM_PFX(HandleTlbRefillStart):
+ 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 // refill hi,lo0,lo1
+ csrrd $t0, LOONGARCH_CSR_TLBRSAVE
+ ertn
+ASM_PFX(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(InvalidTlb):
+ invtlb INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0
+ jirl $zero, $ra, 0
+
+ .end
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
new file mode 100644
index 0000000000..ad8f751ad7
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
@@ -0,0 +1,279 @@
+/** @file
+
+ Copyright (c) 2023 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_
+
+#include <Library/CpuMmuLib.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))
+
+#define HUGEP_PAGE_MASK (~(((UINTN)(1) << (PMD_SHIFT)) - 1) & \
+ (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
+
+#define INVALID_PAGE 0
+
+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) (PTE){(((((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 The page table is invalid.
+ @retval 0 The page table is valid.
+**/
+#define PGD_IS_EMPTY(Val) (PGD_VAL(Val) == INVALID_PAGE)
+
+/**
+ Check that the page upper directory table entry is empty.
+
+ @param pud Page upper directory struct variables.
+
+ @retval 1 The page table is invalid.
+ @retval 0 The page table is valid.
+**/
+#define PUD_IS_EMPTY(Val) (PUD_VAL(Val) == INVALID_PAGE)
+
+/**
+ Check that the page middle directory table entry is empty.
+
+ @param pmd Page middle directory struct variables.
+
+ @retval 1 The page table is invalid.
+ @retval 0 The page table is valid.
+**/
+#define PMD_IS_EMPTY(Val) (PMD_VAL(Val) == INVALID_PAGE)
+
+/**
+ Check that the page the page table entry is empty.
+
+ @param pte Page table entry struct variables.
+
+ @retval 1 The page table is invalid.
+ @retval 0 The page table is valid.
+**/
+#define PTE_IS_EMPTY(Val) (!(PTE_VAL(Val) & (~PAGE_VALID)))
+#endif // PAGE_H_
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
new file mode 100644
index 0000000000..42a424b84d
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
@@ -0,0 +1,165 @@
+/** @file
+ CPU Memory Map Unit PEI phase driver.
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - 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/CpuMmuLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/CpuMmuLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include "Page.h"
+#include "Tlb.h"
+#include "CommonMmuLib.h"
+
+/**
+ Create a page table and initialize the memory management unit(MMU).
+
+ @param[in] MemoryTable A pointer to a memory ragion table.
+ @param[out] TranslationTableBase A pointer to a translation table base address.
+ @param[out] TranslationTableSize A pointer to a translation table base size.
+
+ @retval EFI_SUCCESS Configure MMU successfully.
+ EFI_INVALID_PARAMETER MemoryTable is NULL.
+ EFI_UNSUPPORTED Out of memory space or size not aligned.
+**/
+EFI_STATUS
+EFIAPI
+ConfigureMemoryManagementUint (
+ IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
+ OUT VOID **TranslationTableBase OPTIONAL,
+ OUT UINTN *TranslationTableSize OPTIONAL
+ )
+{
+ PGD *SwapperPageDir;
+ UINTN PgdShift;
+ UINTN PgdWide;
+ UINTN PudShift;
+ UINTN PudWide;
+ UINTN PmdShift;
+ UINTN PmdWide;
+ UINTN PteShift;
+ UINTN PteWide;
+ UINTN Length;
+ UINTN TlbReEntry;
+ UINTN TlbReEntryOffset;
+ RETURN_STATUS Status;
+
+ SwapperPageDir = NULL;
+ PgdShift = PGD_SHIFT;
+ PgdWide = PGD_WIDE;
+ PudShift = PUD_SHIFT;
+ PudWide = PUD_WIDE;
+ PmdShift = PMD_SHIFT;
+ PmdWide = PMD_WIDE;
+ PteShift = PTE_SHIFT;
+ PteWide = PTE_WIDE;
+
+ if (MemoryTable == NULL) {
+ ASSERT (MemoryTable != NULL);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ ZeroMem (SwapperPageDir, PGD_TABLE_SIZE);
+
+ if (SwapperPageDir == NULL) {
+ goto FreeTranslationTable;
+ }
+
+ CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir);
+
+ while (MemoryTable->Length != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n",
+ __func__,
+ __LINE__,
+ MemoryTable->VirtualBase,
+ (MemoryTable->Length + MemoryTable->VirtualBase),
+ MemoryTable->Attributes
+ ));
+
+ Status = FillTranslationTable (MemoryTable);
+ if (EFI_ERROR (Status)) {
+ goto FreeTranslationTable;
+ }
+
+ MemoryTable++;
+ }
+
+ //
+ // TLB Re-entry address at the end of exception vector, a vector is up to 512 bytes,
+ // so the starting address is: total exception vector size + total interrupt vector size + base.
+ // The total size of TLB handler and exception vector size and interrupt vector size should not
+ // be lager than 64KB.
+ //
+ Length = (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart;
+ TlbReEntryOffset = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512;
+ TlbReEntry = PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryOffset;
+ if ((TlbReEntryOffset + Length) > SIZE_64KB) {
+ goto FreeTranslationTable;
+ }
+
+ //
+ // Make sure TLB refill exception base address alignment is greater than or equal to 4KB and valid
+ //
+ if (TlbReEntry & (SIZE_4KB - 1)) {
+ goto FreeTranslationTable;
+ }
+
+ CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%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
+ ));
+
+ //
+ // Set the address of TLB refill exception handler
+ //
+ SetTlbRebaseAddress ((UINTN)TlbReEntry);
+
+ //
+ // Set page size
+ //
+ CsrXChg (LOONGARCH_CSR_TLBIDX, (DEFAULT_PAGE_SIZE << CSR_TLBIDX_SIZE), CSR_TLBIDX_SIZE_MASK);
+ CsrWrite (LOONGARCH_CSR_STLBPGSIZE, DEFAULT_PAGE_SIZE);
+ CsrXChg (LOONGARCH_CSR_TLBREHI, (DEFAULT_PAGE_SIZE << CSR_TLBREHI_PS_SHIFT), CSR_TLBREHI_PS);
+
+ CsrWrite (LOONGARCH_CSR_PWCTL0, (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25));
+ CsrWrite (LOONGARCH_CSR_PWCTL1, (PgdShift | PgdWide << 6));
+
+ DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
+
+ return EFI_SUCCESS;
+
+FreeTranslationTable:
+ if (SwapperPageDir != NULL) {
+ FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ }
+
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
new file mode 100644
index 0000000000..e746c3b1a7
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
@@ -0,0 +1,44 @@
+## @file
+# CPU Memory Map Unit PEI phase driver.
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuMmuLib
+ MODULE_UNI_FILE = PeiCpuMmuLib.uni
+ FILE_GUID = F67EB983-AC2A-7550-AB69-3BC51A1C895B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuMmuLib | SEC PEIM
+
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources]
+ TlbOperation.S | GCC
+ PeiCpuMmuLib.c
+ CommonMmuLib.c
+ CommonMmuLib.h
+ Tlb.h
+ Page.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[PCD]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
+
+[LibraryClasses]
+ MemoryAllocationLib
+ CacheMaintenanceLib
+ PcdLib
+ DebugLib
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
new file mode 100644
index 0000000000..331500543c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CPU Memory Manager Unit library instance for PEI modules.
+//
+// CPU Memory Manager Unit library instance for PEI modules.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for PEI modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for PEI modules."
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
new file mode 100644
index 0000000000..5d3f80fe34
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
@@ -0,0 +1,48 @@
+/** @file
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TLB_H_
+#define TLB_H_
+
+/**
+ Invalid corresponding TLB entries are based on the address given
+
+ @param Address The address corresponding to the invalid page table entry
+
+ @retval none
+**/
+VOID
+InvalidTlb (
+ UINTN Address
+ );
+
+/**
+ TLB refill handler start.
+
+ @param none
+
+ @retval none
+**/
+VOID
+HandleTlbRefillStart (
+ VOID
+ );
+
+/**
+ TLB refill handler end.
+
+ @param none
+
+ @retval none
+**/
+VOID
+HandleTlbRefillEnd (
+ VOID
+ );
+
+#endif // TLB_H_
diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
new file mode 100644
index 0000000000..e446f0839c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
@@ -0,0 +1,44 @@
+#------------------------------------------------------------------------------
+#
+# TLB operation functions
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-----------------------------------------------------------------------------
+
+#include <Register/LoongArch64/Csr.h>
+
+ASM_GLOBAL ASM_PFX(HandleTlbRefillStart)
+ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd)
+ASM_GLOBAL ASM_PFX(InvalidTlb)
+
+#
+# Refill the page table.
+# @param VOID
+# @retval VOID
+#
+ASM_PFX(HandleTlbRefillStart):
+ 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 // refill hi,lo0,lo1
+ csrrd $t0, LOONGARCH_CSR_TLBRSAVE
+ ertn
+ASM_PFX(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(InvalidTlb):
+ invtlb INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0
+ jirl $zero, $ra, 0
+
+ .end
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 872f20fc36..709992d327 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -209,6 +209,8 @@
UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+ UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
+ UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111367): https://edk2.groups.io/g/devel/message/111367
Mute This Topic: https://groups.io/mt/102644769/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 15/39] UefiCpuPkg: Add multiprocessor library for LoongArch64
[not found] <20231117095742.3605778-1-lichao@loongs>
` (13 preceding siblings ...)
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 14/39] UefiCpuPkg: Add LoongArch64CpuMmuLib " Chao Li
@ 2023-11-17 10:00 ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 16/39] UefiCpuPkg: Add CpuDxe driver " Chao Li
` (25 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:00 UTC (permalink / raw)
To: devel; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
Added a new library named LoongArch64MpInitLib.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Ray Ni <ray.ni@intel.com>
---
.../LoongArch64MpInitLib/DxeMpInitLib.inf | 45 +
.../LoongArch64MpInitLib/DxeMpInitLib.uni | 15 +
.../Library/LoongArch64MpInitLib/DxeMpLib.c | 481 +++++
.../Library/LoongArch64MpInitLib/MpLib.c | 1596 +++++++++++++++++
.../Library/LoongArch64MpInitLib/MpLib.h | 361 ++++
.../LoongArch64MpInitLib/PeiMpInitLib.inf | 37 +
.../LoongArch64MpInitLib/PeiMpInitLib.uni | 15 +
.../Library/LoongArch64MpInitLib/PeiMpLib.c | 404 +++++
UefiCpuPkg/UefiCpuPkg.dsc | 2 +
9 files changed, 2956 insertions(+)
create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf
create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni
create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c
create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c
create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h
create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf
create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni
create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c
diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf
new file mode 100644
index 0000000000..48086ce0a3
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf
@@ -0,0 +1,45 @@
+## @file
+# LoongArch64 MP initialize support functions for DXE phase.
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeMpInitLib
+ MODULE_UNI_FILE = DxeMpInitLib.uni
+ FILE_GUID = C3B9ACAA-B67C-D3E0-E70D-7982B6EA2931
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = MpInitLib|DXE_DRIVER
+
+[Sources.common]
+ DxeMpLib.c
+ MpLib.c
+ MpLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ HobLib
+ CpuLib
+ UefiBootServicesTableLib
+ DebugAgentLib
+ SynchronizationLib
+ TimerLib
+
+[Protocols]
+ gEfiTimerArchProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds ## CONSUMES
diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni
new file mode 100644
index 0000000000..aebbdbbb0e
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// MP Initialize Library instance for DXE driver.
+//
+// MP Initialize Library instance for DXE driver.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "MP Initialize Library instance for DXE driver."
+
+#string STR_MODULE_DESCRIPTION #language en-US "MP Initialize Library instance for DXE driver."
diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c
new file mode 100644
index 0000000000..008016b225
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c
@@ -0,0 +1,481 @@
+/** @file
+ LoongArch64 MP initialize support functions for DXE phase.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/DxeServicesTableLib.h>
+
+#include <Protocol/Timer.h>
+
+CPU_MP_DATA *mCpuMpData = NULL;
+EFI_EVENT mCheckAllApsEvent = NULL;
+volatile BOOLEAN mStopCheckAllApsStatus = TRUE;
+
+/**
+ Enable Debug Agent to support source debugging on AP function.
+
+**/
+VOID
+EnableDebugAgent (
+ VOID
+ )
+{
+ //
+ // Initialize Debug Agent to support source level debug in DXE phase
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);
+}
+
+/**
+ Get the pointer to CPU MP Data structure.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ )
+{
+ ASSERT (mCpuMpData != NULL);
+ return mCpuMpData;
+}
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ mCpuMpData = CpuMpData;
+}
+
+/**
+ Get available EfiBootServicesCode memory below 4GB by specified size.
+
+ This buffer is required to safely transfer AP from real address mode to
+ protected mode or long mode, due to the fact that the buffer returned by
+ GetWakeupBuffer() may be marked as non-executable.
+
+ @param[in] BufferSize Wakeup transition buffer size.
+
+ @retval other Return wakeup transition buffer address below 4GB.
+ @retval 0 Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+ IN UINTN BufferSize
+ )
+{
+ return 0;
+}
+
+/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ )
+{
+ UINTN ProcessorNumber;
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // First, check whether pending StartupAllAPs() exists.
+ //
+ if (CpuMpData->WaitEvent != NULL) {
+ Status = CheckAllAPs ();
+ //
+ // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
+ //
+ if (Status != EFI_NOT_READY) {
+ Status = gBS->SignalEvent (CpuMpData->WaitEvent);
+ CpuMpData->WaitEvent = NULL;
+ }
+ }
+
+ //
+ // Second, check whether pending StartupThisAPs() callings exist.
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {
+ continue;
+ }
+
+ Status = CheckThisAP (ProcessorNumber);
+
+ if (Status != EFI_NOT_READY) {
+ gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);
+ CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;
+ }
+ }
+}
+
+/**
+ Checks APs' status periodically.
+
+ This function is triggered by timer periodically to check the
+ state of APs for StartupAllAPs() and StartupThisAP() executed
+ in non-blocking mode.
+
+ @param[in] Event Event triggered.
+ @param[in] Context Parameter passed with the event.
+
+**/
+VOID
+EFIAPI
+CheckApsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // If CheckApsStatus() is not stopped, otherwise return immediately.
+ //
+ if (!mStopCheckAllApsStatus) {
+ CheckAndUpdateApsStatus ();
+ }
+}
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ EFI_STATUS Status;
+
+ SaveCpuMpData (CpuMpData);
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ CheckApsStatus,
+ NULL,
+ &mCheckAllApsEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set timer to check all APs status.
+ //
+ Status = gBS->SetTimer (
+ mCheckAllApsEvent,
+ TimerPeriodic,
+ EFI_TIMER_PERIOD_MICROSECONDS (
+ PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds)
+ )
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This service executes a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroSeconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure, or TimeoutInMicroSeconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by MpInitLibStartupAllAPs() or
+ MPInitLibStartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
+ if all APs finish successfully, then its
+ content is set to NULL. If not all APs
+ finish before timeout expires, then its
+ content is set to address of the buffer
+ holding handle numbers of the failed APs.
+ The buffer is allocated by MP Initialization
+ library, and it's the caller's responsibility to
+ free the buffer with FreePool() service.
+ In blocking mode, it is ready for consumption
+ when the call returns. In non-blocking mode,
+ it is ready when WaitEvent is signaled. The
+ list of failed CPU is terminated by
+ END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllAPs (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
+ //
+ mStopCheckAllApsStatus = TRUE;
+
+ Status = StartupAllCPUsWorker (
+ Procedure,
+ SingleThread,
+ TRUE,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ FailedCpuList
+ );
+
+ //
+ // Start checkAllApsStatus
+ //
+ mStopCheckAllApsStatus = FALSE;
+
+ return Status;
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on the
+ designated AP of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ MpInitLibGetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until this AP finish
+ or TimeoutInMicroSeconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on this AP,
+ and go on executing immediately. If this AP
+ return from Procedure or TimeoutInMicroSeconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ this AP to finish this Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ this AP returns from Procedure, then Procedure
+ on the AP is terminated. The
+ AP is available for next function assigned
+ by MpInitLibStartupAllAPs() or
+ MpInitLibStartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure on the
+ specified AP.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupThisAP (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // temporarily stop checkAllApsStatus for avoid resource dead-lock.
+ //
+ mStopCheckAllApsStatus = TRUE;
+
+ Status = StartupThisAPWorker (
+ Procedure,
+ ProcessorNumber,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ Finished
+ );
+
+ mStopCheckAllApsStatus = FALSE;
+
+ return Status;
+}
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ MpInitLibGetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of AP.
+ The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ MpInitLibGetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c
new file mode 100644
index 0000000000..864c1464be
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c
@@ -0,0 +1,1596 @@
+/** @file
+ LoongArch64 CPU MP Initialize Library common functions.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include <Uefi/UefiBaseType.h>
+
+EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
+EFI_GUID mProcessorResourceHobGuid = PROCESSOR_RESOURCE_HOB_GUID;
+
+/**
+ Get the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
+
+ @return The AP status
+**/
+CPU_STATE
+GetApState (
+ IN CPU_AP_DATA *CpuData
+ )
+{
+ return CpuData->State;
+}
+
+/**
+ Set the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
+ @param[in] State The AP status
+**/
+VOID
+SetApState (
+ IN CPU_AP_DATA *CpuData,
+ IN CPU_STATE State
+ )
+{
+ AcquireSpinLock (&CpuData->ApLock);
+ CpuData->State = State;
+ ReleaseSpinLock (&CpuData->ApLock);
+}
+
+/**
+ Get APIC ID of the executing processor.
+
+ @return 32-bit APIC ID of the executing processor.
+**/
+UINT32
+GetApicId (
+ VOID
+ )
+{
+ UINTN CpuNum;
+
+ CpuNum = CsrRead (LOONGARCH_CSR_CPUNUM);
+
+ return CpuNum & 0x3ff;
+}
+
+/**
+ Find the current Processor number by APIC ID.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+ @param[out] ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN CPU_MP_DATA *CpuMpData,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN TotalProcessorNumber;
+ UINTN Index;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+
+ CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+
+ TotalProcessorNumber = CpuMpData->CpuCount;
+ for (Index = 0; Index < TotalProcessorNumber; Index++) {
+ if (CpuInfoInHob[Index].ApicId == GetApicId ()) {
+ *ProcessorNumber = Index;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Sort the APIC ID of all processors.
+
+ This function sorts the APIC ID of all processors so that processor number is
+ assigned in the ascending order of APIC ID which eases MP debugging.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+SortApicId (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Index3;
+ UINT32 ApicId;
+ CPU_INFO_IN_HOB CpuInfo;
+ UINT32 ApCount;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ volatile UINT32 *StartupApSignal;
+
+ ApCount = CpuMpData->CpuCount - 1;
+ CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+ if (ApCount != 0) {
+ for (Index1 = 0; Index1 < ApCount; Index1++) {
+ Index3 = Index1;
+ //
+ // Sort key is the hardware default APIC ID
+ //
+ ApicId = CpuInfoInHob[Index1].ApicId;
+ for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
+ if (ApicId > CpuInfoInHob[Index2].ApicId) {
+ Index3 = Index2;
+ ApicId = CpuInfoInHob[Index2].ApicId;
+ }
+ }
+
+ if (Index3 != Index1) {
+ CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof (CPU_INFO_IN_HOB));
+ CopyMem (
+ &CpuInfoInHob[Index3],
+ &CpuInfoInHob[Index1],
+ sizeof (CPU_INFO_IN_HOB)
+ );
+ CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));
+
+ //
+ // Also exchange the StartupApSignal.
+ //
+ StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal;
+ CpuMpData->CpuData[Index3].StartupApSignal =
+ CpuMpData->CpuData[Index1].StartupApSignal;
+ CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;
+ }
+ }
+
+ //
+ // Get the processor number for the BSP
+ //
+ ApicId = GetApicId ();
+ for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
+ if (CpuInfoInHob[Index1].ApicId == ApicId) {
+ CpuMpData->BspNumber = (UINT32)Index1;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Get pointer to Processor Resource Data structure from GUIDd HOB.
+
+ @return The pointer to Processor Resource Data structure.
+**/
+PROCESSOR_RESOURCE_DATA *
+GetProcessorResourceDataFromGuidedHob (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+ PROCESSOR_RESOURCE_DATA *ResourceData;
+
+ ResourceData = NULL;
+ GuidHob = GetFirstGuidHob (&mProcessorResourceHobGuid);
+ if (GuidHob != NULL) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ ResourceData = (PROCESSOR_RESOURCE_DATA *)(*(UINTN *)DataInHob);
+ }
+
+ return ResourceData;
+}
+
+/**
+ This function will get CPU count in the system.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+
+ @return CPU count detected
+**/
+UINTN
+CollectProcessorCount (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ PROCESSOR_RESOURCE_DATA *ProcessorResourceData;
+
+ ProcessorResourceData = NULL;
+
+ //
+ // Set the default loop mode for APs.
+ //
+ CpuMpData->ApLoopMode = ApInRunLoop;
+
+ //
+ // Beacuse LoongArch does not have SIPI now, the APIC ID must be obtained before
+ // calling IPI to wake up the APs. If NULL is obtained, NODE0 Core0 Mailbox0 is used
+ // as the first broadcast method to wake up all APs, and all of APs will read NODE0
+ // Core0 Mailbox0 in an infinit loop.
+ //
+ ProcessorResourceData = GetProcessorResourceDataFromGuidedHob ();
+
+ if (ProcessorResourceData != NULL) {
+ CpuMpData->ApLoopMode = ApInHltLoop;
+ CpuMpData->CpuCount = ProcessorResourceData->CpuCount;
+ CpuMpData->CpuInfoInHob = (UINTN)(ProcessorResourceData->CpuInfoInHob);
+ }
+
+ //
+ // Send 1st broadcast IPI to APs to wakeup APs
+ //
+ CpuMpData->InitFlag = ApInitConfig;
+ WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, FALSE);
+ CpuMpData->InitFlag = ApInitDone;
+
+ //
+ // When InitFlag == ApInitConfig, WakeUpAP () guarantees all APs are checked in.
+ // FinishedCount is the number of check-in APs.
+ //
+ CpuMpData->CpuCount = CpuMpData->FinishedCount + 1;
+ ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
+
+ //
+ // Wait for all APs finished the initialization
+ //
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+ CpuPause ();
+ }
+
+ //
+ // Sort BSP/Aps by CPU APIC ID in ascending order
+ //
+ SortApicId (CpuMpData);
+
+ DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
+
+ return CpuMpData->CpuCount;
+}
+
+/**
+ Initialize CPU AP Data when AP is wakeup at the first time.
+
+ @param[in, out] CpuMpData Pointer to PEI CPU MP Data
+ @param[in] ProcessorNumber The handle number of processor
+ @param[in] BistData Processor BIST data
+
+**/
+VOID
+InitializeApData (
+ IN OUT CPU_MP_DATA *CpuMpData,
+ IN UINTN ProcessorNumber,
+ IN UINT32 BistData
+ )
+{
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+
+ CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)(CpuMpData->CpuInfoInHob);
+
+ CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();
+ CpuInfoInHob[ProcessorNumber].Health = BistData;
+
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+ CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
+
+ InitializeSpinLock (&CpuMpData->CpuData[ProcessorNumber].ApLock);
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
+}
+
+/**
+ Ap wake up function.
+
+ Ap will wait for scheduling here, and if the IPI or wake-up signal is enabled,
+ Ap will preform the corresponding functions.
+
+ @param[in] ApIndex Number of current executing AP
+ @param[in] ExchangeInfo Pointer to the MP exchange info buffer
+**/
+VOID
+EFIAPI
+ApWakeupFunction (
+ IN UINTN ApIndex,
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN ProcessorNumber;
+ volatile UINT32 *ApStartupSignalBuffer;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *Parameter;
+
+ CpuMpData = ExchangeInfo->CpuMpData;
+
+ while (TRUE) {
+ if (CpuMpData->InitFlag == ApInitConfig) {
+ ProcessorNumber = ApIndex;
+ //
+ // If the AP can running to here, then the BIST must be zero.
+ //
+ InitializeApData (CpuMpData, ProcessorNumber, 0);
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+ } else {
+ //
+ // Execute AP function if AP is ready
+ //
+ GetProcessorNumber (CpuMpData, &ProcessorNumber);
+
+ //
+ // Clear AP start-up signal when AP waken up
+ //
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+ InterlockedCompareExchange32 (
+ (UINT32 *)ApStartupSignalBuffer,
+ WAKEUP_AP_SIGNAL,
+ 0
+ );
+
+ //
+ // Invoke AP function here
+ //
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
+ Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
+ Parameter = (VOID *)CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
+ if (Procedure != NULL) {
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
+ Procedure (Parameter);
+ }
+
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
+ }
+ }
+
+ //
+ // Updates the finished count
+ //
+ InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount);
+
+ while (TRUE) {
+ //
+ // Clean per-core mail box registers.
+ //
+ IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, 0x0);
+ IoCsrWrite64 (LOONGARCH_IOCSR_MBUF1, 0x0);
+ IoCsrWrite64 (LOONGARCH_IOCSR_MBUF2, 0x0);
+ IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, 0x0);
+
+ //
+ // Enable IPI interrupt and global interrupt
+ //
+ EnableLocalInterrupts (1 << 12);
+ IoCsrWrite32 (LOONGARCH_IOCSR_IPI_EN, 0xFFFFFFFFULL);
+ EnableInterrupts ();
+
+ //
+ // Ap entry HLT mode
+ //
+ CpuSleep ();
+
+ //
+ // Disable global interrupts when wake up
+ //
+ DisableInterrupts ();
+
+ //
+ // Update CpuMpData
+ //
+ if (CpuMpData != ExchangeInfo->CpuMpData) {
+ CpuMpData = ExchangeInfo->CpuMpData;
+ GetProcessorNumber (CpuMpData, &ProcessorNumber);
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+ }
+
+ //
+ // Break out of the loop if wake up signal is not NULL.
+ //
+ if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Calculate timeout value and return the current performance counter value.
+
+ Calculate the number of performance counter ticks required for a timeout.
+ If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ as infinity.
+
+ @param[in] TimeoutInMicroseconds Timeout value in microseconds.
+ @param[out] CurrentTime Returns the current value of the performance counter.
+
+ @return Expected time stamp counter for timeout.
+ If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ as infinity.
+
+**/
+UINT64
+CalculateTimeout (
+ IN UINTN TimeoutInMicroseconds,
+ OUT UINT64 *CurrentTime
+ )
+{
+ UINT64 TimeoutInSeconds;
+ UINT64 TimestampCounterFreq;
+
+ //
+ // Read the current value of the performance counter
+ //
+ *CurrentTime = GetPerformanceCounter ();
+
+ //
+ // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ // as infinity.
+ //
+ if (TimeoutInMicroseconds == 0) {
+ return 0;
+ }
+
+ //
+ // GetPerformanceCounterProperties () returns the timestamp counter's frequency
+ // in Hz.
+ //
+ TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Check the potential overflow before calculate the number of ticks for the timeout value.
+ //
+ if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {
+ //
+ // Convert microseconds into seconds if direct multiplication overflows
+ //
+ TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);
+ //
+ // Assertion if the final tick count exceeds MAX_UINT64
+ //
+ ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);
+ return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);
+ } else {
+ //
+ // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
+ // it by 1,000,000, to get the number of ticks for the timeout value.
+ //
+ return DivU64x32 (
+ MultU64x64 (
+ TimestampCounterFreq,
+ TimeoutInMicroseconds
+ ),
+ 1000000
+ );
+ }
+}
+
+/**
+ Checks whether timeout expires.
+
+ Check whether the number of elapsed performance counter ticks required for
+ a timeout condition has been reached.
+ If Timeout is zero, which means infinity, return value is always FALSE.
+
+ @param[in, out] PreviousTime On input, the value of the performance counter
+ when it was last read.
+ On output, the current value of the performance
+ counter
+ @param[in] TotalTime The total amount of elapsed time in performance
+ counter ticks.
+ @param[in] Timeout The number of performance counter ticks required
+ to reach a timeout condition.
+
+ @retval TRUE A timeout condition has been reached.
+ @retval FALSE A timeout condition has not been reached.
+
+**/
+BOOLEAN
+CheckTimeout (
+ IN OUT UINT64 *PreviousTime,
+ IN UINT64 *TotalTime,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Start;
+ UINT64 End;
+ UINT64 CurrentTime;
+ INT64 Delta;
+ INT64 Cycle;
+
+ if (Timeout == 0) {
+ return FALSE;
+ }
+
+ GetPerformanceCounterProperties (&Start, &End);
+ Cycle = End - Start;
+ if (Cycle < 0) {
+ Cycle = -Cycle;
+ }
+
+ Cycle++;
+ CurrentTime = GetPerformanceCounter ();
+ Delta = (INT64)(CurrentTime - *PreviousTime);
+ if (Start > End) {
+ Delta = -Delta;
+ }
+
+ if (Delta < 0) {
+ Delta += Cycle;
+ }
+
+ *TotalTime += Delta;
+ *PreviousTime = CurrentTime;
+ if (*TotalTime > Timeout) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Helper function that waits until the finished AP count reaches the specified
+ limit, or the specified timeout elapses (whichever comes first).
+
+ @param[in] CpuMpData Pointer to CPU MP Data.
+ @param[in] FinishedApLimit The number of finished APs to wait for.
+ @param[in] TimeLimit The number of microseconds to wait for.
+**/
+VOID
+TimedWaitForApFinish (
+ IN CPU_MP_DATA *CpuMpData,
+ IN UINT32 FinishedApLimit,
+ IN UINT32 TimeLimit
+ )
+{
+ //
+ // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
+ // "infinity", so check for (TimeLimit == 0) explicitly.
+ //
+ if (TimeLimit == 0) {
+ return;
+ }
+
+ CpuMpData->TotalTime = 0;
+ CpuMpData->ExpectedTime = CalculateTimeout (
+ TimeLimit,
+ &CpuMpData->CurrentTime
+ );
+ while (CpuMpData->FinishedCount < FinishedApLimit &&
+ !CheckTimeout (
+ &CpuMpData->CurrentTime,
+ &CpuMpData->TotalTime,
+ CpuMpData->ExpectedTime
+ ))
+ {
+ CpuPause ();
+ }
+
+ if (CpuMpData->FinishedCount >= FinishedApLimit) {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
+ __FUNCTION__,
+ FinishedApLimit,
+ DivU64x64Remainder (
+ MultU64x32 (CpuMpData->TotalTime, 1000000),
+ GetPerformanceCounterProperties (NULL, NULL),
+ NULL
+ )
+ ));
+ }
+}
+
+/**
+ Wait for AP wakeup and write AP start-up signal till AP is waken up.
+
+ @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
+**/
+VOID
+WaitApWakeup (
+ IN volatile UINT32 *ApStartupSignalBuffer
+ )
+{
+ //
+ // If AP is waken up, StartupApSignal should be cleared.
+ // Otherwise, write StartupApSignal again till AP waken up.
+ //
+ while (InterlockedCompareExchange32 (
+ (UINT32 *)ApStartupSignalBuffer,
+ WAKEUP_AP_SIGNAL,
+ WAKEUP_AP_SIGNAL
+ ) != 0)
+ {
+ CpuPause ();
+ }
+}
+
+/**
+ This function will fill the exchange info structure.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+
+**/
+VOID
+FillExchangeInfoData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ if (!CpuMpData->MpCpuExchangeInfo) {
+ CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *)AllocatePool (sizeof (MP_CPU_EXCHANGE_INFO));
+ }
+
+ ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
+ ExchangeInfo->CpuMpData = CpuMpData;
+}
+
+/**
+ This function will be called by BSP to wakeup AP.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+ @param[in] Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param[in] ProcessorNumber The handle number of specified processor
+ @param[in] Procedure The function to be invoked by AP
+ @param[in] ProcedureArgument The argument to be passed into AP function
+ @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode. Currently not used on LoongArch.
+**/
+VOID
+WakeUpAP (
+ IN CPU_MP_DATA *CpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINTN ProcessorNumber,
+ IN EFI_AP_PROCEDURE Procedure OPTIONAL,
+ IN VOID *ProcedureArgument OPTIONAL,
+ IN BOOLEAN WakeUpDisabledAps
+ )
+{
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+
+ CpuMpData->FinishedCount = 0;
+
+ CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+
+ if (CpuMpData->InitFlag != ApInitDone) {
+ FillExchangeInfoData (CpuMpData);
+ }
+
+ ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
+ //
+ // If InitFlag is ApInitConfig, broadcasts all APs to initize themselves.
+ //
+ if (CpuMpData->InitFlag == ApInitConfig) {
+ DEBUG ((EFI_D_INFO, "%a: func 0x%llx, ExchangeInfo 0x%llx\n", __func__, ApWakeupFunction, (UINTN)ExchangeInfo));
+ if (CpuMpData->ApLoopMode == ApInHltLoop) {
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ if (Index != CpuMpData->BspNumber) {
+ IoCsrWrite64 (
+ LOONGARCH_IOCSR_MBUF_SEND,
+ (IOCSR_MBUF_SEND_BLOCKING |
+ (IOCSR_MBUF_SEND_BOX_HI (0x3) << IOCSR_MBUF_SEND_BOX_SHIFT) |
+ (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+ ((UINTN)(ExchangeInfo) & IOCSR_MBUF_SEND_H32_MASK))
+ );
+ IoCsrWrite64 (
+ LOONGARCH_IOCSR_MBUF_SEND,
+ (IOCSR_MBUF_SEND_BLOCKING |
+ (IOCSR_MBUF_SEND_BOX_LO (0x3) << IOCSR_MBUF_SEND_BOX_SHIFT) |
+ (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+ ((UINTN)ExchangeInfo) << IOCSR_MBUF_SEND_BUF_SHIFT)
+ );
+
+ IoCsrWrite64 (
+ LOONGARCH_IOCSR_MBUF_SEND,
+ (IOCSR_MBUF_SEND_BLOCKING |
+ (IOCSR_MBUF_SEND_BOX_HI (0x0) << IOCSR_MBUF_SEND_BOX_SHIFT) |
+ (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+ ((UINTN)(ApWakeupFunction) & IOCSR_MBUF_SEND_H32_MASK))
+ );
+ IoCsrWrite64 (
+ LOONGARCH_IOCSR_MBUF_SEND,
+ (IOCSR_MBUF_SEND_BLOCKING |
+ (IOCSR_MBUF_SEND_BOX_LO (0x0) << IOCSR_MBUF_SEND_BOX_SHIFT) |
+ (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+ ((UINTN)ApWakeupFunction) << IOCSR_MBUF_SEND_BUF_SHIFT)
+ );
+
+ //
+ // Send IPI 4 interrupt to wake up APs.
+ //
+ IoCsrWrite64 (
+ LOONGARCH_IOCSR_IPI_SEND,
+ (IOCSR_MBUF_SEND_BLOCKING |
+ (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+ 0x2 // Bit 2
+ )
+ );
+ }
+ }
+ } else {
+ IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, (UINTN)ExchangeInfo);
+ IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, (UINTN)ApWakeupFunction);
+ }
+
+ TimedWaitForApFinish (
+ CpuMpData,
+ PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
+ PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
+ );
+ } else {
+ if (Broadcast) {
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ if (Index != CpuMpData->BspNumber) {
+ CpuData = &CpuMpData->CpuData[Index];
+ if ((GetApState (CpuData) == CpuStateDisabled) && !WakeUpDisabledAps) {
+ continue;
+ }
+
+ CpuData->ApFunction = (UINTN)Procedure;
+ CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;
+ SetApState (CpuData, CpuStateReady);
+ *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
+
+ //
+ // Send IPI 4 interrupt to wake up APs.
+ //
+ IoCsrWrite64 (
+ LOONGARCH_IOCSR_IPI_SEND,
+ (IOCSR_MBUF_SEND_BLOCKING |
+ (CpuInfoInHob[Index].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+ 0x2 // Bit 2
+ )
+ );
+ }
+ }
+
+ //
+ // Wait all APs waken up.
+ //
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ CpuData = &CpuMpData->CpuData[Index];
+ if (Index != CpuMpData->BspNumber) {
+ WaitApWakeup (CpuData->StartupApSignal);
+ }
+ }
+ } else {
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ CpuData->ApFunction = (UINTN)Procedure;
+ CpuData->ApFunctionArgument = (UINTN)ProcedureArgument;
+ SetApState (CpuData, CpuStateReady);
+ //
+ // Wakeup specified AP
+ //
+ *(UINT32 *)CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
+
+ //
+ // Send IPI 4 interrupt to wake up APs.
+ //
+ IoCsrWrite64 (
+ LOONGARCH_IOCSR_IPI_SEND,
+ (IOCSR_MBUF_SEND_BLOCKING |
+ (CpuInfoInHob[ProcessorNumber].ApicId << IOCSR_MBUF_SEND_CPU_SHIFT) |
+ 0x2 // Bit 2
+ )
+ );
+
+ //
+ // Wait specified AP waken up
+ //
+ WaitApWakeup (CpuData->StartupApSignal);
+ }
+ }
+}
+
+/**
+ Searches for the next waiting AP.
+
+ Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
+
+ @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
+
+ @retval EFI_SUCCESS The next waiting AP has been found.
+ @retval EFI_NOT_FOUND No waiting AP exists.
+
+**/
+EFI_STATUS
+GetNextWaitingProcessorNumber (
+ OUT UINTN *NextProcessorNumber
+ )
+{
+ UINTN ProcessorNumber;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ *NextProcessorNumber = ProcessorNumber;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/** Checks status of specified AP.
+
+ This function checks whether the specified AP has finished the task assigned
+ by StartupThisAP(), and whether timeout expires.
+
+ @param[in] ProcessorNumber The handle number of processor.
+
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckThisAP (
+ IN UINTN ProcessorNumber
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ CPU_AP_DATA *CpuData;
+
+ CpuMpData = GetCpuMpData ();
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+
+ //
+ // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
+ //
+ if (GetApState (CpuData) == CpuStateFinished) {
+ if (CpuData->Finished != NULL) {
+ *(CpuData->Finished) = TRUE;
+ }
+
+ SetApState (CpuData, CpuStateIdle);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // If timeout expires for StartupThisAP(), report timeout.
+ //
+ if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
+ if (CpuData->Finished != NULL) {
+ *(CpuData->Finished) = FALSE;
+ }
+
+ return EFI_TIMEOUT;
+ }
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Checks status of all APs.
+
+ This function checks whether all APs have finished task assigned by StartupAllAPs(),
+ and whether timeout expires.
+
+ @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckAllAPs (
+ VOID
+ )
+{
+ UINTN ProcessorNumber;
+ UINTN NextProcessorNumber;
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+ CPU_AP_DATA *CpuData;
+
+ CpuMpData = GetCpuMpData ();
+
+ NextProcessorNumber = 0;
+
+ //
+ // Go through all APs that are responsible for the StartupAllAPs().
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ continue;
+ }
+
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ //
+ // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
+ // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
+ // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
+ //
+ if (GetApState (CpuData) == CpuStateFinished) {
+ CpuMpData->RunningCount--;
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+ SetApState (CpuData, CpuStateIdle);
+
+ //
+ // If in Single Thread mode, then search for the next waiting AP for execution.
+ //
+ if (CpuMpData->SingleThread) {
+ Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
+
+ if (!EFI_ERROR (Status)) {
+ WakeUpAP (
+ CpuMpData,
+ FALSE,
+ (UINT32)NextProcessorNumber,
+ CpuMpData->Procedure,
+ CpuMpData->ProcArguments,
+ TRUE
+ );
+ }
+ }
+ }
+ }
+
+ //
+ // If all APs finish, return EFI_SUCCESS.
+ //
+ if (CpuMpData->RunningCount == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If timeout expires, report timeout.
+ //
+ if (CheckTimeout (
+ &CpuMpData->CurrentTime,
+ &CpuMpData->TotalTime,
+ CpuMpData->ExpectedTime
+ )
+ )
+ {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] ExcludeBsp Whether let BSP also trig this task.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If all APs finish successfully, then its
+ content is set to NULL. If not all APs
+ finish before timeout expires, then its
+ content is set to address of the buffer
+ holding handle numbers of the failed APs.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval others Failed to Startup all APs.
+
+**/
+EFI_STATUS
+StartupAllCPUsWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN BOOLEAN ExcludeBsp,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+ UINTN ProcessorCount;
+ UINTN ProcessorNumber;
+ UINTN CallerNumber;
+ CPU_AP_DATA *CpuData;
+ BOOLEAN HasEnabledAp;
+ CPU_STATE ApState;
+
+ CpuMpData = GetCpuMpData ();
+
+ if (FailedCpuList != NULL) {
+ *FailedCpuList = NULL;
+ }
+
+ if ((CpuMpData->CpuCount == 1) && ExcludeBsp) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Update AP state
+ //
+ CheckAndUpdateApsStatus ();
+
+ ProcessorCount = CpuMpData->CpuCount;
+ HasEnabledAp = FALSE;
+ //
+ // Check whether all enabled APs are idle.
+ // If any enabled AP is not idle, return EFI_NOT_READY.
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ if (ProcessorNumber != CpuMpData->BspNumber) {
+ ApState = GetApState (CpuData);
+ if (ApState != CpuStateDisabled) {
+ HasEnabledAp = TRUE;
+ if (ApState != CpuStateIdle) {
+ //
+ // If any enabled APs are busy, return EFI_NOT_READY.
+ //
+ return EFI_NOT_READY;
+ }
+ }
+ }
+ }
+
+ if (!HasEnabledAp && ExcludeBsp) {
+ //
+ // If no enabled AP exists and not include Bsp to do the procedure, return EFI_NOT_STARTED.
+ //
+ return EFI_NOT_STARTED;
+ }
+
+ CpuMpData->RunningCount = 0;
+ for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ CpuData->Waiting = FALSE;
+ if (ProcessorNumber != CpuMpData->BspNumber) {
+ if (CpuData->State == CpuStateIdle) {
+ //
+ // Mark this processor as responsible for current calling.
+ //
+ CpuData->Waiting = TRUE;
+ CpuMpData->RunningCount++;
+ }
+ }
+ }
+
+ CpuMpData->Procedure = Procedure;
+ CpuMpData->ProcArguments = ProcedureArgument;
+ CpuMpData->SingleThread = SingleThread;
+ CpuMpData->FinishedCount = 0;
+ CpuMpData->ExpectedTime = CalculateTimeout (
+ TimeoutInMicroseconds,
+ &CpuMpData->CurrentTime
+ );
+ CpuMpData->TotalTime = 0;
+ CpuMpData->WaitEvent = WaitEvent;
+
+ if (!SingleThread) {
+ WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE);
+ } else {
+ for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+ if (ProcessorNumber == CallerNumber) {
+ continue;
+ }
+
+ if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
+ break;
+ }
+ }
+ }
+
+ if (!ExcludeBsp) {
+ //
+ // Start BSP.
+ //
+ Procedure (ProcedureArgument);
+ }
+
+ Status = EFI_SUCCESS;
+ if (WaitEvent == NULL) {
+ do {
+ Status = CheckAllAPs ();
+ } while (Status == EFI_NOT_READY);
+ }
+
+ return Status;
+}
+
+/**
+ Worker function to let the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] ProcessorNumber The handle number of the AP.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If AP returns from Procedure before the
+ timeout expires, its content is set to TRUE.
+ Otherwise, the value is set to FALSE.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval others Failed to Startup AP.
+
+**/
+EFI_STATUS
+StartupThisAPWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+ CPU_AP_DATA *CpuData;
+ UINTN CallerNumber;
+
+ CpuMpData = GetCpuMpData ();
+
+ if (Finished != NULL) {
+ *Finished = FALSE;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Check whether processor with the handle specified by ProcessorNumber exists
+ //
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether specified processor is BSP
+ //
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check parameter Procedure
+ //
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Update AP state
+ //
+ CheckAndUpdateApsStatus ();
+
+ //
+ // Check whether specified AP is disabled
+ //
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ CpuData->WaitEvent = WaitEvent;
+ CpuData->Finished = Finished;
+ CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);
+ CpuData->TotalTime = 0;
+
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, FALSE);
+
+ //
+ // If WaitEvent is NULL, execute in blocking mode.
+ // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
+ //
+ Status = EFI_SUCCESS;
+ if (WaitEvent == NULL) {
+ do {
+ Status = CheckThisAP (ProcessorNumber);
+ } while (Status == EFI_NOT_READY);
+ }
+
+ return Status;
+}
+
+/**
+ This service executes a caller provided function on all enabled CPUs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. TimeoutInMicroseconds is ignored
+ for BSP.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+
+ @retval EFI_SUCCESS In blocking mode, all CPUs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled CPUs.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllCPUs (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ return StartupAllCPUsWorker (
+ Procedure,
+ TRUE,
+ FALSE,
+ NULL,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ NULL
+ );
+}
+
+/**
+ MP Initialize Library initialization.
+
+ This service will allocate AP reset vector and wakeup all APs to do APs
+ initialization.
+
+ This service must be invoked before all other MP Initialize Library
+ service are invoked.
+
+ @retval EFI_SUCCESS MP initialization succeeds.
+ @retval Others MP initialization fails.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibInitialize (
+ VOID
+ )
+{
+ CPU_MP_DATA *OldCpuMpData;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ UINT32 MaxLogicalProcessorNumber;
+ UINTN BufferSize;
+ UINTN MonitorBufferSize;
+ VOID *MpBuffer;
+ CPU_MP_DATA *CpuMpData;
+ UINTN Index;
+
+ OldCpuMpData = GetCpuMpDataFromGuidedHob ();
+ if (OldCpuMpData == NULL) {
+ MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+ } else {
+ MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
+ }
+
+ ASSERT (MaxLogicalProcessorNumber != 0);
+
+ MonitorBufferSize = sizeof (WAKEUP_AP_SIGNAL) * MaxLogicalProcessorNumber;
+
+ BufferSize = 0;
+ BufferSize += MonitorBufferSize;
+ BufferSize += sizeof (CPU_MP_DATA);
+ BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
+ MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
+ ASSERT (MpBuffer != NULL);
+ ZeroMem (MpBuffer, BufferSize);
+
+ CpuMpData = (CPU_MP_DATA *)MpBuffer;
+
+ CpuMpData->CpuCount = 1;
+ CpuMpData->BspNumber = 0;
+ CpuMpData->CpuData = (CPU_AP_DATA *)(CpuMpData + 1);
+ CpuMpData->CpuInfoInHob = (UINT64)(UINTN)(CpuMpData->CpuData + MaxLogicalProcessorNumber);
+
+ InitializeSpinLock (&CpuMpData->MpLock);
+
+ //
+ // Set BSP basic information
+ //
+ InitializeApData (CpuMpData, 0, 0);
+
+ //
+ // Set up APs wakeup signal buffer
+ //
+ for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
+ CpuMpData->CpuData[Index].StartupApSignal =
+ (UINT32 *)((MpBuffer + BufferSize - MonitorBufferSize) + (sizeof (WAKEUP_AP_SIGNAL) * Index));
+ }
+
+ if (OldCpuMpData == NULL) {
+ if (MaxLogicalProcessorNumber > 1) {
+ //
+ // Wakeup all APs and calculate the processor count in system
+ //
+ CollectProcessorCount (CpuMpData);
+ }
+ } else {
+ //
+ // APs have been wakeup before, just get the CPU Information
+ // from HOB
+ //
+ CpuMpData->CpuCount = OldCpuMpData->CpuCount;
+ CpuMpData->BspNumber = OldCpuMpData->BspNumber;
+ CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;
+ CpuMpData->MpCpuExchangeInfo = OldCpuMpData->MpCpuExchangeInfo;
+
+ CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
+ CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0) ? TRUE : FALSE;
+ }
+
+ if (CpuMpData->CpuCount > 1) {
+ //
+ // Only needs to use this flag for DXE phase to update the wake up
+ // buffer. Wakeup buffer allocated in PEI phase is no longer valid
+ // in DXE.
+ //
+ CpuMpData->InitFlag = ApInitReconfig;
+ WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE);
+
+ //
+ // Wait for all APs finished initialization
+ //
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+ CpuPause ();
+ }
+
+ CpuMpData->InitFlag = ApInitDone;
+ }
+
+ if (MaxLogicalProcessorNumber > 1) {
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
+ }
+ }
+ }
+
+ //
+ // Initialize global data for MP support
+ //
+ InitMpGlobalData (CpuMpData);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+
+ CpuMpData = GetCpuMpData ();
+ CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ ProcessorInfoBuffer->ProcessorId = (UINT64)CpuInfoInHob[ProcessorNumber].ApicId;
+ ProcessorInfoBuffer->StatusFlag = 0;
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+
+ if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
+ }
+
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
+ ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+ } else {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+ }
+
+ if (HealthData != NULL) {
+ HealthData->Uint32 = CpuInfoInHob[ProcessorNumber].Health;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ @param[out] ProcessorNumber Pointer to the handle number of AP.
+ The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ MpInitLibGetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibWhoAmI (
+ OUT UINTN *ProcessorNumber
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuMpData = GetCpuMpData ();
+
+ return GetProcessorNumber (CpuMpData, ProcessorNumber);
+}
+
+/**
+ Retrieves the number of logical processor in the platform and the number of
+ those logical processors that are enabled on this boot. This service may only
+ be called from the BSP.
+
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors OPTIONAL,
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+ UINTN ProcessorNumber;
+ UINTN EnabledProcessorNumber;
+ UINTN Index;
+
+ CpuMpData = GetCpuMpData ();
+
+ if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorNumber = CpuMpData->CpuCount;
+ EnabledProcessorNumber = 0;
+ for (Index = 0; Index < ProcessorNumber; Index++) {
+ if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
+ EnabledProcessorNumber++;
+ }
+ }
+
+ if (NumberOfProcessors != NULL) {
+ *NumberOfProcessors = ProcessorNumber;
+ }
+
+ if (NumberOfEnabledProcessors != NULL) {
+ *NumberOfEnabledProcessors = EnabledProcessorNumber;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get pointer to CPU MP Data structure from GUIDed HOB.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpDataFromGuidedHob (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
+
+ if (GuidHob != NULL) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ CpuMpData = (CPU_MP_DATA *)(*(UINTN *)DataInHob);
+ }
+
+ return CpuMpData;
+}
diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h
new file mode 100644
index 0000000000..16db52e16c
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h
@@ -0,0 +1,361 @@
+/** @file
+ Common header file for LoongArch MP Initialize Library.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_LIB_H_
+#define MP_LIB_H_
+
+#include <PiPei.h>
+#include <Library/PeiServicesLib.h>
+
+#include <Library/MpInitLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/CpuLib.h>
+#include <Library/TimerLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/HobLib.h>
+
+#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P')
+
+#define CPU_INIT_MP_LIB_HOB_GUID \
+ { \
+ 0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \
+ }
+
+#define PROCESSOR_RESOURCE_HOB_GUID \
+ { \
+ 0xb855c7fe, 0xa758, 0x701f, { 0xa7, 0x30, 0x87, 0xf3, 0x9c, 0x03, 0x46, 0x7e } \
+ }
+
+//
+// AP loop state when APs are in idle state
+// It's value is the same with PcdCpuApLoopMode
+//
+typedef enum {
+ ApInHltLoop = 1,
+ ApInRunLoop = 2
+} AP_LOOP_MODE;
+
+//
+// AP initialization state during APs wakeup
+//
+typedef enum {
+ ApInitConfig = 1,
+ ApInitReconfig = 2,
+ ApInitDone = 3
+} AP_INIT_STATE;
+
+//
+// AP state
+//
+typedef enum {
+ CpuStateIdle,
+ CpuStateReady,
+ CpuStateBusy,
+ CpuStateFinished,
+ CpuStateDisabled
+} CPU_STATE;
+
+//
+// AP related data
+//
+typedef struct {
+ SPIN_LOCK ApLock;
+ volatile UINT32 *StartupApSignal;
+ volatile UINTN ApFunction;
+ volatile UINTN ApFunctionArgument;
+ BOOLEAN CpuHealthy;
+ volatile CPU_STATE State;
+ BOOLEAN Waiting;
+ BOOLEAN *Finished;
+ UINT64 ExpectedTime;
+ UINT64 CurrentTime;
+ UINT64 TotalTime;
+ EFI_EVENT WaitEvent;
+} CPU_AP_DATA;
+
+//
+// Basic CPU information saved in Guided HOB.
+// Because the contents will be shard between PEI and DXE,
+// we need to make sure the each fields offset same in different
+// architecture.
+//
+#pragma pack (1)
+typedef struct {
+ UINT32 ApicId;
+ UINT32 Health;
+} CPU_INFO_IN_HOB;
+#pragma pack ()
+
+typedef struct _CPU_MP_DATA CPU_MP_DATA;
+
+#pragma pack(1)
+
+//
+// MP CPU exchange information for AP reset code
+// This structure is required to be packed because fixed field offsets
+// into this structure are used in assembly code in this module
+//
+typedef struct {
+ CPU_MP_DATA *CpuMpData;
+} MP_CPU_EXCHANGE_INFO;
+
+#pragma pack()
+
+typedef struct {
+ SPIN_LOCK Lock;
+ UINT32 CpuCount;
+ UINT64 CpuInfoInHob;
+} PROCESSOR_RESOURCE_DATA;
+
+//
+// CPU MP Data save in memory
+//
+struct _CPU_MP_DATA {
+ UINT64 CpuInfoInHob;
+ UINT32 CpuCount;
+ UINT32 BspNumber;
+ //
+ // The above fields data will be passed from PEI to DXE
+ // Please make sure the fields offset same in the different
+ // architecture.
+ //
+ SPIN_LOCK MpLock;
+
+ volatile UINT32 FinishedCount;
+ UINT32 RunningCount;
+ BOOLEAN SingleThread;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *ProcArguments;
+ BOOLEAN *Finished;
+ UINT64 ExpectedTime;
+ UINT64 CurrentTime;
+ UINT64 TotalTime;
+ EFI_EVENT WaitEvent;
+
+ AP_INIT_STATE InitFlag;
+ UINT8 ApLoopMode;
+ CPU_AP_DATA *CpuData;
+ volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
+};
+
+extern EFI_GUID mCpuInitMpLibHobGuid;
+extern EFI_GUID mProcessorResourceHobGuid;
+
+/**
+ Get the pointer to CPU MP Data structure.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ );
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
+/**
+ This function will be called by BSP to wakeup AP.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+ @param[in] Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param[in] ProcessorNumber The handle number of specified processor
+ @param[in] Procedure The function to be invoked by AP
+ @param[in] ProcedureArgument The argument to be passed into AP function
+ @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.
+**/
+VOID
+WakeUpAP (
+ IN CPU_MP_DATA *CpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINTN ProcessorNumber,
+ IN EFI_AP_PROCEDURE Procedure OPTIONAL,
+ IN VOID *ProcedureArgument OPTIONAL,
+ IN BOOLEAN WakeUpDisabledAps
+ );
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If all APs finish successfully, then its
+ content is set to NULL. If not all APs
+ finish before timeout expires, then its
+ content is set to address of the buffer
+ holding handle numbers of the failed APs.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval others Failed to Startup all APs.
+
+**/
+EFI_STATUS
+StartupAllCPUsWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN BOOLEAN ExcludeBsp,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ );
+
+/**
+ Worker function to let the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] ProcessorNumber The handle number of the AP.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If AP returns from Procedure before the
+ timeout expires, its content is set to TRUE.
+ Otherwise, the value is set to FALSE.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval others Failed to Startup AP.
+
+**/
+EFI_STATUS
+StartupThisAPWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ );
+
+/**
+ Worker function to let the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+ This instance will be added in the future.
+
+ @param[in] ProcessorNumber The handle number of AP.
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval others Failed to Enable/Disable AP.
+
+**/
+EFI_STATUS
+EnableDisableApWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );
+
+/**
+ Get pointer to CPU MP Data structure from GUIDed HOB.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpDataFromGuidedHob (
+ VOID
+ );
+
+/** Checks status of specified AP.
+
+ This function checks whether the specified AP has finished the task assigned
+ by StartupThisAP(), and whether timeout expires.
+
+ @param[in] ProcessorNumber The handle number of processor.
+
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckThisAP (
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ Checks status of all APs.
+
+ This function checks whether all APs have finished task assigned by StartupAllAPs(),
+ and whether timeout expires.
+
+ @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckAllAPs (
+ VOID
+ );
+
+/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ );
+
+/**
+ Enable Debug Agent to support source debugging on AP function.
+ This instance will added in the future.
+
+**/
+VOID
+EnableDebugAgent (
+ VOID
+ );
+
+#endif
diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf
new file mode 100644
index 0000000000..13711bb458
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf
@@ -0,0 +1,37 @@
+## @file
+# LoongArch64 MP initialize support functions for PEI phase.
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiMpInitLib
+ MODULE_UNI_FILE = PeiMpInitLib.uni
+ FILE_GUID = ED078F16-A2D3-2F34-9267-E24D56E91FCF
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = MpInitLib|PEIM
+
+[Sources.common]
+ PeiMpLib.c
+ MpLib.c
+ MpLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ HobLib
+ CpuLib
+ SynchronizationLib
+ TimerLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## CONSUMES
diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni
new file mode 100644
index 0000000000..f22f09523d
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// MP Initialize Library instance for PEI driver.
+//
+// MP Initialize Library instance for PEI driver.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "MP Initialize Library instance for PEI driver."
+
+#string STR_MODULE_DESCRIPTION #language en-US "MP Initialize Library instance for PEI driver."
diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c
new file mode 100644
index 0000000000..80938599b3
--- /dev/null
+++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c
@@ -0,0 +1,404 @@
+/** @file
+ LoongArch64 MP initialize support functions for PEI phase.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+/**
+ Enable Debug Agent to support source debugging on AP function.
+
+**/
+VOID
+EnableDebugAgent (
+ VOID
+ )
+{
+}
+
+/**
+ Get pointer to CPU MP Data structure.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpDataFromGuidedHob ();
+ ASSERT (CpuMpData != NULL);
+ return CpuMpData;
+}
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ UINT64 Data64;
+
+ //
+ // Build location of CPU MP DATA buffer in HOB
+ //
+ Data64 = (UINT64)(UINTN)CpuMpData;
+ BuildGuidDataHob (
+ &mCpuInitMpLibHobGuid,
+ (VOID *)&Data64,
+ sizeof (UINT64)
+ );
+}
+
+/**
+ Save the Processor Resource Data.
+
+ @param[in] ResourceData The pointer to Processor Resource Data structure will be saved.
+**/
+VOID
+SaveProcessorResourceData (
+ IN PROCESSOR_RESOURCE_DATA *ResourceData
+ )
+{
+ UINT64 Data64;
+
+ //
+ // Build location of Processor Resource Data buffer in HOB
+ //
+ Data64 = (UINT64)(UINTN)ResourceData;
+ BuildGuidDataHob (
+ &mProcessorResourceHobGuid,
+ (VOID *)&Data64,
+ sizeof (UINT64)
+ );
+}
+
+/**
+ Get available EfiBootServicesCode memory below 4GB by specified size.
+
+ This buffer is required to safely transfer AP from real address mode to
+ protected mode or long mode, due to the fact that the buffer returned by
+ GetWakeupBuffer() may be marked as non-executable.
+
+ @param[in] BufferSize Wakeup transition buffer size.
+
+ @retval other Return wakeup transition buffer address below 4GB.
+ @retval 0 Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+ IN UINTN BufferSize
+ )
+{
+ //
+ // PEI phase doesn't need to do such transition. So simply return 0.
+ //
+ return 0;
+}
+
+/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ )
+{
+}
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ SaveCpuMpData (CpuMpData);
+}
+
+/**
+ This service executes a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroSeconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure, or TimeoutInMicroSeconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by MpInitLibStartupAllAPs() or
+ MPInitLibStartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
+ if all APs finish successfully, then its
+ content is set to NULL. If not all APs
+ finish before timeout expires, then its
+ content is set to address of the buffer
+ holding handle numbers of the failed APs.
+ The buffer is allocated by MP Initialization
+ library, and it's the caller's responsibility to
+ free the buffer with FreePool() service.
+ In blocking mode, it is ready for consumption
+ when the call returns. In non-blocking mode,
+ it is ready when WaitEvent is signaled. The
+ list of failed CPU is terminated by
+ END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllAPs (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ if (WaitEvent != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return StartupAllCPUsWorker (
+ Procedure,
+ SingleThread,
+ TRUE,
+ NULL,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ FailedCpuList
+ );
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on the
+ designated AP of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ MpInitLibGetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until this AP finish
+ or TimeoutInMicroSeconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on this AP,
+ and go on executing immediately. If this AP
+ return from Procedure or TimeoutInMicroSeconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ this AP to finish this Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ this AP returns from Procedure, then Procedure
+ on the AP is terminated. The
+ AP is available for next function assigned
+ by MpInitLibStartupAllAPs() or
+ MpInitLibStartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure on the
+ specified AP.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupThisAP (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ if (WaitEvent != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return StartupThisAPWorker (
+ Procedure,
+ ProcessorNumber,
+ NULL,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ Finished
+ );
+}
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ MpInitLibGetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of AP.
+ The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ MpInitLibGetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 709992d327..da49031877 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -211,6 +211,8 @@
UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
+ UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf
+ UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf
[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111368): https://edk2.groups.io/g/devel/message/111368
Mute This Topic: https://groups.io/mt/102644771/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 16/39] UefiCpuPkg: Add CpuDxe driver for LoongArch64
[not found] <20231117095742.3605778-1-lichao@loongs>
` (14 preceding siblings ...)
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 15/39] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
@ 2023-11-17 10:00 ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 17/39] EmbeddedPkg: Add PcdPrePiCpuIoSize width for LOONGARCH64 Chao Li
` (24 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:00 UTC (permalink / raw)
To: devel
Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann, Baoqi Zhang,
Dongyan Qian
Added a new DXE driver named CpuDxeLoongArch64.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
Co-authored-by: Dongyan Qian <qiandongyan@loongson.cn>
---
UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.c | 440 ++++++++++++++++++
UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.h | 261 +++++++++++
UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.inf | 60 +++
UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.uni | 15 +
UefiCpuPkg/CpuDxeLoongArch64/CpuMp.c | 544 +++++++++++++++++++++++
UefiCpuPkg/CpuDxeLoongArch64/CpuMp.h | 471 ++++++++++++++++++++
UefiCpuPkg/CpuDxeLoongArch64/Exception.c | 150 +++++++
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
8 files changed, 1942 insertions(+)
create mode 100644 UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.c
create mode 100644 UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.h
create mode 100644 UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.inf
create mode 100644 UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.uni
create mode 100644 UefiCpuPkg/CpuDxeLoongArch64/CpuMp.c
create mode 100644 UefiCpuPkg/CpuDxeLoongArch64/CpuMp.h
create mode 100644 UefiCpuPkg/CpuDxeLoongArch64/Exception.c
diff --git a/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.c b/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.c
new file mode 100644
index 0000000000..b26e6bc3f7
--- /dev/null
+++ b/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.c
@@ -0,0 +1,440 @@
+/** @file CpuDxe.c
+
+ CPU DXE Module to produce CPU ARCH Protocol.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+#include <Library/CpuMmuLib.h>
+#include <Guid/IdleLoopEvent.h>
+#include <Register/LoongArch64/Csr.h>
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE mCpuHandle = NULL;
+EFI_CPU_ARCH_PROTOCOL gCpu = {
+ CpuFlushCpuDataCache,
+ CpuEnableInterrupt,
+ CpuDisableInterrupt,
+ CpuGetInterruptState,
+ CpuInit,
+ CpuRegisterInterruptHandler,
+ CpuGetTimerValue,
+ CpuSetMemoryAttributes,
+ 0, // NumberOfTimers
+ 4, // DmaBufferAlignment
+};
+
+/**
+ This function flushes the range of addresses from Start to Start+Length
+ from the processor's data cache. If Start is not aligned to a cache line
+ boundary, then the bytes before Start to the preceding cache line boundary
+ are also flushed. If Start+Length is not aligned to a cache line boundary,
+ then the bytes past Start+Length to the end of the next cache line boundary
+ are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+ supported. If the data cache is fully coherent with all DMA operations, then
+ this function can just return EFI_SUCCESS. If the processor does not support
+ flushing a range of the data cache, then the entire data cache can be flushed.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param Start The beginning physical address to flush from the processor's data
+ cache.
+ @param Length The number of bytes to flush from the processor's data cache. This
+ function may flush more bytes than Length specifies depending upon
+ the granularity of the flush operation that the processor supports.
+ @param FlushType Specifies the type of flush operation to perform.
+
+ @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
+ the processor's data cache.
+ @retval EFI_INVALID_PARAMETER The processor does not support the cache flush type specified
+ by FlushType.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ )
+{
+ switch (FlushType) {
+ case EfiCpuFlushTypeWriteBack:
+ WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ case EfiCpuFlushTypeInvalidate:
+ InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ case EfiCpuFlushTypeWriteBackInvalidate:
+ WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function enables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are enabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ EnableInterrupts ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function disables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are disabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ DisableInterrupts ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function retrieves the processor's current interrupt state a returns it in
+ State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+ are currently disabled, then FALSE is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param State A pointer to the processor's current interrupt state. Set to TRUE if
+ interrupts are enabled and FALSE if interrupts are disabled.
+
+ @retval EFI_SUCCESS The processor's current interrupt state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ )
+{
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *State = GetInterruptState ();
+ return EFI_SUCCESS;
+}
+
+/**
+ This function generates an INIT on the processor. If this function succeeds, then the
+ processor will be reset, and control will not be returned to the caller. If InitType is
+ not supported by this processor, or the processor cannot programmatically generate an
+ INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+ occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InitType The type of processor INIT to perform.
+
+ @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
+ @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
+ by this processor.
+ @retval EFI_DEVICE_ERROR The processor INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Registers a function to be called from the CPU interrupt handler.
+
+ @param This Protocol instance structure
+ @param InterruptType Defines which interrupt to hook. IA-32
+ valid range is 0x00 through 0xFF
+ @param InterruptHandler A pointer to a function of type
+ EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. A null
+ pointer is an error condition.
+
+ @retval EFI_SUCCESS If handler installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
+ for InterruptType was previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
+ InterruptType was not previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType
+ is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return RegisterInterruptHandler (InterruptType, InterruptHandler);
+}
+
+/**
+ Returns a timer value from one of the CPU's internal timers. There is no
+ inherent time interval between ticks but is a function of the CPU frequency.
+
+ @param This - Protocol instance structure.
+ @param TimerIndex - Specifies which CPU timer is requested.
+ @param TimerValue - Pointer to the returned timer value.
+ @param TimerPeriod - A pointer to the amount of time that passes
+ in femtoseconds (10-15) for each increment
+ of TimerValue. If TimerValue does not
+ increment at a predictable rate, then 0 is
+ returned. The amount of time that has
+ passed between two calls to GetTimerValue()
+ can be calculated with the formula
+ (TimerValue2 - TimerValue1) * TimerPeriod.
+ This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS - If the CPU timer count was returned.
+ @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
+ @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
+ @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ )
+{
+ 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 EfiAttributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 EfiAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINTN LoongArchAttributes;
+ UINTN RegionBaseAddress;
+ UINTN RegionLength;
+ UINTN RegionLoongArchAttributes;
+
+ RegionLength = 0x0;
+
+ if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
+ //
+ // Minimum granularity is SIZE_4KB.
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_4KB\n",
+ BaseAddress,
+ Length,
+ EfiAttributes
+ ));
+
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Convert the 'Attribute' into LoongArch Attribute
+ //
+ LoongArchAttributes = EfiAttributeConverse (EfiAttributes);
+
+ //
+ // Get the region starting from 'BaseAddress' and its 'Attribute'
+ //
+ RegionBaseAddress = BaseAddress;
+ Status = GetMemoryRegionAttribute (
+ RegionBaseAddress,
+ BaseAddress + Length,
+ &RegionLength,
+ &RegionLoongArchAttributes
+ );
+
+ //
+ // 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)))
+ {
+ SetMemoryRegionAttributes (BaseAddress, Length, EfiAttributes, 0x0);
+ Status = GetMemoryRegionAttribute (
+ RegionBaseAddress,
+ BaseAddress + Length,
+ &RegionLength,
+ &RegionLoongArchAttributes
+ );
+ }
+
+ 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.
+
+**/
+VOID
+EFIAPI
+IdleLoopEventCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ CpuSleep ();
+}
+
+/**
+ IPI Interrupt Handler.
+
+ @param InterruptType The type of interrupt that occurred
+ @param SystemContext A pointer to the system context when the interrupt occurred
+**/
+VOID
+EFIAPI
+IpiInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINT32 IpiStatus;
+
+ VOID (*Procedure) (
+ VOID
+ );
+
+ IpiStatus = IoCsrRead32 (LOONGARCH_IOCSR_IPI_STATUS);
+
+ //
+ // Clear interrupt.
+ //
+ IoCsrWrite32 (LOONGARCH_IOCSR_IPI_CLEAR, IpiStatus);
+
+ MemoryFence ();
+
+ //
+ // If the IPI IRQ is SMP_BOOT_CPU, it means the BSP is waking up the APs from the kernel.
+ // So read out the boot vector and jump to it.
+ //
+ if (IpiStatus & SMP_BOOT_CPU) {
+ Procedure = (VOID *)IoCsrRead64 (LOONGARCH_IOCSR_MBUF0);
+ Procedure ();
+ }
+}
+
+/**
+ 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 (&gCpu);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mCpuHandle,
+ &gEfiCpuArchProtocolGuid,
+ &gCpu,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Setup a callback for idle events
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ IdleLoopEventCallback,
+ NULL,
+ &gIdleLoopEventGuid,
+ &IdleLoopEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gCpu.RegisterInterruptHandler (
+ &gCpu,
+ EXCEPT_LOONGARCH_INT_IPI,
+ IpiInterruptHandler
+ );
+
+ InitializeMpSupport ();
+
+ return Status;
+}
diff --git a/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.h b/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.h
new file mode 100644
index 0000000000..a76db96ae9
--- /dev/null
+++ b/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.h
@@ -0,0 +1,261 @@
+/** @file CpuDxe.c
+
+ CPU DXE Module to produce CPU ARCH Protocol.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef CPU_DXE_H_
+#define CPU_DXE_H_
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/UefiLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MpInitLib.h>
+
+#include <Guid/DebugImageInfoTable.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/LoadedImage.h>
+
+/*
+ This function flushes the range of addresses from Start to Start+Length
+ from the processor's data cache. If Start is not aligned to a cache line
+ boundary, then the bytes before Start to the preceding cache line boundary
+ are also flushed. If Start+Length is not aligned to a cache line boundary,
+ then the bytes past Start+Length to the end of the next cache line boundary
+ are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+ supported. If the data cache is fully coherent with all DMA operations, then
+ this function can just return EFI_SUCCESS. If the processor does not support
+ flushing a range of the data cache, then the entire data cache can be flushed.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param Start The beginning physical address to flush from the processor's data
+ cache.
+ @param Length The number of bytes to flush from the processor's data cache. This
+ function may flush more bytes than Length specifies depending upon
+ the granularity of the flush operation that the processor supports.
+ @param FlushType Specifies the type of flush operation to perform.
+
+ @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
+ the processor's data cache.
+ @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified
+ by FlushType.
+ @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
+ from the processor's data cache.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ );
+
+/**
+ This function enables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are enabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+/**
+ This function disables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are disabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+/**
+ This function retrieves the processor's current interrupt state a returns it in
+ State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+ are currently disabled, then FALSE is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param State A pointer to the processor's current interrupt state. Set to TRUE if
+ interrupts are enabled and FALSE if interrupts are disabled.
+
+ @retval EFI_SUCCESS The processor's current interrupt state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ );
+
+/**
+ This function generates an INIT on the processor. If this function succeeds, then the
+ processor will be reset, and control will not be returned to the caller. If InitType is
+ not supported by this processor, or the processor cannot programmatically generate an
+ INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+ occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InitType The type of processor INIT to perform.
+
+ @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
+ @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
+ by this processor.
+ @retval EFI_DEVICE_ERROR The processor INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ );
+
+/**
+ Registers a function to be called from the CPU interrupt handler.
+
+ @param This Protocol instance structure
+ @param InterruptType Defines which interrupt to hook. IA-32
+ valid range is 0x00 through 0xFF
+ @param InterruptHandler A pointer to a function of type
+ EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. A null
+ pointer is an error condition.
+
+ @retval EFI_SUCCESS If handler installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
+ for InterruptType was previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
+ InterruptType was not previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType
+ is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+/**
+ Returns a timer value from one of the CPU's internal timers. There is no
+ inherent time interval between ticks but is a function of the CPU frequency.
+
+ @param This - Protocol instance structure.
+ @param TimerIndex - Specifies which CPU timer is requested.
+ @param TimerValue - Pointer to the returned timer value.
+ @param TimerPeriod - A pointer to the amount of time that passes
+ in femtoseconds (10-15) for each increment
+ of TimerValue. If TimerValue does not
+ increment at a predictable rate, then 0 is
+ returned. The amount of time that has
+ passed between two calls to GetTimerValue()
+ can be calculated with the formula
+ (TimerValue2 - TimerValue1) * TimerPeriod.
+ This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS - If the CPU timer count was returned.
+ @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
+ @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
+ @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ );
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+/**
+ This function modifies the attributes for the memory region specified by BaseAddress and
+ Length from their current attributes to the attributes specified by Attributes.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+VOID
+InitializeExceptions (
+ IN EFI_CPU_ARCH_PROTOCOL *gCpu
+ );
+
+#endif // CPU_DXE_H_
diff --git a/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.inf b/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.inf
new file mode 100644
index 0000000000..11554edcbf
--- /dev/null
+++ b/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.inf
@@ -0,0 +1,60 @@
+## @file
+# CPU driver installs CPU Architecture Protocol and CPU MP protocol.
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CpuDxe
+ MODULE_UNI_FILE = CpuDxe.uni
+ FILE_GUID = BF954921-25C1-48C0-9BFB-8D0CD7EE92DA
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = CpuDxeInitialize
+
+[Sources.Common]
+ CpuDxe.c
+ CpuMp.c
+ Exception.c
+ CpuDxe.h
+ CpuMp.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+ CpuLib
+ DebugLib
+ DxeServicesTableLib
+ HobLib
+ PeCoffGetEntryPointLib
+ UefiDriverEntryPoint
+ UefiLib
+ MpInitLib
+ CpuExceptionHandlerLib
+ CpuMmuLib
+
+[Protocols]
+ gEfiCpuArchProtocolGuid
+ gEfiMpServiceProtocolGuid
+
+[Guids]
+ gEfiDebugImageInfoTableGuid
+ gIdleLoopEventGuid
+ gEfiVectorHandoffTableGuid
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
+
+[Depex]
+ TRUE
diff --git a/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.uni b/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.uni
new file mode 100644
index 0000000000..6db717b829
--- /dev/null
+++ b/UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.uni
@@ -0,0 +1,15 @@
+// /** @file
+// CPU driver installs CPU Architecture Protocol and CPU MP Protocol.
+//
+// CPU driver installs CPU Architecture Protocol and CPU MP Protocol.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU driver installs CPU Architecture Protocol and CPU MP Protocol."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU driver installs CPU Architecture Protocol and CPU MP Protocol."
diff --git a/UefiCpuPkg/CpuDxeLoongArch64/CpuMp.c b/UefiCpuPkg/CpuDxeLoongArch64/CpuMp.c
new file mode 100644
index 0000000000..562ae484ac
--- /dev/null
+++ b/UefiCpuPkg/CpuDxeLoongArch64/CpuMp.c
@@ -0,0 +1,544 @@
+/** @file
+ CPU DXE Module to produce CPU MP Protocol.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+
+EFI_HANDLE mMpServiceHandle = NULL;
+UINTN mNumberOfProcessors = 1;
+
+EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {
+ GetNumberOfProcessors,
+ GetProcessorInfo,
+ StartupAllAPs,
+ StartupThisAP,
+ SwitchBSP,
+ EnableDisableAP,
+ WhoAmI
+};
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Protocol provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return MpInitLibGetNumberOfProcessors (
+ NumberOfProcessors,
+ NumberOfEnabledProcessors
+ );
+}
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of operation,
+ slot numbers is all considered platform-related information and is not provided
+ by this service.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
+}
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
+ APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
+ mode, and the BSP returns from this service without waiting for APs. If a
+ non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+ is signaled, then EFI_UNSUPPORTED must be returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Protocol does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. EFI services and protocols may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroseconds expires.
+
+ In non-blocking execution mode, BSP is freed to return to the caller and then
+ proceed to the next task without having to wait for APs. The following
+ sequence needs to occur in a non-blocking execution mode:
+
+ -# The caller that intends to use this MP Services Protocol in non-blocking
+ mode creates WaitEvent by calling the EFI CreateEvent() service. The caller
+ invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
+ is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
+ the function specified by Procedure to be started on all the enabled APs,
+ and releases the BSP to continue with other tasks.
+ -# The caller can use the CheckEvent() and WaitForEvent() services to check
+ the state of the WaitEvent created in step 1.
+ -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
+ Service signals WaitEvent by calling the EFI SignalEvent() function. If
+ FailedCpuList is not NULL, its content is available when WaitEvent is
+ signaled. If all APs returned from Procedure prior to the timeout, then
+ FailedCpuList is set to NULL. If not all APs return from Procedure before
+ the timeout, then FailedCpuList is filled in with the list of the failed
+ APs. The buffer is allocated by MP Service Protocol using AllocatePool().
+ It is the caller's responsibility to free the buffer with FreePool() service.
+ -# This invocation of SignalEvent() function informs the caller that invoked
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
+ the specified task or a timeout occurred. The contents of FailedCpuList
+ can be examined to determine which APs did not complete the specified task
+ prior to the timeout.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure, or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
+ if all APs finish successfully, then its
+ content is set to NULL. If not all APs
+ finish before timeout expires, then its
+ content is set to address of the buffer
+ holding handle numbers of the failed APs.
+ The buffer is allocated by MP Service Protocol,
+ and it's the caller's responsibility to
+ free the buffer with FreePool() service.
+ In blocking mode, it is ready for consumption
+ when the call returns. In non-blocking mode,
+ it is ready when WaitEvent is signaled. The
+ list of failed CPU is terminated by
+ END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ return MpInitLibStartupAllAPs (
+ Procedure,
+ SingleThread,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ FailedCpuList
+ );
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
+ is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
+ BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
+ is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
+ then EFI_UNSUPPORTED must be returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+ EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on the
+ designated AP of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until this AP finish
+ or TimeoutInMicroSeconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on this AP,
+ and go on executing immediately. If this AP
+ return from Procedure or TimeoutInMicroSeconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ this AP to finish this Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ this AP returns from Procedure, then Procedure
+ on the AP is terminated. The
+ AP is available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure on the
+ specified AP.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ return MpInitLibStartupThisAP (
+ Procedure,
+ ProcessorNumber,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ Finished
+ );
+}
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+ is signaled.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
+}
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system. This service may not be supported
+ after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP.
+ The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. The total number of logical processors can be retrieved
+ with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
+ called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] ProcessorNumber Pointer to the handle number of AP.
+ The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ return MpInitLibWhoAmI (ProcessorNumber);
+}
+
+/**
+ Initialize Multi-processor support.
+**/
+VOID
+InitializeMpSupport (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfProcessors;
+ UINTN NumberOfEnabledProcessors;
+
+ //
+ // Wakeup APs to do initialization
+ //
+ Status = MpInitLibInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors);
+ mNumberOfProcessors = NumberOfProcessors;
+ DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mMpServiceHandle,
+ &gEfiMpServiceProtocolGuid,
+ &mMpServicesTemplate,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/UefiCpuPkg/CpuDxeLoongArch64/CpuMp.h b/UefiCpuPkg/CpuDxeLoongArch64/CpuMp.h
new file mode 100644
index 0000000000..7994305206
--- /dev/null
+++ b/UefiCpuPkg/CpuDxeLoongArch64/CpuMp.h
@@ -0,0 +1,471 @@
+/** @file
+ CPU DXE MP support
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_MP_H_
+#define CPU_MP_H_
+
+#define SMP_BOOT_CPU BIT0
+
+/**
+ Initialize Multi-processor support.
+
+**/
+VOID
+InitializeMpSupport (
+ VOID
+ );
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Protocol provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of operation,
+ slot numbers is all considered platform-related information and is not provided
+ by this service.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
+ APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
+ mode, and the BSP returns from this service without waiting for APs. If a
+ non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+ is signaled, then EFI_UNSUPPORTED must be returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Protocol does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. EFI services and protocols may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroseconds expires.
+
+ In non-blocking execution mode, BSP is freed to return to the caller and then
+ proceed to the next task without having to wait for APs. The following
+ sequence needs to occur in a non-blocking execution mode:
+
+ -# The caller that intends to use this MP Services Protocol in non-blocking
+ mode creates WaitEvent by calling the EFI CreateEvent() service. The caller
+ invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
+ is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
+ the function specified by Procedure to be started on all the enabled APs,
+ and releases the BSP to continue with other tasks.
+ -# The caller can use the CheckEvent() and WaitForEvent() services to check
+ the state of the WaitEvent created in step 1.
+ -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
+ Service signals WaitEvent by calling the EFI SignalEvent() function. If
+ FailedCpuList is not NULL, its content is available when WaitEvent is
+ signaled. If all APs returned from Procedure prior to the timeout, then
+ FailedCpuList is set to NULL. If not all APs return from Procedure before
+ the timeout, then FailedCpuList is filled in with the list of the failed
+ APs. The buffer is allocated by MP Service Protocol using AllocatePool().
+ It is the caller's responsibility to free the buffer with FreePool() service.
+ -# This invocation of SignalEvent() function informs the caller that invoked
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
+ the specified task or a timeout occurred. The contents of FailedCpuList
+ can be examined to determine which APs did not complete the specified task
+ prior to the timeout.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure, or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
+ if all APs finish successfully, then its
+ content is set to NULL. If not all APs
+ finish before timeout expires, then its
+ content is set to address of the buffer
+ holding handle numbers of the failed APs.
+ The buffer is allocated by MP Service Protocol,
+ and it's the caller's responsibility to
+ free the buffer with FreePool() service.
+ In blocking mode, it is ready for consumption
+ when the call returns. In non-blocking mode,
+ it is ready when WaitEvent is signaled. The
+ list of failed CPU is terminated by
+ END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ );
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
+ is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
+ BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
+ is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
+ then EFI_UNSUPPORTED must be returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+ EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ );
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+ is signaled.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ );
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system. This service may not be supported
+ after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. The total number of logical processors can be retrieved
+ with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
+ called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ );
+
+#endif // CPU_MP_H_
diff --git a/UefiCpuPkg/CpuDxeLoongArch64/Exception.c b/UefiCpuPkg/CpuDxeLoongArch64/Exception.c
new file mode 100644
index 0000000000..fc3823570f
--- /dev/null
+++ b/UefiCpuPkg/CpuDxeLoongArch64/Exception.c
@@ -0,0 +1,150 @@
+/** @file Exception.c
+
+ CPU DXE Module initialization exception instance.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include <Guid/VectorHandoffTable.h>
+#include <Library/CpuExceptionHandlerLib.h>
+
+VOID
+ExceptionEntryStart (
+ VOID
+ );
+
+VOID
+ExceptionEntryEnd (
+ VOID
+ );
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, InterruptHandler);
+}
+
+/**
+ Update the exception start entry code.
+
+ @retval EFI_SUCCESS Update the exception start entry code down.
+ @retval EFI_OUT_OF_RESOURCES The start entry code size out of bounds.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateExceptionStartEntry (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS ExceptionStartEntry;
+ UINTN VectorLength;
+ UINTN MaxLength;
+ UINTN MaxSizeOfVector;
+
+ VectorLength = (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntryStart;
+
+ //
+ // A vector is up to 512 bytes.
+ //
+ MaxSizeOfVector = 512;
+ MaxLength = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * MaxSizeOfVector;
+
+ if (VectorLength > MaxLength) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ExceptionStartEntry = PcdGet64 (PcdCpuExceptionVectorBaseAddress);
+
+ InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength);
+ CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, VectorLength);
+ InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLength);
+ InvalidateDataCache ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize interrupt handling for DXE phase.
+
+ @param Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
+
+ @return VOID.
+
+**/
+VOID
+InitializeExceptions (
+ IN EFI_CPU_ARCH_PROTOCOL *Cpu
+ )
+{
+ EFI_STATUS Status;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfo;
+ BOOLEAN IrqEnabled;
+
+ VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL;
+ Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
+
+ if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) {
+ VectorInfo = VectorInfoList;
+ }
+
+ //
+ // Disable interrupts
+ //
+ Cpu->GetInterruptState (Cpu, &IrqEnabled);
+ if (IrqEnabled) {
+ Cpu->DisableInterrupt (Cpu);
+ }
+
+ //
+ // Update the Exception Start Entry code to point into CpuDxe.
+ //
+ Status = UpdateExceptionStartEntry ();
+ if (EFI_ERROR (Status)) {
+ DebugPrint (EFI_D_ERROR, "[%a]: Exception start entry code out of bounds!\n", __func__);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Intialize the CpuExceptionHandlerLib so we take over the exception vector table from the DXE Core
+ //
+ Status = InitializeCpuExceptionHandlers (VectorInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Enable interrupts
+ //
+ DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled = %x\n", IrqEnabled);
+ if (!IrqEnabled) {
+ Status = Cpu->EnableInterrupt (Cpu);
+ }
+
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index da49031877..15854dafef 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -213,6 +213,7 @@
UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf
UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf
+ UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.inf
[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111369): https://edk2.groups.io/g/devel/message/111369
Mute This Topic: https://groups.io/mt/102644772/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 17/39] EmbeddedPkg: Add PcdPrePiCpuIoSize width for LOONGARCH64
[not found] <20231117095742.3605778-1-lichao@loongs>
` (15 preceding siblings ...)
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 16/39] UefiCpuPkg: Add CpuDxe driver " Chao Li
@ 2023-11-17 10:00 ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 18/39] ArmVirtPkg: Move PCD of FDT base address and FDT padding to OvmfPkg Chao Li
` (23 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:00 UTC (permalink / raw)
To: devel; +Cc: Leif Lindholm, Ard Biesheuvel, Abner Chang, Daniel Schaefer
Added LoongArch64 architecture CPU IO width.
https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Abner Chang <abner.chang@amd.com>
Cc: Daniel Schaefer <git@danielschaefer.me>
Signed-off-by: Chao Li <lichao@loongson.cn>
Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com>
---
EmbeddedPkg/EmbeddedPkg.dec | 3 +++
1 file changed, 3 insertions(+)
diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
index 341ef5e6a6..241d4f3acc 100644
--- a/EmbeddedPkg/EmbeddedPkg.dec
+++ b/EmbeddedPkg/EmbeddedPkg.dec
@@ -165,6 +165,9 @@
[PcdsFixedAtBuild.X64]
gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16|UINT8|0x00000011
+[PcdsFixedAtBuild.LOONGARCH64]
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16|UINT8|0x00000011
+
[PcdsFixedAtBuild.common, PcdsDynamic.common]
#
# Value to add to a host address to obtain a device address, using
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111370): https://edk2.groups.io/g/devel/message/111370
Mute This Topic: https://groups.io/mt/102644774/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 18/39] ArmVirtPkg: Move PCD of FDT base address and FDT padding to OvmfPkg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (16 preceding siblings ...)
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 17/39] EmbeddedPkg: Add PcdPrePiCpuIoSize width for LOONGARCH64 Chao Li
@ 2023-11-17 10:01 ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 19/39] MdePkg: Add a PCD feature flag named PcdPciIoTranslationIsEnabled Chao Li
` (22 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:01 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Gerd Hoffmann,
Jiewen Yao, Jordan Justen
Moved PcdDeviceTreeInitialBaseAddress and PcdDeviceTreeAllocationPadding
to OvmfPkg for easier use by other architectures.
Build-tested only (with "ArmVirtQemu.dsc").
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
---
ArmVirtPkg/ArmVirtCloudHv.dsc | 2 +-
ArmVirtPkg/ArmVirtKvmTool.dsc | 2 +-
ArmVirtPkg/ArmVirtPkg.dec | 14 --------------
ArmVirtPkg/ArmVirtQemu.dsc | 2 +-
ArmVirtPkg/ArmVirtQemuKernel.dsc | 2 +-
ArmVirtPkg/ArmVirtXen.dsc | 2 +-
.../ArmVirtPsciResetSystemPeiLib.inf | 3 ++-
.../CloudHvVirtMemInfoPeiLib.inf | 3 ++-
.../DebugLibFdtPL011UartFlash.inf | 3 ++-
.../EarlyFdt16550SerialPortHookLib.inf | 3 ++-
.../EarlyFdtPL011SerialPortLib.inf | 3 ++-
.../KvmtoolPlatformPeiLib.inf | 5 +++--
.../Library/PlatformPeiLib/PlatformPeiLib.inf | 10 +++++-----
.../QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf | 3 ++-
.../PrePi/ArmVirtPrePiUniCoreRelocatable.inf | 3 ++-
OvmfPkg/OvmfPkg.dec | 15 +++++++++++++++
16 files changed, 42 insertions(+), 33 deletions(-)
diff --git a/ArmVirtPkg/ArmVirtCloudHv.dsc b/ArmVirtPkg/ArmVirtCloudHv.dsc
index 2cb89ce10c..76c0d28544 100644
--- a/ArmVirtPkg/ArmVirtCloudHv.dsc
+++ b/ArmVirtPkg/ArmVirtCloudHv.dsc
@@ -129,7 +129,7 @@
gArmTokenSpaceGuid.PcdSystemMemoryBase|0x40000000
# initial location of the device tree blob passed by Cloud Hypervisor -- base of DRAM
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x40000000
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x40000000
gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }
diff --git a/ArmVirtPkg/ArmVirtKvmTool.dsc b/ArmVirtPkg/ArmVirtKvmTool.dsc
index f50d53bf15..cac4fe06d3 100644
--- a/ArmVirtPkg/ArmVirtKvmTool.dsc
+++ b/ArmVirtPkg/ArmVirtKvmTool.dsc
@@ -179,7 +179,7 @@
# We are booting from RAM using the Linux kernel boot protocol,
# x0 will point to the DTB image in memory.
#
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x0
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x0
gArmTokenSpaceGuid.PcdFdBaseAddress|0x0
gArmTokenSpaceGuid.PcdFvBaseAddress|0x0
diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec
index 0f2d787327..2451644844 100644
--- a/ArmVirtPkg/ArmVirtPkg.dec
+++ b/ArmVirtPkg/ArmVirtPkg.dec
@@ -42,20 +42,6 @@
gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled|FALSE|BOOLEAN|0x00000004
[PcdsFixedAtBuild, PcdsPatchableInModule]
- #
- # This is the physical address where the device tree is expected to be stored
- # upon first entry into UEFI. This needs to be a FixedAtBuild PCD, so that we
- # can do a first pass over the device tree in the SEC phase to discover the
- # UART base address.
- #
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x0|UINT64|0x00000001
-
- #
- # Padding in bytes to add to the device tree allocation, so that the DTB can
- # be modified in place (default: 256 bytes)
- #
- gArmVirtTokenSpaceGuid.PcdDeviceTreeAllocationPadding|256|UINT32|0x00000002
-
#
# Binary representation of the GUID that determines the terminal type. The
# size must be exactly 16 bytes. The default value corresponds to
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 30e3cfc8b9..cf306cac08 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -201,7 +201,7 @@
gArmTokenSpaceGuid.PcdSystemMemoryBase|0x40000000
# initial location of the device tree blob passed by QEMU -- base of DRAM
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x40000000
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x40000000
gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }
diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
index b50f8e84a3..c0d079e28d 100644
--- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
+++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
@@ -198,7 +198,7 @@
# Define a default initial address for the device tree.
# Ignored if x0 != 0 at entry.
#
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x40000000
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x40000000
gArmTokenSpaceGuid.PcdFdBaseAddress|0x0
gArmTokenSpaceGuid.PcdFvBaseAddress|0x0
diff --git a/ArmVirtPkg/ArmVirtXen.dsc b/ArmVirtPkg/ArmVirtXen.dsc
index f0d15b823b..5809832e66 100644
--- a/ArmVirtPkg/ArmVirtXen.dsc
+++ b/ArmVirtPkg/ArmVirtXen.dsc
@@ -115,7 +115,7 @@
#
gArmTokenSpaceGuid.PcdSystemMemoryBase|0x0
gArmTokenSpaceGuid.PcdSystemMemorySize|0x0
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x0
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x0
gArmTokenSpaceGuid.PcdFdBaseAddress|0x0
gArmTokenSpaceGuid.PcdFvBaseAddress|0x0
diff --git a/ArmVirtPkg/Library/ArmVirtPsciResetSystemPeiLib/ArmVirtPsciResetSystemPeiLib.inf b/ArmVirtPkg/Library/ArmVirtPsciResetSystemPeiLib/ArmVirtPsciResetSystemPeiLib.inf
index 3a65706e8d..79217d296d 100644
--- a/ArmVirtPkg/Library/ArmVirtPsciResetSystemPeiLib/ArmVirtPsciResetSystemPeiLib.inf
+++ b/ArmVirtPkg/Library/ArmVirtPsciResetSystemPeiLib/ArmVirtPsciResetSystemPeiLib.inf
@@ -26,6 +26,7 @@
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
[LibraryClasses]
ArmSmcLib
@@ -36,4 +37,4 @@
HobLib
[Pcd]
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
diff --git a/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLib.inf b/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLib.inf
index 666b5d9711..6df26ccd64 100644
--- a/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLib.inf
+++ b/ArmVirtPkg/Library/CloudHvVirtMemInfoLib/CloudHvVirtMemInfoPeiLib.inf
@@ -26,6 +26,7 @@
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
[LibraryClasses]
ArmLib
@@ -44,4 +45,4 @@
[FixedPcd]
gArmTokenSpaceGuid.PcdFdSize
gArmTokenSpaceGuid.PcdFvSize
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
diff --git a/ArmVirtPkg/Library/DebugLibFdtPL011Uart/DebugLibFdtPL011UartFlash.inf b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/DebugLibFdtPL011UartFlash.inf
index 7870ca2ae4..f35a0913f0 100644
--- a/ArmVirtPkg/Library/DebugLibFdtPL011Uart/DebugLibFdtPL011UartFlash.inf
+++ b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/DebugLibFdtPL011UartFlash.inf
@@ -30,6 +30,7 @@
ArmPlatformPkg/ArmPlatformPkg.dec
ArmVirtPkg/ArmVirtPkg.dec
MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
[LibraryClasses]
BaseLib
@@ -41,7 +42,7 @@
PrintLib
[Pcd]
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress # Flash.c
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress # Flash.c
gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask
gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel
diff --git a/ArmVirtPkg/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf b/ArmVirtPkg/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
index 22aba53d9b..3e2303b7f4 100644
--- a/ArmVirtPkg/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
+++ b/ArmVirtPkg/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
@@ -29,7 +29,8 @@
ArmVirtPkg/ArmVirtPkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
[Pcd]
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase
diff --git a/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.inf b/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.inf
index f47692f06a..e677f1d9e7 100644
--- a/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.inf
+++ b/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.inf
@@ -28,9 +28,10 @@
MdePkg/MdePkg.dec
ArmPlatformPkg/ArmPlatformPkg.dec
ArmVirtPkg/ArmVirtPkg.dec
+ OvmfPkg/OvmfPkg.dec
[Pcd]
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
diff --git a/ArmVirtPkg/Library/KvmtoolPlatformPeiLib/KvmtoolPlatformPeiLib.inf b/ArmVirtPkg/Library/KvmtoolPlatformPeiLib/KvmtoolPlatformPeiLib.inf
index f201aee50c..77c0b923bd 100644
--- a/ArmVirtPkg/Library/KvmtoolPlatformPeiLib/KvmtoolPlatformPeiLib.inf
+++ b/ArmVirtPkg/Library/KvmtoolPlatformPeiLib/KvmtoolPlatformPeiLib.inf
@@ -24,6 +24,7 @@
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
[LibraryClasses]
DebugLib
@@ -34,12 +35,12 @@
[FixedPcd]
gArmTokenSpaceGuid.PcdFvSize
- gArmVirtTokenSpaceGuid.PcdDeviceTreeAllocationPadding
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeAllocationPadding
[Pcd]
gArmTokenSpaceGuid.PcdFvBaseAddress
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
[Guids]
gFdtHobGuid
diff --git a/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf b/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf
index b867d8bb89..e9a34b6e2e 100644
--- a/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf
+++ b/ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.inf
@@ -41,16 +41,16 @@
[FixedPcd]
gArmTokenSpaceGuid.PcdFvSize
- gArmVirtTokenSpaceGuid.PcdDeviceTreeAllocationPadding
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeAllocationPadding
[Pcd]
gArmTokenSpaceGuid.PcdFvBaseAddress
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
- gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_PRODUCES
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
[Ppis]
- gOvmfTpmDiscoveredPpiGuid ## SOMETIMES_PRODUCES
- gPeiTpmInitializationDonePpiGuid ## SOMETIMES_PRODUCES
+ gOvmfTpmDiscoveredPpiGuid ## SOMETIMES_PRODUCES
+ gPeiTpmInitializationDonePpiGuid ## SOMETIMES_PRODUCES
[Guids]
gEarlyPL011BaseAddressGuid
diff --git a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf
index f045e39a41..76c3c5d3c8 100644
--- a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf
+++ b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf
@@ -26,6 +26,7 @@
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
[LibraryClasses]
ArmLib
@@ -44,4 +45,4 @@
gArmTokenSpaceGuid.PcdSystemMemorySize
gArmTokenSpaceGuid.PcdFdSize
gArmTokenSpaceGuid.PcdFvSize
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
diff --git a/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf b/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf
index 7edf501808..6b9244bd1a 100755
--- a/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf
+++ b/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf
@@ -35,6 +35,7 @@
ArmPkg/ArmPkg.dec
ArmPlatformPkg/ArmPlatformPkg.dec
ArmVirtPkg/ArmVirtPkg.dec
+ OvmfPkg/OvmfPkg.dec
[LibraryClasses]
BaseLib
@@ -93,6 +94,6 @@
[Pcd]
gArmTokenSpaceGuid.PcdSystemMemoryBase
gArmTokenSpaceGuid.PcdSystemMemorySize
- gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
gArmTokenSpaceGuid.PcdFdBaseAddress
gArmTokenSpaceGuid.PcdFvBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index e3861e5c1b..89091e8bf1 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -481,6 +481,21 @@
#
gUefiOvmfPkgTokenSpaceGuid.PcdForceNoAcpi|0x0|BOOLEAN|0x69
+[PcdsFixedAtBuild, PcdsPatchableInModule]
+ #
+ # This is the physical address where the device tree is expected to be stored
+ # upon first entry into UEFI. This needs to be a FixedAtBuild PCD, so that we
+ # can do a first pass over the device tree in the SEC phase to discover the
+ # UART base address.
+ #
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x0|UINT64|0x6e
+
+ #
+ # Padding in bytes to add to the device tree allocation, so that the DTB can
+ # be modified in place (default: 256 bytes)
+ #
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeAllocationPadding|256|UINT32|0x6f
+
[PcdsFeatureFlag]
gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation|TRUE|BOOLEAN|0x1c
gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation|FALSE|BOOLEAN|0x1d
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111371): https://edk2.groups.io/g/devel/message/111371
Mute This Topic: https://groups.io/mt/102644777/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 19/39] MdePkg: Add a PCD feature flag named PcdPciIoTranslationIsEnabled
[not found] <20231117095742.3605778-1-lichao@loongs>
` (17 preceding siblings ...)
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 18/39] ArmVirtPkg: Move PCD of FDT base address and FDT padding to OvmfPkg Chao Li
@ 2023-11-17 10:01 ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 20/39] UefiCpuPkg: Add MMIO method in CpuIo2Dxe Chao Li
` (21 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:01 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu
Some ARCH need to use MMIO to access PCI IO, such as ARM AARCH64 RISC-V
and LOONGARCH64. In some drivers, a PCD value is added to determine
whether to use MMIO.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
MdePkg/MdePkg.dec | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index ac54338089..55f5230c31 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -2018,6 +2018,12 @@
# @Prompt Validate ORDERED_COLLECTION structure
gEfiMdePkgTokenSpaceGuid.PcdValidateOrderedCollection|FALSE|BOOLEAN|0x0000002a
+ ## Indicates if PCI IO translation is used.
+ # TRUE - PCI IO translation is enable.
+ # FALSE - PCI IO translation is disable.
+ # @Prompt Pci Io Translation Is Enabled.
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled|FALSE|BOOLEAN|0x00000043
+
[PcdsFixedAtBuild]
## Status code value for indicating a watchdog timer has expired.
# EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_TIMER_EXPIRED
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111372): https://edk2.groups.io/g/devel/message/111372
Mute This Topic: https://groups.io/mt/102644778/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 20/39] UefiCpuPkg: Add MMIO method in CpuIo2Dxe
[not found] <20231117095742.3605778-1-lichao@loongs>
` (18 preceding siblings ...)
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 19/39] MdePkg: Add a PCD feature flag named PcdPciIoTranslationIsEnabled Chao Li
@ 2023-11-17 10:01 ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 21/39] ArmVirtPkg: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
` (20 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:01 UTC (permalink / raw)
To: devel
Cc: Ray Ni, Rahul Kumar, Gerd Hoffmann, Leif Lindholm, Ard Biesheuvel,
Sami Mujawar
CpuIo2Dxe only supports IO to access PCI IO. Some ARCH requires
MMIO to access PCI IO, add the MMIO access method in CpuIo2Dxe.
The MMIO methods depend on PcdPciIoTranslationIsEnabled and
PcdPciIoTransLation. The code is referenced from ArmPkg.
Build-tested only (with "OvmfPkgX64.dsc").
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c | 147 +++++++++++++++++++----------
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.h | 2 +
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf | 8 +-
UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.uni | 2 +
4 files changed, 109 insertions(+), 50 deletions(-)
diff --git a/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c b/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c
index 87f4f805ca..8b0967793c 100644
--- a/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c
+++ b/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c
@@ -3,6 +3,8 @@
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -149,7 +151,7 @@ CpuIoCheckParameter (
//
// 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 oveflow conditions.
+ // 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).
@@ -398,6 +400,18 @@ CpuIoServiceRead (
EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
UINT8 *Uint8Buffer;
+ UINT8 EFIAPI (*CpuIoRead8) (
+ UINTN
+ );
+
+ UINT16 EFIAPI (*CpuIoRead16) (
+ UINTN
+ );
+
+ UINT32 EFIAPI (*CpuIoRead32) (
+ UINTN
+ );
+
Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
if (EFI_ERROR (Status)) {
return Status;
@@ -410,37 +424,47 @@ CpuIoServiceRead (
OutStride = mOutStride[Width];
OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);
- //
- // Fifo operations supported for (mInStride[Width] == 0)
- //
- if (InStride == 0) {
- switch (OperationWidth) {
- case EfiCpuIoWidthUint8:
- IoReadFifo8 ((UINTN)Address, Count, Buffer);
- return EFI_SUCCESS;
- case EfiCpuIoWidthUint16:
- IoReadFifo16 ((UINTN)Address, Count, Buffer);
- return EFI_SUCCESS;
- case EfiCpuIoWidthUint32:
- IoReadFifo32 ((UINTN)Address, Count, Buffer);
- return EFI_SUCCESS;
- default:
- //
- // The CpuIoCheckParameter call above will ensure that this
- // path is not taken.
- //
- ASSERT (FALSE);
- break;
+ if (FeaturePcdGet (PcdPciIoTranslationIsEnabled) == FALSE) {
+ //
+ // Fifo operations supported for (mInStride[Width] == 0)
+ //
+ if (InStride == 0) {
+ switch (OperationWidth) {
+ case EfiCpuIoWidthUint8:
+ IoReadFifo8 ((UINTN)Address, Count, Buffer);
+ return EFI_SUCCESS;
+ case EfiCpuIoWidthUint16:
+ IoReadFifo16 ((UINTN)Address, Count, Buffer);
+ return EFI_SUCCESS;
+ case EfiCpuIoWidthUint32:
+ IoReadFifo32 ((UINTN)Address, Count, Buffer);
+ return EFI_SUCCESS;
+ default:
+ //
+ // The CpuIoCheckParameter call above will ensure that this
+ // path is not taken.
+ //
+ ASSERT (FALSE);
+ break;
+ }
}
+ CpuIoRead8 = IoRead8;
+ CpuIoRead16 = IoRead16;
+ CpuIoRead32 = IoRead32;
+ } else {
+ Address += PcdGet64 (PcdPciIoTranslation);
+ CpuIoRead8 = MmioRead8;
+ CpuIoRead16 = MmioRead16;
+ CpuIoRead32 = MmioRead32;
}
for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
if (OperationWidth == EfiCpuIoWidthUint8) {
- *Uint8Buffer = IoRead8 ((UINTN)Address);
+ *Uint8Buffer = CpuIoRead8 ((UINTN)Address);
} else if (OperationWidth == EfiCpuIoWidthUint16) {
- *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address);
+ *((UINT16 *)Uint8Buffer) = CpuIoRead16 ((UINTN)Address);
} else if (OperationWidth == EfiCpuIoWidthUint32) {
- *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address);
+ *((UINT32 *)Uint8Buffer) = CpuIoRead32 ((UINTN)Address);
}
}
@@ -502,6 +526,21 @@ CpuIoServiceWrite (
EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
UINT8 *Uint8Buffer;
+ UINT8 EFIAPI (*CpuIoWrite8) (
+ UINTN,
+ UINT8
+ );
+
+ UINT16 EFIAPI (*CpuIoWrite16) (
+ UINTN,
+ UINT16
+ );
+
+ UINT32 EFIAPI (*CpuIoWrite32) (
+ UINTN,
+ UINT32
+ );
+
//
// Make sure the parameters are valid
//
@@ -517,37 +556,47 @@ CpuIoServiceWrite (
OutStride = mOutStride[Width];
OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03);
- //
- // Fifo operations supported for (mInStride[Width] == 0)
- //
- if (InStride == 0) {
- switch (OperationWidth) {
- case EfiCpuIoWidthUint8:
- IoWriteFifo8 ((UINTN)Address, Count, Buffer);
- return EFI_SUCCESS;
- case EfiCpuIoWidthUint16:
- IoWriteFifo16 ((UINTN)Address, Count, Buffer);
- return EFI_SUCCESS;
- case EfiCpuIoWidthUint32:
- IoWriteFifo32 ((UINTN)Address, Count, Buffer);
- return EFI_SUCCESS;
- default:
- //
- // The CpuIoCheckParameter call above will ensure that this
- // path is not taken.
- //
- ASSERT (FALSE);
- break;
+ if (FeaturePcdGet (PcdPciIoTranslationIsEnabled) == FALSE) {
+ //
+ // Fifo operations supported for (mInStride[Width] == 0)
+ //
+ if (InStride == 0) {
+ switch (OperationWidth) {
+ case EfiCpuIoWidthUint8:
+ IoWriteFifo8 ((UINTN)Address, Count, Buffer);
+ return EFI_SUCCESS;
+ case EfiCpuIoWidthUint16:
+ IoWriteFifo16 ((UINTN)Address, Count, Buffer);
+ return EFI_SUCCESS;
+ case EfiCpuIoWidthUint32:
+ IoWriteFifo32 ((UINTN)Address, Count, Buffer);
+ return EFI_SUCCESS;
+ default:
+ //
+ // The CpuIoCheckParameter call above will ensure that this
+ // path is not taken.
+ //
+ ASSERT (FALSE);
+ break;
+ }
}
+ CpuIoWrite8 = IoWrite8;
+ CpuIoWrite16 = IoWrite16;
+ CpuIoWrite32 = IoWrite32;
+ } else {
+ Address += PcdGet64 (PcdPciIoTranslation);
+ CpuIoWrite8 = MmioWrite8;
+ CpuIoWrite16 = MmioWrite16;
+ CpuIoWrite32 = MmioWrite32;
}
for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
if (OperationWidth == EfiCpuIoWidthUint8) {
- IoWrite8 ((UINTN)Address, *Uint8Buffer);
+ CpuIoWrite8 ((UINTN)Address, *Uint8Buffer);
} else if (OperationWidth == EfiCpuIoWidthUint16) {
- IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+ CpuIoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
} else if (OperationWidth == EfiCpuIoWidthUint32) {
- IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+ CpuIoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
}
}
diff --git a/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.h b/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.h
index 7ebde0759b..5256a583e1 100644
--- a/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.h
+++ b/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.h
@@ -2,6 +2,8 @@
Internal include file for the CPU I/O 2 Protocol.
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
diff --git a/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf b/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
index 499258491f..271c47371b 100644
--- a/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
+++ b/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
@@ -3,6 +3,8 @@
#
# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -20,7 +22,7 @@
#
# The following information is for reference only and not required by the build tools.
#
-# VALID_ARCHITECTURES = IA32 X64 EBC
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64 LOONGARCH64
#
[Sources]
@@ -37,6 +39,10 @@
IoLib
UefiBootServicesTableLib
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
+
[Protocols]
gEfiCpuIo2ProtocolGuid ## PRODUCES
diff --git a/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.uni b/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.uni
index 8d4e5dd6b4..14a36ff888 100644
--- a/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.uni
+++ b/UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.uni
@@ -4,6 +4,8 @@
// Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
//
// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+// Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+// Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111373): https://edk2.groups.io/g/devel/message/111373
Mute This Topic: https://groups.io/mt/102644780/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 21/39] ArmVirtPkg: Enable UefiCpuPkg version CpuIo2Dxe
[not found] <20231117095742.3605778-1-lichao@loongs>
` (19 preceding siblings ...)
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 20/39] UefiCpuPkg: Add MMIO method in CpuIo2Dxe Chao Li
@ 2023-11-17 10:01 ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg Chao Li
` (19 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:01 UTC (permalink / raw)
To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Gerd Hoffmann
Since the UefiCpuPkg/CpuIo2Dxe already supports MMIO, it is enabled at
this thime.
Build-tested only (with "ArmVirtQemu.dsc").
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
ArmVirtPkg/ArmVirtCloudHv.dsc | 4 +++-
ArmVirtPkg/ArmVirtCloudHv.fdf | 2 +-
ArmVirtPkg/ArmVirtKvmTool.dsc | 4 +++-
ArmVirtPkg/ArmVirtKvmTool.fdf | 2 +-
ArmVirtPkg/ArmVirtQemu.dsc | 4 +++-
ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc | 2 +-
ArmVirtPkg/ArmVirtQemuKernel.dsc | 4 +++-
7 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/ArmVirtPkg/ArmVirtCloudHv.dsc b/ArmVirtPkg/ArmVirtCloudHv.dsc
index 76c0d28544..0f80fb34cc 100644
--- a/ArmVirtPkg/ArmVirtCloudHv.dsc
+++ b/ArmVirtPkg/ArmVirtCloudHv.dsc
@@ -85,6 +85,8 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled|TRUE
+
[PcdsFixedAtBuild.common]
!if $(ARCH) == AARCH64
gArmTokenSpaceGuid.PcdVFPEnabled|1
@@ -341,7 +343,7 @@
#
# PCI support
#
- ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf {
+ UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf {
<LibraryClasses>
NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
}
diff --git a/ArmVirtPkg/ArmVirtCloudHv.fdf b/ArmVirtPkg/ArmVirtCloudHv.fdf
index 56d1ea6e8c..9c59433c5f 100644
--- a/ArmVirtPkg/ArmVirtCloudHv.fdf
+++ b/ArmVirtPkg/ArmVirtCloudHv.fdf
@@ -201,7 +201,7 @@ READ_LOCK_STATUS = TRUE
#
# PCI support
#
- INF ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
+ INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/ArmVirtPkg/ArmVirtKvmTool.dsc b/ArmVirtPkg/ArmVirtKvmTool.dsc
index cac4fe06d3..31d5bc13cf 100644
--- a/ArmVirtPkg/ArmVirtKvmTool.dsc
+++ b/ArmVirtPkg/ArmVirtKvmTool.dsc
@@ -128,6 +128,8 @@
gArmTokenSpaceGuid.PcdMonitorConduitHvc|TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled|TRUE
+
[PcdsFixedAtBuild.common]
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000000F
@@ -372,7 +374,7 @@
#
# PCI support
#
- ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf {
+ UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf {
<LibraryClasses>
NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
NULL|OvmfPkg/Library/BaseCachingPciExpressLib/BaseCachingPciExpressLib.inf
diff --git a/ArmVirtPkg/ArmVirtKvmTool.fdf b/ArmVirtPkg/ArmVirtKvmTool.fdf
index 82aff47673..8d5c3c83b1 100644
--- a/ArmVirtPkg/ArmVirtKvmTool.fdf
+++ b/ArmVirtPkg/ArmVirtKvmTool.fdf
@@ -195,7 +195,7 @@ READ_LOCK_STATUS = TRUE
#
# PCI support
#
- INF ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
+ INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index cf306cac08..204344ea0b 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -149,6 +149,8 @@
gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled|$(TPM2_ENABLE)
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled|TRUE
+
[PcdsFixedAtBuild.common]
!if $(ARCH) == AARCH64
gArmTokenSpaceGuid.PcdVFPEnabled|1
@@ -526,7 +528,7 @@
#
# PCI support
#
- ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf {
+ UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf {
<LibraryClasses>
NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
}
diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
index 9b3e37d5c9..b44d72158d 100644
--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
+++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
@@ -153,7 +153,7 @@ READ_LOCK_STATUS = TRUE
#
# PCI support
#
- INF ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
+ INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
index c0d079e28d..c2938883d8 100644
--- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
+++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
@@ -115,6 +115,8 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled|TRUE
+
[PcdsFixedAtBuild.common]
!if $(ARCH) == AARCH64
gArmTokenSpaceGuid.PcdVFPEnabled|1
@@ -431,7 +433,7 @@
#
# PCI support
#
- ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf {
+ UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf {
<LibraryClasses>
NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
}
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111374): https://edk2.groups.io/g/devel/message/111374
Mute This Topic: https://groups.io/mt/102644781/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (20 preceding siblings ...)
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 21/39] ArmVirtPkg: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
@ 2023-11-17 10:01 ` Chao Li
2023-11-17 13:13 ` Leif Lindholm
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
` (18 subsequent siblings)
40 siblings, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:01 UTC (permalink / raw)
To: devel; +Cc: Leif Lindholm, Ard Biesheuvel, Sami Mujawar
ArmPciCpuIo2Dxe has been merged into CpuIo2Dxe, and CpuIo2Dxe is already
used by all ARM virtual platforms, so remove it.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com>
---
ArmPkg/ArmPkg.dsc | 1 -
.../Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c | 556 ------------------
.../ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf | 47 --
3 files changed, 604 deletions(-)
delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 6dd91e6941..7af25a91a1 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -143,7 +143,6 @@
ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
- ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf
ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf
diff --git a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
deleted file mode 100644
index 5a2866ccd8..0000000000
--- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
+++ /dev/null
@@ -1,556 +0,0 @@
-/** @file
- Produces the CPU I/O 2 Protocol.
-
-Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
-Copyright (c) 2016, Linaro Ltd. 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>
-
-#define MAX_IO_PORT_ADDRESS 0xFFFF
-
-//
-// 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.
-
-**/
-STATIC
-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.
-
-**/
-STATIC
-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.
-
-**/
-STATIC
-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.
-
-**/
-STATIC
-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.
-
-**/
-STATIC
-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
-ArmPciCpuIo2Initialize (
- 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/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
deleted file mode 100644
index 9339c2b532..0000000000
--- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
+++ /dev/null
@@ -1,47 +0,0 @@
-## @file
-# Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
-#
-# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
-# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = ArmPciCpuIo2Dxe
- FILE_GUID = 168D1A6E-F4A5-448A-9E95-795661BB3067
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = ArmPciCpuIo2Initialize
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = ARM AARCH64
-#
-
-[Sources]
- ArmPciCpuIo2Dxe.c
-
-[Packages]
- ArmPkg/ArmPkg.dec
- MdePkg/MdePkg.dec
-
-[LibraryClasses]
- UefiDriverEntryPoint
- BaseLib
- DebugLib
- IoLib
- PcdLib
- UefiBootServicesTableLib
-
-[Pcd]
- gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
-
-[Protocols]
- gEfiCpuIo2ProtocolGuid ## PRODUCES
-
-[Depex]
- TRUE
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111375): https://edk2.groups.io/g/devel/message/111375
Mute This Topic: https://groups.io/mt/102644788/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version CpuIo2Dxe
[not found] <20231117095742.3605778-1-lichao@loongs>
` (21 preceding siblings ...)
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg Chao Li
@ 2023-11-17 10:01 ` Chao Li
2023-11-17 20:15 ` Andrei Warkentin
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 24/39] OvmfPkg/RiscVVirt: Remove PciCpuIo2Dxe from RiscVVirt Chao Li
` (17 subsequent siblings)
40 siblings, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:01 UTC (permalink / raw)
To: devel; +Cc: Sunil V L, Andrei Warkentin
Since the UefiCpuPkg/CpuIo2Dxe already supports MMIO, it is enabled at
this thime.
Build-tested only (with "RiscVVirtQemu.dsc").
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Andrei Warkentin <andrei.warkentin@intel.com>
---
OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc | 4 +++-
OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
index 34b2037824..499902e445 100644
--- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
+++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
@@ -143,6 +143,8 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled|TRUE
+
[PcdsFixedAtBuild.common]
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
@@ -445,7 +447,7 @@
#
# PCI support
#
- OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf {
+ UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf {
<LibraryClasses>
NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
}
diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf b/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
index 40d12e0f4c..dd138957a0 100644
--- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
+++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
@@ -184,7 +184,7 @@ INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
#
# PCI support
#
-INF OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
+INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111436): https://edk2.groups.io/g/devel/message/111436
Mute This Topic: https://groups.io/mt/102700998/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 24/39] OvmfPkg/RiscVVirt: Remove PciCpuIo2Dxe from RiscVVirt
[not found] <20231117095742.3605778-1-lichao@loongs>
` (22 preceding siblings ...)
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
@ 2023-11-17 10:01 ` Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 25/39] ArmVirtPkg: Move the FdtSerialPortAddressLib to OvmfPkg Chao Li
` (16 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:01 UTC (permalink / raw)
To: devel; +Cc: Sunil V L, Andrei Warkentin
CpuIo2Dxe is already used by RiscVVirt, so remove it.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Andrei Warkentin <andrei.warkentin@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.c | 557 ------------------
.../RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf | 48 --
2 files changed, 605 deletions(-)
delete mode 100644 OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.c
delete mode 100644 OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
diff --git a/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.c b/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.c
deleted file mode 100644
index f3bf07e631..0000000000
--- a/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.c
+++ /dev/null
@@ -1,557 +0,0 @@
-/** @file
- Produces the CPU I/O 2 Protocol.
-
-Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
-Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
-Copyright (c) 2022, Ventana Micro Systems Inc. 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>
-
-#define MAX_IO_PORT_ADDRESS 0xFFFF
-
-//
-// 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.
-
-**/
-STATIC
-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.
-
-**/
-STATIC
-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.
-
-**/
-STATIC
-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.
-
-**/
-STATIC
-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.
-
-**/
-STATIC
-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/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf b/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
deleted file mode 100644
index 4f78cfa406..0000000000
--- a/OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
+++ /dev/null
@@ -1,48 +0,0 @@
-## @file
-# Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
-#
-# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
-# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
-# Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x0001001B
- BASE_NAME = PciCpuIo2Dxe
- FILE_GUID = 9BD3C765-2579-4CF0-9349-D77205565030
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = PciCpuIo2Initialize
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = RISCV64
-#
-
-[Sources]
- PciCpuIo2Dxe.c
-
-[Packages]
- OvmfPkg/OvmfPkg.dec
- MdePkg/MdePkg.dec
-
-[LibraryClasses]
- UefiDriverEntryPoint
- BaseLib
- DebugLib
- IoLib
- PcdLib
- UefiBootServicesTableLib
-
-[Pcd]
- gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
-
-[Protocols]
- gEfiCpuIo2ProtocolGuid ## PRODUCES
-
-[Depex]
- TRUE
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111376): https://edk2.groups.io/g/devel/message/111376
Mute This Topic: https://groups.io/mt/102644790/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 25/39] ArmVirtPkg: Move the FdtSerialPortAddressLib to OvmfPkg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (23 preceding siblings ...)
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 24/39] OvmfPkg/RiscVVirt: Remove PciCpuIo2Dxe from RiscVVirt Chao Li
@ 2023-11-17 10:02 ` Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 26/39] ArmVirtPkg: Move the PcdTerminalTypeGuidBuffer into OvmfPkg Chao Li
` (15 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:02 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Gerd Hoffmann,
Jiewen Yao, Laszlo Ersek
Move the FdtSerialPortAddressLib to Ovmfpkg so that other ARCH can
easily use it.
Build-tested only (with "ArmVirtQemu.dsc").
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
ArmVirtPkg/ArmVirt.dsc.inc | 2 +-
.../Include/Library/FdtSerialPortAddressLib.h | 0
.../Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c | 0
.../Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf | 2 +-
4 files changed, 2 insertions(+), 2 deletions(-)
rename {ArmVirtPkg => OvmfPkg}/Include/Library/FdtSerialPortAddressLib.h (100%)
rename {ArmVirtPkg => OvmfPkg}/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c (100%)
rename {ArmVirtPkg => OvmfPkg}/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf (90%)
diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc
index fe6488ee99..034523b271 100644
--- a/ArmVirtPkg/ArmVirt.dsc.inc
+++ b/ArmVirtPkg/ArmVirt.dsc.inc
@@ -121,7 +121,7 @@
# ARM PL011 UART Driver
PL011UartLib|ArmPlatformPkg/Library/PL011UartLib/PL011UartLib.inf
SerialPortLib|ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.inf
- FdtSerialPortAddressLib|ArmVirtPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
+ FdtSerialPortAddressLib|OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
PeCoffExtraActionLib|ArmPkg/Library/DebugPeCoffExtraActionLib/DebugPeCoffExtraActionLib.inf
#PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
diff --git a/ArmVirtPkg/Include/Library/FdtSerialPortAddressLib.h b/OvmfPkg/Include/Library/FdtSerialPortAddressLib.h
similarity index 100%
rename from ArmVirtPkg/Include/Library/FdtSerialPortAddressLib.h
rename to OvmfPkg/Include/Library/FdtSerialPortAddressLib.h
diff --git a/ArmVirtPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c
similarity index 100%
rename from ArmVirtPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c
rename to OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c
diff --git a/ArmVirtPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
similarity index 90%
rename from ArmVirtPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
rename to OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
index ae6d0d374b..e27742e9fa 100644
--- a/ArmVirtPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
+++ b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
@@ -18,9 +18,9 @@
FdtSerialPortAddressLib.c
[Packages]
- ArmVirtPkg/ArmVirtPkg.dec
EmbeddedPkg/EmbeddedPkg.dec
MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
[LibraryClasses]
BaseLib
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111377): https://edk2.groups.io/g/devel/message/111377
Mute This Topic: https://groups.io/mt/102644793/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 26/39] ArmVirtPkg: Move the PcdTerminalTypeGuidBuffer into OvmfPkg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (24 preceding siblings ...)
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 25/39] ArmVirtPkg: Move the FdtSerialPortAddressLib to OvmfPkg Chao Li
@ 2023-11-17 10:02 ` Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 27/39] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg Chao Li
` (14 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:02 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Gerd Hoffmann,
Jiewen Yao
Move the PcdTerminalTypeGuidBuffer into OvmfPkg so other ARCH can easily
use it.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
ArmVirtPkg/ArmVirtPkg.dec | 7 -------
ArmVirtPkg/ArmVirtQemu.dsc | 2 +-
ArmVirtPkg/ArmVirtQemuKernel.dsc | 2 +-
.../PlatformBootManagerLib/PlatformBootManagerLib.inf | 2 +-
OvmfPkg/OvmfPkg.dec | 7 +++++++
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec
index 2451644844..315db4e8ea 100644
--- a/ArmVirtPkg/ArmVirtPkg.dec
+++ b/ArmVirtPkg/ArmVirtPkg.dec
@@ -42,13 +42,6 @@
gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled|FALSE|BOOLEAN|0x00000004
[PcdsFixedAtBuild, PcdsPatchableInModule]
- #
- # Binary representation of the GUID that determines the terminal type. The
- # size must be exactly 16 bytes. The default value corresponds to
- # EFI_VT_100_GUID.
- #
- gArmVirtTokenSpaceGuid.PcdTerminalTypeGuidBuffer|{0x65, 0x60, 0xA6, 0xDF, 0x19, 0xB4, 0xD3, 0x11, 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D}|VOID*|0x00000007
-
##
# This is the physical address of Rsdp which is the core struct of Acpi.
# Cloud Hypervisor has no other way to pass Rsdp address to the guest except use a PCD.
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 204344ea0b..6b2b4d1086 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -184,7 +184,7 @@
!if $(TTY_TERMINAL) == TRUE
gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|4
# Set terminal type to TtyTerm, the value encoded is EFI_TTY_TERM_GUID
- gArmVirtTokenSpaceGuid.PcdTerminalTypeGuidBuffer|{0x80, 0x6d, 0x91, 0x7d, 0xb1, 0x5b, 0x8c, 0x45, 0xa4, 0x8f, 0xe2, 0x5f, 0xdd, 0x51, 0xef, 0x94}
+ gUefiOvmfPkgTokenSpaceGuid.PcdTerminalTypeGuidBuffer|{0x80, 0x6d, 0x91, 0x7d, 0xb1, 0x5b, 0x8c, 0x45, 0xa4, 0x8f, 0xe2, 0x5f, 0xdd, 0x51, 0xef, 0x94}
!else
gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|1
!endif
diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
index c2938883d8..34fdf5d5a9 100644
--- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
+++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
@@ -149,7 +149,7 @@
!if $(TTY_TERMINAL) == TRUE
gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|4
# Set terminal type to TtyTerm, the value encoded is EFI_TTY_TERM_GUID
- gArmVirtTokenSpaceGuid.PcdTerminalTypeGuidBuffer|{0x80, 0x6d, 0x91, 0x7d, 0xb1, 0x5b, 0x8c, 0x45, 0xa4, 0x8f, 0xe2, 0x5f, 0xdd, 0x51, 0xef, 0x94}
+ gUefiOvmfPkgTokenSpaceGuid.PcdTerminalTypeGuidBuffer|{0x80, 0x6d, 0x91, 0x7d, 0xb1, 0x5b, 0x8c, 0x45, 0xa4, 0x8f, 0xe2, 0x5f, 0xdd, 0x51, 0xef, 0x94}
!else
gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|1
!endif
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
index 997eb1a442..9d3ccd815a 100644
--- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+++ b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -61,7 +61,7 @@
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
[Pcd]
- gArmVirtTokenSpaceGuid.PcdTerminalTypeGuidBuffer
+ gUefiOvmfPkgTokenSpaceGuid.PcdTerminalTypeGuidBuffer
gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
[Guids]
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 89091e8bf1..f9a40bad7c 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -496,6 +496,13 @@
#
gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeAllocationPadding|256|UINT32|0x6f
+ #
+ # Binary representation of the GUID that determines the terminal type. The
+ # size must be exactly 16 bytes. The default value corresponds to
+ # EFI_VT_100_GUID.
+ #
+ gUefiOvmfPkgTokenSpaceGuid.PcdTerminalTypeGuidBuffer|{0x65, 0x60, 0xA6, 0xDF, 0x19, 0xB4, 0xD3, 0x11, 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D}|VOID*|0x66
+
[PcdsFeatureFlag]
gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation|TRUE|BOOLEAN|0x1c
gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation|FALSE|BOOLEAN|0x1d
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111378): https://edk2.groups.io/g/devel/message/111378
Mute This Topic: https://groups.io/mt/102644794/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 27/39] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg
[not found] <20231117095742.3605778-1-lichao@loongs>
` (25 preceding siblings ...)
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 26/39] ArmVirtPkg: Move the PcdTerminalTypeGuidBuffer into OvmfPkg Chao Li
@ 2023-11-17 10:02 ` Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 28/39] OvmfPkg/LoongArchVirt: Add stable timer driver Chao Li
` (13 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:02 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Gerd Hoffmann,
Jiewen Yao, Lazlo Ersek
Moved the PlatformBootManagerLib to OvmfPkg and renamed to
PlatformBootManagerLibLight for easy use by other ARCH.
Build-tested only (with "ArmVirtQemu.dsc").
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Lazlo Ersek <lersek@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
ArmPkg/ArmPkg.dsc | 1 -
ArmVirtPkg/ArmVirtCloudHv.dsc | 2 +-
ArmVirtPkg/ArmVirtKvmTool.dsc | 2 +-
ArmVirtPkg/ArmVirtQemu.dsc | 2 +-
ArmVirtPkg/ArmVirtQemuKernel.dsc | 2 +-
ArmVirtPkg/ArmVirtXen.dsc | 2 +-
.../Library/PlatformBootManagerLibLight}/PlatformBm.c | 0
.../Library/PlatformBootManagerLibLight}/PlatformBm.h | 0
.../PlatformBootManagerLibLight}/PlatformBootManagerLib.inf | 2 +-
.../Library/PlatformBootManagerLibLight}/QemuKernel.c | 0
10 files changed, 6 insertions(+), 7 deletions(-)
rename {ArmVirtPkg/Library/PlatformBootManagerLib => OvmfPkg/Library/PlatformBootManagerLibLight}/PlatformBm.c (100%)
rename {ArmVirtPkg/Library/PlatformBootManagerLib => OvmfPkg/Library/PlatformBootManagerLibLight}/PlatformBm.h (100%)
rename {ArmVirtPkg/Library/PlatformBootManagerLib => OvmfPkg/Library/PlatformBootManagerLibLight}/PlatformBootManagerLib.inf (93%)
rename {ArmVirtPkg/Library/PlatformBootManagerLib => OvmfPkg/Library/PlatformBootManagerLibLight}/QemuKernel.c (100%)
diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 7af25a91a1..f0667c72f8 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -151,7 +151,6 @@
ArmPkg/Library/ArmSoftFloatLib/ArmSoftFloatLib.inf
ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.inf
ArmPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
- ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
ArmPkg/Library/LinuxBootBootManagerLib/LinuxBootBootManagerLib.inf
ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.inf
diff --git a/ArmVirtPkg/ArmVirtCloudHv.dsc b/ArmVirtPkg/ArmVirtCloudHv.dsc
index 0f80fb34cc..aeed77ffcb 100644
--- a/ArmVirtPkg/ArmVirtCloudHv.dsc
+++ b/ArmVirtPkg/ArmVirtCloudHv.dsc
@@ -43,7 +43,7 @@
TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
- PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
diff --git a/ArmVirtPkg/ArmVirtKvmTool.dsc b/ArmVirtPkg/ArmVirtKvmTool.dsc
index 31d5bc13cf..e2b90e000f 100644
--- a/ArmVirtPkg/ArmVirtKvmTool.dsc
+++ b/ArmVirtPkg/ArmVirtKvmTool.dsc
@@ -56,7 +56,7 @@
# BDS Libraries
UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
- PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 6b2b4d1086..ac980a2736 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -70,7 +70,7 @@
CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
- PlatformBootManagerLib|ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
index 34fdf5d5a9..b8867ea6fe 100644
--- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
+++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
@@ -69,7 +69,7 @@
CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
- PlatformBootManagerLib|ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
diff --git a/ArmVirtPkg/ArmVirtXen.dsc b/ArmVirtPkg/ArmVirtXen.dsc
index 5809832e66..c8cef06d3e 100644
--- a/ArmVirtPkg/ArmVirtXen.dsc
+++ b/ArmVirtPkg/ArmVirtXen.dsc
@@ -50,7 +50,7 @@
CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
- PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c b/OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBm.c
similarity index 100%
rename from ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
rename to OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBm.c
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.h b/OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBm.h
similarity index 100%
rename from ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.h
rename to OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBm.h
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
similarity index 93%
rename from ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
rename to OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
index 9d3ccd815a..3c63e3395c 100644
--- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+++ b/OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
@@ -20,7 +20,7 @@
#
# The following information is for reference only and not required by the build tools.
#
-# VALID_ARCHITECTURES = ARM AARCH64
+# VALID_ARCHITECTURES = ARM AARCH64 LOONGARCH64
#
[Sources]
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c b/OvmfPkg/Library/PlatformBootManagerLibLight/QemuKernel.c
similarity index 100%
rename from ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
rename to OvmfPkg/Library/PlatformBootManagerLibLight/QemuKernel.c
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111379): https://edk2.groups.io/g/devel/message/111379
Mute This Topic: https://groups.io/mt/102644799/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 28/39] OvmfPkg/LoongArchVirt: Add stable timer driver
[not found] <20231117095742.3605778-1-lichao@loongs>
` (26 preceding siblings ...)
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 27/39] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg Chao Li
@ 2023-11-17 10:02 ` Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 29/39] OvmfPkg/LoongArchVirt: Add a NULL library named CollectApResouceLibNull Chao Li
` (12 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:02 UTC (permalink / raw)
To: devel; +Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Baoqi Zhang
Add a CPU timer driver named StableTimerDxe, which proviedes
EFI_TIMER_ARCH_PROTOCOL for LoongArch.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
---
.../Drivers/StableTimerDxe/Timer.c | 381 ++++++++++++++++++
.../Drivers/StableTimerDxe/Timer.h | 127 ++++++
.../Drivers/StableTimerDxe/TimerDxe.inf | 41 ++
3 files changed, 549 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/Timer.c
create mode 100644 OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/Timer.h
create mode 100644 OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/TimerDxe.inf
diff --git a/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/Timer.c b/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/Timer.c
new file mode 100644
index 0000000000..9f0feaa786
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/Timer.c
@@ -0,0 +1,381 @@
+/** @file
+ Timer Architectural Protocol as defined in the DXE CIS
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Protocol/Cpu.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include "Timer.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;
+
+/**
+ 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;
+ CsrWrite (LOONGARCH_CSR_TMCFG, 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.
+ //
+ CsrWrite (LOONGARCH_CSR_TINTCLR, 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 * GetPerformanceCounterProperties (NULL, NULL) / 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
+ */
+ CsrWrite (LOONGARCH_CSR_TMCFG, 0x0);
+}
+
+/**
+ 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
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "===========Stable timer freq %d Hz=============\n",
+ GetPerformanceCounterProperties (NULL, NULL)
+ ));
+
+ //
+ // 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
+ //
+ EnableLocalInterrupts (1 << EXCEPT_LOONGARCH_INT_TIMER);
+
+ //
+ // 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/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/Timer.h b/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/Timer.h
new file mode 100644
index 0000000000..12a59af1ed
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/Timer.h
@@ -0,0 +1,127 @@
+/** @file
+ Private data structures
+
+ Copyright (c) 2023 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
+
+//
+// The current period of the timer interrupt
+//
+volatile UINT64 mTimerPeriod = 0;
+volatile UINT64 mTimerTicks = 0;
+
+/**
+ 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
+ );
+
+#endif // TIMER_H_
diff --git a/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/TimerDxe.inf b/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/TimerDxe.inf
new file mode 100644
index 0000000000..12c78a4088
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/TimerDxe.inf
@@ -0,0 +1,41 @@
+## @file
+# Stable timer driver that provides Timer Arch protocol.
+#
+# Copyright (c) 2023 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.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ BaseLib
+ DebugLib
+ UefiDriverEntryPoint
+ IoLib
+ TimerLib
+
+[Protocols]
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiTimerArchProtocolGuid ## PRODUCES
+
+[depex]
+ gEfiCpuArchProtocolGuid
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111380): https://edk2.groups.io/g/devel/message/111380
Mute This Topic: https://groups.io/mt/102644800/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 29/39] OvmfPkg/LoongArchVirt: Add a NULL library named CollectApResouceLibNull
[not found] <20231117095742.3605778-1-lichao@loongs>
` (27 preceding siblings ...)
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 28/39] OvmfPkg/LoongArchVirt: Add stable timer driver Chao Li
@ 2023-11-17 10:02 ` Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 30/39] OvmfPkg/LoongArchVirt: Add serial port hook library Chao Li
` (11 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:02 UTC (permalink / raw)
To: devel; +Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann
This Library is used to collect APs resources, but is currently NULL
for OvmfPkg, because it is not used by the LoongArch virtual machine.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
.../CollectApResourceLibNull.c | 35 +++++++++++++++++++
.../CollectApResourceLibNull.inf | 32 +++++++++++++++++
.../CollectApResourceLibNull.uni | 9 +++++
3 files changed, 76 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.inf
create mode 100644 OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.uni
diff --git a/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.c b/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.c
new file mode 100644
index 0000000000..528914973e
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.c
@@ -0,0 +1,35 @@
+/** @file
+ LoongArch64 CPU Collect AP resource NULL Library functions.
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include "../../../UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h"
+
+VOID
+SaveProcessorResourceData (
+ IN PROCESSOR_RESOURCE_DATA *
+ );
+
+VOID
+EFIAPI
+SaveProcessorResource (
+ PROCESSOR_RESOURCE_DATA *mProcessorResource
+ )
+{
+ SaveProcessorResourceData (mProcessorResource);
+}
+
+VOID
+EFIAPI
+CollectAllProcessorResource (
+ VOID
+ )
+{
+ return;
+}
diff --git a/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.inf b/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.inf
new file mode 100644
index 0000000000..d8d281421c
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.inf
@@ -0,0 +1,32 @@
+## @file
+# LoongArch64 CPU Collect AP resource NULL Library.
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CollectApResourceLibNull
+ MODULE_UNI_FILE = CollectApResourceLibNull.uni
+ FILE_GUID = 8C3B54BF-6A9F-E8B4-4D57-67B3AB578DD6
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = BaseLib
+
+[Sources.common]
+ CollectApResourceLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ HobLib
+ SynchronizationLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
diff --git a/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.uni b/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.uni
new file mode 100644
index 0000000000..701e2d7e6b
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.uni
@@ -0,0 +1,9 @@
+// @file
+// LoongArch64 CPU Collect AP resource NULL Library.
+//
+// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Collect AP resource NULL Library."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Collect AP resource NULL Library."
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111381): https://edk2.groups.io/g/devel/message/111381
Mute This Topic: https://groups.io/mt/102644802/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 30/39] OvmfPkg/LoongArchVirt: Add serial port hook library
[not found] <20231117095742.3605778-1-lichao@loongs>
` (28 preceding siblings ...)
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 29/39] OvmfPkg/LoongArchVirt: Add a NULL library named CollectApResouceLibNull Chao Li
@ 2023-11-17 10:02 ` Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 31/39] OvmfPkg/LoongArchVirt: Add the early serial port output library Chao Li
` (10 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:02 UTC (permalink / raw)
To: devel; +Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann
Add a serial port hook library in LoongArchVirt named
Fdt16550SerialProtHookLib, this library is referenced from ArmVirtPkg.
LoongArch QEMU virtual machine uses register of LOONGARCH_CSR_KS1 to
transfer serial port base addres from the PEI phase to the DXE phase.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
.../EarlyFdt16550SerialPortHookLib.c | 55 +++++++++++++++++++
.../EarlyFdt16550SerialPortHookLib.inf | 37 +++++++++++++
.../Fdt16550SerialPortHookLib.c | 41 ++++++++++++++
.../Fdt16550SerialPortHookLib.inf | 33 +++++++++++
.../Fdt16550SerialPortHookLib.uni | 13 +++++
5 files changed, 179 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
create mode 100644 OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.inf
create mode 100644 OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.uni
diff --git a/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.c b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.c
new file mode 100644
index 0000000000..b819b42d56
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.c
@@ -0,0 +1,55 @@
+/** @file
+ PEI Phase Early Platform Hook Library instance for 16550 Uart.
+
+ Copyright (c) 2020 - 2023, Arm Ltd. All rights reserved.<BR>
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <libfdt.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PlatformHookLib.h>
+#include <Library/FdtSerialPortAddressLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+/** Platform hook to retrieve the 16550 UART base address from the platform
+ Device tree and store it in the reigster LOONGARCH_CSR_KS1.
+
+ @retval RETURN_SUCCESS Success.
+ @retval RETURN_INVALID_PARAMETER A parameter was invalid.
+ @retval RETURN_NOT_FOUND Serial port information not found.
+
+**/
+RETURN_STATUS
+EFIAPI
+PlatformHookSerialPortInitialize (
+ VOID
+ )
+{
+ RETURN_STATUS Status;
+ VOID *DeviceTreeBase;
+ UINT64 SerialConsoleAddress;
+
+ if (PcdGet64 (PcdSerialRegisterBase) != 0) {
+ return RETURN_SUCCESS;
+ }
+
+ DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
+ if (DeviceTreeBase == NULL) {
+ return RETURN_NOT_FOUND;
+ }
+
+ Status = FdtSerialGetConsolePort (DeviceTreeBase, &SerialConsoleAddress);
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+
+ CsrWrite (LOONGARCH_CSR_KS1, (UINTN)SerialConsoleAddress);
+
+ return RETURN_SUCCESS;
+}
diff --git a/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
new file mode 100644
index 0000000000..9a8819dbeb
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
@@ -0,0 +1,37 @@
+## @file
+# PEI Phase Early Platform Hook Library instance for 16550 Uart.
+#
+# Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = EarlyFdt16550SerialPortHookLib
+ MODULE_UNI_FILE = Fdt16550SerialPortHookLib.uni
+ FILE_GUID = 6A5FEBCB-C676-A7C1-A96C-B79D4860EEC5
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformHookLib|SEC PEI_CORE PEIM
+
+[Sources]
+ EarlyFdt16550SerialPortHookLib.c
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ FdtLib
+ FdtSerialPortAddressLib
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase
diff --git a/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.c b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.c
new file mode 100644
index 0000000000..46e159d7c2
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.c
@@ -0,0 +1,41 @@
+/** @file
+ Platform Hook Library instance for 16550 Uart.
+
+ Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PlatformHookLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+/** Platform hook to retrieve the 16550 UART base address from register
+ LOONGARCH_CSR_KS1 that caches the UART base address from early boot
+ stage and store it in PcdSerialRegisterBase.
+
+ @retval RETURN_SUCCESS Success.
+ @retval RETURN_NOT_FOUND Serial Port information not found.
+
+**/
+RETURN_STATUS
+EFIAPI
+PlatformHookSerialPortInitialize (
+ VOID
+ )
+{
+ UINT64 *UartBase;
+
+ if (PcdGet64 (PcdSerialRegisterBase) != 0) {
+ return RETURN_SUCCESS;
+ }
+
+ *UartBase = CsrRead (LOONGARCH_CSR_KS1);
+
+ return (RETURN_STATUS)PcdSet64S (PcdSerialRegisterBase, (UINTN)*UartBase);
+}
diff --git a/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.inf b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.inf
new file mode 100644
index 0000000000..3db9de4f7e
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.inf
@@ -0,0 +1,33 @@
+## @file
+# Platform Hook Library instance for 16550 Uart.
+#
+# Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = Fdt16550SerialPortHookLib
+ MODULE_UNI_FILE = Fdt16550SerialPortHookLib.uni
+ FILE_GUID = 808335DB-220E-A353-887C-9AA1B7D433A1
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformHookLib|DXE_CORE DXE_DRIVER UEFI_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = PlatformHookSerialPortInitialize
+
+[Sources]
+ Fdt16550SerialPortHookLib.c
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase
diff --git a/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.uni b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.uni
new file mode 100644
index 0000000000..70356534e9
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.uni
@@ -0,0 +1,13 @@
+// /** @file
+// Platform Hook Library instance for 16550 Uart.
+//
+//
+// Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Platform Hook Library instance for 16550 Uart."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Platform Hook Library instance for 16550 Uart."
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111382): https://edk2.groups.io/g/devel/message/111382
Mute This Topic: https://groups.io/mt/102644804/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 31/39] OvmfPkg/LoongArchVirt: Add the early serial port output library
[not found] <20231117095742.3605778-1-lichao@loongs>
` (29 preceding siblings ...)
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 30/39] OvmfPkg/LoongArchVirt: Add serial port hook library Chao Li
@ 2023-11-17 10:03 ` Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 32/39] OvmfPkg/LoongArchVirt: Add real time clock library Chao Li
` (9 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:03 UTC (permalink / raw)
To: devel; +Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Xianglai Li
Add a early serial port output library into LoongArchVirt that named
EarlyFdtSerialPortLib16550, this library is referenced from
MdeModulePkg.
This library is used in the PEI phase. Since the serial port address can
not be saved in memory of the LoongArch QEMU virtual machine in the PEI
phase, the serial prot base address will be obtained from the FDT before
each output.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
---
.../EarlyFdtSerialPortLib16550.c | 816 ++++++++++++++++++
.../EarlyFdtSerialPortLib16550.inf | 47 +
2 files changed, 863 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.inf
diff --git a/OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.c b/OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.c
new file mode 100644
index 0000000000..4a4d365cd2
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.c
@@ -0,0 +1,816 @@
+/** @file
+ 16550 UART Serial Port library functions
+
+ Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/FdtSerialPortAddressLib.h>
+#include <Library/BaseLib.h>
+#include <libfdt.h>
+
+//
+// PCI Defintions.
+//
+#define PCI_BRIDGE_32_BIT_IO_SPACE 0x01
+
+//
+// 16550 UART register offsets and bitfields
+//
+#define R_UART_RXBUF 0 // LCR_DLAB = 0
+#define R_UART_TXBUF 0 // LCR_DLAB = 0
+#define R_UART_BAUD_LOW 0 // LCR_DLAB = 1
+#define R_UART_BAUD_HIGH 1 // LCR_DLAB = 1
+#define R_UART_IER 1 // LCR_DLAB = 0
+#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
+
+/**
+ Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
+ MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
+ parameter Offset is added to the base address of the 16550 registers that is specified
+ by PcdSerialRegisterBase. PcdSerialRegisterAccessWidth specifies the MMIO space access
+ width and defaults to 8 bit access, and supports 8 or 32 bit access.
+
+ @param Base The base address register of UART device.
+ @param Offset The offset of the 16550 register to read.
+
+ @return The value read from the 16550 register.
+**/
+UINT8
+SerialPortReadRegister (
+ UINTN Base,
+ UINTN Offset
+ )
+{
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ if (PcdGet8 (PcdSerialRegisterAccessWidth) == 32) {
+ return (UINT8)MmioRead32 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
+ }
+
+ return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
+ } else {
+ return IoRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
+ }
+}
+
+/**
+ Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to
+ MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The
+ parameter Offset is added to the base address of the 16550 registers that is specified
+ by PcdSerialRegisterBase. PcdSerialRegisterAccessWidth specifies the MMIO space access
+ width and defaults to 8 bit access, and supports 8 or 32 bit access.
+
+ @param Base The base address register of UART device.
+ @param Offset The offset of the 16550 register to write.
+ @param Value The value to write to the 16550 register specified by Offset.
+
+ @return The value written to the 16550 register.
+**/
+UINT8
+SerialPortWriteRegister (
+ UINTN Base,
+ UINTN Offset,
+ UINT8 Value
+ )
+{
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ if (PcdGet8 (PcdSerialRegisterAccessWidth) == 32) {
+ return (UINT8)MmioWrite32 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), (UINT8)Value);
+ }
+
+ return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
+ } else {
+ return IoWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
+ }
+}
+
+/**
+ Retrieve the I/O or MMIO base address register for the PCI UART device.
+
+ This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
+ Device if they are not already enabled.
+
+ @return The base address register of the UART device.
+**/
+UINTN
+GetSerialRegisterBase (
+ VOID
+ )
+{
+ VOID *Base;
+ RETURN_STATUS Status;
+ UINT64 SerialConsoleAddress;
+
+ Base = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
+ Status = FdtSerialGetConsolePort (Base, &SerialConsoleAddress);
+ if (RETURN_ERROR (Status)) {
+ return (UINTN)0;
+ }
+
+ return SerialConsoleAddress;
+}
+
+/**
+ Return whether the hardware flow control signal allows writing.
+
+ @param SerialRegisterBase The base address register of UART device.
+
+ @retval TRUE The serial port is writable.
+ @retval FALSE The serial port is not writable.
+**/
+BOOLEAN
+SerialPortWritable (
+ UINTN SerialRegisterBase
+ )
+{
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ if (PcdGetBool (PcdSerialDetectCable)) {
+ //
+ // Wait for both DSR and CTS to be set
+ // DSR is set if a cable is connected.
+ // CTS is set if it is ok to transmit data
+ //
+ // DSR CTS Description Action
+ // === === ======================================== ========
+ // 0 0 No cable connected. Wait
+ // 0 1 No cable connected. Wait
+ // 1 0 Cable connected, but not clear to send. Wait
+ // 1 1 Cable connected, and clear to send. Transmit
+ //
+ return (BOOLEAN)((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));
+ } else {
+ //
+ // Wait for both DSR and CTS to be set OR for DSR to be clear.
+ // DSR is set if a cable is connected.
+ // CTS is set if it is ok to transmit data
+ //
+ // DSR CTS Description Action
+ // === === ======================================== ========
+ // 0 0 No cable connected. Transmit
+ // 0 1 No cable connected. Transmit
+ // 1 0 Cable connected, but not clear to send. Wait
+ // 1 1 Cable connected, and clar to send. Transmit
+ //
+ return (BOOLEAN)((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Initialize the serial device hardware.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+ If the serial device was successfully 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 serial device could not be initialized.
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+ VOID
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT32 Divisor;
+ UINT32 CurrentDivisor;
+ BOOLEAN Initialized;
+
+ //
+ // Calculate divisor for baud generator
+ // Ref_Clk_Rate / Baud_Rate / 16
+ //
+ Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);
+ if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {
+ Divisor++;
+ }
+
+ //
+ // Get the base address of the serial port in either I/O or MMIO space
+ //
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase == 0) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ //
+ // See if the serial port is already initialized
+ //
+ Initialized = TRUE;
+ if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {
+ Initialized = FALSE;
+ }
+
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));
+ CurrentDivisor = SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;
+ CurrentDivisor |= (UINT32)SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));
+ if (CurrentDivisor != Divisor) {
+ Initialized = FALSE;
+ }
+
+ if (Initialized) {
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // Wait for the serial port to be ready.
+ // Verify that both the transmit FIFO and the shift register are empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
+ }
+
+ //
+ // Configure baud rate
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8)(Divisor >> 8));
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8)(Divisor & 0xff));
+
+ //
+ // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
+ // Strip reserved bits from PcdSerialLineControl
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));
+
+ //
+ // Enable and reset FIFOs
+ // Strip reserved bits from PcdSerialFifoControl
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
+
+ //
+ // Set FIFO Polled Mode by clearing IER after setting FCR
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_IER, 0x00);
+
+ //
+ // Put Modem Control Register(MCR) into its reset state of 0x00.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, 0x00);
+
+ 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 write operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ UINTN SerialRegisterBase;
+ UINTN Result;
+ UINTN Index;
+ UINTN FifoSize;
+
+ if (Buffer == NULL) {
+ return 0;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase == 0) {
+ return 0;
+ }
+
+ if (NumberOfBytes == 0) {
+ //
+ // Flush the hardware
+ //
+
+ //
+ // Wait for both the transmit FIFO and shift register empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
+ }
+
+ //
+ // Wait for the hardware flow control signal
+ //
+ while (!SerialPortWritable (SerialRegisterBase)) {
+ }
+
+ return 0;
+ }
+
+ //
+ // Compute the maximum size of the Tx FIFO
+ //
+ FifoSize = 1;
+ if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {
+ if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {
+ FifoSize = 16;
+ } else {
+ FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);
+ }
+ }
+
+ Result = NumberOfBytes;
+ while (NumberOfBytes != 0) {
+ //
+ // Wait for the serial port to be ready, to make sure both the transmit FIFO
+ // and shift register empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
+ }
+
+ //
+ // Fill then entire Tx FIFO
+ //
+ for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {
+ //
+ // Wait for the hardware flow control signal
+ //
+ while (!SerialPortWritable (SerialRegisterBase)) {
+ }
+
+ //
+ // Write byte to the transmit buffer.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);
+ }
+ }
+
+ return Result;
+}
+
+/**
+ 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
+SerialPortRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ UINTN SerialRegisterBase;
+ UINTN Result;
+ UINT8 Mcr;
+
+ if (NULL == Buffer) {
+ return 0;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase == 0) {
+ return 0;
+ }
+
+ Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS);
+
+ for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {
+ //
+ // Wait for the serial port to have some data.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Set RTS to let the peer send some data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));
+ }
+ }
+
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Clear RTS to prevent peer from sending data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
+ }
+
+ //
+ // Read byte from the receive buffer.
+ //
+ *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);
+ }
+
+ return Result;
+}
+
+/**
+ 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
+ )
+{
+ UINTN SerialRegisterBase;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase == 0) {
+ return FALSE;
+ }
+
+ //
+ // Read the serial port status
+ //
+ if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Clear RTS to prevent peer from sending data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));
+ }
+
+ return TRUE;
+ }
+
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Set RTS to let the peer send some data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));
+ }
+
+ return FALSE;
+}
+
+/**
+ 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
+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;
+ UINT32 SerialBaudRate;
+ UINTN Divisor;
+ UINT8 Lcr;
+ UINT8 LcrData;
+ UINT8 LcrParity;
+ UINT8 LcrStop;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase == 0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Check for default settings and fill in actual values.
+ //
+ if (*BaudRate == 0) {
+ *BaudRate = PcdGet32 (PcdSerialBaudRate);
+ }
+
+ SerialBaudRate = (UINT32)*BaudRate;
+
+ 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;
+ }
+ }
+
+ //
+ // Calculate divisor for baud generator
+ // Ref_Clk_Rate / Baud_Rate / 16
+ //
+ Divisor = PcdGet32 (PcdSerialClockRate) / (SerialBaudRate * 16);
+ if ((PcdGet32 (PcdSerialClockRate) % (SerialBaudRate * 16)) >= SerialBaudRate * 8) {
+ Divisor++;
+ }
+
+ //
+ // Configure baud rate
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8)(Divisor >> 8));
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8)(Divisor & 0xff));
+
+ //
+ // 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;
+}
diff --git a/OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.inf b/OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.inf
new file mode 100644
index 0000000000..f69db586eb
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.inf
@@ -0,0 +1,47 @@
+## @file
+# SerialPortLib instance for 16550 UART.
+#
+# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EarlySerialPortLib16550
+ FILE_GUID = f4fb883d-8138-4f29-bb0c-c574e9312c74
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = SerialPortLib
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ IoLib
+ PcdLib
+ FdtLib
+ FdtSerialPortAddressLib
+
+[Sources]
+ EarlyFdtSerialPortLib16550.c
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterAccessWidth ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride ## CONSUMES
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress ## CONSUMES
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111383): https://edk2.groups.io/g/devel/message/111383
Mute This Topic: https://groups.io/mt/102644805/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 32/39] OvmfPkg/LoongArchVirt: Add real time clock library
[not found] <20231117095742.3605778-1-lichao@loongs>
` (30 preceding siblings ...)
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 31/39] OvmfPkg/LoongArchVirt: Add the early serial port output library Chao Li
@ 2023-11-17 10:03 ` Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 33/39] OvmfPkg/LoongArchVirt: Add NorFlashQemuLib Chao Li
` (8 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:03 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Baoqi Zhang, Xianglai Li
This library is provides real time clock for LoongArch virtual machine.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
---
.../DxeLsRealTimeClockLib.c | 333 ++++++++++++++++++
.../DxeLsRealTimeClockLib.inf | 42 +++
.../LsRealTimeClockLib/LsRealTimeClock.h | 47 +++
.../PeiLsRealTimeClockLib.c | 31 ++
.../PeiLsRealTimeClockLib.inf | 29 ++
5 files changed, 482 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.inf
create mode 100644 OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/LsRealTimeClock.h
create mode 100644 OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.inf
diff --git a/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.c b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.c
new file mode 100644
index 0000000000..d634d30fd1
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.c
@@ -0,0 +1,333 @@
+/** @file
+ Implement EFI RealTimeClock runtime services via RTC Lib.
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/GlobalVariable.h>
+
+#include <Include/Base.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.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/UefiRuntimeLib.h>
+
+#include "LsRealTimeClock.h"
+
+STATIC BOOLEAN mInitialized = FALSE;
+STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;
+STATIC UINTN mRtcBase;
+
+/*
+ Enable Real-time clock.
+
+ @param VOID
+
+ @retval VOID
+ */
+VOID
+InitRtc (
+ VOID
+ )
+{
+ UINTN Val;
+ EFI_HOB_GUID_TYPE *GuidHob = NULL;
+ VOID *DataInHob = NULL;
+
+ if (!mInitialized) {
+ /* Enable rtc */
+ GuidHob = GetFirstGuidHob (&mRtcRegisterBaseAddressGuid);
+ if (GuidHob) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ mRtcBase = (UINT64)(*(UINTN *)DataInHob);
+ Val = MmioRead32 (mRtcBase + RTC_CTRL_REG);
+ Val |= TOY_ENABLE_BIT | OSC_ENABLE_BIT;
+ MmioWrite32 (mRtcBase + RTC_CTRL_REG, Val);
+ mInitialized = TRUE;
+ } else {
+ DebugPrint (EFI_D_INFO, "RTC register address not found!\n");
+ ASSERT (FALSE);
+ }
+ }
+}
+
+/**
+ 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;
+ }
+
+ 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
+
+ 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
+VirtualNotifyEvent (
+ 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;
+
+ InitRtc ();
+ 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;
+ }
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mRtcVirtualAddrChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.inf b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.inf
new file mode 100644
index 0000000000..3b8a21b25c
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.inf
@@ -0,0 +1,42 @@
+## @file
+# LoongArch64 CPU Real Time Clock DXE Phase Library.
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LsRealTimeClockLib
+ FILE_GUID = 9793a3da-1869-4fdf-88b1-c6484341f50b
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RealTimeClockLib
+
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources.common]
+ DxeLsRealTimeClockLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[LibraryClasses]
+ IoLib
+ UefiLib
+ DebugLib
+ PcdLib
+ HobLib
+ DxeServicesTableLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+
+[Depex]
+ TRUE
diff --git a/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/LsRealTimeClock.h b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/LsRealTimeClock.h
new file mode 100644
index 0000000000..fc8663da56
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/LsRealTimeClock.h
@@ -0,0 +1,47 @@
+/** @file
+ Implement EFI RealTimeClock runtime services via RTC Lib.
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ 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
+
+#define RTC_REGISTER_ADDRESS_HOB_GUID \
+ { \
+ 0x0d7c012b, 0x79c1, 0xfa58, { 0x6f, 0x91, 0xbe, 0x3e, 0xee, 0x46, 0x5f, 0x71 } \
+ }
+
+EFI_GUID mRtcRegisterBaseAddressGuid = RTC_REGISTER_ADDRESS_HOB_GUID;
+
+#endif // LS_REAL_TIME_CLOCK_H_
diff --git a/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.c b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.c
new file mode 100644
index 0000000000..d6f71f66ad
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.c
@@ -0,0 +1,31 @@
+/** @file
+ Implement EFI RealTimeClock PEI phase RTC Lib.
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/HobLib.h>
+
+#include "LsRealTimeClock.h"
+
+VOID
+SaveRtcRegisterAddressHob (
+ UINT64 RtcRegisterBase
+ )
+{
+ UINT64 Data64;
+
+ //
+ // Build location of RTC register base address buffer in HOB
+ //
+ Data64 = (UINT64)(UINTN)RtcRegisterBase;
+
+ BuildGuidDataHob (
+ &mRtcRegisterBaseAddressGuid,
+ (VOID *)&Data64,
+ sizeof (UINT64)
+ );
+}
diff --git a/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.inf b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.inf
new file mode 100644
index 0000000000..8b78040331
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.inf
@@ -0,0 +1,29 @@
+## @file
+# LoongArch64 CPU Real Time Clock PEI Phase Library.
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiLsRealTimeClockLib
+ FILE_GUID = d4358430-15ec-9358-1b12-26dab955e9c6
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RealTimeClockLib|PEIM
+
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources.common]
+ PeiLsRealTimeClockLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ HobLib
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111384): https://edk2.groups.io/g/devel/message/111384
Mute This Topic: https://groups.io/mt/102644806/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 33/39] OvmfPkg/LoongArchVirt: Add NorFlashQemuLib
[not found] <20231117095742.3605778-1-lichao@loongs>
` (31 preceding siblings ...)
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 32/39] OvmfPkg/LoongArchVirt: Add real time clock library Chao Li
@ 2023-11-17 10:03 ` Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 34/39] OvmfPkg/LoongArchVirt: Add FdtQemuFwCfgLib Chao Li
` (7 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:03 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Xianglai Li, Bibo Mao
Add NorFlashQemuLib for LoongArch, it is referenced from ArmVirtPkg.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
.../Library/NorFlashQemuLib/NorFlashQemuLib.c | 140 ++++++++++++++++++
.../NorFlashQemuLib/NorFlashQemuLib.inf | 43 ++++++
2 files changed, 183 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.inf
diff --git a/OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.c b/OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.c
new file mode 100644
index 0000000000..578735a7c6
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.c
@@ -0,0 +1,140 @@
+/** @file
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/VirtNorFlashPlatformLib.h>
+
+#include <Protocol/FdtClient.h>
+
+#define QEMU_NOR_BLOCK_SIZE SIZE_128KB
+
+EFI_STATUS
+VirtNorFlashPlatformInitialization (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
+
+STATIC VIRT_NOR_FLASH_DESCRIPTION mNorFlashDevices;
+
+EFI_STATUS
+VirtNorFlashPlatformGetDevices (
+ OUT VIRT_NOR_FLASH_DESCRIPTION **NorFlashDescriptions,
+ OUT UINT32 *Count
+ )
+{
+ FDT_CLIENT_PROTOCOL *FdtClient;
+ INT32 Node;
+ EFI_STATUS Status;
+ EFI_STATUS FindNodeStatus;
+ CONST UINT32 *Reg;
+ UINT32 PropSize;
+ UINT64 Base;
+ UINT64 Size;
+
+ Status = gBS->LocateProtocol (
+ &gFdtClientProtocolGuid,
+ NULL,
+ (VOID **)&FdtClient
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FindNodeStatus = FdtClient->FindCompatibleNode (
+ FdtClient,
+ "cfi-flash",
+ &Node
+ );
+ ASSERT_EFI_ERROR (FindNodeStatus);
+
+ Status = FdtClient->GetNodeProperty (
+ FdtClient,
+ Node,
+ "reg",
+ (CONST VOID **)&Reg,
+ &PropSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: GetNodeProperty () failed (Status == %r)\n",
+ __FUNCTION__,
+ Status
+ ));
+ return Status;
+ }
+
+ ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
+
+ if (PropSize < (4 * sizeof (UINT32))) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: reg node size(%d) is too small \n",
+ __FUNCTION__,
+ PropSize
+ ));
+ return EFI_NOT_FOUND;
+ }
+
+ Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
+ Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
+
+ mNorFlashDevices.DeviceBaseAddress = (UINTN)Base;
+ mNorFlashDevices.RegionBaseAddress = (UINTN)Base;
+ mNorFlashDevices.Size = (UINTN)Size;
+ mNorFlashDevices.BlockSize = QEMU_NOR_BLOCK_SIZE;
+
+ Status = PcdSet32S (PcdFlashNvStorageVariableBase, Base);
+ ASSERT_EFI_ERROR (Status);
+
+ /*
+ * Base is the value of PcdFlashNvStorageVariableBase,
+ * PcdFlashNvStorageFtwWorkingBase can be got by
+ * PcdFlashNvStorageVariableBase + PcdFlashNvStorageVariableSize
+ */
+ Base += PcdGet32 (PcdFlashNvStorageVariableSize);
+ Status = PcdSet32S (PcdFlashNvStorageFtwWorkingBase, Base);
+ ASSERT_EFI_ERROR (Status);
+
+ /*
+ * Now,Base is the value of PcdFlashNvStorageFtwWorkingBase,
+ * PcdFlashNvStorageFtwSpareBase can be got by
+ * PcdFlashNvStorageFtwWorkingBase + PcdFlashNvStorageFtwWorkingSize.
+ */
+ Base += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
+ Status = PcdSet32S (PcdFlashNvStorageFtwSpareBase, Base);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // UEFI takes ownership of the NOR flash, and exposes its functionality
+ // through the UEFI Runtime Services GetVariable, SetVariable, etc. This
+ // means we need to disable it in the device tree to prevent the OS from
+ // attaching its device driver as well.
+ // Note that this also hides other flash banks, but the only other flash
+ // bank we expect to encounter is the one that carries the UEFI executable
+ // code, which is not intended to be guest updatable, and is usually backed
+ // in a readonly manner by QEMU anyway.
+ //
+ Status = FdtClient->SetNodeProperty (
+ FdtClient,
+ Node,
+ "status",
+ "disabled",
+ sizeof ("disabled")
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Failed to set NOR flash status to 'disabled'\n"));
+ }
+
+ *NorFlashDescriptions = &mNorFlashDevices;
+ *Count = 1;
+
+ return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.inf b/OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.inf
new file mode 100644
index 0000000000..0d3d34e686
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.inf
@@ -0,0 +1,43 @@
+## @file
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = NorFlashQemuLib
+ FILE_GUID = E225C90F-6CB9-8AF3-095B-2668FC633A57
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VirtNorFlashPlatformLib
+
+[Sources.common]
+ NorFlashQemuLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ OvmfPkg/OvmfPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gFdtClientProtocolGuid ## CONSUMES
+
+[Depex]
+ gFdtClientProtocolGuid
+
+[Pcd]
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111385): https://edk2.groups.io/g/devel/message/111385
Mute This Topic: https://groups.io/mt/102644810/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 34/39] OvmfPkg/LoongArchVirt: Add FdtQemuFwCfgLib
[not found] <20231117095742.3605778-1-lichao@loongs>
` (32 preceding siblings ...)
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 33/39] OvmfPkg/LoongArchVirt: Add NorFlashQemuLib Chao Li
@ 2023-11-17 10:03 ` Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 35/39] OvmfPkg/LoongArchVirt: Add reset system library Chao Li
` (6 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:03 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Xianglai Li, Bibo Mao
This library for PEI phase, and obtains the QemuFwCfg base address by
directly parsing the FDT, reads and writes the data in QemuFwCfg by
operating on the QemuFwCfg base address.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
.../FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.c | 505 ++++++++++++++++++
.../FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.inf | 42 ++
.../FdtQemuFwCfgLib/QemuFwCfgLibInternal.h | 73 +++
.../Library/FdtQemuFwCfgLib/QemuFwCfgPei.c | 117 ++++
4 files changed, 737 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.inf
create mode 100644 OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/QemuFwCfgLibInternal.h
create mode 100644 OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/QemuFwCfgPei.c
diff --git a/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.c b/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.c
new file mode 100644
index 0000000000..4009a76a80
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.c
@@ -0,0 +1,505 @@
+/** @file
+
+ Copyright (c) 2023 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 <Base.h>
+#include <PiPei.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 <Uefi/UefiBaseType.h>
+#include <Library/HobLib.h>
+#include <libfdt.h>
+#include "QemuFwCfgLibInternal.h"
+
+EFI_GUID mFwCfgSelectorAddressGuid = FW_CONFIG_SELECTOR_ADDRESS_HOB_GUID;
+EFI_GUID mFwCfgDataAddressGuid = FW_CONFIG_DATA_ADDRESS_HOB_GUID;
+
+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;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+
+ FwCfgSelectorAddress = mFwCfgSelectorAddress;
+ GuidHob = NULL;
+ DataInHob = NULL;
+
+ if (FwCfgSelectorAddress == 0) {
+ GuidHob = GetFirstGuidHob (&mFwCfgSelectorAddressGuid);
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ FwCfgSelectorAddress = (UINT64)(*(UINTN *)DataInHob);
+ }
+
+ return FwCfgSelectorAddress;
+}
+
+/**
+ To get firmware configure Data address.
+
+ @param VOID
+
+ @retval firmware configure data address
+**/
+UINTN
+EFIAPI
+QemuGetFwCfgDataAddress (
+ VOID
+ )
+{
+ UINTN FwCfgDataAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+
+ FwCfgDataAddress = mFwCfgDataAddress;
+ GuidHob = NULL;
+ DataInHob = NULL;
+
+ if (FwCfgDataAddress == 0) {
+ GuidHob = GetFirstGuidHob (&mFwCfgDataAddressGuid);
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ FwCfgDataAddress = (UINT64)(*(UINTN *)DataInHob);
+ }
+
+ 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
+FdtQemuFwCfgInitialize (
+ VOID
+ )
+{
+ VOID *DeviceTreeBase;
+ INT32 Node;
+ INT32 Prev;
+ CONST CHAR8 *Type;
+ INT32 Len;
+ CONST UINT64 *RegProp;
+ UINT64 FwCfgSelectorAddress;
+ UINT64 FwCfgDataAddress;
+ UINT64 FwCfgDataSize;
+
+ DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
+ 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;
+
+ BuildGuidDataHob (
+ &mFwCfgSelectorAddressGuid,
+ (VOID *)&FwCfgSelectorAddress,
+ sizeof (UINT64)
+ );
+
+ BuildGuidDataHob (
+ &mFwCfgDataAddressGuid,
+ (VOID *)&FwCfgDataAddress,
+ sizeof (UINT64)
+ );
+ break;
+ } else {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to parse FDT QemuCfg node\n",
+ __FUNCTION__
+ ));
+ break;
+ }
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
diff --git a/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.inf b/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.inf
new file mode 100644
index 0000000000..4c9d4bcd81
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.inf
@@ -0,0 +1,42 @@
+## @file
+# initialized fw_cfg library.
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FdtQemuFwCfgPeiLib
+ FILE_GUID = cdf9a9d5-7422-4dcb-b41d-607151ad320b
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FtdQemuFwCfgLib|PEIM
+ CONSTRUCTOR = FdtQemuFwCfgInitialize
+
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources]
+ FdtQemuFwCfgPeiLib.c
+ QemuFwCfgPei.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ HobLib
+ DebugLib
+ IoLib
+ MemoryAllocationLib
+ FdtLib
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
diff --git a/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/QemuFwCfgLibInternal.h b/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/QemuFwCfgLibInternal.h
new file mode 100644
index 0000000000..17866cb9d5
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/QemuFwCfgLibInternal.h
@@ -0,0 +1,73 @@
+/** @file
+ fw_cfg library implementation.
+
+ Copyright (c) 2023 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_
+
+#define FW_CONFIG_SELECTOR_ADDRESS_HOB_GUID \
+ { \
+ 0x3cc47b04, 0x0d3e, 0xaa64, { 0x06, 0xa6, 0x4b, 0xdc, 0x9a, 0x2c, 0x61, 0x19 } \
+ }
+
+#define FW_CONFIG_DATA_ADDRESS_HOB_GUID \
+ { \
+ 0xef854788, 0x10f3, 0x8e7a, { 0x3e, 0xd0, 0x4d, 0x16, 0xc1, 0x79, 0x55, 0x2f } \
+ }
+
+/**
+ 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/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/QemuFwCfgPei.c b/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/QemuFwCfgPei.c
new file mode 100644
index 0000000000..07dc3d1c23
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/QemuFwCfgPei.c
@@ -0,0 +1,117 @@
+/** @file
+ fw_cfg library implementation.
+
+ Copyright (c) 2023 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 ();
+}
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111386): https://edk2.groups.io/g/devel/message/111386
Mute This Topic: https://groups.io/mt/102644811/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 35/39] OvmfPkg/LoongArchVirt: Add reset system library
[not found] <20231117095742.3605778-1-lichao@loongs>
` (33 preceding siblings ...)
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 34/39] OvmfPkg/LoongArchVirt: Add FdtQemuFwCfgLib Chao Li
@ 2023-11-17 10:03 ` Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 36/39] OvmfPkg/LoongArchVirt: Support SEC phase Chao Li
` (5 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:03 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Xianglai Li, Bibo Mao
This library provides interface related to restart and shudown the
LoongArch64 virtual machine.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
.../BaseResetSystemAcpiGed.c | 148 ++++++++++
.../BaseResetSystemAcpiGedLib.inf | 37 +++
.../DxeResetSystemAcpiGed.c | 259 ++++++++++++++++++
.../DxeResetSystemAcpiGedLib.inf | 41 +++
.../ResetSystemAcpiLib/ResetSystemAcpiGed.c | 128 +++++++++
.../ResetSystemAcpiLib/ResetSystemAcpiGed.h | 23 ++
6 files changed, 636 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
create mode 100644 OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
create mode 100644 OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c
create mode 100644 OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h
diff --git a/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c
new file mode 100644
index 0000000000..adb66f365a
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGed.c
@@ -0,0 +1,148 @@
+/** @file
+ Base ResetSystem library implementation.
+
+ Copyright (c) 2023 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/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
new file mode 100644
index 0000000000..7027a688ee
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
@@ -0,0 +1,37 @@
+## @file
+# Base library instance for ResetSystem library class for LoongArch
+#
+# Copyright (c) 2023 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 = BA521997-9016-32B5-65DF-EA5F560A3837
+ 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/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c
new file mode 100644
index 0000000000..3fbb4046b5
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGed.c
@@ -0,0 +1,259 @@
+/** @file
+ Dxe ResetSystem library implementation.
+
+ Copyright (c) 2023 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/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
new file mode 100644
index 0000000000..e54ae5e0b8
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
@@ -0,0 +1,41 @@
+## @file
+# DXE library instance for ResetSystem library class for LoongArch.
+#
+# Copyright (c) 2023 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 = F05197D5-5827-AA61-FB2D-BC69259F17A9
+ 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/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c
new file mode 100644
index 0000000000..d9283cecd5
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.c
@@ -0,0 +1,128 @@
+/** @file
+ ResetSystem library implementation.
+
+ Copyright (c) 2023 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/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h
new file mode 100644
index 0000000000..23c722a0f1
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/ResetSystemAcpiGed.h
@@ -0,0 +1,23 @@
+/** @file
+ ResetSystem lib head file.
+
+ Copyright (c) 2023 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.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111387): https://edk2.groups.io/g/devel/message/111387
Mute This Topic: https://groups.io/mt/102644814/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 36/39] OvmfPkg/LoongArchVirt: Support SEC phase
[not found] <20231117095742.3605778-1-lichao@loongs>
` (34 preceding siblings ...)
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 35/39] OvmfPkg/LoongArchVirt: Add reset system library Chao Li
@ 2023-11-17 10:03 ` Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 37/39] OvmfPkg/LoongArchVirt: Support PEI phase Chao Li
` (4 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:03 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Xianglai Li, Bibo Mao
Add SEC code for LoongArch virtual machine.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S | 176 ++++++
OvmfPkg/LoongArchVirt/Sec/SecMain.c | 507 ++++++++++++++++++
OvmfPkg/LoongArchVirt/Sec/SecMain.inf | 53 ++
3 files changed, 736 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
create mode 100644 OvmfPkg/LoongArchVirt/Sec/SecMain.c
create mode 100644 OvmfPkg/LoongArchVirt/Sec/SecMain.inf
diff --git a/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S b/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
new file mode 100644
index 0000000000..21cc9f3388
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Sec/LoongArch64/Start.S
@@ -0,0 +1,176 @@
+#------------------------------------------------------------------------------
+#
+# Start for Loongson LoongArch processor
+#
+# Copyright (c) 2023 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/BaseMemoryLib.h>
+#include <Register/LoongArch64/Csr.h>
+#include <Protocol/DebugSupport.h>
+
+#define BOOTCORE_ID 0
+
+ASM_GLOBAL ASM_PFX(_ModuleEntryPoint)
+ASM_PFX(_ModuleEntryPoint):
+ /* Disable interrupt */
+ li.d $t0, (1 << 2)
+ csrxchg $zero, $t0, LOONGARCH_CSR_CRMD
+
+ /* Read physical cpu number id */
+ bl GetApicId
+ li.d $t0, BOOTCORE_ID //0
+ bne $a0, $t0, SlaveMain
+
+ /* Configure BSP reset ebase */
+ li.d $a0, FixedPcdGet64(PcdCpuExceptionVectorBaseAddress)
+ bl SetExceptionBaseAddress
+ move $t1, $a0
+
+ /* Set BSP stack */
+ li.d $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + FixedPcdGet32(PcdOvmfSecPeiTempRamSize) # stack base
+ move $sp, $t0
+ addi.d $sp, $sp, -0x8
+
+ /* Construct SEC and PEI step exception environment */
+ la.pcrel $a1, ExceptionEntryStart
+ la.pcrel $t0, ExceptionEntryEnd
+ sub.d $a2, $t0, $a1
+ li.w $t0, (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512
+ bgeu $a2, $t0, DeadLoop
+ move $a0, $t1
+ bl CopyMem
+
+CallEntry:
+ /* Call C function make sure parameter true */
+ li.d $a0, FixedPcdGet64(PcdOvmfFdBaseAddress) # FW base
+ addi.d $a1, $sp, 0x8
+ bl SecCoreStartupWithStack
+# End of _ModuleEntryPoint
+
+ASM_PFX(ClearMailBox):
+ /* Clear mailbox */
+ li.d $t1, LOONGARCH_IOCSR_MBUF3
+ iocsrwr.d $zero, $t1
+ li.d $t1, LOONGARCH_IOCSR_MBUF2
+ iocsrwr.d $zero, $t1
+ li.d $t1, LOONGARCH_IOCSR_MBUF1
+ iocsrwr.d $zero, $t1
+ li.d $t1, LOONGARCH_IOCSR_MBUF0
+ iocsrwr.d $zero, $t1
+ jirl $zero, $ra, 0
+# End of ClearMailBox
+
+ASM_PFX(EnableIPI):
+ /* Enable IPI interrupt */
+ li.d $t1, (1 << 12)
+ csrxchg $t1, $t1, LOONGARCH_CSR_ECFG
+
+ addi.d $t2, $zero, -1
+ li.d $t1, LOONGARCH_IOCSR_IPI_EN
+ iocsrwr.w $t2, $t1
+ jirl $zero, $ra, 0
+# End of EeableIPI
+
+#/**
+# Get APIC ID for every CPU.
+#
+# @param NULL
+# @return APICID
+#
+# UINTN
+# EFI_API
+# GetApicId (
+# VOID
+# )
+#**/
+ASM_PFX(GetApicId):
+ csrrd $a0, LOONGARCH_CSR_CPUNUM
+ andi $a0, $a0, 0x3ff
+ jirl $zero, $ra, 0
+# End of GetApicId
+
+ASM_PFX(ApInitStack):
+ li.d $t1, SIZE_1KB
+ csrrd $t0, LOONGARCH_CSR_TMID
+ mul.d $t1, $t0, $t1
+ li.d $t2, FixedPcdGet32(PcdCpuMaxLogicalProcessorNumber)
+ bgeu $t0, $t2, DeadLoop
+ li.d $t0, FixedPcdGet64(PcdOvmfSecPeiTempRamBase) + FixedPcdGet32(PcdOvmfSecPeiTempRamSize) - SIZE_64KB
+ sub.d $sp, $t0, $t1
+ addi.d $sp, $sp, -0x8
+ jirl $zero, $ra, 0
+# End of ApInitStack
+
+ASM_PFX(SlaveMain):
+ /* Set AP exception handle in flash */
+ la.pcrel $a0, ApException
+ bl SetExceptionBaseAddress
+
+ /* Clean up local mail box and open INT */
+ bl ClearMailBox
+ bl EnableIPI
+ bl EnableInterrupts
+
+WaitForWake:
+ /* Wait for wakeup */
+ bl CpuSleep
+ li.d $t1, LOONGARCH_IOCSR_MBUF0
+ iocsrrd.w $t2, $t1
+ beqz $t2, WaitForWake
+
+ /* Disable global interrupt */
+ bl DisableInterrupts
+
+ /* 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, LOONGARCH_IOCSR_MBUF0
+ iocsrrd.d $t0, $t1
+ li.d $t1, LOONGARCH_IOCSR_MBUF3
+ iocsrrd.d $a1, $t1
+ bl ClearMailBox
+ beqz $a1, NoParameterCall
+
+ //
+ // If the parameters are not NULL, then calling happened in FW ENV.
+ // Set the EBASE to be the same as BSP.
+ //
+ li.d $a0, FixedPcdGet64(PcdCpuExceptionVectorBaseAddress)
+ bl SetExceptionBaseAddress
+
+ bl ApInitStack
+ bl GetApicId
+NoParameterCall:
+ move $ra, $t0
+ jirl $zero, $ra, 0x0
+# End of SlaveMain
+
+.align 12
+ASM_PFX(ApException):
+ csrrd $t0, LOONGARCH_CSR_ESTAT
+ srli.d $t0, $t0, 12
+ beqz $t0, DeadLoop
+
+ li.d $t0, LOONGARCH_IOCSR_IPI_STATUS
+ iocsrrd.w $t1, $t0
+ li.d $t0, LOONGARCH_IOCSR_IPI_CLEAR
+ iocsrwr.w $t1, $t0
+ ertn
+# End of ApException
+
+ASM_PFX(DeadLoop):
+ b DeadLoop
+# End of DeadLoop
+.end
diff --git a/OvmfPkg/LoongArchVirt/Sec/SecMain.c b/OvmfPkg/LoongArchVirt/Sec/SecMain.c
new file mode 100644
index 0000000000..417b95407c
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Sec/SecMain.c
@@ -0,0 +1,507 @@
+/** @file
+ Main SEC phase code. Transitions to PEI.
+
+ Copyright (c) 2023 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)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase)),
+ (UINTN)(FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
+ ));
+
+ // |-------------| <-- TopOfCurrentStack
+ // | BSP Stack | 32k
+ // |-------------|
+ // | BSP Heap | 32k
+ // |-------------| <-- SecCoreData.TemporaryRamBase
+ // | Ap Stack | 384k
+ // |-------------|
+ // | Exception | 64k
+ // |-------------| <-- PcdOvmfSecPeiTempRamBase
+
+ ASSERT (
+ (UINTN)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) +
+ FixedPcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
+ (UINTN)TopOfCurrentStack
+ );
+
+ //
+ // Initialize SEC hand-off state
+ //
+ SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
+
+ SecCoreData.TemporaryRamSize = (UINTN)SIZE_64KB;
+ SecCoreData.TemporaryRamBase = (VOID *)(FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) - SecCoreData.TemporaryRamSize);
+
+ 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/OvmfPkg/LoongArchVirt/Sec/SecMain.inf b/OvmfPkg/LoongArchVirt/Sec/SecMain.inf
new file mode 100644
index 0000000000..d528aae02b
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Sec/SecMain.inf
@@ -0,0 +1,53 @@
+## @file
+# SEC Driver
+#
+# Copyright (c) 2023 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]
+ OvmfPkg/OvmfPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ PcdLib
+ DebugAgentLib
+ IoLib
+ PeCoffLib
+ PeCoffGetEntryPointLib
+ PeCoffExtraActionLib
+ CpuExceptionHandlerLib
+
+[Ppis]
+ gEfiTemporaryRamSupportPpiGuid # PPI ALWAYS_PRODUCED
+
+[FixedPcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111388): https://edk2.groups.io/g/devel/message/111388
Mute This Topic: https://groups.io/mt/102644817/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 37/39] OvmfPkg/LoongArchVirt: Support PEI phase
[not found] <20231117095742.3605778-1-lichao@loongs>
` (35 preceding siblings ...)
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 36/39] OvmfPkg/LoongArchVirt: Support SEC phase Chao Li
@ 2023-11-17 10:03 ` Chao Li
2023-11-17 10:04 ` [edk2-devel] [PATCH v3 38/39] OvmfPkg/LoongArchVirt: Add build file Chao Li
` (3 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:03 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Xianglai Li, Bibo Mao
Platfrom PEI module for LoongArch platfrom initialization.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
OvmfPkg/LoongArchVirt/PlatformPei/Fv.c | 40 ++
OvmfPkg/LoongArchVirt/PlatformPei/MemDetect.c | 201 +++++++++
OvmfPkg/LoongArchVirt/PlatformPei/Platform.c | 393 ++++++++++++++++++
OvmfPkg/LoongArchVirt/PlatformPei/Platform.h | 127 ++++++
.../LoongArchVirt/PlatformPei/PlatformPei.inf | 72 ++++
5 files changed, 833 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/PlatformPei/Fv.c
create mode 100644 OvmfPkg/LoongArchVirt/PlatformPei/MemDetect.c
create mode 100644 OvmfPkg/LoongArchVirt/PlatformPei/Platform.c
create mode 100644 OvmfPkg/LoongArchVirt/PlatformPei/Platform.h
create mode 100644 OvmfPkg/LoongArchVirt/PlatformPei/PlatformPei.inf
diff --git a/OvmfPkg/LoongArchVirt/PlatformPei/Fv.c b/OvmfPkg/LoongArchVirt/PlatformPei/Fv.c
new file mode 100644
index 0000000000..eb9e29d580
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/PlatformPei/Fv.c
@@ -0,0 +1,40 @@
+/** @file
+ Build FV related hobs for platform.
+
+ Copyright (c) 2023 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 (
+ FixedPcdGet64 (PcdOvmfSecPeiTempRamBase),
+ FixedPcdGet32 (PcdOvmfSecPeiTempRamSize),
+ EfiBootServicesData
+ );
+
+ return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/LoongArchVirt/PlatformPei/MemDetect.c b/OvmfPkg/LoongArchVirt/PlatformPei/MemDetect.c
new file mode 100644
index 0000000000..347a070423
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/PlatformPei/MemDetect.c
@@ -0,0 +1,201 @@
+/** @file
+ Memory Detection for Virtual Machines.
+
+ Copyright (c) 2023 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 <Register/LoongArch64/Csr.h>
+#include "Platform.h"
+
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)
+#define LOONGARCH_FW_RAM_TOP BASE_256MB
+
+/**
+ 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 = FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize);
+ RamTop = LOONGARCH_FW_RAM_TOP;
+ 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;
+ MEMMAP_ENTRY MemoryMapEntry;
+ MEMMAP_ENTRY *StartEntry;
+ 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);
+ }
+
+ //
+ // When 0 address protection is enabled,
+ // 0-4k memory needs to be preallocated to prevent UEFI applications from allocating use,
+ // such as grub
+ //
+ if (PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) {
+ BuildMemoryAllocationHob (
+ 0,
+ EFI_PAGE_SIZE,
+ EfiBootServicesData
+ );
+ }
+}
+
+/**
+ Gets the Virtual Memory Map of corresponding platforms
+
+ This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
+ on corresponding platforms.
+
+ @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
+EFIAPI
+GetMemoryMapPolicy (
+ OUT MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
+ )
+{
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ MEMMAP_ENTRY MemoryMapEntry;
+ MEMMAP_ENTRY *StartEntry;
+ 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
+ );
+
+ //
+ // Add the 0x10000000-0x20000000. In the virtual machine, this area use for CPU UART, flash, PIC etc.
+ //
+ 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;
+}
diff --git a/OvmfPkg/LoongArchVirt/PlatformPei/Platform.c b/OvmfPkg/LoongArchVirt/PlatformPei/Platform.c
new file mode 100644
index 0000000000..81242f50d3
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/PlatformPei/Platform.c
@@ -0,0 +1,393 @@
+/** @file
+ Platform PEI driver
+
+ Copyright (c) 2023 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/BaseLib.h>
+#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 <Library/MpInitLib.h>
+#include <Library/PlatformHookLib.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Guid/FdtHob.h>
+#include <libfdt.h>
+#include <Ppi/MasterBootMode.h>
+#include <Register/LoongArch64/Cpucfg.h>
+#include <Register/LoongArch64/Csr.h>
+
+#include "Platform.h"
+
+VOID
+SaveRtcRegisterAddressHob (
+ UINT64 RtcRegisterBase
+ );
+
+/* 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
+};
+
+STATIC EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
+
+/**
+ 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)
+ );
+}
+
+/** Get the Rtc base address from the DT.
+
+ This function fetches the node referenced in the "loongson,ls7a-rtc"
+ property of the "reg" node and returns the base address of
+ the RTC.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [out] RtcBaseAddress If success, contains the base address
+ of the Rtc.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND RTC info not found in DT.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetRtcAddress (
+ IN CONST VOID *Fdt,
+ OUT UINT64 *RtcBaseAddress
+ )
+{
+ INT32 Node;
+ INT32 Prev;
+ CONST CHAR8 *Type;
+ INT32 Len;
+ CONST UINT64 *RegProp;
+ EFI_STATUS Status;
+
+ if ((Fdt == NULL) || (fdt_check_header (Fdt) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_NOT_FOUND;
+ for (Prev = 0; ; Prev = Node) {
+ Node = fdt_next_node (Fdt, Prev, NULL);
+ if (Node < 0) {
+ break;
+ }
+
+ //
+ // Check for memory node
+ //
+ Type = fdt_getprop (Fdt, Node, "compatible", &Len);
+ if ((Type) && (AsciiStrnCmp (Type, "loongson,ls7a-rtc", 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 (Fdt, Node, "reg", &Len);
+ if ((RegProp != 0) && (Len == (2 * sizeof (UINT64)))) {
+ *RtcBaseAddress = SwapBytes64 (RegProp[0]);
+ Status = RETURN_SUCCESS;
+ DEBUG ((DEBUG_INFO, "%a Len %d RtcBase %llx\n", __func__, Len, *RtcBaseAddress));
+ break;
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT rtc node\n", __FUNCTION__));
+ break;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Misc Initialization.
+
+ @param VOID
+
+ @return VOID
+**/
+VOID
+MiscInitialization (
+ VOID
+ )
+{
+ CPUCFG_REG1_INFO_DATA CpucfgReg1Data;
+ UINT8 CpuPhysMemAddressWidth;
+
+ DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
+
+ //
+ // Get the the CPU physical memory address width.
+ //
+ AsmCpucfg (CPUCFG_REG1_INFO, &CpucfgReg1Data.Uint32);
+
+ CpuPhysMemAddressWidth = (UINT8)(CpucfgReg1Data.Bits.PALEN + 1);
+
+ //
+ // Creat CPU HOBs.
+ //
+ BuildCpuHob (CpuPhysMemAddressWidth, FixedPcdGet8 (PcdPrePiCpuIoSize));
+}
+
+/**
+ add fdt hand off block.
+
+ @param VOID
+
+ @return VOID
+**/
+VOID
+AddFdtHob (
+ VOID
+ )
+{
+ VOID *Base;
+ VOID *NewBase;
+ UINTN FdtSize;
+ UINTN FdtPages;
+ UINT64 *FdtHobData;
+ UINT64 RtcBaseAddress;
+ RETURN_STATUS Status;
+
+ Base = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
+ ASSERT (Base != NULL);
+
+ Status = GetRtcAddress (Base, &RtcBaseAddress);
+ if (RETURN_ERROR (Status)) {
+ return;
+ }
+
+ SaveRtcRegisterAddressHob (RtcBaseAddress);
+
+ FdtSize = fdt_totalsize (Base) + PcdGet32 (PcdDeviceTreeAllocationPadding);
+ 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
+ReportSystemMemorySize (
+ VOID
+ )
+{
+ UINT64 RamSize;
+
+ QemuFwCfgSelectItem (QemuFwCfgItemRamSize);
+ RamSize = QemuFwCfgRead64 ();
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: QEMU reports %dM system memory\n",
+ __FUNCTION__,
+ RamSize/1024/1024
+ ));
+
+ //
+ // Assert false if QEMU report system memory size is less then 256M.
+ //
+ if (RamSize <= SIZE_256MB) {
+ ASSERT (FALSE);
+ }
+}
+
+/**
+ 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;
+ UINTN TranslationTableSize;
+ MEMORY_REGION_DESCRIPTOR *MemoryTable;
+
+ DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
+
+ Status = PeiServicesSetBootMode (mBootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeiServicesInstallPpi (&mPpiListBootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ ReportSystemMemorySize ();
+
+ PublishPeiMemory ();
+
+ PeiFvInitialization ();
+ InitializeRamRegions ();
+ MemMapInitialization ();
+
+ Status = PlatformHookSerialPortInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Collect numbers of on line processors and all of APs APIC ID
+ // TODO: Current, the NULL library is used, this library will be populated in the future.
+ //
+ CollectAllProcessorResource ();
+
+ MiscInitialization ();
+
+ AddFdtHob ();
+
+ GetMemoryMapPolicy (&MemoryTable);
+ Status = ConfigureMemoryManagementUint (
+ MemoryTable,
+ NULL,
+ &TranslationTableSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Open MMU.
+ //
+ DEBUG ((DEBUG_INFO, "Open MMU start.\n"));
+ CsrXChg (LOONGARCH_CSR_CRMD, BIT4, BIT4|BIT3);
+ DEBUG ((DEBUG_INFO, "Open MMU done.\n"));
+
+ MpInitLibInitialize ();
+
+ return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/LoongArchVirt/PlatformPei/Platform.h b/OvmfPkg/LoongArchVirt/PlatformPei/Platform.h
new file mode 100644
index 0000000000..5a23322ad6
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/PlatformPei/Platform.h
@@ -0,0 +1,127 @@
+/** @file
+ Platform PEI module include file.
+
+ Copyright (c) 2023 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>
+#include <IndustryStandard/E820.h>
+#include <Library/CpuMmuLib.h>
+
+typedef struct {
+ UINT64 BaseAddr;
+ UINT64 Length;
+ UINT32 Type;
+ UINT32 Reserved;
+} MEMMAP_ENTRY;
+
+VOID
+EFIAPI
+CollectAllProcessorResource (
+ VOID
+ );
+
+VOID
+EFIAPI
+SaveProcessorResource (
+ VOID
+ );
+
+/**
+ 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
+ );
+
+/**
+ Gets the Virtual Memory Map of corresponding platforms
+
+ This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
+ on corresponding platforms.
+
+ @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
+EFIAPI
+GetMemoryMapPolicy (
+ OUT MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
+ );
+
+#endif // PLATFORM_H_
diff --git a/OvmfPkg/LoongArchVirt/PlatformPei/PlatformPei.inf b/OvmfPkg/LoongArchVirt/PlatformPei/PlatformPei.inf
new file mode 100644
index 0000000000..a9775bab1f
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/PlatformPei/PlatformPei.inf
@@ -0,0 +1,72 @@
+## @file
+# Platform PEI driver
+#
+# Copyright (c) 2023 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
+ UefiCpuPkg/UefiCpuPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Ppis]
+ gEfiPeiMasterBootModePpiGuid
+
+[Guids]
+ gEfiMemoryTypeInformationGuid
+ gFdtHobGuid
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ HobLib
+ IoLib
+ PeiResourcePublicationLib
+ PeiServicesLib
+ PeiServicesTablePointerLib
+ PeimEntryPoint
+ QemuFwCfgLib
+ PcdLib
+ TimerLib
+ CpuMmuLib
+ MpInitLib
+ MemoryAllocationLib
+ RealTimeClockLib
+ CollectApResourceLib
+ PlatformHookLib
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeAllocationPadding
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
+
+[FixedPcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
+
+[Depex]
+ TRUE
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111389): https://edk2.groups.io/g/devel/message/111389
Mute This Topic: https://groups.io/mt/102644819/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 38/39] OvmfPkg/LoongArchVirt: Add build file
[not found] <20231117095742.3605778-1-lichao@loongs>
` (36 preceding siblings ...)
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 37/39] OvmfPkg/LoongArchVirt: Support PEI phase Chao Li
@ 2023-11-17 10:04 ` Chao Li
2023-11-17 10:04 ` [edk2-devel] [PATCH v3 39/39] OvmfPkg/LoongArchVirt: Add self introduction file Chao Li
` (2 subsequent siblings)
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:04 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann,
Xianglai Li, Bibo Mao
Add infrastructure files to build edk2 for LoongArch QEMU virtual
machine.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Xianglai Li <lixianglai@loongson.cn>
Co-authored-by: Bibo Mao <maobibo@loongson.cn>
---
OvmfPkg/LoongArchVirt/LoongArchVirt.fdf.inc | 34 +
OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc | 679 ++++++++++++++++++++
OvmfPkg/LoongArchVirt/LoongArchVirtQemu.fdf | 313 +++++++++
OvmfPkg/LoongArchVirt/VarStore.fdf.inc | 67 ++
4 files changed, 1093 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/LoongArchVirt.fdf.inc
create mode 100644 OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc
create mode 100644 OvmfPkg/LoongArchVirt/LoongArchVirtQemu.fdf
create mode 100644 OvmfPkg/LoongArchVirt/VarStore.fdf.inc
diff --git a/OvmfPkg/LoongArchVirt/LoongArchVirt.fdf.inc b/OvmfPkg/LoongArchVirt/LoongArchVirt.fdf.inc
new file mode 100644
index 0000000000..47bd1e0a05
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/LoongArchVirt.fdf.inc
@@ -0,0 +1,34 @@
+## @file
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+DEFINE BLOCK_SIZE = 0x1000
+
+############################################################################
+# FW total
+DEFINE FW_BASE_ADDRESS = 0x1c000000
+DEFINE FW_BLOCKS = 0x400
+DEFINE FW_SIZE = 0x400000
+
+############################################################################
+#Flash code layout
+#Set Sec size in flash
+DEFINE SECFV_SIZE = 0x00010000
+
+#Set Pei size in flash
+DEFINE PEIFV_SIZE = 0x00040000
+
+#Set Dxe size in flash
+DEFINE DXEFV_SIZE = 0x00350000
+
+#Set FVMAIN size
+DEFINE FVMAIN_SIZE = $(SECFV_SIZE) + $(PEIFV_SIZE) +$(DXEFV_SIZE)
+
+#Set Memory layout
+DEFINE SEC_PEI_TEMP_RAM_BASE = 0x10000
+DEFINE SEC_PEI_TEMP_RAM_SIZE = 0x80000
+DEFINE DEVICE_TREE_RAM_BASE = 0x100000
diff --git a/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc b/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc
new file mode 100644
index 0000000000..c4524f33f7
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc
@@ -0,0 +1,679 @@
+## @file
+#
+# Copyright (c) 2023 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 = LoongArchVirtQemu
+ PLATFORMPKG_NAME = LoongArchVirtQemu
+ 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 = OvmfPkg/LoongArchVirt/LoongArchVirtQemu.fdf
+ TTY_TERMINAL = FALSE
+
+!include LoongArchVirt.fdf.inc
+
+ #
+ # 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.
+# -D FLAG=VALUE
+############################################################################
+[BuildOptions]
+ GCC:RELEASE_*_*_CC_FLAGS = -DSPEEDUP
+
+ #
+ # Disable deprecated APIs.
+ #
+ GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+
+!include NetworkPkg/NetworkBuildOptions.dsc.inc
+
+[BuildOptions.LOONGARCH64.EDKII.SEC]
+ *_*_*_CC_FLAGS =
+
+#
+# Default page size is 16K for loongarch qemu tcg
+# code section separated with data section with 16K page alignment, else data
+# write operation in the same page with code section will cause qemu TB flush.
+#
+[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=0x4000
+
+[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.
+#
+################################################################################
+
+!include MdePkg/MdeLibs.dsc.inc
+
+[LibraryClasses.common]
+ PcdLib | MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ TimerLib | UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.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
+
+ # For stack protector support
+ NULL | MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+
+ 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
+ FdtSerialPortAddressLib | OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf
+ PlatformHookLib | OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/Fdt16550SerialPortHookLib.inf
+ SerialPortLib | MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
+ EfiResetSystemLib | OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/BaseResetSystemAcpiGedLib.inf
+ ResetSystemLib | OvmfPkg/LoongArchVirt/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
+ PciSegmentLib | MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+ PciHostBridgeLib | OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
+ PciHostBridgeUtilityLib | OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.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
+
+ TpmPlatformHierarchyLib | SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf
+ PlatformBmPrintScLib | OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
+ PlatformBootManagerLib | OvmfPkg/Library/PlatformBootManagerLibLight/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
+ VirtNorFlashPlatformLib | OvmfPkg/LoongArchVirt/Library/NorFlashQemuLib/NorFlashQemuLib.inf
+ CollectApResourceLib | OvmfPkg/LoongArchVirt/Library/CollectApResouceLibNull/CollectApResourceLibNull.inf
+
+[LibraryClasses.common.SEC]
+ PcdLib | MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ ReportStatusCodeLib | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+ HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ MemoryAllocationLib | MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+ PeiServicesTablePointerLib | MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
+ PlatformHookLib | OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
+ SerialPortLib | OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.inf
+ CpuExceptionHandlerLib | UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+
+[LibraryClasses.common.PEI_CORE]
+ PcdLib | MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+ HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ PeiServicesTablePointerLib | MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.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 | OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.inf
+ PlatformHookLib | OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
+ SerialPortLib | OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.inf
+
+[LibraryClasses.common.PEIM]
+ HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ PeiServicesTablePointerLib | MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.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 | OvmfPkg/LoongArchVirt/Library/FdtQemuFwCfgLib/FdtQemuFwCfgPeiLib.inf
+ CpuMmuLib | UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
+ MpInitLib | UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf
+ PlatformHookLib | OvmfPkg/LoongArchVirt/Library/Fdt16550SerialPortHookLib/EarlyFdt16550SerialPortHookLib.inf
+ SerialPortLib | OvmfPkg/LoongArchVirt/Library/EarlyFdtSerialPortLib16550/EarlyFdtSerialPortLib16550.inf
+ RealTimeClockLib | OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/PeiLsRealTimeClockLib.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
+ PciExpressLib | MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf
+ PciPcdProducerLib | OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+ CpuExceptionHandlerLib | UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.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 | OvmfPkg/LoongArchVirt/Library/LsRealTimeClockLib/DxeLsRealTimeClockLib.inf
+ VariablePolicyLib | MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
+ QemuFwCfgLib | OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.inf
+ EfiResetSystemLib | OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
+ ResetSystemLib | OvmfPkg/LoongArchVirt/Library/ResetSystemAcpiLib/DxeResetSystemAcpiGedLib.inf
+ PciExpressLib | MdePkg/Library/BasePciExpressLib/BasePciExpressLib.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
+ PciPcdProducerLib | OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.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/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+ ExtractGuidedSectionLib | MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+ QemuFwCfgS3Lib | OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+ QemuFwCfgLib | OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.inf
+ PciPcdProducerLib | OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+ PciExpressLib | MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf
+ AcpiPlatformLib | OvmfPkg/Library/AcpiPlatformLib/DxeAcpiPlatformLib.inf
+ MpInitLib | UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.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
+ PciPcdProducerLib | OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+ PciExpressLib | MdePkg/Library/BasePciExpressLib/BasePciExpressLib.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
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled | TRUE
+[PcdsFixedAtBuild]
+## BaseLib ##
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength | 1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength | 1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength | 1000000
+ gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout | 10000000
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress | $(FW_BASE_ADDRESS)
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize | 1
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange | FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler | 0x10
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize | 0x2000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize | 0x8000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress | 0x0
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask | 0x07
+
+ # Use MMIO for accessing Serial port registers.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio | TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo | {0xFF}
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate | 115200
+
+ # 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
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel | 0x8000004F
+
+ # DEBUG_ASSERT_ENABLED 0x01
+ # DEBUG_PRINT_ENABLED 0x02
+ # DEBUG_CODE_ENABLED 0x04
+ # CLEAR_MEMORY_ENABLED 0x08
+ # ASSERT_BREAKPOINT_ENABLED 0x10
+ # ASSERT_DEADLOOP_ENABLED 0x20
+!if $(TARGET) == RELEASE
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask | 0x21
+!else
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask | 0x2f
+!endif
+
+#######################################################################################
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase | $(SEC_PEI_TEMP_RAM_BASE)
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize | $(SEC_PEI_TEMP_RAM_SIZE)
+ gUefiOvmfPkgTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress | $(DEVICE_TREE_RAM_BASE)
+
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress | gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+
+ #
+ # minimal memory for uefi bios should be 512M
+ # 0x00000000 - 0x10000000
+ # 0x90000000 - 0xA0000000
+ #
+ 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
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize | 0x40000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize | 0x40000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize | 0x40000
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask | 1
+
+################################################################################
+#
+# 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.PcdFlashNvStorageVariableBase | 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
+
+ ## 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
+
+[PcdsPatchableInModule.common]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x0
+
+[Components]
+
+ #
+ # SEC Phase modules
+ #
+ OvmfPkg/LoongArchVirt/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
+ }
+
+ OvmfPkg/LoongArchVirt/PlatformPei/PlatformPei.inf {
+ <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
+ UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.inf {
+ <LibraryClasses>
+ CpuMmuLib | UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
+ }
+ MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+ MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+ MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+ OvmfPkg/LoongArchVirt/Drivers/StableTimerDxe/TimerDxe.inf
+ MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+ MdeModulePkg/Universal/Metronome/Metronome.inf
+ EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+
+ #
+ # Variable
+ #
+ OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+ NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ }
+
+ #
+ # Platform Driver
+ #
+ OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
+ OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
+ OvmfPkg/VirtioRngDxe/VirtioRng.inf
+
+ #
+ # FAT filesystem + GPT/MBR partitioning + UDF filesystem + virtio-fs
+ #
+ 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
+ #
+ MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
+ MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+ MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+ #
+ # NVME Driver
+ #
+ MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
+
+ #
+ # SMBIOS Support
+ #
+ MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf {
+ <LibraryClasses>
+ NULL | OvmfPkg/Library/SmbiosVersionLib/DetectSmbiosVersionLib.inf
+ }
+ OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
+
+ #
+ # PCI
+ #
+ UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf {
+ <LibraryClasses>
+ NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+ NULL|OvmfPkg/Library/BaseCachingPciExpressLib/BaseCachingPciExpressLib.inf
+ }
+ EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf
+ MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
+ <LibraryClasses>
+ NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+ NULL|OvmfPkg/Library/BaseCachingPciExpressLib/BaseCachingPciExpressLib.inf
+ }
+ MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf {
+ <LibraryClasses>
+ NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+ NULL|OvmfPkg/Library/BaseCachingPciExpressLib/BaseCachingPciExpressLib.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/QemuVideoDxe/QemuVideoDxe.inf
+ 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 {
+ <LibraryClasses>
+ NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.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/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.fdf b/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.fdf
new file mode 100644
index 0000000000..b6a0da3142
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.fdf
@@ -0,0 +1,313 @@
+## @file
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+#####################################################################################################
+[Defines]
+!include LoongArchVirt.fdf.inc
+
+#####################################################################################################
+[FD.QEMU_EFI]
+BaseAddress = $(FW_BASE_ADDRESS)
+Size = $(FW_SIZE)
+ErasePolarity = 1
+BlockSize = $(BLOCK_SIZE)
+NumBlocks = $(FW_BLOCKS)
+
+0x0|$(FVMAIN_SIZE)
+FV = FVMAIN_COMPACT
+
+!include VarStore.fdf.inc
+
+#####################################################################################################
+[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 UefiCpuPkg/CpuDxeLoongArch64/CpuDxe.inf
+INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+INF OvmfPkg/LoongArchVirt/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/VirtNorFlashDxe/VirtNorFlashDxe.inf
+INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+#
+# PCI
+#
+INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.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/QemuVideoDxe/QemuVideoDxe.inf
+INF OvmfPkg/QemuRamfbDxe/QemuRamfbDxe.inf
+INF OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
+INF OvmfPkg/PlatformDxe/Platform.inf
+
+#
+# SATA/SCSI
+#
+INF MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf
+INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+#
+# NVME
+#
+INF MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.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
+
+#
+#
+# PEI Phase priori modules
+#
+APRIORI PEI {
+ INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+}
+
+#
+# SEC Phase modules
+#
+INF OvmfPkg/LoongArchVirt/Sec/SecMain.inf
+
+#
+# PEI Phase modules
+#
+INF MdeModulePkg/Core/Pei/PeiMain.inf
+INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+INF OvmfPkg/LoongArchVirt/PlatformPei/PlatformPei.inf
+INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+
+#
+# DXE Phase modules
+#
+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) {
+ 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
+ }
+
+#####################################################################################################
+[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/OvmfPkg/LoongArchVirt/VarStore.fdf.inc b/OvmfPkg/LoongArchVirt/VarStore.fdf.inc
new file mode 100644
index 0000000000..83ce3d8008
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/VarStore.fdf.inc
@@ -0,0 +1,67 @@
+## @file
+#
+# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[FD.QEMU_VARS]
+BaseAddress = 0x0
+Size = 0x1000000
+ErasePolarity = 1
+BlockSize = 0x20000
+NumBlocks = 128
+
+0x00000000|0x00040000
+#NV_VARIABLE_STORE
+DATA = {
+ ## This is the EFI_FIRMWARE_VOLUME_HEADER
+ # ZeroVector []
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ # FileSystemGuid: gEfiSystemNvDataFvGuid =
+ # { 0xFFF12B8D, 0x7696, 0x4C8B,
+ # { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
+ 0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
+ 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
+ # FvLength: 0xC0000
+ 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
+ # Signature "_FVH" # Attributes
+ 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
+ # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
+ 0x48, 0x00, 0x28, 0x09, 0x00, 0x00, 0x00, 0x02,
+ # Blockmap[0]: 0x3 Blocks * 0x40000 Bytes / Block
+ 0x3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ # Blockmap[1]: End
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ## This is the VARIABLE_STORE_HEADER
+ # It is compatible with SECURE_BOOT_ENABLE == FALSE as well.
+ # Signature: gEfiAuthenticatedVariableGuid =
+ # { 0xaaf32c78, 0x947b, 0x439a,
+ # { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
+ 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
+ 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
+ # Size: 0x40000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
+ # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x3ffb8
+ # This can speed up the Variable Dispatch a bit.
+ 0xB8, 0xFF, 0x03, 0x00,
+ # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
+ 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+0x00040000|0x00040000
+#NV_FTW_WORKING
+DATA = {
+ # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
+ # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
+ 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
+ 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95,
+ # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
+ 0x5b, 0xe7, 0xc6, 0x86, 0xFE, 0xFF, 0xFF, 0xFF,
+ # WriteQueueSize: UINT64
+ 0xE0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+0x00080000|0x00040000
+#NV_FTW_SPARE
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111390): https://edk2.groups.io/g/devel/message/111390
Mute This Topic: https://groups.io/mt/102644822/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [edk2-devel] [PATCH v3 39/39] OvmfPkg/LoongArchVirt: Add self introduction file
[not found] <20231117095742.3605778-1-lichao@loongs>
` (37 preceding siblings ...)
2023-11-17 10:04 ` [edk2-devel] [PATCH v3 38/39] OvmfPkg/LoongArchVirt: Add build file Chao Li
@ 2023-11-17 10:04 ` Chao Li
[not found] ` <179860C0A131BC70.3002@groups.io>
[not found] ` <179860DB0A3E8D83.6542@groups.io>
40 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-17 10:04 UTC (permalink / raw)
To: devel; +Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann
Add self introduction file for LoongArch virtual machine.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
---
OvmfPkg/LoongArchVirt/Readme.md | 67 +++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 OvmfPkg/LoongArchVirt/Readme.md
diff --git a/OvmfPkg/LoongArchVirt/Readme.md b/OvmfPkg/LoongArchVirt/Readme.md
new file mode 100644
index 0000000000..57fc74c296
--- /dev/null
+++ b/OvmfPkg/LoongArchVirt/Readme.md
@@ -0,0 +1,67 @@
+# LoongArch QEMU virt platform
+
+## Overview
+
+ LoongArch QEMU virt is a generic platform that dose not require any actual hardware.
+ The minimum required QEMU version is [8.1](https://gitlab.com/qemu-project/qemu/-/tags), the minimum required GCC version is [GCC13](https://gcc.gnu.org/gcc-13/), the minimum required Binutils version is [2.40](https://ftp.gnu.org/gnu/binutils/).
+
+## Prepare (X86 Linux Environment)
+
+### Fedora39
+Install LoongArch64 cross compiler, LoongArch system QEMU.
+
+ yum install gcc-loongarch64-linux-gnu
+ yum install qemu-system-loongarch64
+
+### Others X86 OS ENV
+#### Configure cross-tools
+
+**Download:**
+
+ wget https://github.com/loongson/build-tools/releases/download/2023.08.08/x86_64-cross-tools-loongarch64-binutils_2.41-gcc_13.2.0.tar.xz
+
+**Configure the cross-tools environment:**
+
+ mkdir /opt/loongarch64_cross-toolchain/
+ tar -vxf x86_64-cross-tools-loongarch64-binutils_2.41-gcc_13.2.0.tar.xz -C /opt/loongarch64_cross-toolchain/
+ export PATH=/opt/loongarch64_cross-toolchain/cross-tools/bin:$PATH
+
+Note: Please obtain [the latest cross-compilation](https://github.com/loongson/build-tools) toolchains.
+
+#### Build QEMU
+
+ git clone https://gitlab.com/qemu-project/qemu.git
+
+Note: Please refer to QEMU compilation rules, located in qemu/doc/system/loongarch/virt.rst.
+
+
+## Build LoongArch QEMU virtual machine firmware
+#### Get edk2 resouces
+
+ git clone --recurse-submodule https://github.com/tianocore/edk2.git
+
+#### Building LoongArch QEMU virt FW with GCC
+
+ export WORKSPACE=`pwd`
+ export GCC5_LOONGARCH64_PREFIX=loongarch64-unknown-linux-gnu-
+ export PACKAGES_PATH=$WORKSPACE/edk2
+ export EDK_TOOLS_PATH=$WORKSPACE/edk2/BaseTools
+ source edk2/edksetup.sh --reconfig
+ make -C edk2/BaseTools
+ source edk2/edksetup.sh BaseTools
+ build -b RELEASE -t GCC5 -a LOONGARCH64 -p OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc
+
+## Test LoongArch QEMU virtual machine firmware
+ qemu-system-loongarch64 \
+ -m 4G \
+ -M virt \
+ -smp 2 \
+ -cpu la464 \
+ -bios Build/LoongArchVirtQemu/RELEASE_GCC5/FV/QEMU_EFI.fd \
+ -serial stdio
+
+## Test LoongArch QEMU virtual machine OS
+
+* Download ArchLinux QCOW [images](https://mirrors.pku.edu.cn/loongarch/archlinux/images) for LoongArch.
+
+* [Running LoongArch ArchLinux on virtual machine](https://mirrors.pku.edu.cn/loongarch/archlinux/images/README.html).
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111391): https://edk2.groups.io/g/devel/message/111391
Mute This Topic: https://groups.io/mt/102644826/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg Chao Li
@ 2023-11-17 11:35 ` Leif Lindholm
2023-11-20 3:07 ` Chao Li
2023-11-21 14:37 ` Laszlo Ersek
1 sibling, 1 reply; 71+ messages in thread
From: Leif Lindholm @ 2023-11-17 11:35 UTC (permalink / raw)
To: Chao Li
Cc: devel, Michael D Kinney, Liming Gao, Zhiguang Liu, Ard Biesheuvel,
Sami Mujawar, Laszlo Ersek, Sunil V L
Not my package, just spotted a typo below:
On Fri, Nov 17, 2023 at 17:59:49 +0800, Chao Li wrote:
> Since some ARCH or platform not require execute code on memory during
> PEI phase, some values may transferred via CPU registers.
>
> Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
> table pointer depend by a CPU register, this library can accommodate lot
> of platforms who not require execte code on memory during PEI phase.
>
> Adding PeiServiceTablePointerLibReg to allows setting and getting the
> PEI service table pointer via CPU registers, and the library can
> accommodate many platforms that do not need to execute code on memory
> during the PEI phase.
>
> The idea of this library is derived from
> ArmPkg/Library/PeiServicesTablePointerLib/
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Signed-off-by: Chao Li <lichao@loongson.cn>
> ---
> .../Library/PeiServicesTablePointerLib.h | 37 +++++++-
> .../PeiServicesTablePointer.c | 86 +++++++++++++++++++
> .../PeiServicesTablePointerLib.uni | 20 +++++
> .../PeiServicesTablePointerLibReg.inf | 40 +++++++++
> MdePkg/MdePkg.dsc | 1 +
> 5 files changed, 180 insertions(+), 4 deletions(-)
> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>
> diff --git a/MdePkg/Include/Library/PeiServicesTablePointerLib.h b/MdePkg/Include/Library/PeiServicesTablePointerLib.h
> index 61635eff00..f5c764cb13 100644
> --- a/MdePkg/Include/Library/PeiServicesTablePointerLib.h
> +++ b/MdePkg/Include/Library/PeiServicesTablePointerLib.h
> @@ -52,10 +52,11 @@ SetPeiServicesTablePointer (
> 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.
> + For Itanium, ARM and LoongArch 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, ARM and
> + LoongArch CPUs.
>
> **/
> VOID
> @@ -64,4 +65,32 @@ MigratePeiServicesTablePointer (
> VOID
> );
>
> +/**
> + Retrieves the cached value of the PEI Services Table pointer from a CPU register.
> +
> + 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.
> +
> + @return The pointer to PeiServices.
> +**/
> +CONST EFI_PEI_SERVICES **
> +EFIAPI
> +GetPeiServicesTablePointerFromRegister (
> + VOID
> + );
> +
> +/**
> + Set the pointer PEI Service Table to a CPU register.
> +
> + Caches the pointer to the PEI Services Table specified by PeiServicesTablePointer
> + in a platform specific manner.
> +
> + @param PeiServicesTablePointer The address of PeiServices.
> +**/
> +VOID
> +EFIAPI
> +SetPeiServicesTablePointerToRegester (
SetPeiServicesTablePointerToRegester ->
SetPeiServicesTablePointerToRegister
Regester -> Register.
/
Leif
> + IN UINTN PeiServicesTablePointer
> + );
> #endif
> diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
> new file mode 100644
> index 0000000000..0227f98871
> --- /dev/null
> +++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
> @@ -0,0 +1,86 @@
> +/** @file
> + PEI Services Table Pointer Library For Reigseter Mechanism.
> +
> + This library is used for PEIM which does executed from flash device directly but
> + executed in memory.
> +
> + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
> + Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
> + Copyright (c) 2023 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>
> +
> +/**
> + 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
> + )
> +{
> + ASSERT (PeiServicesTablePointer != NULL);
> + SetPeiServicesTablePointerToRegester ((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
> + )
> +{
> + CONST EFI_PEI_SERVICES **PeiServices;
> +
> + PeiServices = GetPeiServicesTablePointerFromRegister ();
> + ASSERT (PeiServices != NULL);
> + return PeiServices;
> +}
> +
> +/**
> + 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, ARM and LoongArch 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, ARM and
> + LoongArch CPUs.
> +
> +**/
> +VOID
> +EFIAPI
> +MigratePeiServicesTablePointer (
> + VOID
> + )
> +{
> + return;
> +}
> diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
> new file mode 100644
> index 0000000000..937cf857d9
> --- /dev/null
> +++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// Instance of PEI Services Table Pointer Library using CPU register for the table pointer.
> +//
> +// PEI Services Table Pointer Library implementation that retrieves a pointer to the
> +// PEI Services Table from a CPU register. Applies to modules that execute from
> +// read-only memory.
> +//
> +// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
> +// Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
> +// Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT #language en-US "Instance of PEI Services Table Pointer Library using CPU register for the table pointer"
> +
> +#string STR_MODULE_DESCRIPTION #language en-US "The PEI Services Table Pointer Library implementation that retrieves a pointer to the PEI Services Table from a CPU register. Applies to modules that execute from read-only memory."
> +
> diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
> new file mode 100644
> index 0000000000..22499e22ad
> --- /dev/null
> +++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
> @@ -0,0 +1,40 @@
> +## @file
> +# Instance of PEI Services Table Pointer Library using CPU register for the table pointer.
> +#
> +# PEI Services Table Pointer Library implementation that retrieves a pointer to the
> +# PEI Services Table from a CPU register. Applies to modules that execute from
> +# read-only memory.
> +#
> +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = PeiServicesTablePointerLib
> + MODULE_UNI_FILE = PeiServicesTablePointerLib.uni
> + FILE_GUID = 619950D1-7C5F-EA1B-D6DD-2FF7B0A4A2B7
> + MODULE_TYPE = PEIM
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = PeiServicesTablePointerLib|PEIM PEI_CORE SEC
> +
> +#
> +# VALID_ARCHITECTURES = IA32 X64 AARCH64 RISCV64 LOONGARCH64
> +#
> +
> +[Sources]
> + PeiServicesTablePointer.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> + DebugLib
> +
> +[Pcd]
> +
> diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
> index 3abd1a1e23..2e9a3d4b4c 100644
> --- a/MdePkg/MdePkg.dsc
> +++ b/MdePkg/MdePkg.dsc
> @@ -103,6 +103,7 @@
> MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf
> MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
> MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
> + MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
> MdePkg/Library/PeiSmbusLibSmbus2Ppi/PeiSmbusLibSmbus2Ppi.inf
> MdePkg/Library/PeiPciLibPciCfg2/PeiPciLibPciCfg2.inf
> MdePkg/Library/PeiPciSegmentLibPciCfg2/PeiPciSegmentLibPciCfg2.inf
> --
> 2.27.0
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111393): https://edk2.groups.io/g/devel/message/111393
Mute This Topic: https://groups.io/mt/102644754/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg Chao Li
@ 2023-11-17 13:13 ` Leif Lindholm
2023-11-20 3:24 ` Chao Li
0 siblings, 1 reply; 71+ messages in thread
From: Leif Lindholm @ 2023-11-17 13:13 UTC (permalink / raw)
To: Chao Li; +Cc: devel, Ard Biesheuvel, Sami Mujawar
On Fri, Nov 17, 2023 at 18:01:39 +0800, Chao Li wrote:
> ArmPciCpuIo2Dxe has been merged into CpuIo2Dxe, and CpuIo2Dxe is already
> used by all ARM virtual platforms, so remove it.
This does affect 15 platforms in edk2-platforms.
You should ping the maintainers of the affected platforms, or even
better write a patch yourself, so we don't end up with sudden
mass-breakage.
It might be worth splitting this patch out of the rest of the set in
order to permit a more graceful switchover.
/
Leif
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> ---
> ArmPkg/ArmPkg.dsc | 1 -
> .../Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c | 556 ------------------
> .../ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf | 47 --
> 3 files changed, 604 deletions(-)
> delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
> delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>
> diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
> index 6dd91e6941..7af25a91a1 100644
> --- a/ArmPkg/ArmPkg.dsc
> +++ b/ArmPkg/ArmPkg.dsc
> @@ -143,7 +143,6 @@
>
> ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
>
> - ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
> ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
> ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf
> ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf
> diff --git a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
> deleted file mode 100644
> index 5a2866ccd8..0000000000
> --- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
> +++ /dev/null
> @@ -1,556 +0,0 @@
> -/** @file
> - Produces the CPU I/O 2 Protocol.
> -
> -Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
> -Copyright (c) 2016, Linaro Ltd. 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>
> -
> -#define MAX_IO_PORT_ADDRESS 0xFFFF
> -
> -//
> -// 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.
> -
> -**/
> -STATIC
> -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.
> -
> -**/
> -STATIC
> -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.
> -
> -**/
> -STATIC
> -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.
> -
> -**/
> -STATIC
> -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.
> -
> -**/
> -STATIC
> -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
> -ArmPciCpuIo2Initialize (
> - 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/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
> deleted file mode 100644
> index 9339c2b532..0000000000
> --- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
> +++ /dev/null
> @@ -1,47 +0,0 @@
> -## @file
> -# Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
> -#
> -# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
> -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> -#
> -# SPDX-License-Identifier: BSD-2-Clause-Patent
> -#
> -##
> -
> -[Defines]
> - INF_VERSION = 0x00010005
> - BASE_NAME = ArmPciCpuIo2Dxe
> - FILE_GUID = 168D1A6E-F4A5-448A-9E95-795661BB3067
> - MODULE_TYPE = DXE_DRIVER
> - VERSION_STRING = 1.0
> - ENTRY_POINT = ArmPciCpuIo2Initialize
> -
> -#
> -# The following information is for reference only and not required by the build tools.
> -#
> -# VALID_ARCHITECTURES = ARM AARCH64
> -#
> -
> -[Sources]
> - ArmPciCpuIo2Dxe.c
> -
> -[Packages]
> - ArmPkg/ArmPkg.dec
> - MdePkg/MdePkg.dec
> -
> -[LibraryClasses]
> - UefiDriverEntryPoint
> - BaseLib
> - DebugLib
> - IoLib
> - PcdLib
> - UefiBootServicesTableLib
> -
> -[Pcd]
> - gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
> -
> -[Protocols]
> - gEfiCpuIo2ProtocolGuid ## PRODUCES
> -
> -[Depex]
> - TRUE
> --
> 2.27.0
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111399): https://edk2.groups.io/g/devel/message/111399
Mute This Topic: https://groups.io/mt/102644788/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version CpuIo2Dxe
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
@ 2023-11-17 20:15 ` Andrei Warkentin
2023-11-20 3:04 ` Chao Li
0 siblings, 1 reply; 71+ messages in thread
From: Andrei Warkentin @ 2023-11-17 20:15 UTC (permalink / raw)
To: Chao Li, devel@edk2.groups.io; +Cc: Sunil V L
So are you saying the UefiCpuPkg version of CpuIo2 is equivalent in function to the OvmfPkg one?
> -----Original Message-----
> From: Chao Li <lichao@loongson.cn>
> Sent: Friday, November 17, 2023 4:02 AM
> To: devel@edk2.groups.io
> Cc: Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei
> <andrei.warkentin@intel.com>
> Subject: [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version
> CpuIo2Dxe
>
> Since the UefiCpuPkg/CpuIo2Dxe already supports MMIO, it is enabled at
> this thime.
>
> Build-tested only (with "RiscVVirtQemu.dsc").
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Cc: Andrei Warkentin <andrei.warkentin@intel.com>
> ---
> OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc | 4 +++-
> OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf | 2 +-
> 2 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
> b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
> index 34b2037824..499902e445 100644
> --- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
> +++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
> @@ -143,6 +143,8 @@
>
> gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE
>
> + gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled|TRUE
> +
> [PcdsFixedAtBuild.common]
> gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
> gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
> @@ -445,7 +447,7 @@
> #
> # PCI support
> #
> - OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf {
> + UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf {
> <LibraryClasses>
> NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
> }
> diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
> b/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
> index 40d12e0f4c..dd138957a0 100644
> --- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
> +++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
> @@ -184,7 +184,7 @@ INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
> #
> # PCI support
> #
> -INF OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
> +INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
> INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
> INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
> --
> 2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111411): https://edk2.groups.io/g/devel/message/111411
Mute This Topic: https://groups.io/mt/102655144/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
@ 2023-11-17 20:18 ` Andrei Warkentin
2023-11-20 3:26 ` Chao Li
2023-11-30 0:59 ` Ni, Ray
1 sibling, 1 reply; 71+ messages in thread
From: Andrei Warkentin @ 2023-11-17 20:18 UTC (permalink / raw)
To: Chao Li, devel@edk2.groups.io
Cc: Dong, Eric, Ni, Ray, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Tuan Phan
+Tuan as a heads-up.
This seems reasonable to me. What does the "Uint" mean in ConfigureMemoryManagementUint?
Did you intend to say "Unit"?
Reviewed-by: Andrei Warkentin <andrei.warkentin@intel.com>
> -----Original Message-----
> From: Chao Li <lichao@loongson.cn>
> Sent: Friday, November 17, 2023 4:00 AM
> To: devel@edk2.groups.io
> Cc: Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar,
> Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>;
> Leif Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>;
> Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei
> <andrei.warkentin@intel.com>
> Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
>
> Add a new header file CpuMmuLib.h, whitch is referenced from
> ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
> LoongArch64 is added, and more architectures can be accommodated in the
> future.
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rahul Kumar <rahul1.kumar@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Cc: Andrei Warkentin <andrei.warkentin@intel.com>
> Signed-off-by: Chao Li <lichao@loongson.cn>
> ---
> UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
> +++++++++++++++++++++++++
> UefiCpuPkg/UefiCpuPkg.dec | 4 +
> 2 files changed, 159 insertions(+)
> create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
> b/UefiCpuPkg/Include/Library/CpuMmuLib.h
> new file mode 100644
> index 0000000000..23b2fe34ac
> --- /dev/null
> +++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
> @@ -0,0 +1,155 @@
> +/** @file
> +
> + Copyright (c) 2023 Loongson Technology Corporation Limited. All
> + rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef CPU_MMU_LIB_H_
> +#define CPU_MMU_LIB_H_
> +
> +#include <Uefi/UefiBaseType.h>
> +
> +#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;
> +
> +/**
> + Converts EFI Attributes to corresponding architecture Attributes.
> +
> + @param[in] EfiAttributes Efi Attributes.
> +
> + @retval Corresponding architecture attributes.
> +**/
> +UINTN
> +EfiAttributeConverse (
> + 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
> +GetMemoryRegionAttribute (
> + 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.
> + @param[in] AttributeMask Mask of memory attributes to take into
> account.
> +
> + @retval EFI_SUCCESS The Attributes was set successfully
> +**/
> +EFI_STATUS
> +SetMemoryRegionAttributes (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length,
> + IN UINTN Attributes,
> + IN UINT64 AttributeMask
> + );
> +
> +/**
> + 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
> +SetMemoryRegionNoExec (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length
> + );
> +
> +/**
> + Clears the non-executable Attributes for the specified memory region
> +
> + @param[in] BaseAddress The base address of the memory region to clear
> the Attributes.
> + @param[in] Length The length of the memory region to clear the
> Attributes.
> +
> + @retval EFI_SUCCESS The Attributes was clear successfully
> +**/
> +EFI_STATUS
> +EFIAPI
> +ClearMemoryRegionNoExec (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINT64 Length
> + );
> +
> +/**
> + Sets the read-only 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
> +EFIAPI
> +SetMemoryRegionReadOnly (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINT64 Length
> + );
> +
> +/**
> + Clears the read-only Attributes for the specified memory region
> +
> + @param[in] BaseAddress The base address of the memory region to clear
> the Attributes.
> + @param[in] Length The length of the memory region to clear the
> Attributes.
> +
> + @retval EFI_SUCCESS The Attributes was clear successfully
> +**/
> +EFI_STATUS
> +EFIAPI
> +ClearMemoryRegionReadOnly (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINT64 Length
> + );
> +
> +/**
> + Create a page table and initialize the memory management unit(MMU).
> +
> + @param[in] MemoryTable A pointer to a memory ragion table.
> + @param[out] TranslationTableBase A pointer to a translation table base
> address.
> + @param[out] TranslationTableSize A pointer to a translation table base
> size.
> +
> + @retval EFI_SUCCESS Configure MMU successfully.
> + EFI_INVALID_PARAMETER MemoryTable is NULL.
> + EFI_UNSUPPORTED Out of memory space or size not aligned.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ConfigureMemoryManagementUint (
> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
> + OUT VOID **TranslationTableBase OPTIONAL,
> + OUT UINTN *TranslationTableSize OPTIONAL
> + );
> +
> +#endif // CPU_MMU_LIB_H_
> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index
> 154b1d06fe..150beae981 100644
> --- a/UefiCpuPkg/UefiCpuPkg.dec
> +++ b/UefiCpuPkg/UefiCpuPkg.dec
> @@ -62,6 +62,10 @@
> ## @libraryclass Provides function for manipulating x86 paging structures.
> CpuPageTableLib|Include/Library/CpuPageTableLib.h
>
> +[LibraryClasses.LoongArch64]
> + ## @libraryclass Provides macros and functions for the memory
> management unit.
> + CpuMmuLib|Include/Library/CpuMmuLib.h
> +
> ## @libraryclass Provides functions for manipulating smram savestate
> registers.
> MmSaveStateLib|Include/Library/MmSaveStateLib.h
>
> --
> 2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111412): https://edk2.groups.io/g/devel/message/111412
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version CpuIo2Dxe
2023-11-17 20:15 ` Andrei Warkentin
@ 2023-11-20 3:04 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-20 3:04 UTC (permalink / raw)
To: devel, andrei.warkentin; +Cc: Sunil V L
[-- Attachment #1: Type: text/plain, Size: 3136 bytes --]
Hi Andrei,
Yes, the RISCV version is same as the ArmPkg version. The ArmPkg version
is almost similar to UefiCpuPkg version, excapt that UefiCpuPkg version
doesn't have MMIO methods on CpuIoServiceRead and CpuIoServiceWrite, the
MMIO methods have been added in the patch 20, please check.
Thanks,
Chao
On 2023/11/18 04:15, Andrei Warkentin wrote:
> So are you saying the UefiCpuPkg version of CpuIo2 is equivalent in function to the OvmfPkg one?
>
>> -----Original Message-----
>> From: Chao Li<lichao@loongson.cn>
>> Sent: Friday, November 17, 2023 4:02 AM
>> To:devel@edk2.groups.io
>> Cc: Sunil V L<sunilvl@ventanamicro.com>; Warkentin, Andrei
>> <andrei.warkentin@intel.com>
>> Subject: [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version
>> CpuIo2Dxe
>>
>> Since the UefiCpuPkg/CpuIo2Dxe already supports MMIO, it is enabled at
>> this thime.
>>
>> Build-tested only (with "RiscVVirtQemu.dsc").
>>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Sunil V L<sunilvl@ventanamicro.com>
>> Cc: Andrei Warkentin<andrei.warkentin@intel.com>
>> ---
>> OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc | 4 +++-
>> OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf | 2 +-
>> 2 files changed, 4 insertions(+), 2 deletions(-)
>>
>> diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
>> b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
>> index 34b2037824..499902e445 100644
>> --- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
>> +++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
>> @@ -143,6 +143,8 @@
>>
>> gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE
>>
>> + gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslationIsEnabled|TRUE
>> +
>> [PcdsFixedAtBuild.common]
>> gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
>> gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
>> @@ -445,7 +447,7 @@
>> #
>> # PCI support
>> #
>> - OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf {
>> + UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf {
>> <LibraryClasses>
>> NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
>> }
>> diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
>> b/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
>> index 40d12e0f4c..dd138957a0 100644
>> --- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
>> +++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
>> @@ -184,7 +184,7 @@ INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
>> #
>> # PCI support
>> #
>> -INF OvmfPkg/RiscVVirt/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
>> +INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
>> INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
>> INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
>> INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
>> --
>> 2.27.0
>
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111437): https://edk2.groups.io/g/devel/message/111437
Mute This Topic: https://groups.io/mt/102655144/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 4868 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
2023-11-17 11:35 ` Leif Lindholm
@ 2023-11-20 3:07 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-20 3:07 UTC (permalink / raw)
To: devel, quic_llindhol
Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Ard Biesheuvel,
Sami Mujawar, Laszlo Ersek, Sunil V L
[-- Attachment #1: Type: text/plain, Size: 12055 bytes --]
Hi Leif,
There are indeed typos and I will fix them in V4. Thank you!
Thanks,
Chao
On 2023/11/17 19:35, Leif Lindholm wrote:
> Not my package, just spotted a typo below:
>
> On Fri, Nov 17, 2023 at 17:59:49 +0800, Chao Li wrote:
>> Since some ARCH or platform not require execute code on memory during
>> PEI phase, some values may transferred via CPU registers.
>>
>> Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
>> table pointer depend by a CPU register, this library can accommodate lot
>> of platforms who not require execte code on memory during PEI phase.
>>
>> Adding PeiServiceTablePointerLibReg to allows setting and getting the
>> PEI service table pointer via CPU registers, and the library can
>> accommodate many platforms that do not need to execute code on memory
>> during the PEI phase.
>>
>> The idea of this library is derived from
>> ArmPkg/Library/PeiServicesTablePointerLib/
>>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Michael D Kinney<michael.d.kinney@intel.com>
>> Cc: Liming Gao<gaoliming@byosoft.com.cn>
>> Cc: Zhiguang Liu<zhiguang.liu@intel.com>
>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>> Cc: Laszlo Ersek<lersek@redhat.com>
>> Cc: Sunil V L<sunilvl@ventanamicro.com>
>> Signed-off-by: Chao Li<lichao@loongson.cn>
>> ---
>> .../Library/PeiServicesTablePointerLib.h | 37 +++++++-
>> .../PeiServicesTablePointer.c | 86 +++++++++++++++++++
>> .../PeiServicesTablePointerLib.uni | 20 +++++
>> .../PeiServicesTablePointerLibReg.inf | 40 +++++++++
>> MdePkg/MdePkg.dsc | 1 +
>> 5 files changed, 180 insertions(+), 4 deletions(-)
>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>>
>> diff --git a/MdePkg/Include/Library/PeiServicesTablePointerLib.h b/MdePkg/Include/Library/PeiServicesTablePointerLib.h
>> index 61635eff00..f5c764cb13 100644
>> --- a/MdePkg/Include/Library/PeiServicesTablePointerLib.h
>> +++ b/MdePkg/Include/Library/PeiServicesTablePointerLib.h
>> @@ -52,10 +52,11 @@ SetPeiServicesTablePointer (
>> 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.
>> + For Itanium, ARM and LoongArch 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, ARM and
>> + LoongArch CPUs.
>>
>> **/
>> VOID
>> @@ -64,4 +65,32 @@ MigratePeiServicesTablePointer (
>> VOID
>> );
>>
>> +/**
>> + Retrieves the cached value of the PEI Services Table pointer from a CPU register.
>> +
>> + 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.
>> +
>> + @return The pointer to PeiServices.
>> +**/
>> +CONST EFI_PEI_SERVICES **
>> +EFIAPI
>> +GetPeiServicesTablePointerFromRegister (
>> + VOID
>> + );
>> +
>> +/**
>> + Set the pointer PEI Service Table to a CPU register.
>> +
>> + Caches the pointer to the PEI Services Table specified by PeiServicesTablePointer
>> + in a platform specific manner.
>> +
>> + @param PeiServicesTablePointer The address of PeiServices.
>> +**/
>> +VOID
>> +EFIAPI
>> +SetPeiServicesTablePointerToRegester (
> SetPeiServicesTablePointerToRegester ->
> SetPeiServicesTablePointerToRegister
>
> Regester -> Register.
>
> /
> Leif
>
>> + IN UINTN PeiServicesTablePointer
>> + );
>> #endif
>> diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
>> new file mode 100644
>> index 0000000000..0227f98871
>> --- /dev/null
>> +++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
>> @@ -0,0 +1,86 @@
>> +/** @file
>> + PEI Services Table Pointer Library For Reigseter Mechanism.
>> +
>> + This library is used for PEIM which does executed from flash device directly but
>> + executed in memory.
>> +
>> + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
>> + Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
>> + Copyright (c) 2023 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>
>> +
>> +/**
>> + 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
>> + )
>> +{
>> + ASSERT (PeiServicesTablePointer != NULL);
>> + SetPeiServicesTablePointerToRegester ((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
>> + )
>> +{
>> + CONST EFI_PEI_SERVICES **PeiServices;
>> +
>> + PeiServices = GetPeiServicesTablePointerFromRegister ();
>> + ASSERT (PeiServices != NULL);
>> + return PeiServices;
>> +}
>> +
>> +/**
>> + 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, ARM and LoongArch 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, ARM and
>> + LoongArch CPUs.
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +MigratePeiServicesTablePointer (
>> + VOID
>> + )
>> +{
>> + return;
>> +}
>> diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
>> new file mode 100644
>> index 0000000000..937cf857d9
>> --- /dev/null
>> +++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
>> @@ -0,0 +1,20 @@
>> +// /** @file
>> +// Instance of PEI Services Table Pointer Library using CPU register for the table pointer.
>> +//
>> +// PEI Services Table Pointer Library implementation that retrieves a pointer to the
>> +// PEI Services Table from a CPU register. Applies to modules that execute from
>> +// read-only memory.
>> +//
>> +// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
>> +// Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
>> +// Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +//
>> +// SPDX-License-Identifier: BSD-2-Clause-Patent
>> +//
>> +// **/
>> +
>> +
>> +#string STR_MODULE_ABSTRACT #language en-US "Instance of PEI Services Table Pointer Library using CPU register for the table pointer"
>> +
>> +#string STR_MODULE_DESCRIPTION #language en-US "The PEI Services Table Pointer Library implementation that retrieves a pointer to the PEI Services Table from a CPU register. Applies to modules that execute from read-only memory."
>> +
>> diff --git a/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>> new file mode 100644
>> index 0000000000..22499e22ad
>> --- /dev/null
>> +++ b/MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>> @@ -0,0 +1,40 @@
>> +## @file
>> +# Instance of PEI Services Table Pointer Library using CPU register for the table pointer.
>> +#
>> +# PEI Services Table Pointer Library implementation that retrieves a pointer to the
>> +# PEI Services Table from a CPU register. Applies to modules that execute from
>> +# read-only memory.
>> +#
>> +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
>> +# Copyright (c) 2011 Hewlett-Packard Corporation. All rights reserved.<BR>
>> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +#
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
>> + BASE_NAME = PeiServicesTablePointerLib
>> + MODULE_UNI_FILE = PeiServicesTablePointerLib.uni
>> + FILE_GUID = 619950D1-7C5F-EA1B-D6DD-2FF7B0A4A2B7
>> + MODULE_TYPE = PEIM
>> + VERSION_STRING = 1.0
>> + LIBRARY_CLASS = PeiServicesTablePointerLib|PEIM PEI_CORE SEC
>> +
>> +#
>> +# VALID_ARCHITECTURES = IA32 X64 AARCH64 RISCV64 LOONGARCH64
>> +#
>> +
>> +[Sources]
>> + PeiServicesTablePointer.c
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> +
>> +[LibraryClasses]
>> + DebugLib
>> +
>> +[Pcd]
>> +
>> diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
>> index 3abd1a1e23..2e9a3d4b4c 100644
>> --- a/MdePkg/MdePkg.dsc
>> +++ b/MdePkg/MdePkg.dsc
>> @@ -103,6 +103,7 @@
>> MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf
>> MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
>> MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
>> + MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>> MdePkg/Library/PeiSmbusLibSmbus2Ppi/PeiSmbusLibSmbus2Ppi.inf
>> MdePkg/Library/PeiPciLibPciCfg2/PeiPciLibPciCfg2.inf
>> MdePkg/Library/PeiPciSegmentLibPciCfg2/PeiPciSegmentLibPciCfg2.inf
>> --
>> 2.27.0
>>
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111438): https://edk2.groups.io/g/devel/message/111438
Mute This Topic: https://groups.io/mt/102644754/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 13561 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg
2023-11-17 13:13 ` Leif Lindholm
@ 2023-11-20 3:24 ` Chao Li
2023-11-20 18:47 ` Leif Lindholm
0 siblings, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-11-20 3:24 UTC (permalink / raw)
To: devel, quic_llindhol; +Cc: Ard Biesheuvel, Sami Mujawar
[-- Attachment #1: Type: text/plain, Size: 27281 bytes --]
Hi Leif,
Do you mean that CpuIo2Dxe adds MMIO method first, then waits for this
patch series to be merged, and finally makes a new BZ and remove the ARM
version?
Thanks,
Chao
On 2023/11/17 21:13, Leif Lindholm wrote:
> On Fri, Nov 17, 2023 at 18:01:39 +0800, Chao Li wrote:
>> ArmPciCpuIo2Dxe has been merged into CpuIo2Dxe, and CpuIo2Dxe is already
>> used by all ARM virtual platforms, so remove it.
> This does affect 15 platforms in edk2-platforms.
> You should ping the maintainers of the affected platforms, or even
> better write a patch yourself, so we don't end up with sudden
> mass-breakage.
>
> It might be worth splitting this patch out of the rest of the set in
> order to permit a more graceful switchover.
>
> /
> Leif
>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>> ---
>> ArmPkg/ArmPkg.dsc | 1 -
>> .../Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c | 556 ------------------
>> .../ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf | 47 --
>> 3 files changed, 604 deletions(-)
>> delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
>> delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>>
>> diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
>> index 6dd91e6941..7af25a91a1 100644
>> --- a/ArmPkg/ArmPkg.dsc
>> +++ b/ArmPkg/ArmPkg.dsc
>> @@ -143,7 +143,6 @@
>>
>> ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
>>
>> - ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>> ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
>> ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf
>> ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf
>> diff --git a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
>> deleted file mode 100644
>> index 5a2866ccd8..0000000000
>> --- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
>> +++ /dev/null
>> @@ -1,556 +0,0 @@
>> -/** @file
>> - Produces the CPU I/O 2 Protocol.
>> -
>> -Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
>> -Copyright (c) 2016, Linaro Ltd. 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>
>> -
>> -#define MAX_IO_PORT_ADDRESS 0xFFFF
>> -
>> -//
>> -// 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.
>> -
>> -**/
>> -STATIC
>> -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.
>> -
>> -**/
>> -STATIC
>> -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.
>> -
>> -**/
>> -STATIC
>> -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.
>> -
>> -**/
>> -STATIC
>> -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.
>> -
>> -**/
>> -STATIC
>> -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
>> -ArmPciCpuIo2Initialize (
>> - 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/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>> deleted file mode 100644
>> index 9339c2b532..0000000000
>> --- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>> +++ /dev/null
>> @@ -1,47 +0,0 @@
>> -## @file
>> -# Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
>> -#
>> -# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
>> -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
>> -#
>> -# SPDX-License-Identifier: BSD-2-Clause-Patent
>> -#
>> -##
>> -
>> -[Defines]
>> - INF_VERSION = 0x00010005
>> - BASE_NAME = ArmPciCpuIo2Dxe
>> - FILE_GUID = 168D1A6E-F4A5-448A-9E95-795661BB3067
>> - MODULE_TYPE = DXE_DRIVER
>> - VERSION_STRING = 1.0
>> - ENTRY_POINT = ArmPciCpuIo2Initialize
>> -
>> -#
>> -# The following information is for reference only and not required by the build tools.
>> -#
>> -# VALID_ARCHITECTURES = ARM AARCH64
>> -#
>> -
>> -[Sources]
>> - ArmPciCpuIo2Dxe.c
>> -
>> -[Packages]
>> - ArmPkg/ArmPkg.dec
>> - MdePkg/MdePkg.dec
>> -
>> -[LibraryClasses]
>> - UefiDriverEntryPoint
>> - BaseLib
>> - DebugLib
>> - IoLib
>> - PcdLib
>> - UefiBootServicesTableLib
>> -
>> -[Pcd]
>> - gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
>> -
>> -[Protocols]
>> - gEfiCpuIo2ProtocolGuid ## PRODUCES
>> -
>> -[Depex]
>> - TRUE
>> --
>> 2.27.0
>>
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111441): https://edk2.groups.io/g/devel/message/111441
Mute This Topic: https://groups.io/mt/102644788/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 27269 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
2023-11-17 20:18 ` Andrei Warkentin
@ 2023-11-20 3:26 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-20 3:26 UTC (permalink / raw)
To: devel, andrei.warkentin
Cc: Dong, Eric, Ni, Ray, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Tuan Phan
[-- Attachment #1: Type: text/plain, Size: 8944 bytes --]
Hi Anderi,
There are indeed typos and I will fix them in V4. Thank you!
Thanks,
Chao
On 2023/11/18 04:18, Andrei Warkentin wrote:
> +Tuan as a heads-up.
>
> This seems reasonable to me. What does the "Uint" mean in ConfigureMemoryManagementUint?
>
> Did you intend to say "Unit"?
>
> Reviewed-by: Andrei Warkentin<andrei.warkentin@intel.com>
>
>> -----Original Message-----
>> From: Chao Li<lichao@loongson.cn>
>> Sent: Friday, November 17, 2023 4:00 AM
>> To:devel@edk2.groups.io
>> Cc: Dong, Eric<eric.dong@intel.com>; Ni, Ray<ray.ni@intel.com>; Kumar,
>> Rahul R<rahul.r.kumar@intel.com>; Gerd Hoffmann<kraxel@redhat.com>;
>> Leif Lindholm<quic_llindhol@quicinc.com>; Ard Biesheuvel
>> <ardb+tianocore@kernel.org>; Sami Mujawar<sami.mujawar@arm.com>;
>> Sunil V L<sunilvl@ventanamicro.com>; Warkentin, Andrei
>> <andrei.warkentin@intel.com>
>> Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
>>
>> Add a new header file CpuMmuLib.h, whitch is referenced from
>> ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
>> LoongArch64 is added, and more architectures can be accommodated in the
>> future.
>>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Eric Dong<eric.dong@intel.com>
>> Cc: Ray Ni<ray.ni@intel.com>
>> Cc: Rahul Kumar<rahul1.kumar@intel.com>
>> Cc: Gerd Hoffmann<kraxel@redhat.com>
>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>> Cc: Sunil V L<sunilvl@ventanamicro.com>
>> Cc: Andrei Warkentin<andrei.warkentin@intel.com>
>> Signed-off-by: Chao Li<lichao@loongson.cn>
>> ---
>> UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
>> +++++++++++++++++++++++++
>> UefiCpuPkg/UefiCpuPkg.dec | 4 +
>> 2 files changed, 159 insertions(+)
>> create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
>>
>> diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
>> b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>> new file mode 100644
>> index 0000000000..23b2fe34ac
>> --- /dev/null
>> +++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>> @@ -0,0 +1,155 @@
>> +/** @file
>> +
>> + Copyright (c) 2023 Loongson Technology Corporation Limited. All
>> + rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef CPU_MMU_LIB_H_
>> +#define CPU_MMU_LIB_H_
>> +
>> +#include <Uefi/UefiBaseType.h>
>> +
>> +#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;
>> +
>> +/**
>> + Converts EFI Attributes to corresponding architecture Attributes.
>> +
>> + @param[in] EfiAttributes Efi Attributes.
>> +
>> + @retval Corresponding architecture attributes.
>> +**/
>> +UINTN
>> +EfiAttributeConverse (
>> + 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
>> +GetMemoryRegionAttribute (
>> + 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.
>> + @param[in] AttributeMask Mask of memory attributes to take into
>> account.
>> +
>> + @retval EFI_SUCCESS The Attributes was set successfully
>> +**/
>> +EFI_STATUS
>> +SetMemoryRegionAttributes (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINTN Length,
>> + IN UINTN Attributes,
>> + IN UINT64 AttributeMask
>> + );
>> +
>> +/**
>> + 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
>> +SetMemoryRegionNoExec (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINTN Length
>> + );
>> +
>> +/**
>> + Clears the non-executable Attributes for the specified memory region
>> +
>> + @param[in] BaseAddress The base address of the memory region to clear
>> the Attributes.
>> + @param[in] Length The length of the memory region to clear the
>> Attributes.
>> +
>> + @retval EFI_SUCCESS The Attributes was clear successfully
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ClearMemoryRegionNoExec (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINT64 Length
>> + );
>> +
>> +/**
>> + Sets the read-only 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
>> +EFIAPI
>> +SetMemoryRegionReadOnly (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINT64 Length
>> + );
>> +
>> +/**
>> + Clears the read-only Attributes for the specified memory region
>> +
>> + @param[in] BaseAddress The base address of the memory region to clear
>> the Attributes.
>> + @param[in] Length The length of the memory region to clear the
>> Attributes.
>> +
>> + @retval EFI_SUCCESS The Attributes was clear successfully
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ClearMemoryRegionReadOnly (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINT64 Length
>> + );
>> +
>> +/**
>> + Create a page table and initialize the memory management unit(MMU).
>> +
>> + @param[in] MemoryTable A pointer to a memory ragion table.
>> + @param[out] TranslationTableBase A pointer to a translation table base
>> address.
>> + @param[out] TranslationTableSize A pointer to a translation table base
>> size.
>> +
>> + @retval EFI_SUCCESS Configure MMU successfully.
>> + EFI_INVALID_PARAMETER MemoryTable is NULL.
>> + EFI_UNSUPPORTED Out of memory space or size not aligned.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ConfigureMemoryManagementUint (
>> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
>> + OUT VOID **TranslationTableBase OPTIONAL,
>> + OUT UINTN *TranslationTableSize OPTIONAL
>> + );
>> +
>> +#endif // CPU_MMU_LIB_H_
>> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index
>> 154b1d06fe..150beae981 100644
>> --- a/UefiCpuPkg/UefiCpuPkg.dec
>> +++ b/UefiCpuPkg/UefiCpuPkg.dec
>> @@ -62,6 +62,10 @@
>> ## @libraryclass Provides function for manipulating x86 paging structures.
>> CpuPageTableLib|Include/Library/CpuPageTableLib.h
>>
>> +[LibraryClasses.LoongArch64]
>> + ## @libraryclass Provides macros and functions for the memory
>> management unit.
>> + CpuMmuLib|Include/Library/CpuMmuLib.h
>> +
>> ## @libraryclass Provides functions for manipulating smram savestate
>> registers.
>> MmSaveStateLib|Include/Library/MmSaveStateLib.h
>>
>> --
>> 2.27.0
>
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111442): https://edk2.groups.io/g/devel/message/111442
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 11409 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 14/39] UefiCpuPkg: Add LoongArch64CpuMmuLib to UefiCpuPkg
[not found] ` <179860C0A131BC70.3002@groups.io>
@ 2023-11-20 9:55 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-20 9:55 UTC (permalink / raw)
To: devel
Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann, Baoqi Zhang,
Dongyan Qian, Xianglai Li, Bibo Mao
[-- Attachment #1: Type: text/plain, Size: 105494 bytes --]
This patch includes two folder, both named LoongArch64CpuMmuLib. This
was a mistak when creating the patch, I will fix it in the V4.
Thanks,
Chao
On 2023/11/17 18:00, Chao Li wrote:
> Add a new library LoongArch64CpuMmuLib. It provides two-stage MMU library
> instances, PEI and DXE.
>
> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Eric Dong<eric.dong@intel.com>
> Cc: Ray Ni<ray.ni@intel.com>
> Cc: Rahul Kumar<rahul1.kumar@intel.com>
> Cc: Gerd Hoffmann<kraxel@redhat.com>
> Signed-off-by: Chao Li<lichao@loongson.cn>
> Co-authored-by: Baoqi Zhang<zhangbaoqi@loongson.cn>
> Co-authored-by: Dongyan Qian<qiandongyan@loongson.cn>
> Co-authored-by: Xianglai Li<lixianglai@loongson.cn>
> Co-authored-by: Bibo Mao<maobibo@loongson.cn>
> ---
> .../LoongArch64CpuMmuLib/CommonMmuLib.c | 965 ++++++++++++++++++
> .../LoongArch64CpuMmuLib/CommonMmuLib.h | 43 +
> .../LoongArch64CpuMmuLib/DxeCpuMmuLib.inf | 37 +
> .../LoongArch64CpuMmuLib/DxeCpuMmuLib.uni | 14 +
> .../LoongArch64CpuMmuLib/CommonMmuLib.c | 964 +++++++++++++++++
> .../LoongArch64CpuMmuLib/CommonMmuLib.h | 43 +
> .../LoongArch64CpuMmuLib/DxeCpuMmuLib.inf | 37 +
> .../LoongArch64CpuMmuLib/DxeCpuMmuLib.uni | 14 +
> .../LoongArch64CpuMmuLib/Page.h | 279 +++++
> .../LoongArch64CpuMmuLib/PeiCpuMmuLib.c | 165 +++
> .../LoongArch64CpuMmuLib/PeiCpuMmuLib.inf | 44 +
> .../LoongArch64CpuMmuLib/PeiCpuMmuLib.uni | 14 +
> .../LoongArch64CpuMmuLib/Tlb.h | 48 +
> .../LoongArch64CpuMmuLib/TlbOperation.S | 44 +
> .../Library/LoongArch64CpuMmuLib/Page.h | 279 +++++
> .../LoongArch64CpuMmuLib/PeiCpuMmuLib.c | 165 +++
> .../LoongArch64CpuMmuLib/PeiCpuMmuLib.inf | 44 +
> .../LoongArch64CpuMmuLib/PeiCpuMmuLib.uni | 14 +
> UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h | 48 +
> .../LoongArch64CpuMmuLib/TlbOperation.S | 44 +
> UefiCpuPkg/UefiCpuPkg.dsc | 2 +
> 21 files changed, 3307 insertions(+)
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
> create mode 100644 UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
>
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
> new file mode 100644
> index 0000000000..bd5c7e55b6
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.c
> @@ -0,0 +1,965 @@
> +/** @file
> +
> + CPU Memory Map Unit Handler Library common functions.
> +
> + Copyright (c) 2023 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/CpuMmuLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +#include "Tlb.h"
> +#include "Page.h"
> +
> +BOOLEAN mMmuInited = FALSE;
> +#define SWAP_PAGE_DIR CsrRead(LOONGARCH_CSR_PGDL)
> +
> +/**
> + 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 || (SWAP_PAGE_DIR != 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.
> +
> + @return 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 *)(SWAP_PAGE_DIR) + 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;
> +
> + 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;
> +
> + 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;
> +
> + 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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +**/
> +EFI_STATUS
> +PudAlloc (
> + IN PGD *Pgd
> + )
> +{
> + PUD *Pud;
> +
> + Pud = (PUD *)AllocatePages (1);
> + if (Pud == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)INVALID_PAGE);
> +
> + SetPgd (Pgd, 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 *)INVALID_PAGE);
> +
> + SetPud (Pud, 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.
> +**/
> +EFI_STATUS
> +PteAlloc (
> + IN PMD *Pmd
> + )
> +{
> + PTE *Pte;
> +
> + Pte = (PTE *)AllocatePages (1);
> + if (!Pte) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
> +
> + SetPmd (Pmd, 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.
> + @param Address The corresponding virtual address of the page table entry.
> +
> + @retval A pointer to the page upper directory entry. Return NULL, if
> + allocate the memory buffer is fail.
> +**/
> +PUD *
> +PudAllocGet (
> + IN PGD *Pgd,
> + IN UINTN Address
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (PGD_IS_EMPTY (*Pgd)) {
> + Status = PudAlloc (Pgd);
> + ASSERT_EFI_ERROR (Status);
> + if (EFI_ERROR (Status)) {
> + return NULL;
> + }
> + }
> +
> + return 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.
> + @param Address The corresponding virtual address of the page table entry.
> +
> + @retval A pointer to the page middle directory entry. Return NULL, if
> + allocate the memory buffer is fail.
> +**/
> +PMD *
> +PmdAllocGet (
> + IN PUD *Pud,
> + IN UINTN Address
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (PUD_IS_EMPTY (*Pud)) {
> + Status = PmdAlloc (Pud);
> + ASSERT_EFI_ERROR (Status);
> + if (EFI_ERROR (Status)) {
> + return NULL;
> + }
> + }
> +
> + return PmdOffset (Pud, Address);
> +}
> +
> +/**
> + 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.
> + @param Address The corresponding virtual address of the page table entry.
> +
> + @retval A pointer to the page table entry. Return NULL, if allocate
> + the memory buffer is fail.
> +**/
> +PTE *
> +PteAllocGet (
> + IN PMD *Pmd,
> + IN UINTN Address
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (PMD_IS_EMPTY (*Pmd)) {
> + Status = PteAlloc (Pmd);
> + ASSERT_EFI_ERROR (Status);
> + if (EFI_ERROR (Status)) {
> + return NULL;
> + }
> + }
> +
> + return 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_IS_EMPTY (*Pgd)) {
> + return NULL;
> + }
> +
> + Pud = PudOffset (Pgd, Address);
> +
> + if (PUD_IS_EMPTY (*Pud)) {
> + return NULL;
> + }
> +
> + Pmd = PmdOffset (Pud, Address);
> + if (PMD_IS_EMPTY (*Pmd)) {
> + return NULL;
> + }
> +
> + if (IS_HUGE_PAGE (Pmd->PmdVal)) {
> + return ((PTE *)Pmd);
> + }
> +
> + return PteOffset (Pmd, Address);
> +}
> +
> +/**
> + Gets the Attributes of Huge Page.
> +
> + @param Pmd A pointer to the page middle directory.
> +
> + @retval Value of Attributes.
> +**/
> +UINTN
> +GetHugePageAttributes (
> + IN PMD *Pmd
> + )
> +{
> + UINTN Attributes;
> + UINTN GlobalFlag;
> + UINTN HugeVal;
> +
> + HugeVal = PMD_VAL (*Pmd);
> + Attributes = HugeVal & (~HUGEP_PAGE_MASK);
> + GlobalFlag = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT;
> + Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT);
> + Attributes |= GlobalFlag;
> + return Attributes;
> +}
> +
> +/**
> + 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;
> + }
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "%a %d Address %p End %p Attributes %llx\n",
> + __func__,
> + __LINE__,
> + Address,
> + End,
> + Attributes
> + ));
> +
> + do {
> + UpDate = FALSE;
> + PteVal = MAKE_PTE (Address, Attributes);
> +
> + if ((!PTE_IS_EMPTY (*Pte)) &&
> + (PTE_VAL (*Pte) != PTE_VAL (PteVal)))
> + {
> + UpDate = TRUE;
> + }
> +
> + SetPte (Pte, PteVal);
> + if (UpDate) {
> + InvalidTlb (Address);
> + }
> + } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Convert Huge Page to Page.
> +
> + @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
> +ConvertHugePageToPage (
> + IN PMD *Pmd,
> + IN UINTN Address,
> + IN UINTN End,
> + IN UINTN Attributes
> + )
> +{
> + UINTN OldAttributes;
> + UINTN HugePageEnd;
> + UINTN HugePageStart;
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> +
> + if ((PMD_IS_EMPTY (*Pmd)) ||
> + (!IS_HUGE_PAGE (Pmd->PmdVal)))
> + {
> + Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
> + } else {
> + OldAttributes = GetHugePageAttributes (Pmd);
> + if (Attributes == OldAttributes) {
> + return Status;
> + }
> +
> + SetPmd (Pmd, (PTE *)(INVALID_PAGE));
> + HugePageStart = Address & PMD_MASK;
> + HugePageEnd = HugePageStart + HUGE_PAGE_SIZE;
> + ASSERT (HugePageEnd >= End);
> +
> + if (Address > HugePageStart) {
> + Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes);
> + }
> +
> + Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
> +
> + if (End < HugePageEnd) {
> + Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes);
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + 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;
> + UINTN Next;
> + PTE PteVal;
> + BOOLEAN UpDate;
> +
> + 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_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal)))
> + {
> + UpDate = FALSE;
> + PteVal = MAKE_HUGE_PTE (Address, Attributes);
> +
> + if ((!PMD_IS_EMPTY (*Pmd)) &&
> + (PMD_VAL (*Pmd) != PTE_VAL (PteVal)))
> + {
> + UpDate = TRUE;
> + }
> +
> + SetPmd (Pmd, (PTE *)PteVal.PteVal);
> + if (UpDate) {
> + InvalidTlb (Address);
> + }
> + } else {
> + ConvertHugePageToPage (Pmd, Address, Next, Attributes);
> + }
> + } while (Pmd++, Address = Next, Address != End);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + 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 (EFI_ERROR (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;
> + EFI_STATUS Err;
> +
> + Address = Start;
> +
> + /* Get PGD(PTE PMD PUD PGD) in PageTables */
> + Pgd = PgdOffset (Address);
> + do {
> + Next = PGD_ADDRESS_END (Address, End);
> + /* Get Next Align Page to Map */
> + 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
> + );
> +}
> +
> +/**
> + Convert EFI Attributes to Loongarch Attributes.
> +
> + @param[in] EfiAttributes Efi Attributes.
> +
> + @retval Corresponding architecture attributes.
> +**/
> +UINTN
> +EfiAttributeConverse (
> + IN UINTN EfiAttributes
> + )
> +{
> + UINTN LoongArchAttributes;
> +
> + LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | 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) ||
> + ((EfiAttributes & EFI_MEMORY_WP) != 0))
> + {
> + LoongArchAttributes &= ~PAGE_DIRTY;
> + }
> +
> + if ((EfiAttributes & EFI_MEMORY_RP) != 0) {
> + LoongArchAttributes |= PAGE_NO_READ;
> + }
> +
> + // 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
> +GetMemoryRegionAttribute (
> + IN UINTN BaseAddress,
> + IN UINTN EndAddress,
> + OUT UINTN *RegionLength,
> + OUT UINTN *RegionAttributes
> + )
> +{
> + PTE *Pte;
> + UINTN Attributes;
> + UINTN AttributesTmp;
> + UINTN MaxAddress;
> +
> + if (!MmuIsInit ()) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
> + Pte = GetPteAddress (BaseAddress);
> +
> + 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.
> + @param[in] AttributeMask Mask of memory attributes to take into account.
> +
> + @retval EFI_SUCCESS The Attributes was set successfully
> +**/
> +EFI_STATUS
> +SetMemoryRegionAttributes (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length,
> + IN UINTN Attributes,
> + IN UINT64 AttributeMask
> + )
> +{
> + if (!MmuIsInit ()) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + Attributes = EfiAttributeConverse (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
> +SetMemoryRegionNoExec (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length
> + )
> +{
> + if (MmuIsInit ()) {
> + Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
> + SetMemoryRegionAttributes (BaseAddress, Length, EFI_MEMORY_XP, 0x0);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Check to see if mmu successfully initializes and saves the result.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval RETURN_SUCCESS Initialization succeeded.
> +**/
> +RETURN_STATUS
> +EFIAPI
> +MmuInitialize (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + if (SWAP_PAGE_DIR != 0) {
> + mMmuInited = TRUE;
> + }
> +
> + return RETURN_SUCCESS;
> +}
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
> new file mode 100644
> index 0000000000..aa96f5143c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/CommonMmuLib.h
> @@ -0,0 +1,43 @@
> +/** @file
> +
> + Copyright (c) 2023 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/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> new file mode 100644
> index 0000000000..d153354dd2
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> @@ -0,0 +1,37 @@
> +## @file
> +# CPU Memory Map Unit DXE phase driver.
> +#
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = DxeCpuMmuLib
> + MODULE_UNI_FILE = DxeCpuMmuLib.uni
> + FILE_GUID = DA8F0232-FB14-42F0-922C-63104D2C70BE
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = CpuMmuLib | DXE_DRIVER
> + CONSTRUCTOR = MmuInitialize
> +
> +#
> +# VALID_ARCHITECTURES = LOONGARCH64
> +#
> +
> +[Sources]
> + TlbOperation.S | GCC
> + CommonMmuLib.c
> + Tlb.h
> + Page.h
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + UefiCpuPkg/UefiCpuPkg.dec
> +
> +[LibraryClasses]
> + MemoryAllocationLib
> + PcdLib
> + DebugLib
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> new file mode 100644
> index 0000000000..2e841d714c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// CPU Memory Manager Unit library instance for DXE modules.
> +//
> +// CPU Memory Manager Unit library instance for DXE modules.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for DXE modules."
> +
> +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for DXE modules."
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
> new file mode 100644
> index 0000000000..f5e632a237
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.c
> @@ -0,0 +1,964 @@
> +/** @file
> +
> + CPU Memory Map Unit Handler Library common functions.
> +
> + Copyright (c) 2023 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/CpuMmuLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +#include "Tlb.h"
> +#include "Page.h"
> +
> +BOOLEAN mMmuInited = FALSE;
> +#define SWAP_PAGE_DIR CsrRead(LOONGARCH_CSR_PGDL)
> +
> +/**
> + 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 || (SWAP_PAGE_DIR != 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.
> +
> + @return 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 *)(SWAP_PAGE_DIR) + 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;
> +
> + 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;
> +
> + 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;
> +
> + 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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +
> +**/
> +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.
> +**/
> +EFI_STATUS
> +PudAlloc (
> + IN PGD *Pgd
> + )
> +{
> + PUD *Pud;
> +
> + Pud = (PUD *)AllocatePages (1);
> + if (Pud == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)INVALID_PAGE);
> +
> + SetPgd (Pgd, 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 *)INVALID_PAGE);
> +
> + SetPud (Pud, 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.
> +**/
> +EFI_STATUS
> +PteAlloc (
> + IN PMD *Pmd
> + )
> +{
> + PTE *Pte;
> +
> + Pte = (PTE *)AllocatePages (1);
> + if (!Pte) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
> +
> + SetPmd (Pmd, 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.
> + @param Address The corresponding virtual address of the page table entry.
> +
> + @retval A pointer to the page upper directory entry. Return NULL, if
> + allocate the memory buffer is fail.
> +**/
> +PUD *
> +PudAllocGet (
> + IN PGD *Pgd,
> + IN UINTN Address
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (PGD_IS_EMPTY (*Pgd)) {
> + Status = PudAlloc (Pgd);
> + ASSERT_EFI_ERROR (Status);
> + if (EFI_ERROR (Status)) {
> + return NULL;
> + }
> + }
> +
> + return 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.
> + @param Address The corresponding virtual address of the page table entry.
> +
> + @retval A pointer to the page middle directory entry. Return NULL, if
> + allocate the memory buffer is fail.
> +**/
> +PMD *
> +PmdAllocGet (
> + IN PUD *Pud,
> + IN UINTN Address
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (PUD_IS_EMPTY (*Pud)) {
> + Status = PmdAlloc (Pud);
> + ASSERT_EFI_ERROR (Status);
> + if (EFI_ERROR (Status)) {
> + return NULL;
> + }
> + }
> +
> + return PmdOffset (Pud, Address);
> +}
> +
> +/**
> + 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.
> + @param Address The corresponding virtual address of the page table entry.
> +
> + @retval A pointer to the page table entry. Return NULL, if allocate
> + the memory buffer is fail.
> +**/
> +PTE *
> +PteAllocGet (
> + IN PMD *Pmd,
> + IN UINTN Address
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (PMD_IS_EMPTY (*Pmd)) {
> + Status = PteAlloc (Pmd);
> + ASSERT_EFI_ERROR (Status);
> + if (EFI_ERROR (Status)) {
> + return NULL;
> + }
> + }
> +
> + return 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_IS_EMPTY (*Pgd)) {
> + return NULL;
> + }
> +
> + Pud = PudOffset (Pgd, Address);
> +
> + if (PUD_IS_EMPTY (*Pud)) {
> + return NULL;
> + }
> +
> + Pmd = PmdOffset (Pud, Address);
> + if (PMD_IS_EMPTY (*Pmd)) {
> + return NULL;
> + }
> +
> + if (IS_HUGE_PAGE (Pmd->PmdVal)) {
> + return ((PTE *)Pmd);
> + }
> +
> + return PteOffset (Pmd, Address);
> +}
> +
> +/**
> + Gets the Attributes of Huge Page.
> +
> + @param Pmd A pointer to the page middle directory.
> +
> + @retval Value of Attributes.
> +**/
> +UINTN
> +GetHugePageAttributes (
> + IN PMD *Pmd
> + )
> +{
> + UINTN Attributes;
> + UINTN GlobalFlag;
> + UINTN HugeVal;
> +
> + HugeVal = PMD_VAL (*Pmd);
> + Attributes = HugeVal & (~HUGEP_PAGE_MASK);
> + GlobalFlag = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT;
> + Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT);
> + Attributes |= GlobalFlag;
> + return Attributes;
> +}
> +
> +/**
> + 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;
> + }
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "%a %d Address %p End %p Attributes %llx\n",
> + __func__,
> + __LINE__,
> + Address,
> + End,
> + Attributes
> + ));
> +
> + do {
> + UpDate = FALSE;
> + PteVal = MAKE_PTE (Address, Attributes);
> +
> + if ((!PTE_IS_EMPTY (*Pte)) &&
> + (PTE_VAL (*Pte) != PTE_VAL (PteVal)))
> + {
> + UpDate = TRUE;
> + }
> +
> + SetPte (Pte, PteVal);
> + if (UpDate) {
> + InvalidTlb (Address);
> + }
> + } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Convert Huge Page to Page.
> +
> + @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
> +ConvertHugePageToPage (
> + IN PMD *Pmd,
> + IN UINTN Address,
> + IN UINTN End,
> + IN UINTN Attributes
> + )
> +{
> + UINTN OldAttributes;
> + UINTN HugePageEnd;
> + UINTN HugePageStart;
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> +
> + if ((PMD_IS_EMPTY (*Pmd)) ||
> + (!IS_HUGE_PAGE (Pmd->PmdVal)))
> + {
> + Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
> + } else {
> + OldAttributes = GetHugePageAttributes (Pmd);
> + if (Attributes == OldAttributes) {
> + return Status;
> + }
> +
> + SetPmd (Pmd, (PTE *)(INVALID_PAGE));
> + HugePageStart = Address & PMD_MASK;
> + HugePageEnd = HugePageStart + HUGE_PAGE_SIZE;
> + ASSERT (HugePageEnd >= End);
> +
> + if (Address > HugePageStart) {
> + Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes);
> + }
> +
> + Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
> +
> + if (End < HugePageEnd) {
> + Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes);
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + 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;
> + UINTN Next;
> + PTE PteVal;
> + BOOLEAN UpDate;
> +
> + 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_IS_EMPTY (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal)))
> + {
> + UpDate = FALSE;
> + PteVal = MAKE_HUGE_PTE (Address, Attributes);
> +
> + if ((!PMD_IS_EMPTY (*Pmd)) &&
> + (PMD_VAL (*Pmd) != PTE_VAL (PteVal)))
> + {
> + UpDate = TRUE;
> + }
> +
> + SetPmd (Pmd, (PTE *)PteVal.PteVal);
> + if (UpDate) {
> + InvalidTlb (Address);
> + }
> + } else {
> + ConvertHugePageToPage (Pmd, Address, Next, Attributes);
> + }
> + } while (Pmd++, Address = Next, Address != End);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + 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 (EFI_ERROR (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;
> + EFI_STATUS Err;
> +
> + Address = Start;
> +
> + /* Get PGD(PTE PMD PUD PGD) in PageTables */
> + Pgd = PgdOffset (Address);
> + do {
> + Next = PGD_ADDRESS_END (Address, End);
> + /* Get Next Align Page to Map */
> + 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
> + );
> +}
> +
> +/**
> + Convert EFI Attributes to Loongarch Attributes.
> +
> + @param[in] EfiAttributes Efi Attributes.
> +
> + @retval Corresponding architecture attributes.
> +**/
> +UINTN
> +EfiAttributeConverse (
> + IN UINTN EfiAttributes
> + )
> +{
> + UINTN LoongArchAttributes;
> +
> + LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | 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) ||
> + ((EfiAttributes & EFI_MEMORY_WP) != 0))
> + {
> + LoongArchAttributes &= ~PAGE_DIRTY;
> + }
> +
> + if ((EfiAttributes & EFI_MEMORY_RP) != 0) {
> + LoongArchAttributes |= PAGE_NO_READ;
> + }
> +
> + // 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
> +GetMemoryRegionAttribute (
> + IN UINTN BaseAddress,
> + IN UINTN EndAddress,
> + OUT UINTN *RegionLength,
> + OUT UINTN *RegionAttributes
> + )
> +{
> + PTE *Pte;
> + UINTN Attributes;
> + UINTN AttributesTmp;
> + UINTN MaxAddress;
> +
> + if (!MmuIsInit ()) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
> + Pte = GetPteAddress (BaseAddress);
> +
> + 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
> +SetMemoryRegionAttributes (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length,
> + IN UINTN Attributes,
> + IN UINT64 AttributeMask
> + )
> +{
> + if (!MmuIsInit ()) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + Attributes = EfiAttributeConverse (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
> +SetMemoryRegionNoExec (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length
> + )
> +{
> + if (MmuIsInit ()) {
> + Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
> + SetMemoryRegionAttributes (BaseAddress, Length, EFI_MEMORY_XP, 0x0);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Check to see if mmu successfully initializes and saves the result.
> +
> + @param[in] ImageHandle The firmware allocated handle for the EFI image.
> + @param[in] SystemTable A pointer to the EFI System Table.
> +
> + @retval RETURN_SUCCESS Initialization succeeded.
> +**/
> +RETURN_STATUS
> +EFIAPI
> +MmuInitialize (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + if (SWAP_PAGE_DIR != 0) {
> + mMmuInited = TRUE;
> + }
> +
> + return RETURN_SUCCESS;
> +}
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
> new file mode 100644
> index 0000000000..aa96f5143c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/CommonMmuLib.h
> @@ -0,0 +1,43 @@
> +/** @file
> +
> + Copyright (c) 2023 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/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> new file mode 100644
> index 0000000000..d153354dd2
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
> @@ -0,0 +1,37 @@
> +## @file
> +# CPU Memory Map Unit DXE phase driver.
> +#
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = DxeCpuMmuLib
> + MODULE_UNI_FILE = DxeCpuMmuLib.uni
> + FILE_GUID = DA8F0232-FB14-42F0-922C-63104D2C70BE
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = CpuMmuLib | DXE_DRIVER
> + CONSTRUCTOR = MmuInitialize
> +
> +#
> +# VALID_ARCHITECTURES = LOONGARCH64
> +#
> +
> +[Sources]
> + TlbOperation.S | GCC
> + CommonMmuLib.c
> + Tlb.h
> + Page.h
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + UefiCpuPkg/UefiCpuPkg.dec
> +
> +[LibraryClasses]
> + MemoryAllocationLib
> + PcdLib
> + DebugLib
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> new file mode 100644
> index 0000000000..2e841d714c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/DxeCpuMmuLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// CPU Memory Manager Unit library instance for DXE modules.
> +//
> +// CPU Memory Manager Unit library instance for DXE modules.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for DXE modules."
> +
> +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for DXE modules."
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
> new file mode 100644
> index 0000000000..ad8f751ad7
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Page.h
> @@ -0,0 +1,279 @@
> +/** @file
> +
> + Copyright (c) 2023 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_
> +
> +#include <Library/CpuMmuLib.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))
> +
> +#define HUGEP_PAGE_MASK (~(((UINTN)(1) << (PMD_SHIFT)) - 1) & \
> + (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
> +
> +#define INVALID_PAGE 0
> +
> +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) (PTE){(((((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 The page table is invalid.
> + @retval 0 The page table is valid.
> +**/
> +#define PGD_IS_EMPTY(Val) (PGD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> + Check that the page upper directory table entry is empty.
> +
> + @param pud Page upper directory struct variables.
> +
> + @retval 1 The page table is invalid.
> + @retval 0 The page table is valid.
> +**/
> +#define PUD_IS_EMPTY(Val) (PUD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> + Check that the page middle directory table entry is empty.
> +
> + @param pmd Page middle directory struct variables.
> +
> + @retval 1 The page table is invalid.
> + @retval 0 The page table is valid.
> +**/
> +#define PMD_IS_EMPTY(Val) (PMD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> + Check that the page the page table entry is empty.
> +
> + @param pte Page table entry struct variables.
> +
> + @retval 1 The page table is invalid.
> + @retval 0 The page table is valid.
> +**/
> +#define PTE_IS_EMPTY(Val) (!(PTE_VAL(Val) & (~PAGE_VALID)))
> +#endif // PAGE_H_
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> new file mode 100644
> index 0000000000..42a424b84d
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> @@ -0,0 +1,165 @@
> +/** @file
> + CPU Memory Map Unit PEI phase driver.
> +
> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - 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/CpuMmuLib.h>
> +#include <Library/CacheMaintenanceLib.h>
> +#include <Library/CpuMmuLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +
> +#include "Page.h"
> +#include "Tlb.h"
> +#include "CommonMmuLib.h"
> +
> +/**
> + Create a page table and initialize the memory management unit(MMU).
> +
> + @param[in] MemoryTable A pointer to a memory ragion table.
> + @param[out] TranslationTableBase A pointer to a translation table base address.
> + @param[out] TranslationTableSize A pointer to a translation table base size.
> +
> + @retval EFI_SUCCESS Configure MMU successfully.
> + EFI_INVALID_PARAMETER MemoryTable is NULL.
> + EFI_UNSUPPORTED Out of memory space or size not aligned.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ConfigureMemoryManagementUint (
> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
> + OUT VOID **TranslationTableBase OPTIONAL,
> + OUT UINTN *TranslationTableSize OPTIONAL
> + )
> +{
> + PGD *SwapperPageDir;
> + UINTN PgdShift;
> + UINTN PgdWide;
> + UINTN PudShift;
> + UINTN PudWide;
> + UINTN PmdShift;
> + UINTN PmdWide;
> + UINTN PteShift;
> + UINTN PteWide;
> + UINTN Length;
> + UINTN TlbReEntry;
> + UINTN TlbReEntryOffset;
> + RETURN_STATUS Status;
> +
> + SwapperPageDir = NULL;
> + PgdShift = PGD_SHIFT;
> + PgdWide = PGD_WIDE;
> + PudShift = PUD_SHIFT;
> + PudWide = PUD_WIDE;
> + PmdShift = PMD_SHIFT;
> + PmdWide = PMD_WIDE;
> + PteShift = PTE_SHIFT;
> + PteWide = PTE_WIDE;
> +
> + if (MemoryTable == NULL) {
> + ASSERT (MemoryTable != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> + ZeroMem (SwapperPageDir, PGD_TABLE_SIZE);
> +
> + if (SwapperPageDir == NULL) {
> + goto FreeTranslationTable;
> + }
> +
> + CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir);
> +
> + while (MemoryTable->Length != 0) {
> + DEBUG ((
> + DEBUG_INFO,
> + "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n",
> + __func__,
> + __LINE__,
> + MemoryTable->VirtualBase,
> + (MemoryTable->Length + MemoryTable->VirtualBase),
> + MemoryTable->Attributes
> + ));
> +
> + Status = FillTranslationTable (MemoryTable);
> + if (EFI_ERROR (Status)) {
> + goto FreeTranslationTable;
> + }
> +
> + MemoryTable++;
> + }
> +
> + //
> + // TLB Re-entry address at the end of exception vector, a vector is up to 512 bytes,
> + // so the starting address is: total exception vector size + total interrupt vector size + base.
> + // The total size of TLB handler and exception vector size and interrupt vector size should not
> + // be lager than 64KB.
> + //
> + Length = (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart;
> + TlbReEntryOffset = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512;
> + TlbReEntry = PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryOffset;
> + if ((TlbReEntryOffset + Length) > SIZE_64KB) {
> + goto FreeTranslationTable;
> + }
> +
> + //
> + // Make sure TLB refill exception base address alignment is greater than or equal to 4KB and valid
> + //
> + if (TlbReEntry & (SIZE_4KB - 1)) {
> + goto FreeTranslationTable;
> + }
> +
> + CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
> + InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length);
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "%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
> + ));
> +
> + //
> + // Set the address of TLB refill exception handler
> + //
> + SetTlbRebaseAddress ((UINTN)TlbReEntry);
> +
> + //
> + // Set page size
> + //
> + CsrXChg (LOONGARCH_CSR_TLBIDX, (DEFAULT_PAGE_SIZE << CSR_TLBIDX_SIZE), CSR_TLBIDX_SIZE_MASK);
> + CsrWrite (LOONGARCH_CSR_STLBPGSIZE, DEFAULT_PAGE_SIZE);
> + CsrXChg (LOONGARCH_CSR_TLBREHI, (DEFAULT_PAGE_SIZE << CSR_TLBREHI_PS_SHIFT), CSR_TLBREHI_PS);
> +
> + CsrWrite (LOONGARCH_CSR_PWCTL0, (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25));
> + CsrWrite (LOONGARCH_CSR_PWCTL1, (PgdShift | PgdWide << 6));
> +
> + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
> +
> + return EFI_SUCCESS;
> +
> +FreeTranslationTable:
> + if (SwapperPageDir != NULL) {
> + FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> new file mode 100644
> index 0000000000..e746c3b1a7
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> @@ -0,0 +1,44 @@
> +## @file
> +# CPU Memory Map Unit PEI phase driver.
> +#
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = PeiCpuMmuLib
> + MODULE_UNI_FILE = PeiCpuMmuLib.uni
> + FILE_GUID = F67EB983-AC2A-7550-AB69-3BC51A1C895B
> + MODULE_TYPE = PEIM
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = CpuMmuLib | SEC PEIM
> +
> +#
> +# VALID_ARCHITECTURES = LOONGARCH64
> +#
> +
> +[Sources]
> + TlbOperation.S | GCC
> + PeiCpuMmuLib.c
> + CommonMmuLib.c
> + CommonMmuLib.h
> + Tlb.h
> + Page.h
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + UefiCpuPkg/UefiCpuPkg.dec
> +
> +[PCD]
> + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
> + gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
> +
> +[LibraryClasses]
> + MemoryAllocationLib
> + CacheMaintenanceLib
> + PcdLib
> + DebugLib
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> new file mode 100644
> index 0000000000..331500543c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// CPU Memory Manager Unit library instance for PEI modules.
> +//
> +// CPU Memory Manager Unit library instance for PEI modules.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for PEI modules."
> +
> +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for PEI modules."
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
> new file mode 100644
> index 0000000000..5d3f80fe34
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/Tlb.h
> @@ -0,0 +1,48 @@
> +/** @file
> +
> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef TLB_H_
> +#define TLB_H_
> +
> +/**
> + Invalid corresponding TLB entries are based on the address given
> +
> + @param Address The address corresponding to the invalid page table entry
> +
> + @retval none
> +**/
> +VOID
> +InvalidTlb (
> + UINTN Address
> + );
> +
> +/**
> + TLB refill handler start.
> +
> + @param none
> +
> + @retval none
> +**/
> +VOID
> +HandleTlbRefillStart (
> + VOID
> + );
> +
> +/**
> + TLB refill handler end.
> +
> + @param none
> +
> + @retval none
> +**/
> +VOID
> +HandleTlbRefillEnd (
> + VOID
> + );
> +
> +#endif // TLB_H_
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
> new file mode 100644
> index 0000000000..e446f0839c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/LoongArch64CpuMmuLib/TlbOperation.S
> @@ -0,0 +1,44 @@
> +#------------------------------------------------------------------------------
> +#
> +# TLB operation functions
> +#
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#-----------------------------------------------------------------------------
> +
> +#include <Register/LoongArch64/Csr.h>
> +
> +ASM_GLOBAL ASM_PFX(HandleTlbRefillStart)
> +ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd)
> +ASM_GLOBAL ASM_PFX(InvalidTlb)
> +
> +#
> +# Refill the page table.
> +# @param VOID
> +# @retval VOID
> +#
> +ASM_PFX(HandleTlbRefillStart):
> + 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 // refill hi,lo0,lo1
> + csrrd $t0, LOONGARCH_CSR_TLBRSAVE
> + ertn
> +ASM_PFX(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(InvalidTlb):
> + invtlb INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0
> + jirl $zero, $ra, 0
> +
> + .end
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
> new file mode 100644
> index 0000000000..ad8f751ad7
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Page.h
> @@ -0,0 +1,279 @@
> +/** @file
> +
> + Copyright (c) 2023 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_
> +
> +#include <Library/CpuMmuLib.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))
> +
> +#define HUGEP_PAGE_MASK (~(((UINTN)(1) << (PMD_SHIFT)) - 1) & \
> + (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
> +
> +#define INVALID_PAGE 0
> +
> +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) (PTE){(((((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 The page table is invalid.
> + @retval 0 The page table is valid.
> +**/
> +#define PGD_IS_EMPTY(Val) (PGD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> + Check that the page upper directory table entry is empty.
> +
> + @param pud Page upper directory struct variables.
> +
> + @retval 1 The page table is invalid.
> + @retval 0 The page table is valid.
> +**/
> +#define PUD_IS_EMPTY(Val) (PUD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> + Check that the page middle directory table entry is empty.
> +
> + @param pmd Page middle directory struct variables.
> +
> + @retval 1 The page table is invalid.
> + @retval 0 The page table is valid.
> +**/
> +#define PMD_IS_EMPTY(Val) (PMD_VAL(Val) == INVALID_PAGE)
> +
> +/**
> + Check that the page the page table entry is empty.
> +
> + @param pte Page table entry struct variables.
> +
> + @retval 1 The page table is invalid.
> + @retval 0 The page table is valid.
> +**/
> +#define PTE_IS_EMPTY(Val) (!(PTE_VAL(Val) & (~PAGE_VALID)))
> +#endif // PAGE_H_
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> new file mode 100644
> index 0000000000..42a424b84d
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.c
> @@ -0,0 +1,165 @@
> +/** @file
> + CPU Memory Map Unit PEI phase driver.
> +
> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Glossary:
> + - 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/CpuMmuLib.h>
> +#include <Library/CacheMaintenanceLib.h>
> +#include <Library/CpuMmuLib.h>
> +#include <Register/LoongArch64/Csr.h>
> +
> +#include "Page.h"
> +#include "Tlb.h"
> +#include "CommonMmuLib.h"
> +
> +/**
> + Create a page table and initialize the memory management unit(MMU).
> +
> + @param[in] MemoryTable A pointer to a memory ragion table.
> + @param[out] TranslationTableBase A pointer to a translation table base address.
> + @param[out] TranslationTableSize A pointer to a translation table base size.
> +
> + @retval EFI_SUCCESS Configure MMU successfully.
> + EFI_INVALID_PARAMETER MemoryTable is NULL.
> + EFI_UNSUPPORTED Out of memory space or size not aligned.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ConfigureMemoryManagementUint (
> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
> + OUT VOID **TranslationTableBase OPTIONAL,
> + OUT UINTN *TranslationTableSize OPTIONAL
> + )
> +{
> + PGD *SwapperPageDir;
> + UINTN PgdShift;
> + UINTN PgdWide;
> + UINTN PudShift;
> + UINTN PudWide;
> + UINTN PmdShift;
> + UINTN PmdWide;
> + UINTN PteShift;
> + UINTN PteWide;
> + UINTN Length;
> + UINTN TlbReEntry;
> + UINTN TlbReEntryOffset;
> + RETURN_STATUS Status;
> +
> + SwapperPageDir = NULL;
> + PgdShift = PGD_SHIFT;
> + PgdWide = PGD_WIDE;
> + PudShift = PUD_SHIFT;
> + PudWide = PUD_WIDE;
> + PmdShift = PMD_SHIFT;
> + PmdWide = PMD_WIDE;
> + PteShift = PTE_SHIFT;
> + PteWide = PTE_WIDE;
> +
> + if (MemoryTable == NULL) {
> + ASSERT (MemoryTable != NULL);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> + ZeroMem (SwapperPageDir, PGD_TABLE_SIZE);
> +
> + if (SwapperPageDir == NULL) {
> + goto FreeTranslationTable;
> + }
> +
> + CsrWrite (LOONGARCH_CSR_PGDL, (UINTN)SwapperPageDir);
> +
> + while (MemoryTable->Length != 0) {
> + DEBUG ((
> + DEBUG_INFO,
> + "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n",
> + __func__,
> + __LINE__,
> + MemoryTable->VirtualBase,
> + (MemoryTable->Length + MemoryTable->VirtualBase),
> + MemoryTable->Attributes
> + ));
> +
> + Status = FillTranslationTable (MemoryTable);
> + if (EFI_ERROR (Status)) {
> + goto FreeTranslationTable;
> + }
> +
> + MemoryTable++;
> + }
> +
> + //
> + // TLB Re-entry address at the end of exception vector, a vector is up to 512 bytes,
> + // so the starting address is: total exception vector size + total interrupt vector size + base.
> + // The total size of TLB handler and exception vector size and interrupt vector size should not
> + // be lager than 64KB.
> + //
> + Length = (UINTN)HandleTlbRefillEnd - (UINTN)HandleTlbRefillStart;
> + TlbReEntryOffset = (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) * 512;
> + TlbReEntry = PcdGet64 (PcdCpuExceptionVectorBaseAddress) + TlbReEntryOffset;
> + if ((TlbReEntryOffset + Length) > SIZE_64KB) {
> + goto FreeTranslationTable;
> + }
> +
> + //
> + // Make sure TLB refill exception base address alignment is greater than or equal to 4KB and valid
> + //
> + if (TlbReEntry & (SIZE_4KB - 1)) {
> + goto FreeTranslationTable;
> + }
> +
> + CopyMem ((VOID *)TlbReEntry, HandleTlbRefillStart, Length);
> + InvalidateInstructionCacheRange ((VOID *)(UINTN)HandleTlbRefillStart, Length);
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "%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
> + ));
> +
> + //
> + // Set the address of TLB refill exception handler
> + //
> + SetTlbRebaseAddress ((UINTN)TlbReEntry);
> +
> + //
> + // Set page size
> + //
> + CsrXChg (LOONGARCH_CSR_TLBIDX, (DEFAULT_PAGE_SIZE << CSR_TLBIDX_SIZE), CSR_TLBIDX_SIZE_MASK);
> + CsrWrite (LOONGARCH_CSR_STLBPGSIZE, DEFAULT_PAGE_SIZE);
> + CsrXChg (LOONGARCH_CSR_TLBREHI, (DEFAULT_PAGE_SIZE << CSR_TLBREHI_PS_SHIFT), CSR_TLBREHI_PS);
> +
> + CsrWrite (LOONGARCH_CSR_PWCTL0, (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25));
> + CsrWrite (LOONGARCH_CSR_PWCTL1, (PgdShift | PgdWide << 6));
> +
> + DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
> +
> + return EFI_SUCCESS;
> +
> +FreeTranslationTable:
> + if (SwapperPageDir != NULL) {
> + FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
> + }
> +
> + return EFI_UNSUPPORTED;
> +}
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> new file mode 100644
> index 0000000000..e746c3b1a7
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> @@ -0,0 +1,44 @@
> +## @file
> +# CPU Memory Map Unit PEI phase driver.
> +#
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = PeiCpuMmuLib
> + MODULE_UNI_FILE = PeiCpuMmuLib.uni
> + FILE_GUID = F67EB983-AC2A-7550-AB69-3BC51A1C895B
> + MODULE_TYPE = PEIM
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = CpuMmuLib | SEC PEIM
> +
> +#
> +# VALID_ARCHITECTURES = LOONGARCH64
> +#
> +
> +[Sources]
> + TlbOperation.S | GCC
> + PeiCpuMmuLib.c
> + CommonMmuLib.c
> + CommonMmuLib.h
> + Tlb.h
> + Page.h
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + UefiCpuPkg/UefiCpuPkg.dec
> +
> +[PCD]
> + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
> + gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress
> +
> +[LibraryClasses]
> + MemoryAllocationLib
> + CacheMaintenanceLib
> + PcdLib
> + DebugLib
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> new file mode 100644
> index 0000000000..331500543c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.uni
> @@ -0,0 +1,14 @@
> +// /** @file
> +// CPU Memory Manager Unit library instance for PEI modules.
> +//
> +// CPU Memory Manager Unit library instance for PEI modules.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +#string STR_MODULE_ABSTRACT #language en-US "CPU Memory Manager Unit library instance for PEI modules."
> +
> +#string STR_MODULE_DESCRIPTION #language en-US "CPU Memory Manager Unit library instance for PEI modules."
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
> new file mode 100644
> index 0000000000..5d3f80fe34
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/Tlb.h
> @@ -0,0 +1,48 @@
> +/** @file
> +
> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef TLB_H_
> +#define TLB_H_
> +
> +/**
> + Invalid corresponding TLB entries are based on the address given
> +
> + @param Address The address corresponding to the invalid page table entry
> +
> + @retval none
> +**/
> +VOID
> +InvalidTlb (
> + UINTN Address
> + );
> +
> +/**
> + TLB refill handler start.
> +
> + @param none
> +
> + @retval none
> +**/
> +VOID
> +HandleTlbRefillStart (
> + VOID
> + );
> +
> +/**
> + TLB refill handler end.
> +
> + @param none
> +
> + @retval none
> +**/
> +VOID
> +HandleTlbRefillEnd (
> + VOID
> + );
> +
> +#endif // TLB_H_
> diff --git a/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
> new file mode 100644
> index 0000000000..e446f0839c
> --- /dev/null
> +++ b/UefiCpuPkg/Library/LoongArch64CpuMmuLib/TlbOperation.S
> @@ -0,0 +1,44 @@
> +#------------------------------------------------------------------------------
> +#
> +# TLB operation functions
> +#
> +# Copyright (c) 2023 Loongson Technology Corporation Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#-----------------------------------------------------------------------------
> +
> +#include <Register/LoongArch64/Csr.h>
> +
> +ASM_GLOBAL ASM_PFX(HandleTlbRefillStart)
> +ASM_GLOBAL ASM_PFX(HandleTlbRefillEnd)
> +ASM_GLOBAL ASM_PFX(InvalidTlb)
> +
> +#
> +# Refill the page table.
> +# @param VOID
> +# @retval VOID
> +#
> +ASM_PFX(HandleTlbRefillStart):
> + 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 // refill hi,lo0,lo1
> + csrrd $t0, LOONGARCH_CSR_TLBRSAVE
> + ertn
> +ASM_PFX(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(InvalidTlb):
> + invtlb INVTLB_ADDR_GTRUE_OR_ASID, $zero, $a0
> + jirl $zero, $ra, 0
> +
> + .end
> diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
> index 872f20fc36..709992d327 100644
> --- a/UefiCpuPkg/UefiCpuPkg.dsc
> +++ b/UefiCpuPkg/UefiCpuPkg.dsc
> @@ -209,6 +209,8 @@
> UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
> UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
> UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
> + UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf
> + UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf
>
> [BuildOptions]
> *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111465): https://edk2.groups.io/g/devel/message/111465
Mute This Topic: https://groups.io/mt/102644769/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 101532 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg
2023-11-20 3:24 ` Chao Li
@ 2023-11-20 18:47 ` Leif Lindholm
2023-11-21 1:10 ` Chao Li
0 siblings, 1 reply; 71+ messages in thread
From: Leif Lindholm @ 2023-11-20 18:47 UTC (permalink / raw)
To: Chao Li; +Cc: devel, Ard Biesheuvel, Sami Mujawar
Hi Chao,
Yes, correct.
So we can update the existing users of this driver in edk2-platforms
before deleting it.
Regards,
Leif
On Mon, Nov 20, 2023 at 11:24:03 +0800, Chao Li wrote:
> Hi Leif,
>
> Do you mean that CpuIo2Dxe adds MMIO method first, then waits for this patch
> series to be merged, and finally makes a new BZ and remove the ARM version?
>
>
> Thanks,
> Chao
> On 2023/11/17 21:13, Leif Lindholm wrote:
> > On Fri, Nov 17, 2023 at 18:01:39 +0800, Chao Li wrote:
> > > ArmPciCpuIo2Dxe has been merged into CpuIo2Dxe, and CpuIo2Dxe is already
> > > used by all ARM virtual platforms, so remove it.
> > This does affect 15 platforms in edk2-platforms.
> > You should ping the maintainers of the affected platforms, or even
> > better write a patch yourself, so we don't end up with sudden
> > mass-breakage.
> >
> > It might be worth splitting this patch out of the rest of the set in
> > order to permit a more graceful switchover.
> >
> > /
> > Leif
> >
> > > BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
> > >
> > > Cc: Leif Lindholm<quic_llindhol@quicinc.com>
> > > Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
> > > Cc: Sami Mujawar<sami.mujawar@arm.com>
> > > ---
> > > ArmPkg/ArmPkg.dsc | 1 -
> > > .../Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c | 556 ------------------
> > > .../ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf | 47 --
> > > 3 files changed, 604 deletions(-)
> > > delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
> > > delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
> > >
> > > diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
> > > index 6dd91e6941..7af25a91a1 100644
> > > --- a/ArmPkg/ArmPkg.dsc
> > > +++ b/ArmPkg/ArmPkg.dsc
> > > @@ -143,7 +143,6 @@
> > > ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
> > > - ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
> > > ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
> > > ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf
> > > ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf
> > > diff --git a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
> > > deleted file mode 100644
> > > index 5a2866ccd8..0000000000
> > > --- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
> > > +++ /dev/null
> > > @@ -1,556 +0,0 @@
> > > -/** @file
> > > - Produces the CPU I/O 2 Protocol.
> > > -
> > > -Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
> > > -Copyright (c) 2016, Linaro Ltd. 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>
> > > -
> > > -#define MAX_IO_PORT_ADDRESS 0xFFFF
> > > -
> > > -//
> > > -// 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.
> > > -
> > > -**/
> > > -STATIC
> > > -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.
> > > -
> > > -**/
> > > -STATIC
> > > -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.
> > > -
> > > -**/
> > > -STATIC
> > > -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.
> > > -
> > > -**/
> > > -STATIC
> > > -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.
> > > -
> > > -**/
> > > -STATIC
> > > -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
> > > -ArmPciCpuIo2Initialize (
> > > - 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/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
> > > deleted file mode 100644
> > > index 9339c2b532..0000000000
> > > --- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
> > > +++ /dev/null
> > > @@ -1,47 +0,0 @@
> > > -## @file
> > > -# Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
> > > -#
> > > -# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
> > > -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> > > -#
> > > -# SPDX-License-Identifier: BSD-2-Clause-Patent
> > > -#
> > > -##
> > > -
> > > -[Defines]
> > > - INF_VERSION = 0x00010005
> > > - BASE_NAME = ArmPciCpuIo2Dxe
> > > - FILE_GUID = 168D1A6E-F4A5-448A-9E95-795661BB3067
> > > - MODULE_TYPE = DXE_DRIVER
> > > - VERSION_STRING = 1.0
> > > - ENTRY_POINT = ArmPciCpuIo2Initialize
> > > -
> > > -#
> > > -# The following information is for reference only and not required by the build tools.
> > > -#
> > > -# VALID_ARCHITECTURES = ARM AARCH64
> > > -#
> > > -
> > > -[Sources]
> > > - ArmPciCpuIo2Dxe.c
> > > -
> > > -[Packages]
> > > - ArmPkg/ArmPkg.dec
> > > - MdePkg/MdePkg.dec
> > > -
> > > -[LibraryClasses]
> > > - UefiDriverEntryPoint
> > > - BaseLib
> > > - DebugLib
> > > - IoLib
> > > - PcdLib
> > > - UefiBootServicesTableLib
> > > -
> > > -[Pcd]
> > > - gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
> > > -
> > > -[Protocols]
> > > - gEfiCpuIo2ProtocolGuid ## PRODUCES
> > > -
> > > -[Depex]
> > > - TRUE
> > > --
> > > 2.27.0
> > >
> >
> >
> >
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111487): https://edk2.groups.io/g/devel/message/111487
Mute This Topic: https://groups.io/mt/102644788/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg
2023-11-20 18:47 ` Leif Lindholm
@ 2023-11-21 1:10 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-21 1:10 UTC (permalink / raw)
To: devel, quic_llindhol; +Cc: Ard Biesheuvel, Sami Mujawar
[-- Attachment #1: Type: text/plain, Size: 28935 bytes --]
OK, I will remove this patch in V4.
Thanks,
Chao
On 2023/11/21 02:47, Leif Lindholm wrote:
> Hi Chao,
>
> Yes, correct.
>
> So we can update the existing users of this driver in edk2-platforms
> before deleting it.
>
> Regards,
>
> Leif
>
> On Mon, Nov 20, 2023 at 11:24:03 +0800, Chao Li wrote:
>> Hi Leif,
>>
>> Do you mean that CpuIo2Dxe adds MMIO method first, then waits for this patch
>> series to be merged, and finally makes a new BZ and remove the ARM version?
>>
>>
>> Thanks,
>> Chao
>> On 2023/11/17 21:13, Leif Lindholm wrote:
>>> On Fri, Nov 17, 2023 at 18:01:39 +0800, Chao Li wrote:
>>>> ArmPciCpuIo2Dxe has been merged into CpuIo2Dxe, and CpuIo2Dxe is already
>>>> used by all ARM virtual platforms, so remove it.
>>> This does affect 15 platforms in edk2-platforms.
>>> You should ping the maintainers of the affected platforms, or even
>>> better write a patch yourself, so we don't end up with sudden
>>> mass-breakage.
>>>
>>> It might be worth splitting this patch out of the rest of the set in
>>> order to permit a more graceful switchover.
>>>
>>> /
>>> Leif
>>>
>>>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>>>
>>>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>>>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>>>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>>>> ---
>>>> ArmPkg/ArmPkg.dsc | 1 -
>>>> .../Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c | 556 ------------------
>>>> .../ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf | 47 --
>>>> 3 files changed, 604 deletions(-)
>>>> delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
>>>> delete mode 100644 ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>>>>
>>>> diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
>>>> index 6dd91e6941..7af25a91a1 100644
>>>> --- a/ArmPkg/ArmPkg.dsc
>>>> +++ b/ArmPkg/ArmPkg.dsc
>>>> @@ -143,7 +143,6 @@
>>>> ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
>>>> - ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>>>> ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
>>>> ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf
>>>> ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf
>>>> diff --git a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
>>>> deleted file mode 100644
>>>> index 5a2866ccd8..0000000000
>>>> --- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.c
>>>> +++ /dev/null
>>>> @@ -1,556 +0,0 @@
>>>> -/** @file
>>>> - Produces the CPU I/O 2 Protocol.
>>>> -
>>>> -Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
>>>> -Copyright (c) 2016, Linaro Ltd. 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>
>>>> -
>>>> -#define MAX_IO_PORT_ADDRESS 0xFFFF
>>>> -
>>>> -//
>>>> -// 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.
>>>> -
>>>> -**/
>>>> -STATIC
>>>> -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.
>>>> -
>>>> -**/
>>>> -STATIC
>>>> -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.
>>>> -
>>>> -**/
>>>> -STATIC
>>>> -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.
>>>> -
>>>> -**/
>>>> -STATIC
>>>> -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.
>>>> -
>>>> -**/
>>>> -STATIC
>>>> -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
>>>> -ArmPciCpuIo2Initialize (
>>>> - 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/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf b/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>>>> deleted file mode 100644
>>>> index 9339c2b532..0000000000
>>>> --- a/ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
>>>> +++ /dev/null
>>>> @@ -1,47 +0,0 @@
>>>> -## @file
>>>> -# Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
>>>> -#
>>>> -# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
>>>> -# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
>>>> -#
>>>> -# SPDX-License-Identifier: BSD-2-Clause-Patent
>>>> -#
>>>> -##
>>>> -
>>>> -[Defines]
>>>> - INF_VERSION = 0x00010005
>>>> - BASE_NAME = ArmPciCpuIo2Dxe
>>>> - FILE_GUID = 168D1A6E-F4A5-448A-9E95-795661BB3067
>>>> - MODULE_TYPE = DXE_DRIVER
>>>> - VERSION_STRING = 1.0
>>>> - ENTRY_POINT = ArmPciCpuIo2Initialize
>>>> -
>>>> -#
>>>> -# The following information is for reference only and not required by the build tools.
>>>> -#
>>>> -# VALID_ARCHITECTURES = ARM AARCH64
>>>> -#
>>>> -
>>>> -[Sources]
>>>> - ArmPciCpuIo2Dxe.c
>>>> -
>>>> -[Packages]
>>>> - ArmPkg/ArmPkg.dec
>>>> - MdePkg/MdePkg.dec
>>>> -
>>>> -[LibraryClasses]
>>>> - UefiDriverEntryPoint
>>>> - BaseLib
>>>> - DebugLib
>>>> - IoLib
>>>> - PcdLib
>>>> - UefiBootServicesTableLib
>>>> -
>>>> -[Pcd]
>>>> - gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
>>>> -
>>>> -[Protocols]
>>>> - gEfiCpuIo2ProtocolGuid ## PRODUCES
>>>> -
>>>> -[Depex]
>>>> - TRUE
>>>> --
>>>> 2.27.0
>>>>
>>>
>>>
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111493): https://edk2.groups.io/g/devel/message/111493
Mute This Topic: https://groups.io/mt/102644788/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 27818 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 27/39] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg
[not found] ` <179860DB0A3E8D83.6542@groups.io>
@ 2023-11-21 6:39 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-21 6:39 UTC (permalink / raw)
To: devel
Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Gerd Hoffmann,
Jiewen Yao, Lazlo Ersek
[-- Attachment #1: Type: text/plain, Size: 8851 bytes --]
This patch accidentally breaks some platforms, I will fix them in V4.
Thanks,
Chao
On 2023/11/17 18:02, Chao Li wrote:
> Moved the PlatformBootManagerLib to OvmfPkg and renamed to
> PlatformBootManagerLibLight for easy use by other ARCH.
>
> Build-tested only (with "ArmVirtQemu.dsc").
>
> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
> Cc: Sami Mujawar<sami.mujawar@arm.com>
> Cc: Gerd Hoffmann<kraxel@redhat.com>
> Cc: Jiewen Yao<jiewen.yao@intel.com>
> Cc: Lazlo Ersek<lersek@redhat.com>
> Signed-off-by: Chao Li<lichao@loongson.cn>
> ---
> ArmPkg/ArmPkg.dsc | 1 -
> ArmVirtPkg/ArmVirtCloudHv.dsc | 2 +-
> ArmVirtPkg/ArmVirtKvmTool.dsc | 2 +-
> ArmVirtPkg/ArmVirtQemu.dsc | 2 +-
> ArmVirtPkg/ArmVirtQemuKernel.dsc | 2 +-
> ArmVirtPkg/ArmVirtXen.dsc | 2 +-
> .../Library/PlatformBootManagerLibLight}/PlatformBm.c | 0
> .../Library/PlatformBootManagerLibLight}/PlatformBm.h | 0
> .../PlatformBootManagerLibLight}/PlatformBootManagerLib.inf | 2 +-
> .../Library/PlatformBootManagerLibLight}/QemuKernel.c | 0
> 10 files changed, 6 insertions(+), 7 deletions(-)
> rename {ArmVirtPkg/Library/PlatformBootManagerLib => OvmfPkg/Library/PlatformBootManagerLibLight}/PlatformBm.c (100%)
> rename {ArmVirtPkg/Library/PlatformBootManagerLib => OvmfPkg/Library/PlatformBootManagerLibLight}/PlatformBm.h (100%)
> rename {ArmVirtPkg/Library/PlatformBootManagerLib => OvmfPkg/Library/PlatformBootManagerLibLight}/PlatformBootManagerLib.inf (93%)
> rename {ArmVirtPkg/Library/PlatformBootManagerLib => OvmfPkg/Library/PlatformBootManagerLibLight}/QemuKernel.c (100%)
>
> diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
> index 7af25a91a1..f0667c72f8 100644
> --- a/ArmPkg/ArmPkg.dsc
> +++ b/ArmPkg/ArmPkg.dsc
> @@ -151,7 +151,6 @@
> ArmPkg/Library/ArmSoftFloatLib/ArmSoftFloatLib.inf
> ArmPkg/Library/ArmSmcPsciResetSystemLib/ArmSmcPsciResetSystemLib.inf
> ArmPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
> - ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> ArmPkg/Library/LinuxBootBootManagerLib/LinuxBootBootManagerLib.inf
>
> ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.inf
> diff --git a/ArmVirtPkg/ArmVirtCloudHv.dsc b/ArmVirtPkg/ArmVirtCloudHv.dsc
> index 0f80fb34cc..aeed77ffcb 100644
> --- a/ArmVirtPkg/ArmVirtCloudHv.dsc
> +++ b/ArmVirtPkg/ArmVirtCloudHv.dsc
> @@ -43,7 +43,7 @@
> TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
> CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
> BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
> - PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> + PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
> PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
> CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
> FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
> diff --git a/ArmVirtPkg/ArmVirtKvmTool.dsc b/ArmVirtPkg/ArmVirtKvmTool.dsc
> index 31d5bc13cf..e2b90e000f 100644
> --- a/ArmVirtPkg/ArmVirtKvmTool.dsc
> +++ b/ArmVirtPkg/ArmVirtKvmTool.dsc
> @@ -56,7 +56,7 @@
>
> # BDS Libraries
> UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
> - PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> + PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
> BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
>
> CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
> diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
> index 6b2b4d1086..ac980a2736 100644
> --- a/ArmVirtPkg/ArmVirtQemu.dsc
> +++ b/ArmVirtPkg/ArmVirtQemu.dsc
> @@ -70,7 +70,7 @@
>
> CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
> BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
> - PlatformBootManagerLib|ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> + PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
> PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
> CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
> FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
> diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
> index 34fdf5d5a9..b8867ea6fe 100644
> --- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
> +++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
> @@ -69,7 +69,7 @@
>
> CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
> BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
> - PlatformBootManagerLib|ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> + PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
> PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
> CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
> FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
> diff --git a/ArmVirtPkg/ArmVirtXen.dsc b/ArmVirtPkg/ArmVirtXen.dsc
> index 5809832e66..c8cef06d3e 100644
> --- a/ArmVirtPkg/ArmVirtXen.dsc
> +++ b/ArmVirtPkg/ArmVirtXen.dsc
> @@ -50,7 +50,7 @@
> CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
> UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
> BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
> - PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> + PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
> CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
> TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
> TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf
> diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c b/OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBm.c
> similarity index 100%
> rename from ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c
> rename to OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBm.c
> diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.h b/OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBm.h
> similarity index 100%
> rename from ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.h
> rename to OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBm.h
> diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
> similarity index 93%
> rename from ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> rename to OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
> index 9d3ccd815a..3c63e3395c 100644
> --- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> +++ b/OvmfPkg/Library/PlatformBootManagerLibLight/PlatformBootManagerLib.inf
> @@ -20,7 +20,7 @@
> #
> # The following information is for reference only and not required by the build tools.
> #
> -# VALID_ARCHITECTURES = ARM AARCH64
> +# VALID_ARCHITECTURES = ARM AARCH64 LOONGARCH64
> #
>
> [Sources]
> diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c b/OvmfPkg/Library/PlatformBootManagerLibLight/QemuKernel.c
> similarity index 100%
> rename from ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
> rename to OvmfPkg/Library/PlatformBootManagerLibLight/QemuKernel.c
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111513): https://edk2.groups.io/g/devel/message/111513
Mute This Topic: https://groups.io/mt/102644799/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 10262 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg Chao Li
2023-11-17 11:35 ` Leif Lindholm
@ 2023-11-21 14:37 ` Laszlo Ersek
2023-11-22 1:47 ` Chao Li
1 sibling, 1 reply; 71+ messages in thread
From: Laszlo Ersek @ 2023-11-21 14:37 UTC (permalink / raw)
To: devel, lichao
Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L
On 11/17/23 10:59, Chao Li wrote:
> Since some ARCH or platform not require execute code on memory during
> PEI phase, some values may transferred via CPU registers.
>
> Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
> table pointer depend by a CPU register, this library can accommodate lot
> of platforms who not require execte code on memory during PEI phase.
>
> Adding PeiServiceTablePointerLibReg to allows setting and getting the
> PEI service table pointer via CPU registers, and the library can
> accommodate many platforms that do not need to execute code on memory
> during the PEI phase.
>
> The idea of this library is derived from
> ArmPkg/Library/PeiServicesTablePointerLib/
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Signed-off-by: Chao Li <lichao@loongson.cn>
> ---
> .../Library/PeiServicesTablePointerLib.h | 37 +++++++-
> .../PeiServicesTablePointer.c | 86 +++++++++++++++++++
> .../PeiServicesTablePointerLib.uni | 20 +++++
> .../PeiServicesTablePointerLibReg.inf | 40 +++++++++
> MdePkg/MdePkg.dsc | 1 +
> 5 files changed, 180 insertions(+), 4 deletions(-)
> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
In my opinion, the PeiServicesTablePointerLib class header should not be
extended with new interfaces. I understand that the generality is
attractive, but it is not put to use; only the loongarch architecture
applies the new interfaces (in the subsequent patch), and for example
the ARM code (ArmPkg/Library/PeiServicesTablePointerLib) is not reworked
in terms of these new interfaces.
What's more, the new library interfaces, even though they are exposed in
the lib class header, are not implemented for other architectures, so
they aren't even callable on those arches.
I'm commenting on this patch and the subsequent patch in the series
together, as seen squashed together. NB I'm not an MdePkg maintainer, so
this is just my opinion.
(1) As noted above, the library class should not be modified.
(2) Modifying the *comments* in
"MdePkg/Include/Library/PeiServicesTablePointerLib.h" is welcome, I
think, but then we might want to add a (separate!) patch for removing
the Itanium language, as edk2 no longer supports Itanium.
(3) The PeiServicesTablePointerLibReg instance should be called
PeiServicesTablePointerLibCsrKs0 or just PeiServicesTablePointerLibKs0.
This follows the example of the lib instance name
"PeiServicesTablePointerLibIdt". The whole library instance should be
loongaarch-specific IMO; there isn't much code that's being duplicated,
so the extra interfaces (internal or external) do not help with code
unification.
(4) "PeiServicesTablePointerLib.uni" should be named similarly (suffix
missing).
(5) BASE_NAME in the library instance INF file should be defined
similarly (suffix missing).
(6) The contents of the UNI file should be loongarch-specific, i.e. be
explicit about CSR KS0, in both comments and string constants.
(7) The comments in the library instance INF file should be similarly
loongarch-specific.
(8) I suggest dropping VALID_ARCHITECTURES altogether. If we want to
keep it, it should exclusively say LOONGARCH64.
(9) The new library instance should be listed in
[Components.LOONGARCH64] in MdePkg.dec.
This section does not exist yet; I suggest introducing it under
[Components.RISCV64].
(10) There need not / should not be two separate C source files; just
access the KS0 CSR in SetPeiServicesTablePointer() and
GetPeiServicesTablePointer() directly.
(11) The new library instance should probably not introduce new
references to Itanium.
Thanks,
Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111550): https://edk2.groups.io/g/devel/message/111550
Mute This Topic: https://groups.io/mt/102644754/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
2023-11-21 14:37 ` Laszlo Ersek
@ 2023-11-22 1:47 ` Chao Li
2023-11-24 11:35 ` Laszlo Ersek
0 siblings, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-11-22 1:47 UTC (permalink / raw)
To: Laszlo Ersek, devel
Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L
[-- Attachment #1: Type: text/plain, Size: 5672 bytes --]
Hi Laszlo,
Thanks,
Chao
On 2023/11/21 22:37, Laszlo Ersek wrote:
> On 11/17/23 10:59, Chao Li wrote:
>> Since some ARCH or platform not require execute code on memory during
>> PEI phase, some values may transferred via CPU registers.
>>
>> Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
>> table pointer depend by a CPU register, this library can accommodate lot
>> of platforms who not require execte code on memory during PEI phase.
>>
>> Adding PeiServiceTablePointerLibReg to allows setting and getting the
>> PEI service table pointer via CPU registers, and the library can
>> accommodate many platforms that do not need to execute code on memory
>> during the PEI phase.
>>
>> The idea of this library is derived from
>> ArmPkg/Library/PeiServicesTablePointerLib/
>>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Michael D Kinney<michael.d.kinney@intel.com>
>> Cc: Liming Gao<gaoliming@byosoft.com.cn>
>> Cc: Zhiguang Liu<zhiguang.liu@intel.com>
>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>> Cc: Laszlo Ersek<lersek@redhat.com>
>> Cc: Sunil V L<sunilvl@ventanamicro.com>
>> Signed-off-by: Chao Li<lichao@loongson.cn>
>> ---
>> .../Library/PeiServicesTablePointerLib.h | 37 +++++++-
>> .../PeiServicesTablePointer.c | 86 +++++++++++++++++++
>> .../PeiServicesTablePointerLib.uni | 20 +++++
>> .../PeiServicesTablePointerLibReg.inf | 40 +++++++++
>> MdePkg/MdePkg.dsc | 1 +
>> 5 files changed, 180 insertions(+), 4 deletions(-)
>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
> In my opinion, the PeiServicesTablePointerLib class header should not be
> extended with new interfaces. I understand that the generality is
> attractive, but it is not put to use; only the loongarch architecture
> applies the new interfaces (in the subsequent patch), and for example
> the ARM code (ArmPkg/Library/PeiServicesTablePointerLib) is not reworked
> in terms of these new interfaces.
This libarary have ability of accommodate more ARCH why not? I checked
the PI SPEC, all ARCH except IA32 and X64 using the register mechanism,
if this library can be approved, all of them can moved into this
libraryso that code con be reused more, I think this library is fine.
>
> What's more, the new library interfaces, even though they are exposed in
> the lib class header, are not implemented for other architectures, so
> they aren't even callable on those arches.
The patch 10 in this series has added LoongArch instance of this
library, please check.
>
> I'm commenting on this patch and the subsequent patch in the series
> together, as seen squashed together. NB I'm not an MdePkg maintainer, so
> this is just my opinion.
So, Mike and Liming, what do your think?
>
> (1) As noted above, the library class should not be modified.
>
> (2) Modifying the *comments* in
> "MdePkg/Include/Library/PeiServicesTablePointerLib.h" is welcome, I
> think, but then we might want to add a (separate!) patch for removing
> the Itanium language, as edk2 no longer supports Itanium.
>
> (3) The PeiServicesTablePointerLibReg instance should be called
> PeiServicesTablePointerLibCsrKs0 or just PeiServicesTablePointerLibKs0.
This library will be a public libray which using the reigster mechanism,
so the name like PeiServiceTablePointerLibCsrKs0 would not appropriate.
>
> This follows the example of the lib instance name
> "PeiServicesTablePointerLibIdt". The whole library instance should be
> loongaarch-specific IMO; there isn't much code that's being duplicated,
> so the extra interfaces (internal or external) do not help with code
> unification.
>
> (4) "PeiServicesTablePointerLib.uni" should be named similarly (suffix
> missing).
>
> (5) BASE_NAME in the library instance INF file should be defined
> similarly (suffix missing).
>
> (6) The contents of the UNI file should be loongarch-specific, i.e. be
> explicit about CSR KS0, in both comments and string constants.
>
> (7) The comments in the library instance INF file should be similarly
> loongarch-specific.
>
> (8) I suggest dropping VALID_ARCHITECTURES altogether. If we want to
> keep it, it should exclusively say LOONGARCH64.
>
> (9) The new library instance should be listed in
> [Components.LOONGARCH64] in MdePkg.dec.
>
> This section does not exist yet; I suggest introducing it under
> [Components.RISCV64].
No, it is RISC-V area, not LOONGARCH64. And I do not recommend going
this way. I believe this library should be a public library for register
mechanism.
>
> (10) There need not / should not be two separate C source files; just
> access the KS0 CSR in SetPeiServicesTablePointer() and
> GetPeiServicesTablePointer() directly.
>
> (11) The new library instance should probably not introduce new
> references to Itanium.
>
> Thanks,
> Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111592): https://edk2.groups.io/g/devel/message/111592
Mute This Topic: https://groups.io/mt/102644754/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 8433 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library Chao Li
@ 2023-11-22 16:12 ` Laszlo Ersek
2023-11-22 16:13 ` Laszlo Ersek
2023-11-23 11:43 ` Chao Li
0 siblings, 2 replies; 71+ messages in thread
From: Laszlo Ersek @ 2023-11-22 16:12 UTC (permalink / raw)
To: devel, lichao; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
On 11/17/23 11:00, Chao Li wrote:
> Add the LoongArch64 CPU Timer library, using CPUCFG 0x4 and 0x5 for
> Stable Counter frequency.
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rahul Kumar <rahul1.kumar@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Chao Li <lichao@loongson.cn>
> ---
> .../BaseLoongArch64CpuTimerLib.inf | 30 +++
> .../BaseLoongArch64CpuTimerLib.uni | 15 ++
> .../BaseLoongArch64CpuTimerLib/CpuTimerLib.c | 226 ++++++++++++++++++
> UefiCpuPkg/UefiCpuPkg.dsc | 3 +
> 4 files changed, 274 insertions(+)
> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
(1) sorry about the annoying comment, but the library should be called
(preferably) BaseTimerLibLoongArch64Cpu.
We're frequently not consistent with the following library instance
naming scheme, but in theory anyway, library instances should be named
as follows:
<firmware module type><lib class name><library instance identifier>
Thus, in this case, Base + TimerLib + LoongArch64Cpu.
update UNI file name, INF file name, directory name, BASE_NAME and
MODULE_UNI_FILE accordingly (if you agree)
>
> diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
> new file mode 100644
> index 0000000000..c00c215aec
> --- /dev/null
> +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
> @@ -0,0 +1,30 @@
> +## @file
> +# Base CPU Timer Library
> +#
> +# Provides base timer support using CPUCFG 0x4 and 0x5 stable counter frequency.
> +#
> +# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x00010005
(2) Can you use the most recent INF file version? (Generally applies to
all new INF files in the series.)
The latest version is 1.29
<https://tianocore-docs.github.io/edk2-InfSpecification/draft/>, and you
can just write "1.29" here.
> + BASE_NAME = BaseLoongArch64CpuTimerLib
> + FILE_GUID = 740389C7-CC44-4A2F-88DC-89D97D312E7C
> + MODULE_TYPE = BASE
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = TimerLib
> + MODULE_UNI_FILE = BaseLoongArch64CpuTimerLib.uni
> +
> +[Sources.common]
> + CpuTimerLib.c
(3) ".common" is not an error, but superfluous here.
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> + UefiCpuPkg/UefiCpuPkg.dec
(4) Do you actually consume any artifact from "UefiCpuPkg.dec"?
Unless you do, there's no need to depend on "UefiCpuPkg.dec" here.
(5) Relatedly: the TimerLib class is declared in "MdePkg.dec". Thus, if
you indeed don't need anything from "UefiCpuPkg.dec", I'd suggest moving
this library instance under MdePkg.
> +
> +[LibraryClasses]
> + BaseLib
> + PcdLib
> + DebugLib
(6) If it's not too much of a burden, it's best to keep library classes
alphabetically sorted.
> diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
> new file mode 100644
> index 0000000000..72d38ec679
> --- /dev/null
> +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
> @@ -0,0 +1,15 @@
> +// /** @file
> +// Base CPU Timer Library
> +//
> +// Provides base timer support using CPUCFG 0x4 and 0x5 stable counter frequency.
> +//
> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT #language en-US "LOONGARCH CPU Timer Library"
> +
> +#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUCFG 0x4 and 0x5 stable counter frequency."
> diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
> new file mode 100644
> index 0000000000..349b881cbc
> --- /dev/null
> +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
> @@ -0,0 +1,226 @@
> +/** @file
> + CPUCFG 0x4 and 0x5 for Stable Counter frequency instance of Timer Library.
> +
> + Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <Base.h>
> +#include <Library/TimerLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Register/LoongArch64/Cpucfg.h>
(7) It's best to keep the Library includes in sync with the
[LibraryClasses] section from the INF file.
(And to keep the #include directives alphabetically sorted as well.)
You are including <Library/TimerLib.h> here because the file is going to
define those functions. OK. This is the sole justified difference
between the Library #includes here and the [LibraryClasses] section in
the INF file.
Regarding dependencies, you are including <Library/BaseLib.h> and
<Library/DebugLib.h>, but [LibraryClasses] in addition lists PcdLib.
Thus, <Library/PcdLib.h> is missing here. (You are likely getting it
included recursively, but that's not clean enough.)
> +
> +/**
> + Calculate clock frequency using CPUCFG 0x4 and 0x5 registers.
> +
> + @param VOID.
(8) This @param is useless and should be avoided, AFAICT. I think the
EccCheck plugin will not complain.
> +
> + @return The frequency in Hz.
> +
> +**/
> +UINT32
> +EFIAPI
> +CalcConstFreq (
(9) Should be STATIC, and should *not* be EFIAPI. It is not a public
library or protocol interface.
> + VOID
> + )
> +{
> + UINT32 BaseFreq;
> + UINT32 ClockMultiplier;
> + UINT32 ClockDivide;
> + CPUCFG_REG4_INFO_DATA CCFreq;
(10) Per edk2 coding style, when acronyms and abbreviations are grouped
together, each individual acronym itself is supposed to be CamelCase.
For example, when we use "PCI" in identifiers, it becomes "Pci". So I
think this variable should be called "CcFreq", where "CC" stands for
"CPU Config". If I'm wrong about "CC", then please ignore this point.
> + CPUCFG_REG5_INFO_DATA CpucfgReg5Data;
> + UINT32 StableTimerFreq;
> +
> + //
> + // Get the the crystal frequency corresponding to the constant
> + // frequency timer and the clock used by the timer.
> + //
> + AsmCpucfg (CPUCFG_REG4_INFO, &CCFreq.Uint32);
> +
> + //
> + // Get the multiplication factor and frequency division factor
> + // corresponding to the constant frequency timer and the clock
> + // used by the timer.
> + //
> + AsmCpucfg (CPUCFG_REG5_INFO, &CpucfgReg5Data.Uint32);
> +
> + BaseFreq = CCFreq.Bits.CC_FREQ;
(11) My comment here probably affects the header file where you
introduced the CC_FREQ field name. It should be CcFreq.
Same for MUL and DIV below.
> + ClockMultiplier = CpucfgReg5Data.Bits.CC_MUL & 0xFFFFULL;
> + ClockDivide = CpucfgReg5Data.Bits.CC_DIV & 0xFFFFULL;
(12) Seeing how the Uint32 members of the unions (?) are used for
populating the bitfields, the ULL suffix on the masks seems superfluous.
The results are stored to UINT32 local variables, too. 0xFFFF should
suffice.
> +
> + if (!BaseFreq || !ClockMultiplier || !ClockDivide) {
(13) The edk2 coding style does not like scalar types *other* than
BOOLEAN to be used in logical context. Please rewrite as:
(BaseFreq == 0) || (ClockMultiplier == 0) || (ClockDivide == 0)
> + DEBUG ((DEBUG_ERROR, "LoongArch Stable Timer is not available in the CPU, hence this library cannot be used.\n"));
(13) I think this line is a bit too long (117 chars). I think the
currently accepted limit (?) is 100 characters (but I'm unsure).
Recommend to break this up to multiple lines.
> + StableTimerFreq = 0;
(14) Needless assignment AFAICT.
> + ASSERT (0);
(15) Should be ASSERT (FALSE).
(16) I recommend that a CpuDeadLoop() call be added here too, because
ASSERT()s are compiled out of RELEASE builds.
> + } else {
(17) an "else" branch seems awkward here; code after ASSERT (FALSE) /
CpuDeadLoop() is supposed to be unreachable, so whatever you do here can
just be unnested.
> + StableTimerFreq = (BaseFreq * ClockMultiplier / ClockDivide);
(18) Unsafe multiplication.
ClockMultiplier is at most 0xFFFF, but BaseFreq (from CC_FREQ) may
theoretically be as high as MAX_UINT32.
- If there is a LoongArch64 specification that places a 0xFFFF limit on
CC_FREQ, then please add such an ASSERT() here.
- If there is no such specification, then cast either BaseFreq or
ClockMultiplier to UINT64. A UINT64 multiplication will not overflow
here (because MAX_UINT32 * 0xFFFF fits in 32+16=48 bits).
(19) In turn, the result of the division needs to be checked against two
boundaries:
- it must not be zero (could occur if the divisor is too large, relative
to the product). Returning zero from this function would case problems
elsewhere.
- it must fit in a UINT32. Better yet, change the return type of the
function to UINT64.
> + }
> +
> + 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, Ticks, Start, End;
> +
> + Count = (CalcConstFreq () * MicroSeconds) / 1000000;
(20) Unchecked multiplication. CalcConstFreq() may be as large as
(MAX_UINT32 * 0xFFFF / 1)
and then dependent on MicroSeconds we could overflow even a UINT64 here.
This function does not permit returning errors, so I'm not fully sure
what to do. Normally I'd recommend a safe UINT64 multiplication from
SafeIntLib (and then storing the quotient, from the division, in a UINT64).
> + Start = AsmReadStableCounter ();
> + End = Start + Count;
> +
> + do {
> + Ticks = AsmReadStableCounter ();
> + } while (Ticks < End);
The rest of this patch indicates that
(a) the performance counter is just the stable counter
(GetPerformanceCounter() simply calls AsmReadStableCounter()), and that
(b) the range is [BIT2, BIT48-1] (both sides inclusive).
(21) The problem is that this simple loop does not consider wrap-around.
We should do something like this:
RETURN_STATUS Status;
UINT64 Remaining;
UINT64 Start;
Status = SafeUint64Mult (CalcConstFreq (), MicroSeconds, &Remaining);
ASSERT_RETURN_ERROR (Status);
if (RETURN_ERROR (Status)) {
CpuDeadLoop ();
}
//
// for the given number of microseconds, the needed tick count should
// be rounded upwards
//
Status = SafeUint64Add (Remaining, 1000000 - 1, &Remaining);
ASSERT_RETURN_ERROR (Status);
if (RETURN_ERROR (Status)) {
CpuDeadLoop ();
}
Remaining = DivU64x32 (Remaining, 1000000);
Start = AsmReadStableCounter ();
while (Remaining > 0) {
UINT64 Stop;
UINT64 Diff;
Stop = AsmReadStableCounter ();
if (Start <= Stop) {
//
// no wrap-around
//
Diff = Stop - Start;
} else {
//
// wrap-around
//
Diff = (BIT48 - Start) + (Stop - BIT2);
}
Start = Stop;
Remaining -= MIN (Remaining, Diff);
}
> +
> + 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;
> + }
(22) MicroSeconds should have type UINTN.
(23) Using DivU64x32Remainder() would be more idiomatic.
(
I agree that, if we find that the remainder is nonzero, adding 1 to the
quotient is safe, for the original UINTN range too.
Initial condition:
ns <= MAX_UINTN
Divide by 1000 (mathematically):
ns/1000 <= MAX_UINTN/1000
Because floor(x) <= x, we can expand the left hand side:
floor(ns/1000) <= ns/1000 <= MAX_UINTN/1000
Drop the middle:
floor(ns/1000) <= MAX_UINTN/1000
Add 1:
floor(ns/1000) + 1 <= MAX_UINTN/1000 + 1
At the left hand side, we now have the C language result (the truncated,
then incremented, quotinent).
Now, a small detour:
1/1000 < 1
Multiply by x (assuming x>0):
x / 1000 < x
Substitute MAX_UINTN for x (MAX_UINTN is positive):
MAX_UINTN/1000 < MAX_UINTN
Then use this to expand the right hand side:
floor(ns/1000) + 1 <= MAX_UINTN/1000 + 1 < MAX_UINTN + 1
Drop the middle:
floor(ns/1000) + 1 < MAX_UINTN + 1
Given that both sides are integers, we get
floor(ns/1000) + 1 <= MAX_UINTN
which is what we needed.
)
> +
> + 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 AsmReadStableCounter ();
> +}
> +
> +/**
> + 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 CalcConstFreq ();
> +}
> +
> +/**
> + Converts elapsed ticks of performance counter to time in nanoseconds.
> +
> + This function converts the elapsed ticks of running performance counter to
> + time value in unit of nanoseconds.
> +
> + @param Ticks The number of elapsed ticks of running performance counter.
> +
> + @return The elapsed time in nanoseconds.
> +
> +**/
> +UINT64
> +EFIAPI
> +GetTimeInNanoSecond (
> + IN UINT64 Ticks
> + )
> +{
> + UINT64 Frequency;
> + UINT64 NanoSeconds;
> + UINT64 Remainder;
> + INTN Shift;
> +
> + Frequency = GetPerformanceCounterProperties (NULL, NULL);
> +
> + //
> + // Ticks
> + // Time = --------- x 1,000,000,000
> + // Frequency
> + //
> + NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
(24) I understand this is being copied from elsewhere, but the
multiplication by 10^9 should be checked against overflow, using
SafeIntLib. If we have e.g. a 100 MHz clock, then passing in
Ticks=MAX_UINT64 will lead to an overflow. :(
> +
> + //
> + // 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.
> + //
What we want here is (Remainder * 10^9 / Frequency), and in that we want
the product not to overflow 2^64 - 1. Thus, we need
Remainder * 10^9 <= 2^64 - 1
Remainder <= (2^64 - 1) / 10^9
The floor -- i.e., integral part -- of the RHS is 18,446,744,073
decimal, or 100_01001011_10000010_11111010_00001001 binary. The most
significant bit that is set is bit 34. But that's not a sufficient
condition, if we only consider the MSB in Remainder, because other bits
that should be clear (such as bit 33) could still be set. The sufficient
condition is thus that the MSB be <= 33. Therefore the comment is OK.
> + Shift = MAX (0, HighBitSet64 (Remainder) - 33);
Quirky, but correct.
If Remainder is 0, then HighBitSet64 returns -1, and we compare -34 vs.
0 -- we get zero. OK, no shift needed.
Otherwise, if HighBitSet64 returns a value in the range [0..33], then we
compare [-33..0] vs 0 -- we get zero from MAX. OK, no shift needed.
Otherwise, HighBitSet64 returns a value from the range [34..63], then we
compare [1..30] against zero, and the former prevails (gets stored to
Shift). OK.
> + Remainder = RShiftU64 (Remainder, (UINTN)Shift);
> + Frequency = RShiftU64 (Frequency, (UINTN)Shift);
I *think* this approach will ensure that Frequency is not zero.
Remainder is strictly smaller than Frequency, and we shift out only so
many LSBs from Remainder (and Frequency) that (Remainder * 10^9) below
*just* not overflow. That means Remainder should not end up being zeroed
out, and so Frequency shouldn't either (the MSB of the original
Frequency is larger than or equal to the MSB of the original Remainder). OK.
> + NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
So the RHS here may give us a proper NanoSeconds increment, but how do
we know that the addition will not overflow NanoSeconds?
Here's an example:
Ticks = 18,446,744,055,553,255,925 (0xFFFF_FFFB_C5CC_E9F5)
Frequency = 999,999,999 (0x3B9A_C9FF)
(
The idea with this example is that dividing Ticks by Frequency and then
multiplying the result with 1,000,000,000 causes a *very slight* blow-up:
Ticks / 999,999,999 * 1,000,000,000 =
Ticks * (1,000,000,000 / 999,999,999)
in such a tricky way that this blow-up:
(a) *just* doesn't overflow the first part of the function (where we use
the integral multiples of Frequency), but
(b) does overflow the last part (where we use the remaining, fractional,
multiple of Frequency).
The way to achieve that, after setting Frequency to just below 1GHz for
the above blow-up, is to start with Ticks = MAX_UINT64, perform the
division, then maximize Remainder in comprison to the divisor (i.e.,
Frequency) -- increase Remainder to (Frequency-1) --, then recalculate
Ticks from that *backwards* (increase Ticks the same as we increased
Remainder).
)
And then this happens:
- the initial DivU64x64Remainder (Ticks, Frequency, &Remainder) call
returns 18,446,744,073 (0x4_4B82_FA09) as quotient, and sets Remainder
to 999,999,998 (0x3B9A_C9FE, binary 111011_10011010_11001001_11111110).
- the first MultU64x32() call produces 18,446,744,073,000,000,000 in
NanoSeconds (0xFFFF_FFFF_D5B5_1A00).
- Remainder's MSB is bit 29, thus Shift gets assigned 0.
- Multiplying Remainder by 1,000,000,000 produces
999,999,998,000,000,000 (0xDE0_B6B3_302E_6C00). No overflow, as intended.
- Dividing that product by Frequency produces 999,999,998 (0x3B9A_C9FE)
as the *increment* for NanoSeconds.
- Adding this increment (0x3B9A_C9FE) to NanoSeconds from earlier
(0xFFFF_FFFF_D5B5_1A00) *does* overflow: the result would be
0x1_0000_0000_114F_E3FE!
(25) This proves that, generally speaking, the final "+=" operation
(increment) is unsafe -- in every TimerLib instance in edk2 that uses
this calculation --, and should be replaced with an addition from
SafeIntLib.
I'm not asking for a tree-wide fix, but using SafeIntLib here would be nice.
> +
> + return NanoSeconds;
> +}
> diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
> index 074fd77461..8e34a9cd6b 100644
> --- a/UefiCpuPkg/UefiCpuPkg.dsc
> +++ b/UefiCpuPkg/UefiCpuPkg.dsc
> @@ -205,5 +205,8 @@
> UefiCpuPkg/CpuTimerDxeRiscV64/CpuTimerDxeRiscV64.inf
> UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
>
> +[Components.LOONGARCH64]
> + UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
> +
> [BuildOptions]
> *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
(26) And then this should go into MdePkg.dec, according to points (4)
and (5) above.
Thanks
Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111613): https://edk2.groups.io/g/devel/message/111613
Mute This Topic: https://groups.io/mt/102644766/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library
2023-11-22 16:12 ` Laszlo Ersek
@ 2023-11-22 16:13 ` Laszlo Ersek
2023-11-23 11:43 ` Chao Li
1 sibling, 0 replies; 71+ messages in thread
From: Laszlo Ersek @ 2023-11-22 16:13 UTC (permalink / raw)
To: devel, lichao; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
On 11/22/23 17:12, Laszlo Ersek wrote:
> On 11/17/23 11:00, Chao Li wrote:
>> +
>> + if (!BaseFreq || !ClockMultiplier || !ClockDivide) {
>
> (13) The edk2 coding style does not like scalar types *other* than
> BOOLEAN to be used in logical context. Please rewrite as:
>
> (BaseFreq == 0) || (ClockMultiplier == 0) || (ClockDivide == 0)
>
>> + DEBUG ((DEBUG_ERROR, "LoongArch Stable Timer is not available in the CPU, hence this library cannot be used.\n"));
>
> (13) I think this line is a bit too long (117 chars). I think the
> currently accepted limit (?) is 100 characters (but I'm unsure).
>
> Recommend to break this up to multiple lines.
>
>> + StableTimerFreq = 0;
>
Sorry, this was a complex and long review; I messed up the comment
numbering -- it seems I made two points (13). :)
Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111614): https://edk2.groups.io/g/devel/message/111614
Mute This Topic: https://groups.io/mt/102644766/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library
2023-11-22 16:12 ` Laszlo Ersek
2023-11-22 16:13 ` Laszlo Ersek
@ 2023-11-23 11:43 ` Chao Li
2023-12-11 17:16 ` Laszlo Ersek
1 sibling, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-11-23 11:43 UTC (permalink / raw)
To: devel, lersek; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
[-- Attachment #1: Type: text/plain, Size: 26249 bytes --]
Hi Laszlo,
Thanks so carefully to review this patch, I'm guessing it took your a
long time. :)
Thanks,
Chao
On 2023/11/23 00:12, Laszlo Ersek wrote:
> On 11/17/23 11:00, Chao Li wrote:
>> Add the LoongArch64 CPU Timer library, using CPUCFG 0x4 and 0x5 for
>> Stable Counter frequency.
>>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Eric Dong<eric.dong@intel.com>
>> Cc: Ray Ni<ray.ni@intel.com>
>> Cc: Rahul Kumar<rahul1.kumar@intel.com>
>> Cc: Gerd Hoffmann<kraxel@redhat.com>
>> Signed-off-by: Chao Li<lichao@loongson.cn>
>> ---
>> .../BaseLoongArch64CpuTimerLib.inf | 30 +++
>> .../BaseLoongArch64CpuTimerLib.uni | 15 ++
>> .../BaseLoongArch64CpuTimerLib/CpuTimerLib.c | 226 ++++++++++++++++++
>> UefiCpuPkg/UefiCpuPkg.dsc | 3 +
>> 4 files changed, 274 insertions(+)
>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
> (1) sorry about the annoying comment, but the library should be called
> (preferably) BaseTimerLibLoongArch64Cpu.
>
> We're frequently not consistent with the following library instance
> naming scheme, but in theory anyway, library instances should be named
> as follows:
>
> <firmware module type><lib class name><library instance identifier>
>
> Thus, in this case, Base + TimerLib + LoongArch64Cpu.
>
> update UNI file name, INF file name, directory name, BASE_NAME and
> MODULE_UNI_FILE accordingly (if you agree)
There has a SPEC for naming style:
https://github.com/tianocore-docs/edk2-CCodingStandardsSpecification/blob/master/4_naming_conventions/42_directory_names.md
Please check 4.2.3 EDKII Library directory, and most directory naming
follows this SPEC.
>
>> diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
>> new file mode 100644
>> index 0000000000..c00c215aec
>> --- /dev/null
>> +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
>> @@ -0,0 +1,30 @@
>> +## @file
>> +# Base CPU Timer Library
>> +#
>> +# Provides base timer support using CPUCFG 0x4 and 0x5 stable counter frequency.
>> +#
>> +# Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
> (2) Can you use the most recent INF file version? (Generally applies to
> all new INF files in the series.)
>
> The latest version is 1.29
> <https://tianocore-docs.github.io/edk2-InfSpecification/draft/>, and you
> can just write "1.29" here.
OK, I will update this version, include all new INF files for this series.
>
>> + BASE_NAME = BaseLoongArch64CpuTimerLib
>> + FILE_GUID = 740389C7-CC44-4A2F-88DC-89D97D312E7C
>> + MODULE_TYPE = BASE
>> + VERSION_STRING = 1.0
>> + LIBRARY_CLASS = TimerLib
>> + MODULE_UNI_FILE = BaseLoongArch64CpuTimerLib.uni
>> +
>> +[Sources.common]
>> + CpuTimerLib.c
> (3) ".common" is not an error, but superfluous here.
Yes, I will remove it in V4.
>
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> + UefiCpuPkg/UefiCpuPkg.dec
> (4) Do you actually consume any artifact from "UefiCpuPkg.dec"?
>
> Unless you do, there's no need to depend on "UefiCpuPkg.dec" here.
Yes, the UefiCpuPkg.dec is indeed not necessary, so I will remove it in
this file for V4.
>
> (5) Relatedly: the TimerLib class is declared in "MdePkg.dec". Thus, if
> you indeed don't need anything from "UefiCpuPkg.dec", I'd suggest moving
> this library instance under MdePkg.
It is inappropriate to place this library in MdePkg, because the MdePkg
doesn't have any CpuTimerLib instance, and this class library are HW
implementation-related, so it more appropriate to place it in UefiCpuPkg.
>
>> +
>> +[LibraryClasses]
>> + BaseLib
>> + PcdLib
>> + DebugLib
> (6) If it's not too much of a burden, it's best to keep library classes
> alphabetically sorted.
OK, I will sort them for V4.
>
>> diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
>> new file mode 100644
>> index 0000000000..72d38ec679
>> --- /dev/null
>> +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
>> @@ -0,0 +1,15 @@
>> +// /** @file
>> +// Base CPU Timer Library
>> +//
>> +// Provides base timer support using CPUCFG 0x4 and 0x5 stable counter frequency.
>> +//
>> +// Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +//
>> +// SPDX-License-Identifier: BSD-2-Clause-Patent
>> +//
>> +// **/
>> +
>> +
>> +#string STR_MODULE_ABSTRACT #language en-US "LOONGARCH CPU Timer Library"
>> +
>> +#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUCFG 0x4 and 0x5 stable counter frequency."
>> diff --git a/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
>> new file mode 100644
>> index 0000000000..349b881cbc
>> --- /dev/null
>> +++ b/UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
>> @@ -0,0 +1,226 @@
>> +/** @file
>> + CPUCFG 0x4 and 0x5 for Stable Counter frequency instance of Timer Library.
>> +
>> + Copyright (c) 2023, Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include <Base.h>
>> +#include <Library/TimerLib.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Register/LoongArch64/Cpucfg.h>
> (7) It's best to keep the Library includes in sync with the
> [LibraryClasses] section from the INF file.
>
> (And to keep the #include directives alphabetically sorted as well.)
>
> You are including <Library/TimerLib.h> here because the file is going to
> define those functions. OK. This is the sole justified difference
> between the Library #includes here and the [LibraryClasses] section in
> the INF file.
>
> Regarding dependencies, you are including <Library/BaseLib.h> and
> <Library/DebugLib.h>, but [LibraryClasses] in addition lists PcdLib.
> Thus, <Library/PcdLib.h> is missing here. (You are likely getting it
> included recursively, but that's not clean enough.)
OK, I see, I will sort them and keep them in sync with corresponding
libraries.
>
>> +
>> +/**
>> + Calculate clock frequency using CPUCFG 0x4 and 0x5 registers.
>> +
>> + @param VOID.
> (8) This @param is useless and should be avoided, AFAICT. I think the
> EccCheck plugin will not complain.
The EccCheck already passed... Any way, I will remove it in V4.
>
>> +
>> + @return The frequency in Hz.
>> +
>> +**/
>> +UINT32
>> +EFIAPI
>> +CalcConstFreq (
> (9) Should be STATIC, and should *not* be EFIAPI. It is not a public
> library or protocol interface.
I will fix it in V4.
>
>> + VOID
>> + )
>> +{
>> + UINT32 BaseFreq;
>> + UINT32 ClockMultiplier;
>> + UINT32 ClockDivide;
>> + CPUCFG_REG4_INFO_DATA CCFreq;
> (10) Per edk2 coding style, when acronyms and abbreviations are grouped
> together, each individual acronym itself is supposed to be CamelCase.
> For example, when we use "PCI" in identifiers, it becomes "Pci". So I
> think this variable should be called "CcFreq", where "CC" stands for
> "CPU Config". If I'm wrong about "CC", then please ignore this point.
The two letter 'C' means: first 'C' means Constant, and the second means
Crystal. In LoongArch SPEC, this area is named CC_FREQ, which means:
Constant frequency timer and the crystal frequency corresponding to the
clock used by the timer. So I think CCFreq is more suitable.
>
>> + CPUCFG_REG5_INFO_DATA CpucfgReg5Data;
>> + UINT32 StableTimerFreq;
>> +
>> + //
>> + // Get the the crystal frequency corresponding to the constant
>> + // frequency timer and the clock used by the timer.
>> + //
>> + AsmCpucfg (CPUCFG_REG4_INFO, &CCFreq.Uint32);
>> +
>> + //
>> + // Get the multiplication factor and frequency division factor
>> + // corresponding to the constant frequency timer and the clock
>> + // used by the timer.
>> + //
>> + AsmCpucfg (CPUCFG_REG5_INFO, &CpucfgReg5Data.Uint32);
>> +
>> + BaseFreq = CCFreq.Bits.CC_FREQ;
> (11) My comment here probably affects the header file where you
> introduced the CC_FREQ field name. It should be CcFreq.
>
> Same for MUL and DIV below.
The same to above.
>
>> + ClockMultiplier = CpucfgReg5Data.Bits.CC_MUL & 0xFFFFULL;
>> + ClockDivide = CpucfgReg5Data.Bits.CC_DIV & 0xFFFFULL;
> (12) Seeing how the Uint32 members of the unions (?) are used for
> populating the bitfields, the ULL suffix on the masks seems superfluous.
> The results are stored to UINT32 local variables, too. 0xFFFF should
> suffice.
Yes, the ULL does seem redundant, the UINT32 means unsigned INT32 and
0xFFFF shoud be unsigned, I thought when I wrote this code, ULL was
added to ensure that the value was unsigned.
>
>> +
>> + if (!BaseFreq || !ClockMultiplier || !ClockDivide) {
> (13) The edk2 coding style does not like scalar types *other* than
> BOOLEAN to be used in logical context. Please rewrite as:
>
> (BaseFreq == 0) || (ClockMultiplier == 0) || (ClockDivide == 0)
>
>> + DEBUG ((DEBUG_ERROR, "LoongArch Stable Timer is not available in the CPU, hence this library cannot be used.\n"));
> (13) I think this line is a bit too long (117 chars). I think the
> currently accepted limit (?) is 100 characters (but I'm unsure).
>
> Recommend to break this up to multiple lines.
>
>> + StableTimerFreq = 0;
> (14) Needless assignment AFAICT.
>
>> + ASSERT (0);
> (15) Should be ASSERT (FALSE).
>
> (16) I recommend that a CpuDeadLoop() call be added here too, because
> ASSERT()s are compiled out of RELEASE builds.
>
>> + } else {
> (17) an "else" branch seems awkward here; code after ASSERT (FALSE) /
> CpuDeadLoop() is supposed to be unreachable, so whatever you do here can
> just be unnested.
For double (13), (14), (15), (16) and (17), I agree, will fix them in
V4. But for 15, did the CpuDeadLoop() be needed? I think if the DEBUG
mode doesn't work, the RELEASE mode can not be created.
>
>> + StableTimerFreq = (BaseFreq * ClockMultiplier / ClockDivide);
> (18) Unsafe multiplication.
>
> ClockMultiplier is at most 0xFFFF, but BaseFreq (from CC_FREQ) may
> theoretically be as high as MAX_UINT32.
>
> - If there is a LoongArch64 specification that places a 0xFFFF limit on
> CC_FREQ, then please add such an ASSERT() here.
>
> - If there is no such specification, then cast either BaseFreq or
> ClockMultiplier to UINT64. A UINT64 multiplication will not overflow
> here (because MAX_UINT32 * 0xFFFF fits in 32+16=48 bits).
Yes, you are right, there is a risk of overflow, I think changing the
ClockMultiplier to UINT64 would do the trick, or force transferring the
result to ensure it doesn't overflow? Something like: ((UINT64)(BaseFreq
* ClockMultiplier) / ClockDivide).
>
>
> (19) In turn, the result of the division needs to be checked against two
> boundaries:
>
> - it must not be zero (could occur if the divisor is too large, relative
> to the product). Returning zero from this function would case problems
> elsewhere.
I will ASSERT here if the result is zero.
>
> - it must fit in a UINT32. Better yet, change the return type of the
> function to UINT64.
Agree.
>
>
>> + }
>> +
>> + 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, Ticks, Start, End;
>> +
>> + Count = (CalcConstFreq () * MicroSeconds) / 1000000;
> (20) Unchecked multiplication. CalcConstFreq() may be as large as
>
> (MAX_UINT32 * 0xFFFF / 1)
>
> and then dependent on MicroSeconds we could overflow even a UINT64 here.
>
> This function does not permit returning errors, so I'm not fully sure
> what to do. Normally I'd recommend a safe UINT64 multiplication from
> SafeIntLib (and then storing the quotient, from the division, in a UINT64).
OK, I will use the SafeIntLib here.
>
>> + Start = AsmReadStableCounter ();
>> + End = Start + Count;
>> +
>> + do {
>> + Ticks = AsmReadStableCounter ();
>> + } while (Ticks < End);
> The rest of this patch indicates that
>
> (a) the performance counter is just the stable counter
> (GetPerformanceCounter() simply calls AsmReadStableCounter()), and that
>
> (b) the range is [BIT2, BIT48-1] (both sides inclusive).
Sorry, The PerformanceCounter function series are updated in our
internal, I will update them in V4. I would say, the performance counter
is not same to stable counter, and the stable count in LoongArch64 are
64 bits wide, so no warparound occurs. PLS wait for V4.
>
> (21) The problem is that this simple loop does not consider wrap-around.
>
> We should do something like this:
>
> RETURN_STATUS Status;
> UINT64 Remaining;
> UINT64 Start;
>
> Status = SafeUint64Mult (CalcConstFreq (), MicroSeconds, &Remaining);
> ASSERT_RETURN_ERROR (Status);
> if (RETURN_ERROR (Status)) {
> CpuDeadLoop ();
> }
>
> //
> // for the given number of microseconds, the needed tick count should
> // be rounded upwards
> //
> Status = SafeUint64Add (Remaining, 1000000 - 1, &Remaining);
> ASSERT_RETURN_ERROR (Status);
> if (RETURN_ERROR (Status)) {
> CpuDeadLoop ();
> }
>
> Remaining = DivU64x32 (Remaining, 1000000);
> Start = AsmReadStableCounter ();
>
> while (Remaining > 0) {
> UINT64 Stop;
> UINT64 Diff;
>
> Stop = AsmReadStableCounter ();
>
> if (Start <= Stop) {
> //
> // no wrap-around
> //
> Diff = Stop - Start;
> } else {
> //
> // wrap-around
> //
> Diff = (BIT48 - Start) + (Stop - BIT2);
> }
>
> Start = Stop;
>
> Remaining -= MIN (Remaining, Diff);
> }
Refer to above.
>
>> +
>> + 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;
>> + }
> (22) MicroSeconds should have type UINTN.
Agree.
>
> (23) Using DivU64x32Remainder() would be more idiomatic.
>
> (
>
> I agree that, if we find that the remainder is nonzero, adding 1 to the
> quotient is safe, for the original UINTN range too.
>
> Initial condition:
>
> ns <= MAX_UINTN
>
> Divide by 1000 (mathematically):
>
> ns/1000 <= MAX_UINTN/1000
>
> Because floor(x) <= x, we can expand the left hand side:
>
> floor(ns/1000) <= ns/1000 <= MAX_UINTN/1000
>
> Drop the middle:
>
> floor(ns/1000) <= MAX_UINTN/1000
>
> Add 1:
>
> floor(ns/1000) + 1 <= MAX_UINTN/1000 + 1
>
> At the left hand side, we now have the C language result (the truncated,
> then incremented, quotinent).
>
> Now, a small detour:
>
> 1/1000 < 1
>
> Multiply by x (assuming x>0):
>
> x / 1000 < x
>
> Substitute MAX_UINTN for x (MAX_UINTN is positive):
>
> MAX_UINTN/1000 < MAX_UINTN
>
> Then use this to expand the right hand side:
>
> floor(ns/1000) + 1 <= MAX_UINTN/1000 + 1 < MAX_UINTN + 1
>
> Drop the middle:
>
> floor(ns/1000) + 1 < MAX_UINTN + 1
>
> Given that both sides are integers, we get
>
> floor(ns/1000) + 1 <= MAX_UINTN
>
> which is what we needed.
>
> )
OK, I see. In V4, I will use the DivU64X32Remainder() to change this
operation.
>
>> +
>> + 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 AsmReadStableCounter ();
>> +}
>> +
>> +/**
>> + 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 CalcConstFreq ();
>> +}
>> +
>> +/**
>> + Converts elapsed ticks of performance counter to time in nanoseconds.
>> +
>> + This function converts the elapsed ticks of running performance counter to
>> + time value in unit of nanoseconds.
>> +
>> + @param Ticks The number of elapsed ticks of running performance counter.
>> +
>> + @return The elapsed time in nanoseconds.
>> +
>> +**/
>> +UINT64
>> +EFIAPI
>> +GetTimeInNanoSecond (
>> + IN UINT64 Ticks
>> + )
>> +{
>> + UINT64 Frequency;
>> + UINT64 NanoSeconds;
>> + UINT64 Remainder;
>> + INTN Shift;
>> +
>> + Frequency = GetPerformanceCounterProperties (NULL, NULL);
>> +
>> + //
>> + // Ticks
>> + // Time = --------- x 1,000,000,000
>> + // Frequency
>> + //
>> + NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
> (24) I understand this is being copied from elsewhere, but the
> multiplication by 10^9 should be checked against overflow, using
> SafeIntLib. If we have e.g. a 100 MHz clock, then passing in
> Ticks=MAX_UINT64 will lead to an overflow. :(
OK, in V4, I will use the SafeIntLib.
>
>> +
>> + //
>> + // 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.
>> + //
> What we want here is (Remainder * 10^9 / Frequency), and in that we want
> the product not to overflow 2^64 - 1. Thus, we need
>
> Remainder * 10^9 <= 2^64 - 1
>
> Remainder <= (2^64 - 1) / 10^9
>
> The floor -- i.e., integral part -- of the RHS is 18,446,744,073
> decimal, or 100_01001011_10000010_11111010_00001001 binary. The most
> significant bit that is set is bit 34. But that's not a sufficient
> condition, if we only consider the MSB in Remainder, because other bits
> that should be clear (such as bit 33) could still be set. The sufficient
> condition is thus that the MSB be <= 33. Therefore the comment is OK.
>
>> + Shift = MAX (0, HighBitSet64 (Remainder) - 33);
> Quirky, but correct.
>
> If Remainder is 0, then HighBitSet64 returns -1, and we compare -34 vs.
> 0 -- we get zero. OK, no shift needed.
>
> Otherwise, if HighBitSet64 returns a value in the range [0..33], then we
> compare [-33..0] vs 0 -- we get zero from MAX. OK, no shift needed.
>
> Otherwise, HighBitSet64 returns a value from the range [34..63], then we
> compare [1..30] against zero, and the former prevails (gets stored to
> Shift). OK.
>
>> + Remainder = RShiftU64 (Remainder, (UINTN)Shift);
>> + Frequency = RShiftU64 (Frequency, (UINTN)Shift);
> I *think* this approach will ensure that Frequency is not zero.
> Remainder is strictly smaller than Frequency, and we shift out only so
> many LSBs from Remainder (and Frequency) that (Remainder * 10^9) below
> *just* not overflow. That means Remainder should not end up being zeroed
> out, and so Frequency shouldn't either (the MSB of the original
> Frequency is larger than or equal to the MSB of the original Remainder). OK.
>
>> + NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
> So the RHS here may give us a proper NanoSeconds increment, but how do
> we know that the addition will not overflow NanoSeconds?
>
> Here's an example:
>
> Ticks = 18,446,744,055,553,255,925 (0xFFFF_FFFB_C5CC_E9F5)
> Frequency = 999,999,999 (0x3B9A_C9FF)
>
> (
>
> The idea with this example is that dividing Ticks by Frequency and then
> multiplying the result with 1,000,000,000 causes a *very slight* blow-up:
>
> Ticks / 999,999,999 * 1,000,000,000 =
> Ticks * (1,000,000,000 / 999,999,999)
>
> in such a tricky way that this blow-up:
>
> (a) *just* doesn't overflow the first part of the function (where we use
> the integral multiples of Frequency), but
>
> (b) does overflow the last part (where we use the remaining, fractional,
> multiple of Frequency).
>
> The way to achieve that, after setting Frequency to just below 1GHz for
> the above blow-up, is to start with Ticks = MAX_UINT64, perform the
> division, then maximize Remainder in comprison to the divisor (i.e.,
> Frequency) -- increase Remainder to (Frequency-1) --, then recalculate
> Ticks from that *backwards* (increase Ticks the same as we increased
> Remainder).
>
> )
>
> And then this happens:
>
> - the initial DivU64x64Remainder (Ticks, Frequency, &Remainder) call
> returns 18,446,744,073 (0x4_4B82_FA09) as quotient, and sets Remainder
> to 999,999,998 (0x3B9A_C9FE, binary 111011_10011010_11001001_11111110).
>
> - the first MultU64x32() call produces 18,446,744,073,000,000,000 in
> NanoSeconds (0xFFFF_FFFF_D5B5_1A00).
>
> - Remainder's MSB is bit 29, thus Shift gets assigned 0.
>
> - Multiplying Remainder by 1,000,000,000 produces
> 999,999,998,000,000,000 (0xDE0_B6B3_302E_6C00). No overflow, as intended.
>
> - Dividing that product by Frequency produces 999,999,998 (0x3B9A_C9FE)
> as the *increment* for NanoSeconds.
>
> - Adding this increment (0x3B9A_C9FE) to NanoSeconds from earlier
> (0xFFFF_FFFF_D5B5_1A00) *does* overflow: the result would be
> 0x1_0000_0000_114F_E3FE!
>
> (25) This proves that, generally speaking, the final "+=" operation
> (increment) is unsafe -- in every TimerLib instance in edk2 that uses
> this calculation --, and should be replaced with an addition from
> SafeIntLib.
Do you recommend changing the final "+=" to the SafeIntLib way?
Something like: NanoSeconds = SafeUint64Add (NanoSeconds,
DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency,
NULL), &NanoSeconds).
>
> I'm not asking for a tree-wide fix, but using SafeIntLib here would be nice.
>
>
>> +
>> + return NanoSeconds;
>> +}
>> diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
>> index 074fd77461..8e34a9cd6b 100644
>> --- a/UefiCpuPkg/UefiCpuPkg.dsc
>> +++ b/UefiCpuPkg/UefiCpuPkg.dsc
>> @@ -205,5 +205,8 @@
>> UefiCpuPkg/CpuTimerDxeRiscV64/CpuTimerDxeRiscV64.inf
>> UefiCpuPkg/CpuDxeRiscV64/CpuDxeRiscV64.inf
>>
>> +[Components.LOONGARCH64]
>> + UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
>> +
>> [BuildOptions]
>> *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
> (26) And then this should go into MdePkg.dec, according to points (4)
> and (5) above.
Same to above.
>
> Thanks
> Laszlo
>
>
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111667): https://edk2.groups.io/g/devel/message/111667
Mute This Topic: https://groups.io/mt/102644766/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 33980 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
2023-11-22 1:47 ` Chao Li
@ 2023-11-24 11:35 ` Laszlo Ersek
2023-11-27 3:27 ` Chao Li
[not found] ` <179B5D231F190982.32091@groups.io>
0 siblings, 2 replies; 71+ messages in thread
From: Laszlo Ersek @ 2023-11-24 11:35 UTC (permalink / raw)
To: Chao Li, devel
Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L
On 11/22/23 02:47, Chao Li wrote:
> Hi Laszlo,
>
>
> Thanks,
> Chao
> On 2023/11/21 22:37, Laszlo Ersek wrote:
>> On 11/17/23 10:59, Chao Li wrote:
>>> Since some ARCH or platform not require execute code on memory during
>>> PEI phase, some values may transferred via CPU registers.
>>>
>>> Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
>>> table pointer depend by a CPU register, this library can accommodate lot
>>> of platforms who not require execte code on memory during PEI phase.
>>>
>>> Adding PeiServiceTablePointerLibReg to allows setting and getting the
>>> PEI service table pointer via CPU registers, and the library can
>>> accommodate many platforms that do not need to execute code on memory
>>> during the PEI phase.
>>>
>>> The idea of this library is derived from
>>> ArmPkg/Library/PeiServicesTablePointerLib/
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>>
>>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>> Cc: Liming Gao <gaoliming@byosoft.com.cn>
>>> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
>>> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
>>> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
>>> Cc: Sami Mujawar <sami.mujawar@arm.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>> Cc: Sunil V L <sunilvl@ventanamicro.com>
>>> Signed-off-by: Chao Li <lichao@loongson.cn>
>>> ---
>>> .../Library/PeiServicesTablePointerLib.h | 37 +++++++-
>>> .../PeiServicesTablePointer.c | 86 +++++++++++++++++++
>>> .../PeiServicesTablePointerLib.uni | 20 +++++
>>> .../PeiServicesTablePointerLibReg.inf | 40 +++++++++
>>> MdePkg/MdePkg.dsc | 1 +
>>> 5 files changed, 180 insertions(+), 4 deletions(-)
>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>> In my opinion, the PeiServicesTablePointerLib class header should not be
>> extended with new interfaces. I understand that the generality is
>> attractive, but it is not put to use; only the loongarch architecture
>> applies the new interfaces (in the subsequent patch), and for example
>> the ARM code (ArmPkg/Library/PeiServicesTablePointerLib) is not reworked
>> in terms of these new interfaces.
>
> This libarary have ability of accommodate more ARCH why not? I checked
> the PI SPEC, all ARCH except IA32 and X64 using the register mechanism,
> if this library can be approved, all of them can moved into this
> libraryso that code con be reused more, I think this library is fine.
The library may be fine from a design point of view, but without
actually putting the extra generality to use, it's a waste. It's a
maintenance burden. There's a name for this anti-pattern: it is called
"speculative generality". "It might be useful down the road."
The new generality is only useful if it carries its own weight; namely,
if other platform code (aarch64, x64) is converted to it immediately, in
the same series. (I'm not asking for this series to be longer. You could
even split it up into multiple "waves" of series.) Just saying that
"could prove useful later" is a prime way to generate technical debt.
>
>> What's more, the new library interfaces, even though they are exposed in
>> the lib class header, are not implemented for other architectures, so
>> they aren't even callable on those arches.
> The patch 10 in this series has added LoongArch instance of this
> library, please check.
Yes, I'm aware. That's not the point.
When you extend a library *class* with a new API, that means all
*clients* of the library class can stat calling that API. Which in turn
means that *all* existent instances of the library class must implement
the API as well.
Your series extends the lib class with a new API, but (IIUC) only
implements the new API in one (new) lib instance, and not in the other
(existent) instances. This has the potential to cause linkage errors,
dependent on the actual library instance that a platform DSC chooses.
>> I'm commenting on this patch and the subsequent patch in the series
>> together, as seen squashed together. NB I'm not an MdePkg maintainer, so
>> this is just my opinion.
> So, Mike and Liming, what do your think?
>> (1) As noted above, the library class should not be modified.
>>
>> (2) Modifying the *comments* in
>> "MdePkg/Include/Library/PeiServicesTablePointerLib.h" is welcome, I
>> think, but then we might want to add a (separate!) patch for removing
>> the Itanium language, as edk2 no longer supports Itanium.
>>
>> (3) The PeiServicesTablePointerLibReg instance should be called
>> PeiServicesTablePointerLibCsrKs0 or just PeiServicesTablePointerLibKs0.
> This library will be a public libray which using the reigster mechanism,
> so the name like PeiServiceTablePointerLibCsrKs0 would not appropriate.
Of course that name is wrong for a generic library instance, but my
whole point is that this library instance should be loongarch-specific.
(Unless you port the existent (x64 IDT / aarch64 register) libraries
over to it.)
>> This follows the example of the lib instance name
>> "PeiServicesTablePointerLibIdt". The whole library instance should be
>> loongaarch-specific IMO; there isn't much code that's being duplicated,
>> so the extra interfaces (internal or external) do not help with code
>> unification.
>>
>> (4) "PeiServicesTablePointerLib.uni" should be named similarly (suffix
>> missing).
>>
>> (5) BASE_NAME in the library instance INF file should be defined
>> similarly (suffix missing).
>>
>> (6) The contents of the UNI file should be loongarch-specific, i.e. be
>> explicit about CSR KS0, in both comments and string constants.
>>
>> (7) The comments in the library instance INF file should be similarly
>> loongarch-specific.
>>
>> (8) I suggest dropping VALID_ARCHITECTURES altogether. If we want to
>> keep it, it should exclusively say LOONGARCH64.
>>
>> (9) The new library instance should be listed in
>> [Components.LOONGARCH64] in MdePkg.dec.
>>
>> This section does not exist yet; I suggest introducing it under
>> [Components.RISCV64].
> No, it is RISC-V area, not LOONGARCH64.
You misunderstood.
I didn't suggest to list the *library instance* under [Components.RISCV64].
I suggested to introduce the [Components.LOONGARCH64] *section* under
[Components.RISCV64].
> And I do not recommend going
> this way. I believe this library should be a public library for register
> mechanism.
That's entirely fine, as long as you do the work of porting the existent
ARM and X64 IDT code over to it. In my opinion anyway; MdePkg
maintainers are the authoritative sources here.
Laszlo
>> (10) There need not / should not be two separate C source files; just
>> access the KS0 CSR in SetPeiServicesTablePointer() and
>> GetPeiServicesTablePointer() directly.
>>
>> (11) The new library instance should probably not introduce new
>> references to Itanium.
>>
>> Thanks,
>> Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111700): https://edk2.groups.io/g/devel/message/111700
Mute This Topic: https://groups.io/mt/102644754/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
2023-11-24 11:35 ` Laszlo Ersek
@ 2023-11-27 3:27 ` Chao Li
2023-12-01 0:32 ` 回复: " gaoliming via groups.io
[not found] ` <179B5D231F190982.32091@groups.io>
1 sibling, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-11-27 3:27 UTC (permalink / raw)
To: Laszlo Ersek, devel
Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L
[-- Attachment #1: Type: text/plain, Size: 8061 bytes --]
Hi Mike and Liming,
You opinion is very important, it will decide the direction. I will send
the V4 this week, so can you please review the new patch of MdePkg for
this series?
Thanks,
Chao
On 2023/11/24 19:35, Laszlo Ersek wrote:
> On 11/22/23 02:47, Chao Li wrote:
>> Hi Laszlo,
>>
>>
>> Thanks,
>> Chao
>> On 2023/11/21 22:37, Laszlo Ersek wrote:
>>> On 11/17/23 10:59, Chao Li wrote:
>>>> Since some ARCH or platform not require execute code on memory during
>>>> PEI phase, some values may transferred via CPU registers.
>>>>
>>>> Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
>>>> table pointer depend by a CPU register, this library can accommodate lot
>>>> of platforms who not require execte code on memory during PEI phase.
>>>>
>>>> Adding PeiServiceTablePointerLibReg to allows setting and getting the
>>>> PEI service table pointer via CPU registers, and the library can
>>>> accommodate many platforms that do not need to execute code on memory
>>>> during the PEI phase.
>>>>
>>>> The idea of this library is derived from
>>>> ArmPkg/Library/PeiServicesTablePointerLib/
>>>>
>>>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>>>
>>>> Cc: Michael D Kinney<michael.d.kinney@intel.com>
>>>> Cc: Liming Gao<gaoliming@byosoft.com.cn>
>>>> Cc: Zhiguang Liu<zhiguang.liu@intel.com>
>>>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>>>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>>>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>>>> Cc: Laszlo Ersek<lersek@redhat.com>
>>>> Cc: Sunil V L<sunilvl@ventanamicro.com>
>>>> Signed-off-by: Chao Li<lichao@loongson.cn>
>>>> ---
>>>> .../Library/PeiServicesTablePointerLib.h | 37 +++++++-
>>>> .../PeiServicesTablePointer.c | 86 +++++++++++++++++++
>>>> .../PeiServicesTablePointerLib.uni | 20 +++++
>>>> .../PeiServicesTablePointerLibReg.inf | 40 +++++++++
>>>> MdePkg/MdePkg.dsc | 1 +
>>>> 5 files changed, 180 insertions(+), 4 deletions(-)
>>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
>>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
>>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>>> In my opinion, the PeiServicesTablePointerLib class header should not be
>>> extended with new interfaces. I understand that the generality is
>>> attractive, but it is not put to use; only the loongarch architecture
>>> applies the new interfaces (in the subsequent patch), and for example
>>> the ARM code (ArmPkg/Library/PeiServicesTablePointerLib) is not reworked
>>> in terms of these new interfaces.
>> This libarary have ability of accommodate more ARCH why not? I checked
>> the PI SPEC, all ARCH except IA32 and X64 using the register mechanism,
>> if this library can be approved, all of them can moved into this
>> libraryso that code con be reused more, I think this library is fine.
> The library may be fine from a design point of view, but without
> actually putting the extra generality to use, it's a waste. It's a
> maintenance burden. There's a name for this anti-pattern: it is called
> "speculative generality". "It might be useful down the road."
>
> The new generality is only useful if it carries its own weight; namely,
> if other platform code (aarch64, x64) is converted to it immediately, in
> the same series. (I'm not asking for this series to be longer. You could
> even split it up into multiple "waves" of series.) Just saying that
> "could prove useful later" is a prime way to generate technical debt.
>
>>> What's more, the new library interfaces, even though they are exposed in
>>> the lib class header, are not implemented for other architectures, so
>>> they aren't even callable on those arches.
>> The patch 10 in this series has added LoongArch instance of this
>> library, please check.
> Yes, I'm aware. That's not the point.
>
> When you extend a library *class* with a new API, that means all
> *clients* of the library class can stat calling that API. Which in turn
> means that *all* existent instances of the library class must implement
> the API as well.
>
> Your series extends the lib class with a new API, but (IIUC) only
> implements the new API in one (new) lib instance, and not in the other
> (existent) instances. This has the potential to cause linkage errors,
> dependent on the actual library instance that a platform DSC chooses.
>
>
>>> I'm commenting on this patch and the subsequent patch in the series
>>> together, as seen squashed together. NB I'm not an MdePkg maintainer, so
>>> this is just my opinion.
>> So, Mike and Liming, what do your think?
>>> (1) As noted above, the library class should not be modified.
>>>
>>> (2) Modifying the *comments* in
>>> "MdePkg/Include/Library/PeiServicesTablePointerLib.h" is welcome, I
>>> think, but then we might want to add a (separate!) patch for removing
>>> the Itanium language, as edk2 no longer supports Itanium.
>>>
>>> (3) The PeiServicesTablePointerLibReg instance should be called
>>> PeiServicesTablePointerLibCsrKs0 or just PeiServicesTablePointerLibKs0.
>> This library will be a public libray which using the reigster mechanism,
>> so the name like PeiServiceTablePointerLibCsrKs0 would not appropriate.
> Of course that name is wrong for a generic library instance, but my
> whole point is that this library instance should be loongarch-specific.
>
> (Unless you port the existent (x64 IDT / aarch64 register) libraries
> over to it.)
>
>>> This follows the example of the lib instance name
>>> "PeiServicesTablePointerLibIdt". The whole library instance should be
>>> loongaarch-specific IMO; there isn't much code that's being duplicated,
>>> so the extra interfaces (internal or external) do not help with code
>>> unification.
>>>
>>> (4) "PeiServicesTablePointerLib.uni" should be named similarly (suffix
>>> missing).
>>>
>>> (5) BASE_NAME in the library instance INF file should be defined
>>> similarly (suffix missing).
>>>
>>> (6) The contents of the UNI file should be loongarch-specific, i.e. be
>>> explicit about CSR KS0, in both comments and string constants.
>>>
>>> (7) The comments in the library instance INF file should be similarly
>>> loongarch-specific.
>>>
>>> (8) I suggest dropping VALID_ARCHITECTURES altogether. If we want to
>>> keep it, it should exclusively say LOONGARCH64.
>>>
>>> (9) The new library instance should be listed in
>>> [Components.LOONGARCH64] in MdePkg.dec.
>>>
>>> This section does not exist yet; I suggest introducing it under
>>> [Components.RISCV64].
>> No, it is RISC-V area, not LOONGARCH64.
> You misunderstood.
>
> I didn't suggest to list the *library instance* under [Components.RISCV64].
>
> I suggested to introduce the [Components.LOONGARCH64] *section* under
> [Components.RISCV64].
>
>> And I do not recommend going
>> this way. I believe this library should be a public library for register
>> mechanism.
> That's entirely fine, as long as you do the work of porting the existent
> ARM and X64 IDT code over to it. In my opinion anyway; MdePkg
> maintainers are the authoritative sources here.
>
> Laszlo
>
>>> (10) There need not / should not be two separate C source files; just
>>> access the KS0 CSR in SetPeiServicesTablePointer() and
>>> GetPeiServicesTablePointer() directly.
>>>
>>> (11) The new library instance should probably not introduce new
>>> references to Itanium.
>>>
>>> Thanks,
>>> Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111712): https://edk2.groups.io/g/devel/message/111712
Mute This Topic: https://groups.io/mt/102644754/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 11323 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
[not found] ` <179B5D231F190982.32091@groups.io>
@ 2023-11-29 1:35 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-29 1:35 UTC (permalink / raw)
To: devel, Michael D Kinney, Liming Gao
Cc: Zhiguang Liu, Leif Lindholm, Ard Biesheuvel, Sami Mujawar,
Sunil V L, Laszlo Ersek
[-- Attachment #1: Type: text/plain, Size: 8485 bytes --]
Hi Mike and Liming,
Ping for review, I'd love to know your opinion, as the last email saied,
your opinion can decide the direction, so please review the new patches
of MdePkg for this series, please...
Thanks,
Chao
On 2023/11/27 11:27, Chao Li wrote:
>
> Hi Mike and Liming,
>
> You opinion is very important, it will decide the direction. I will
> send the V4 this week, so can you please review the new patch of
> MdePkg for this series?
>
> On 2023/11/24 19:35, Laszlo Ersek wrote:
>> On 11/22/23 02:47, Chao Li wrote:
>>> Hi Laszlo,
>>>
>>>
>>> Thanks,
>>> Chao
>>> On 2023/11/21 22:37, Laszlo Ersek wrote:
>>>> On 11/17/23 10:59, Chao Li wrote:
>>>>> Since some ARCH or platform not require execute code on memory during
>>>>> PEI phase, some values may transferred via CPU registers.
>>>>>
>>>>> Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
>>>>> table pointer depend by a CPU register, this library can accommodate lot
>>>>> of platforms who not require execte code on memory during PEI phase.
>>>>>
>>>>> Adding PeiServiceTablePointerLibReg to allows setting and getting the
>>>>> PEI service table pointer via CPU registers, and the library can
>>>>> accommodate many platforms that do not need to execute code on memory
>>>>> during the PEI phase.
>>>>>
>>>>> The idea of this library is derived from
>>>>> ArmPkg/Library/PeiServicesTablePointerLib/
>>>>>
>>>>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>>>>
>>>>> Cc: Michael D Kinney<michael.d.kinney@intel.com>
>>>>> Cc: Liming Gao<gaoliming@byosoft.com.cn>
>>>>> Cc: Zhiguang Liu<zhiguang.liu@intel.com>
>>>>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>>>>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>>>>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>>>>> Cc: Laszlo Ersek<lersek@redhat.com>
>>>>> Cc: Sunil V L<sunilvl@ventanamicro.com>
>>>>> Signed-off-by: Chao Li<lichao@loongson.cn>
>>>>> ---
>>>>> .../Library/PeiServicesTablePointerLib.h | 37 +++++++-
>>>>> .../PeiServicesTablePointer.c | 86 +++++++++++++++++++
>>>>> .../PeiServicesTablePointerLib.uni | 20 +++++
>>>>> .../PeiServicesTablePointerLibReg.inf | 40 +++++++++
>>>>> MdePkg/MdePkg.dsc | 1 +
>>>>> 5 files changed, 180 insertions(+), 4 deletions(-)
>>>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
>>>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
>>>>> create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>>>> In my opinion, the PeiServicesTablePointerLib class header should not be
>>>> extended with new interfaces. I understand that the generality is
>>>> attractive, but it is not put to use; only the loongarch architecture
>>>> applies the new interfaces (in the subsequent patch), and for example
>>>> the ARM code (ArmPkg/Library/PeiServicesTablePointerLib) is not reworked
>>>> in terms of these new interfaces.
>>> This libarary have ability of accommodate more ARCH why not? I checked
>>> the PI SPEC, all ARCH except IA32 and X64 using the register mechanism,
>>> if this library can be approved, all of them can moved into this
>>> libraryso that code con be reused more, I think this library is fine.
>> The library may be fine from a design point of view, but without
>> actually putting the extra generality to use, it's a waste. It's a
>> maintenance burden. There's a name for this anti-pattern: it is called
>> "speculative generality". "It might be useful down the road."
>>
>> The new generality is only useful if it carries its own weight; namely,
>> if other platform code (aarch64, x64) is converted to it immediately, in
>> the same series. (I'm not asking for this series to be longer. You could
>> even split it up into multiple "waves" of series.) Just saying that
>> "could prove useful later" is a prime way to generate technical debt.
>>
>>>> What's more, the new library interfaces, even though they are exposed in
>>>> the lib class header, are not implemented for other architectures, so
>>>> they aren't even callable on those arches.
>>> The patch 10 in this series has added LoongArch instance of this
>>> library, please check.
>> Yes, I'm aware. That's not the point.
>>
>> When you extend a library *class* with a new API, that means all
>> *clients* of the library class can stat calling that API. Which in turn
>> means that *all* existent instances of the library class must implement
>> the API as well.
>>
>> Your series extends the lib class with a new API, but (IIUC) only
>> implements the new API in one (new) lib instance, and not in the other
>> (existent) instances. This has the potential to cause linkage errors,
>> dependent on the actual library instance that a platform DSC chooses.
>>
>>
>>>> I'm commenting on this patch and the subsequent patch in the series
>>>> together, as seen squashed together. NB I'm not an MdePkg maintainer, so
>>>> this is just my opinion.
>>> So, Mike and Liming, what do your think?
>>>> (1) As noted above, the library class should not be modified.
>>>>
>>>> (2) Modifying the *comments* in
>>>> "MdePkg/Include/Library/PeiServicesTablePointerLib.h" is welcome, I
>>>> think, but then we might want to add a (separate!) patch for removing
>>>> the Itanium language, as edk2 no longer supports Itanium.
>>>>
>>>> (3) The PeiServicesTablePointerLibReg instance should be called
>>>> PeiServicesTablePointerLibCsrKs0 or just PeiServicesTablePointerLibKs0.
>>> This library will be a public libray which using the reigster mechanism,
>>> so the name like PeiServiceTablePointerLibCsrKs0 would not appropriate.
>> Of course that name is wrong for a generic library instance, but my
>> whole point is that this library instance should be loongarch-specific.
>>
>> (Unless you port the existent (x64 IDT / aarch64 register) libraries
>> over to it.)
>>
>>>> This follows the example of the lib instance name
>>>> "PeiServicesTablePointerLibIdt". The whole library instance should be
>>>> loongaarch-specific IMO; there isn't much code that's being duplicated,
>>>> so the extra interfaces (internal or external) do not help with code
>>>> unification.
>>>>
>>>> (4) "PeiServicesTablePointerLib.uni" should be named similarly (suffix
>>>> missing).
>>>>
>>>> (5) BASE_NAME in the library instance INF file should be defined
>>>> similarly (suffix missing).
>>>>
>>>> (6) The contents of the UNI file should be loongarch-specific, i.e. be
>>>> explicit about CSR KS0, in both comments and string constants.
>>>>
>>>> (7) The comments in the library instance INF file should be similarly
>>>> loongarch-specific.
>>>>
>>>> (8) I suggest dropping VALID_ARCHITECTURES altogether. If we want to
>>>> keep it, it should exclusively say LOONGARCH64.
>>>>
>>>> (9) The new library instance should be listed in
>>>> [Components.LOONGARCH64] in MdePkg.dec.
>>>>
>>>> This section does not exist yet; I suggest introducing it under
>>>> [Components.RISCV64].
>>> No, it is RISC-V area, not LOONGARCH64.
>> You misunderstood.
>>
>> I didn't suggest to list the *library instance* under [Components.RISCV64].
>>
>> I suggested to introduce the [Components.LOONGARCH64] *section* under
>> [Components.RISCV64].
>>
>>> And I do not recommend going
>>> this way. I believe this library should be a public library for register
>>> mechanism.
>> That's entirely fine, as long as you do the work of porting the existent
>> ARM and X64 IDT code over to it. In my opinion anyway; MdePkg
>> maintainers are the authoritative sources here.
>>
>> Laszlo
>>
>>>> (10) There need not / should not be two separate C source files; just
>>>> access the KS0 CSR in SetPeiServicesTablePointer() and
>>>> GetPeiServicesTablePointer() directly.
>>>>
>>>> (11) The new library instance should probably not introduce new
>>>> references to Itanium.
>>>>
>>>> Thanks,
>>>> Laszlo
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111834): https://edk2.groups.io/g/devel/message/111834
Mute This Topic: https://groups.io/mt/102644754/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 12411 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
2023-11-17 20:18 ` Andrei Warkentin
@ 2023-11-30 0:59 ` Ni, Ray
2023-11-30 2:25 ` Chao Li
[not found] ` <179C457B5B852375.31732@groups.io>
1 sibling, 2 replies; 71+ messages in thread
From: Ni, Ray @ 2023-11-30 0:59 UTC (permalink / raw)
To: Chao Li, devel@edk2.groups.io
Cc: Dong, Eric, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Warkentin, Andrei
Chao,
Since the lib class is so general, I'd like to understand more details to make sure it can properly fit into any CPU arch.
In X86, cache setting is through MSRs and Page tables, and memory access control (read-only, not-present, non-executable) is through page tables.
This CpuMmuLib is to provide both services. How does LoongArch64 manage the cache settings and memory access control?
Is it proper to combine both services into one lib?
If the backend silicon IP is the same one that supports the "one" lib design, can we refine the lib API a bit?
We have (Set|Get)MemoryRegionAttribute() and (Set|Clear)MemoryRegion(NoExec|ReadOnly). Can we merge them together?
And the API ConfigureMemoryManagementUint() accepts MEMORY_REGION_DESCRIPTOR but none of other APIs helps to construct the descriptor.
It seems to me the MmuLib is simply a combination of different random APIs.
It's not a well-designed library class.
We need more discussion to make it be able to be accommodated by other archs in future, at least by figuring out the path of X86, ARM.
Thanks,
Ray
> -----Original Message-----
> From: Chao Li <lichao@loongson.cn>
> Sent: Friday, November 17, 2023 6:00 PM
> To: devel@edk2.groups.io
> Cc: Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar,
> Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>;
> Leif Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>;
> Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei
> <andrei.warkentin@intel.com>
> Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
>
> Add a new header file CpuMmuLib.h, whitch is referenced from
> ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
> LoongArch64 is added, and more architectures can be accommodated in the
> future.
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rahul Kumar <rahul1.kumar@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> Cc: Andrei Warkentin <andrei.warkentin@intel.com>
> Signed-off-by: Chao Li <lichao@loongson.cn>
> ---
> UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
> +++++++++++++++++++++++++
> UefiCpuPkg/UefiCpuPkg.dec | 4 +
> 2 files changed, 159 insertions(+)
> create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
> b/UefiCpuPkg/Include/Library/CpuMmuLib.h
> new file mode 100644
> index 0000000000..23b2fe34ac
> --- /dev/null
> +++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
> @@ -0,0 +1,155 @@
> +/** @file
> +
> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights
> reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef CPU_MMU_LIB_H_
> +#define CPU_MMU_LIB_H_
> +
> +#include <Uefi/UefiBaseType.h>
> +
> +#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;
> +
> +/**
> + Converts EFI Attributes to corresponding architecture Attributes.
> +
> + @param[in] EfiAttributes Efi Attributes.
> +
> + @retval Corresponding architecture attributes.
> +**/
> +UINTN
> +EfiAttributeConverse (
> + 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
> +GetMemoryRegionAttribute (
> + 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.
> + @param[in] AttributeMask Mask of memory attributes to take into
> account.
> +
> + @retval EFI_SUCCESS The Attributes was set successfully
> +**/
> +EFI_STATUS
> +SetMemoryRegionAttributes (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length,
> + IN UINTN Attributes,
> + IN UINT64 AttributeMask
> + );
> +
> +/**
> + 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
> +SetMemoryRegionNoExec (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINTN Length
> + );
> +
> +/**
> + Clears the non-executable Attributes for the specified memory region
> +
> + @param[in] BaseAddress The base address of the memory region to
> clear the Attributes.
> + @param[in] Length The length of the memory region to clear
> the Attributes.
> +
> + @retval EFI_SUCCESS The Attributes was clear successfully
> +**/
> +EFI_STATUS
> +EFIAPI
> +ClearMemoryRegionNoExec (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINT64 Length
> + );
> +
> +/**
> + Sets the read-only 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
> +EFIAPI
> +SetMemoryRegionReadOnly (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINT64 Length
> + );
> +
> +/**
> + Clears the read-only Attributes for the specified memory region
> +
> + @param[in] BaseAddress The base address of the memory region to
> clear the Attributes.
> + @param[in] Length The length of the memory region to clear
> the Attributes.
> +
> + @retval EFI_SUCCESS The Attributes was clear successfully
> +**/
> +EFI_STATUS
> +EFIAPI
> +ClearMemoryRegionReadOnly (
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
> + IN UINT64 Length
> + );
> +
> +/**
> + Create a page table and initialize the memory management unit(MMU).
> +
> + @param[in] MemoryTable A pointer to a memory ragion
> table.
> + @param[out] TranslationTableBase A pointer to a translation table base
> address.
> + @param[out] TranslationTableSize A pointer to a translation table base
> size.
> +
> + @retval EFI_SUCCESS Configure MMU successfully.
> + EFI_INVALID_PARAMETER MemoryTable is NULL.
> + EFI_UNSUPPORTED Out of memory space or
> size not aligned.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ConfigureMemoryManagementUint (
> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
> + OUT VOID **TranslationTableBase OPTIONAL,
> + OUT UINTN *TranslationTableSize OPTIONAL
> + );
> +
> +#endif // CPU_MMU_LIB_H_
> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
> index 154b1d06fe..150beae981 100644
> --- a/UefiCpuPkg/UefiCpuPkg.dec
> +++ b/UefiCpuPkg/UefiCpuPkg.dec
> @@ -62,6 +62,10 @@
> ## @libraryclass Provides function for manipulating x86 paging
> structures.
> CpuPageTableLib|Include/Library/CpuPageTableLib.h
>
> +[LibraryClasses.LoongArch64]
> + ## @libraryclass Provides macros and functions for the memory
> management unit.
> + CpuMmuLib|Include/Library/CpuMmuLib.h
> +
> ## @libraryclass Provides functions for manipulating smram savestate
> registers.
> MmSaveStateLib|Include/Library/MmSaveStateLib.h
>
> --
> 2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111871): https://edk2.groups.io/g/devel/message/111871
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
2023-11-30 0:59 ` Ni, Ray
@ 2023-11-30 2:25 ` Chao Li
[not found] ` <179C457B5B852375.31732@groups.io>
1 sibling, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-11-30 2:25 UTC (permalink / raw)
To: devel, ray.ni
Cc: Dong, Eric, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Warkentin, Andrei
[-- Attachment #1: Type: text/plain, Size: 10862 bytes --]
Hi Ray,
Thanks for review, here are some of my thoughts:
Thanks,
Chao
On 2023/11/30 08:59, Ni, Ray wrote:
> Chao,
> Since the lib class is so general, I'd like to understand more details to make sure it can properly fit into any CPU arch.
>
> In X86, cache setting is through MSRs and Page tables, and memory access control (read-only, not-present, non-executable) is through page tables.
Let me understand, 'cache setting' means does it access a certain
address(probably a memory address) via cache? If so, I'd say the 'cache
setting' should be a part of attributes.
>
> This CpuMmuLib is to provide both services. How does LoongArch64 manage the cache settings and memory access control?
> Is it proper to combine both services into one lib?
In LoongArch64, cache settings and memory access control are performed
via page tables. Please check the patch 14 of this series.
>
> If the backend silicon IP is the same one that supports the "one" lib design, can we refine the lib API a bit?
Yes, I think Attribute's instance family can be bear the memory access
and cache setting. So what are you suggestions if we improve the lib API?
>
> We have (Set|Get)MemoryRegionAttribute() and (Set|Clear)MemoryRegion(NoExec|ReadOnly). Can we merge them together?
Do you means the (Set|Get) merge together(differentiate Get or Set
operations by parameters)? If so, I think it's OK, but maybe some
existing instances will be modified together.
>
> And the API ConfigureMemoryManagementUint() accepts MEMORY_REGION_DESCRIPTOR but none of other APIs helps to construct the descriptor.
Yes, currently, no one helps construct MEMORY_REGION_DESCRIPTOR. I think
the construction of descriptors is not part of the API, it should be the
localized or private when I design them. Do I need to add an API to
construct descripters?
>
> It seems to me the MmuLib is simply a combination of different random APIs.
> It's not a well-designed library class.
>
> We need more discussion to make it be able to be accommodated by other archs in future, at least by figuring out the path of X86, ARM.
Yes, the APIs looks like so fragmented and we should improve them. So we
should talk more about this API, thanks.
>
> Thanks,
> Ray
>> -----Original Message-----
>> From: Chao Li<lichao@loongson.cn>
>> Sent: Friday, November 17, 2023 6:00 PM
>> To:devel@edk2.groups.io
>> Cc: Dong, Eric<eric.dong@intel.com>; Ni, Ray<ray.ni@intel.com>; Kumar,
>> Rahul R<rahul.r.kumar@intel.com>; Gerd Hoffmann<kraxel@redhat.com>;
>> Leif Lindholm<quic_llindhol@quicinc.com>; Ard Biesheuvel
>> <ardb+tianocore@kernel.org>; Sami Mujawar<sami.mujawar@arm.com>;
>> Sunil V L<sunilvl@ventanamicro.com>; Warkentin, Andrei
>> <andrei.warkentin@intel.com>
>> Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
>>
>> Add a new header file CpuMmuLib.h, whitch is referenced from
>> ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
>> LoongArch64 is added, and more architectures can be accommodated in the
>> future.
>>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Eric Dong<eric.dong@intel.com>
>> Cc: Ray Ni<ray.ni@intel.com>
>> Cc: Rahul Kumar<rahul1.kumar@intel.com>
>> Cc: Gerd Hoffmann<kraxel@redhat.com>
>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>> Cc: Sunil V L<sunilvl@ventanamicro.com>
>> Cc: Andrei Warkentin<andrei.warkentin@intel.com>
>> Signed-off-by: Chao Li<lichao@loongson.cn>
>> ---
>> UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
>> +++++++++++++++++++++++++
>> UefiCpuPkg/UefiCpuPkg.dec | 4 +
>> 2 files changed, 159 insertions(+)
>> create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
>>
>> diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
>> b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>> new file mode 100644
>> index 0000000000..23b2fe34ac
>> --- /dev/null
>> +++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>> @@ -0,0 +1,155 @@
>> +/** @file
>> +
>> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights
>> reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef CPU_MMU_LIB_H_
>> +#define CPU_MMU_LIB_H_
>> +
>> +#include <Uefi/UefiBaseType.h>
>> +
>> +#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;
>> +
>> +/**
>> + Converts EFI Attributes to corresponding architecture Attributes.
>> +
>> + @param[in] EfiAttributes Efi Attributes.
>> +
>> + @retval Corresponding architecture attributes.
>> +**/
>> +UINTN
>> +EfiAttributeConverse (
>> + 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
>> +GetMemoryRegionAttribute (
>> + 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.
>> + @param[in] AttributeMask Mask of memory attributes to take into
>> account.
>> +
>> + @retval EFI_SUCCESS The Attributes was set successfully
>> +**/
>> +EFI_STATUS
>> +SetMemoryRegionAttributes (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINTN Length,
>> + IN UINTN Attributes,
>> + IN UINT64 AttributeMask
>> + );
>> +
>> +/**
>> + 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
>> +SetMemoryRegionNoExec (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINTN Length
>> + );
>> +
>> +/**
>> + Clears the non-executable Attributes for the specified memory region
>> +
>> + @param[in] BaseAddress The base address of the memory region to
>> clear the Attributes.
>> + @param[in] Length The length of the memory region to clear
>> the Attributes.
>> +
>> + @retval EFI_SUCCESS The Attributes was clear successfully
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ClearMemoryRegionNoExec (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINT64 Length
>> + );
>> +
>> +/**
>> + Sets the read-only 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
>> +EFIAPI
>> +SetMemoryRegionReadOnly (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINT64 Length
>> + );
>> +
>> +/**
>> + Clears the read-only Attributes for the specified memory region
>> +
>> + @param[in] BaseAddress The base address of the memory region to
>> clear the Attributes.
>> + @param[in] Length The length of the memory region to clear
>> the Attributes.
>> +
>> + @retval EFI_SUCCESS The Attributes was clear successfully
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ClearMemoryRegionReadOnly (
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>> + IN UINT64 Length
>> + );
>> +
>> +/**
>> + Create a page table and initialize the memory management unit(MMU).
>> +
>> + @param[in] MemoryTable A pointer to a memory ragion
>> table.
>> + @param[out] TranslationTableBase A pointer to a translation table base
>> address.
>> + @param[out] TranslationTableSize A pointer to a translation table base
>> size.
>> +
>> + @retval EFI_SUCCESS Configure MMU successfully.
>> + EFI_INVALID_PARAMETER MemoryTable is NULL.
>> + EFI_UNSUPPORTED Out of memory space or
>> size not aligned.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +ConfigureMemoryManagementUint (
>> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
>> + OUT VOID **TranslationTableBase OPTIONAL,
>> + OUT UINTN *TranslationTableSize OPTIONAL
>> + );
>> +
>> +#endif // CPU_MMU_LIB_H_
>> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
>> index 154b1d06fe..150beae981 100644
>> --- a/UefiCpuPkg/UefiCpuPkg.dec
>> +++ b/UefiCpuPkg/UefiCpuPkg.dec
>> @@ -62,6 +62,10 @@
>> ## @libraryclass Provides function for manipulating x86 paging
>> structures.
>> CpuPageTableLib|Include/Library/CpuPageTableLib.h
>>
>> +[LibraryClasses.LoongArch64]
>> + ## @libraryclass Provides macros and functions for the memory
>> management unit.
>> + CpuMmuLib|Include/Library/CpuMmuLib.h
>> +
>> ## @libraryclass Provides functions for manipulating smram savestate
>> registers.
>> MmSaveStateLib|Include/Library/MmSaveStateLib.h
>>
>> --
>> 2.27.0
>
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111882): https://edk2.groups.io/g/devel/message/111882
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 14415 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* 回复: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
2023-11-27 3:27 ` Chao Li
@ 2023-12-01 0:32 ` gaoliming via groups.io
2023-12-01 8:20 ` Chao Li
0 siblings, 1 reply; 71+ messages in thread
From: gaoliming via groups.io @ 2023-12-01 0:32 UTC (permalink / raw)
To: 'Chao Li', 'Laszlo Ersek', devel
Cc: 'Michael D Kinney', 'Zhiguang Liu',
'Leif Lindholm', 'Ard Biesheuvel',
'Sami Mujawar', 'Sunil V L'
[-- Attachment #1: Type: text/plain, Size: 8817 bytes --]
Chao:
I agree with Laszlo. I want to highlight that current design has meet with your requirement. So, I don’t think we need to add new APIs in PeiServicesTablePointerLib header file. Loong Arch can implement its PeiServicesTablePointerLib library instance base on its specific register.
Thanks
Liming
发件人: Chao Li <lichao@loongson.cn>
发送时间: 2023年11月27日 11:28
收件人: Laszlo Ersek <lersek@redhat.com>; devel@edk2.groups.io
抄送: Michael D Kinney <michael.d.kinney@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>; Zhiguang Liu <zhiguang.liu@intel.com>; Leif Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>; Sunil V L <sunilvl@ventanamicro.com>
主题: Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
Hi Mike and Liming,
You opinion is very important, it will decide the direction. I will send the V4 this week, so can you please review the new patch of MdePkg for this series?
Thanks,
Chao
On 2023/11/24 19:35, Laszlo Ersek wrote:
On 11/22/23 02:47, Chao Li wrote:
Hi Laszlo,
Thanks,
Chao
On 2023/11/21 22:37, Laszlo Ersek wrote:
On 11/17/23 10:59, Chao Li wrote:
Since some ARCH or platform not require execute code on memory during
PEI phase, some values may transferred via CPU registers.
Adding PeiServcieTablePointerLibReg to allow set and get the PEI service
table pointer depend by a CPU register, this library can accommodate lot
of platforms who not require execte code on memory during PEI phase.
Adding PeiServiceTablePointerLibReg to allows setting and getting the
PEI service table pointer via CPU registers, and the library can
accommodate many platforms that do not need to execute code on memory
during the PEI phase.
The idea of this library is derived from
ArmPkg/Library/PeiServicesTablePointerLib/
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Michael D Kinney <mailto:michael.d.kinney@intel.com> <michael.d.kinney@intel.com>
Cc: Liming Gao <mailto:gaoliming@byosoft.com.cn> <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <mailto:zhiguang.liu@intel.com> <zhiguang.liu@intel.com>
Cc: Leif Lindholm <mailto:quic_llindhol@quicinc.com> <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <mailto:ardb+tianocore@kernel.org> <ardb+tianocore@kernel.org>
Cc: Sami Mujawar <mailto:sami.mujawar@arm.com> <sami.mujawar@arm.com>
Cc: Laszlo Ersek <mailto:lersek@redhat.com> <lersek@redhat.com>
Cc: Sunil V L <mailto:sunilvl@ventanamicro.com> <sunilvl@ventanamicro.com>
Signed-off-by: Chao Li <mailto:lichao@loongson.cn> <lichao@loongson.cn>
---
.../Library/PeiServicesTablePointerLib.h | 37 +++++++-
.../PeiServicesTablePointer.c | 86 +++++++++++++++++++
.../PeiServicesTablePointerLib.uni | 20 +++++
.../PeiServicesTablePointerLibReg.inf | 40 +++++++++
MdePkg/MdePkg.dsc | 1 +
5 files changed, 180 insertions(+), 4 deletions(-)
create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
create mode 100644 MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
In my opinion, the PeiServicesTablePointerLib class header should not be
extended with new interfaces. I understand that the generality is
attractive, but it is not put to use; only the loongarch architecture
applies the new interfaces (in the subsequent patch), and for example
the ARM code (ArmPkg/Library/PeiServicesTablePointerLib) is not reworked
in terms of these new interfaces.
This libarary have ability of accommodate more ARCH why not? I checked
the PI SPEC, all ARCH except IA32 and X64 using the register mechanism,
if this library can be approved, all of them can moved into this
libraryso that code con be reused more, I think this library is fine.
The library may be fine from a design point of view, but without
actually putting the extra generality to use, it's a waste. It's a
maintenance burden. There's a name for this anti-pattern: it is called
"speculative generality". "It might be useful down the road."
The new generality is only useful if it carries its own weight; namely,
if other platform code (aarch64, x64) is converted to it immediately, in
the same series. (I'm not asking for this series to be longer. You could
even split it up into multiple "waves" of series.) Just saying that
"could prove useful later" is a prime way to generate technical debt.
What's more, the new library interfaces, even though they are exposed in
the lib class header, are not implemented for other architectures, so
they aren't even callable on those arches.
The patch 10 in this series has added LoongArch instance of this
library, please check.
Yes, I'm aware. That's not the point.
When you extend a library *class* with a new API, that means all
*clients* of the library class can stat calling that API. Which in turn
means that *all* existent instances of the library class must implement
the API as well.
Your series extends the lib class with a new API, but (IIUC) only
implements the new API in one (new) lib instance, and not in the other
(existent) instances. This has the potential to cause linkage errors,
dependent on the actual library instance that a platform DSC chooses.
I'm commenting on this patch and the subsequent patch in the series
together, as seen squashed together. NB I'm not an MdePkg maintainer, so
this is just my opinion.
So, Mike and Liming, what do your think?
(1) As noted above, the library class should not be modified.
(2) Modifying the *comments* in
"MdePkg/Include/Library/PeiServicesTablePointerLib.h" is welcome, I
think, but then we might want to add a (separate!) patch for removing
the Itanium language, as edk2 no longer supports Itanium.
(3) The PeiServicesTablePointerLibReg instance should be called
PeiServicesTablePointerLibCsrKs0 or just PeiServicesTablePointerLibKs0.
This library will be a public libray which using the reigster mechanism,
so the name like PeiServiceTablePointerLibCsrKs0 would not appropriate.
Of course that name is wrong for a generic library instance, but my
whole point is that this library instance should be loongarch-specific.
(Unless you port the existent (x64 IDT / aarch64 register) libraries
over to it.)
This follows the example of the lib instance name
"PeiServicesTablePointerLibIdt". The whole library instance should be
loongaarch-specific IMO; there isn't much code that's being duplicated,
so the extra interfaces (internal or external) do not help with code
unification.
(4) "PeiServicesTablePointerLib.uni" should be named similarly (suffix
missing).
(5) BASE_NAME in the library instance INF file should be defined
similarly (suffix missing).
(6) The contents of the UNI file should be loongarch-specific, i.e. be
explicit about CSR KS0, in both comments and string constants.
(7) The comments in the library instance INF file should be similarly
loongarch-specific.
(8) I suggest dropping VALID_ARCHITECTURES altogether. If we want to
keep it, it should exclusively say LOONGARCH64.
(9) The new library instance should be listed in
[Components.LOONGARCH64] in MdePkg.dec.
This section does not exist yet; I suggest introducing it under
[Components.RISCV64].
No, it is RISC-V area, not LOONGARCH64.
You misunderstood.
I didn't suggest to list the *library instance* under [Components.RISCV64].
I suggested to introduce the [Components.LOONGARCH64] *section* under
[Components.RISCV64].
And I do not recommend going
this way. I believe this library should be a public library for register
mechanism.
That's entirely fine, as long as you do the work of porting the existent
ARM and X64 IDT code over to it. In my opinion anyway; MdePkg
maintainers are the authoritative sources here.
Laszlo
(10) There need not / should not be two separate C source files; just
access the KS0 CSR in SetPeiServicesTablePointer() and
GetPeiServicesTablePointer() directly.
(11) The new library instance should probably not introduce new
references to Itanium.
Thanks,
Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111933): https://edk2.groups.io/g/devel/message/111933
Mute This Topic: https://groups.io/mt/102906469/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 21665 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: 回复: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg
2023-12-01 0:32 ` 回复: " gaoliming via groups.io
@ 2023-12-01 8:20 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-12-01 8:20 UTC (permalink / raw)
To: gaoliming, 'Laszlo Ersek', devel
Cc: 'Michael D Kinney', 'Zhiguang Liu',
'Leif Lindholm', 'Ard Biesheuvel',
'Sami Mujawar', 'Sunil V L'
[-- Attachment #1: Type: text/plain, Size: 11459 bytes --]
Hi Liming,
Ok, I see. In V4 I will add the PeiServicesTablePointerLib only for
LoongArch, and it probably be named PeiServicesTablePointerLibKs0.
Thanks,
Chao
On 2023/12/1 08:32, gaoliming wrote:
>
> Chao:
>
> I agree with Laszlo. I want to highlight that current design has meet
> with your requirement. So, I don’t think we need to add new APIs in
> PeiServicesTablePointerLib header file. Loong Arch can implement its
> PeiServicesTablePointerLib library instance base on its specific
> register.
>
> Thanks
>
> Liming
>
> *发件人:*Chao Li <lichao@loongson.cn>
> *发送时间:*2023年11月27日11:28
> *收件人:*Laszlo Ersek <lersek@redhat.com>; devel@edk2.groups.io
> *抄送:*Michael D Kinney <michael.d.kinney@intel.com>; Liming Gao
> <gaoliming@byosoft.com.cn>; Zhiguang Liu <zhiguang.liu@intel.com>;
> Leif Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>;
> Sunil V L <sunilvl@ventanamicro.com>
> *主题:*Re: [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named
> PeiServicesTablePointerLibReg
>
> Hi Mike and Liming,
>
> You opinion is very important, it will decide the direction. I will
> send the V4 this week, so can you please review the new patch of
> MdePkg for this series?
>
> Thanks,
> Chao
>
> On 2023/11/24 19:35, Laszlo Ersek wrote:
>
> On 11/22/23 02:47, Chao Li wrote:
>
> Hi Laszlo,
>
> Thanks,
>
> Chao
>
> On 2023/11/21 22:37, Laszlo Ersek wrote:
>
> On 11/17/23 10:59, Chao Li wrote:
>
> Since some ARCH or platform not require execute code
> on memory during
>
> PEI phase, some values may transferred via CPU registers.
>
> Adding PeiServcieTablePointerLibReg to allow set and
> get the PEI service
>
> table pointer depend by a CPU register, this library
> can accommodate lot
>
> of platforms who not require execte code on memory
> during PEI phase.
>
> Adding PeiServiceTablePointerLibReg to allows setting
> and getting the
>
> PEI service table pointer via CPU registers, and the
> library can
>
> accommodate many platforms that do not need to execute
> code on memory
>
> during the PEI phase.
>
> The idea of this library is derived from
>
> ArmPkg/Library/PeiServicesTablePointerLib/
>
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> <mailto:michael.d.kinney@intel.com>
>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> <mailto:gaoliming@byosoft.com.cn>
>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> <mailto:zhiguang.liu@intel.com>
>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> <mailto:quic_llindhol@quicinc.com>
>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> <mailto:ardb+tianocore@kernel.org>
>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> <mailto:sami.mujawar@arm.com>
>
> Cc: Laszlo Ersek <lersek@redhat.com>
> <mailto:lersek@redhat.com>
>
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> <mailto:sunilvl@ventanamicro.com>
>
> Signed-off-by: Chao Li <lichao@loongson.cn>
> <mailto:lichao@loongson.cn>
>
> ---
>
> .../Library/PeiServicesTablePointerLib.h | 37
> +++++++-
>
> .../PeiServicesTablePointer.c | 86
> +++++++++++++++++++
>
> .../PeiServicesTablePointerLib.uni | 20 +++++
>
> .../PeiServicesTablePointerLibReg.inf | 40
> +++++++++
>
> MdePkg/MdePkg.dsc | 1 +
>
> 5 files changed, 180 insertions(+), 4 deletions(-)
>
> create mode 100644
> MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointer.c
>
> create mode 100644
> MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLib.uni
>
> create mode 100644
> MdePkg/Library/PeiServicesTablePointerLibReg/PeiServicesTablePointerLibReg.inf
>
> In my opinion, the PeiServicesTablePointerLib class header
> should not be
>
> extended with new interfaces. I understand that the
> generality is
>
> attractive, but it is not put to use; only the loongarch
> architecture
>
> applies the new interfaces (in the subsequent patch), and
> for example
>
> the ARM code (ArmPkg/Library/PeiServicesTablePointerLib)
> is not reworked
>
> in terms of these new interfaces.
>
> This libarary have ability of accommodate more ARCH why not? I
> checked
>
> the PI SPEC, all ARCH except IA32 and X64 using the register
> mechanism,
>
> if this library can be approved, all of them can moved into this
>
> libraryso that code con be reused more, I think this library
> is fine.
>
> The library may be fine from a design point of view, but without
>
> actually putting the extra generality to use, it's a waste. It's a
>
> maintenance burden. There's a name for this anti-pattern: it is called
>
> "speculative generality". "It might be useful down the road."
>
> The new generality is only useful if it carries its own weight;
> namely,
>
> if other platform code (aarch64, x64) is converted to it
> immediately, in
>
> the same series. (I'm not asking for this series to be longer. You
> could
>
> even split it up into multiple "waves" of series.) Just saying that
>
> "could prove useful later" is a prime way to generate technical debt.
>
> What's more, the new library interfaces, even though they
> are exposed in
>
> the lib class header, are not implemented for other
> architectures, so
>
> they aren't even callable on those arches.
>
> The patch 10 in this series has added LoongArch instance of this
>
> library, please check.
>
> Yes, I'm aware. That's not the point.
>
> When you extend a library *class* with a new API, that means all
>
> *clients* of the library class can stat calling that API. Which in
> turn
>
> means that *all* existent instances of the library class must
> implement
>
> the API as well.
>
> Your series extends the lib class with a new API, but (IIUC) only
>
> implements the new API in one (new) lib instance, and not in the other
>
> (existent) instances. This has the potential to cause linkage errors,
>
> dependent on the actual library instance that a platform DSC chooses.
>
> I'm commenting on this patch and the subsequent patch in
> the series
>
> together, as seen squashed together. NB I'm not an MdePkg
> maintainer, so
>
> this is just my opinion.
>
> So, Mike and Liming, what do your think?
>
> (1) As noted above, the library class should not be modified.
>
> (2) Modifying the *comments* in
>
> "MdePkg/Include/Library/PeiServicesTablePointerLib.h" is
> welcome, I
>
> think, but then we might want to add a (separate!) patch
> for removing
>
> the Itanium language, as edk2 no longer supports Itanium.
>
> (3) The PeiServicesTablePointerLibReg instance should be
> called
>
> PeiServicesTablePointerLibCsrKs0 or just
> PeiServicesTablePointerLibKs0.
>
> This library will be a public libray which using the reigster
> mechanism,
>
> so the name like PeiServiceTablePointerLibCsrKs0 would not
> appropriate.
>
> Of course that name is wrong for a generic library instance, but my
>
> whole point is that this library instance should be
> loongarch-specific.
>
> (Unless you port the existent (x64 IDT / aarch64 register) libraries
>
> over to it.)
>
> This follows the example of the lib instance name
>
> "PeiServicesTablePointerLibIdt". The whole library
> instance should be
>
> loongaarch-specific IMO; there isn't much code that's
> being duplicated,
>
> so the extra interfaces (internal or external) do not help
> with code
>
> unification.
>
> (4) "PeiServicesTablePointerLib.uni" should be named
> similarly (suffix
>
> missing).
>
> (5) BASE_NAME in the library instance INF file should be
> defined
>
> similarly (suffix missing).
>
> (6) The contents of the UNI file should be
> loongarch-specific, i.e. be
>
> explicit about CSR KS0, in both comments and string constants.
>
> (7) The comments in the library instance INF file should
> be similarly
>
> loongarch-specific.
>
> (8) I suggest dropping VALID_ARCHITECTURES altogether. If
> we want to
>
> keep it, it should exclusively say LOONGARCH64.
>
> (9) The new library instance should be listed in
>
> [Components.LOONGARCH64] in MdePkg.dec.
>
> This section does not exist yet; I suggest introducing it
> under
>
> [Components.RISCV64].
>
> No, it is RISC-V area, not LOONGARCH64.
>
> You misunderstood.
>
> I didn't suggest to list the *library instance* under
> [Components.RISCV64].
>
> I suggested to introduce the [Components.LOONGARCH64] *section* under
>
> [Components.RISCV64].
>
> And I do not recommend going
>
> this way. I believe this library should be a public library
> for register
>
> mechanism.
>
> That's entirely fine, as long as you do the work of porting the
> existent
>
> ARM and X64 IDT code over to it. In my opinion anyway; MdePkg
>
> maintainers are the authoritative sources here.
>
> Laszlo
>
> (10) There need not / should not be two separate C source
> files; just
>
> access the KS0 CSR in SetPeiServicesTablePointer() and
>
> GetPeiServicesTablePointer() directly.
>
> (11) The new library instance should probably not
> introduce new
>
> references to Itanium.
>
> Thanks,
>
> Laszlo
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111975): https://edk2.groups.io/g/devel/message/111975
Mute This Topic: https://groups.io/mt/102906469/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 27511 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
[not found] ` <179C457B5B852375.31732@groups.io>
@ 2023-12-04 7:31 ` Chao Li
2023-12-05 8:27 ` Ni, Ray
0 siblings, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-12-04 7:31 UTC (permalink / raw)
To: devel, ray.ni
Cc: Dong, Eric, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Warkentin, Andrei
[-- Attachment #1: Type: text/plain, Size: 11915 bytes --]
Hi Ray,
For this patch, I checked again and here are my opinions:
1. (Set|Get)MemoryRegionAttribute is difficult to merge together,
because the parameters between the tow APIs are not similar. So I
suggest they be independent.
2. The EfiAttributeConverse, GetMemoryRegionAttribute,
SetMemoryRegionAttributes and ConfigureMemoryManagementUnit will be
retained and other APIs will be removed. Because the functions expressed
by other APIs can be completed though the retained API.
3. You pointed out MEMORY_REGION_DESCRIPTOR have no one to construct it,
do I need add a new API to construct it? Could it be named
GetMemoryMapPolicy and accept a parameter with MEMORY_REGION_DESCRIPTOR** ?
Hope to hear from you! :)
Thanks,
Chao
On 2023/11/30 10:25, Chao Li wrote:
>
> Hi Ray,
>
> Thanks for review, here are some of my thoughts:
>
> On 2023/11/30 08:59, Ni, Ray wrote:
>> Chao,
>> Since the lib class is so general, I'd like to understand more details to make sure it can properly fit into any CPU arch.
>>
>> In X86, cache setting is through MSRs and Page tables, and memory access control (read-only, not-present, non-executable) is through page tables.
> Let me understand, 'cache setting' means does it access a certain
> address(probably a memory address) via cache? If so, I'd say the
> 'cache setting' should be a part of attributes.
>> This CpuMmuLib is to provide both services. How does LoongArch64 manage the cache settings and memory access control?
>> Is it proper to combine both services into one lib?
> In LoongArch64, cache settings and memory access control are performed
> via page tables. Please check the patch 14 of this series.
>> If the backend silicon IP is the same one that supports the "one" lib design, can we refine the lib API a bit?
> Yes, I think Attribute's instance family can be bear the memory access
> and cache setting. So what are you suggestions if we improve the lib API?
>> We have (Set|Get)MemoryRegionAttribute() and (Set|Clear)MemoryRegion(NoExec|ReadOnly). Can we merge them together?
> Do you means the (Set|Get) merge together(differentiate Get or Set
> operations by parameters)? If so, I think it's OK, but maybe some
> existing instances will be modified together.
>> And the API ConfigureMemoryManagementUint() accepts MEMORY_REGION_DESCRIPTOR but none of other APIs helps to construct the descriptor.
> Yes, currently, no one helps construct MEMORY_REGION_DESCRIPTOR. I
> think the construction of descriptors is not part of the API, it
> should be the localized or private when I design them. Do I need to
> add an API to construct descripters?
>> It seems to me the MmuLib is simply a combination of different random APIs.
>> It's not a well-designed library class.
>>
>> We need more discussion to make it be able to be accommodated by other archs in future, at least by figuring out the path of X86, ARM.
> Yes, the APIs looks like so fragmented and we should improve them. So
> we should talk more about this API, thanks.
>> Thanks,
>> Ray
>>> -----Original Message-----
>>> From: Chao Li<lichao@loongson.cn>
>>> Sent: Friday, November 17, 2023 6:00 PM
>>> To:devel@edk2.groups.io
>>> Cc: Dong, Eric<eric.dong@intel.com>; Ni, Ray<ray.ni@intel.com>; Kumar,
>>> Rahul R<rahul.r.kumar@intel.com>; Gerd Hoffmann<kraxel@redhat.com>;
>>> Leif Lindholm<quic_llindhol@quicinc.com>; Ard Biesheuvel
>>> <ardb+tianocore@kernel.org>; Sami Mujawar<sami.mujawar@arm.com>;
>>> Sunil V L<sunilvl@ventanamicro.com>; Warkentin, Andrei
>>> <andrei.warkentin@intel.com>
>>> Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
>>>
>>> Add a new header file CpuMmuLib.h, whitch is referenced from
>>> ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
>>> LoongArch64 is added, and more architectures can be accommodated in the
>>> future.
>>>
>>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>>
>>> Cc: Eric Dong<eric.dong@intel.com>
>>> Cc: Ray Ni<ray.ni@intel.com>
>>> Cc: Rahul Kumar<rahul1.kumar@intel.com>
>>> Cc: Gerd Hoffmann<kraxel@redhat.com>
>>> Cc: Leif Lindholm<quic_llindhol@quicinc.com>
>>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org>
>>> Cc: Sami Mujawar<sami.mujawar@arm.com>
>>> Cc: Sunil V L<sunilvl@ventanamicro.com>
>>> Cc: Andrei Warkentin<andrei.warkentin@intel.com>
>>> Signed-off-by: Chao Li<lichao@loongson.cn>
>>> ---
>>> UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
>>> +++++++++++++++++++++++++
>>> UefiCpuPkg/UefiCpuPkg.dec | 4 +
>>> 2 files changed, 159 insertions(+)
>>> create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
>>>
>>> diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
>>> b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>>> new file mode 100644
>>> index 0000000000..23b2fe34ac
>>> --- /dev/null
>>> +++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>>> @@ -0,0 +1,155 @@
>>> +/** @file
>>> +
>>> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights
>>> reserved.<BR>
>>> +
>>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +
>>> +**/
>>> +
>>> +#ifndef CPU_MMU_LIB_H_
>>> +#define CPU_MMU_LIB_H_
>>> +
>>> +#include <Uefi/UefiBaseType.h>
>>> +
>>> +#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;
>>> +
>>> +/**
>>> + Converts EFI Attributes to corresponding architecture Attributes.
>>> +
>>> + @param[in] EfiAttributes Efi Attributes.
>>> +
>>> + @retval Corresponding architecture attributes.
>>> +**/
>>> +UINTN
>>> +EfiAttributeConverse (
>>> + 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
>>> +GetMemoryRegionAttribute (
>>> + 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.
>>> + @param[in] AttributeMask Mask of memory attributes to take into
>>> account.
>>> +
>>> + @retval EFI_SUCCESS The Attributes was set successfully
>>> +**/
>>> +EFI_STATUS
>>> +SetMemoryRegionAttributes (
>>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>> + IN UINTN Length,
>>> + IN UINTN Attributes,
>>> + IN UINT64 AttributeMask
>>> + );
>>> +
>>> +/**
>>> + 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
>>> +SetMemoryRegionNoExec (
>>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>> + IN UINTN Length
>>> + );
>>> +
>>> +/**
>>> + Clears the non-executable Attributes for the specified memory region
>>> +
>>> + @param[in] BaseAddress The base address of the memory region to
>>> clear the Attributes.
>>> + @param[in] Length The length of the memory region to clear
>>> the Attributes.
>>> +
>>> + @retval EFI_SUCCESS The Attributes was clear successfully
>>> +**/
>>> +EFI_STATUS
>>> +EFIAPI
>>> +ClearMemoryRegionNoExec (
>>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>> + IN UINT64 Length
>>> + );
>>> +
>>> +/**
>>> + Sets the read-only 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
>>> +EFIAPI
>>> +SetMemoryRegionReadOnly (
>>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>> + IN UINT64 Length
>>> + );
>>> +
>>> +/**
>>> + Clears the read-only Attributes for the specified memory region
>>> +
>>> + @param[in] BaseAddress The base address of the memory region to
>>> clear the Attributes.
>>> + @param[in] Length The length of the memory region to clear
>>> the Attributes.
>>> +
>>> + @retval EFI_SUCCESS The Attributes was clear successfully
>>> +**/
>>> +EFI_STATUS
>>> +EFIAPI
>>> +ClearMemoryRegionReadOnly (
>>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>> + IN UINT64 Length
>>> + );
>>> +
>>> +/**
>>> + Create a page table and initialize the memory management unit(MMU).
>>> +
>>> + @param[in] MemoryTable A pointer to a memory ragion
>>> table.
>>> + @param[out] TranslationTableBase A pointer to a translation table base
>>> address.
>>> + @param[out] TranslationTableSize A pointer to a translation table base
>>> size.
>>> +
>>> + @retval EFI_SUCCESS Configure MMU successfully.
>>> + EFI_INVALID_PARAMETER MemoryTable is NULL.
>>> + EFI_UNSUPPORTED Out of memory space or
>>> size not aligned.
>>> +**/
>>> +EFI_STATUS
>>> +EFIAPI
>>> +ConfigureMemoryManagementUint (
>>> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
>>> + OUT VOID **TranslationTableBase OPTIONAL,
>>> + OUT UINTN *TranslationTableSize OPTIONAL
>>> + );
>>> +
>>> +#endif // CPU_MMU_LIB_H_
>>> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
>>> index 154b1d06fe..150beae981 100644
>>> --- a/UefiCpuPkg/UefiCpuPkg.dec
>>> +++ b/UefiCpuPkg/UefiCpuPkg.dec
>>> @@ -62,6 +62,10 @@
>>> ## @libraryclass Provides function for manipulating x86 paging
>>> structures.
>>> CpuPageTableLib|Include/Library/CpuPageTableLib.h
>>>
>>> +[LibraryClasses.LoongArch64]
>>> + ## @libraryclass Provides macros and functions for the memory
>>> management unit.
>>> + CpuMmuLib|Include/Library/CpuMmuLib.h
>>> +
>>> ## @libraryclass Provides functions for manipulating smram savestate
>>> registers.
>>> MmSaveStateLib|Include/Library/MmSaveStateLib.h
>>>
>>> --
>>> 2.27.0
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112017): https://edk2.groups.io/g/devel/message/112017
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 16601 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
2023-12-04 7:31 ` Chao Li
@ 2023-12-05 8:27 ` Ni, Ray
2023-12-05 12:27 ` Chao Li
[not found] ` <179DEF40376B662A.18076@groups.io>
0 siblings, 2 replies; 71+ messages in thread
From: Ni, Ray @ 2023-12-05 8:27 UTC (permalink / raw)
To: devel@edk2.groups.io, lichao@loongson.cn
Cc: Dong, Eric, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Warkentin, Andrei
[-- Attachment #1: Type: text/plain, Size: 13499 bytes --]
Thanks,
Ray
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Chao Li
Sent: Monday, December 4, 2023 3:32 PM
To: devel@edk2.groups.io; Ni, Ray <ray.ni@intel.com>
Cc: Dong, Eric <eric.dong@intel.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Leif Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>; Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei <andrei.warkentin@intel.com>
Subject: Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
Hi Ray,
For this patch, I checked again and here are my opinions:
1. (Set|Get)MemoryRegionAttribute is difficult to merge together, because the parameters between the tow APIs are not similar. So I suggest they be independent.
[Ray] What I mean is to merge SetMemoryRegion(NonExec|ReadOly) to SetMemoryRegionAttribute(). Similarly, GetXXX can be merged as well. What’s your opinion?
1. The EfiAttributeConverse, GetMemoryRegionAttribute, SetMemoryRegionAttributes and ConfigureMemoryManagementUnit will be retained and other APIs will be removed. Because the functions expressed by other APIs can be completed though the retained API.
[Ray] I didn’t notice EfiAttributeConverse(). I guess callers may not need to know the architectural specific attributes. So EfiAttributeConverse() might be not needed as a public API.
1. You pointed out MEMORY_REGION_DESCRIPTOR have no one to construct it, do I need add a new API to construct it? Could it be named GetMemoryMapPolicy and accept a parameter with MEMORY_REGION_DESCRIPTOR** ?
[Ray] So the GetMemoryRegionAttribute() and SetMemoryRegionAttributes() are performed on the active translation table. ConfigureMemoryManagementUint() is to create a translation table with a list of memory attributes. How about the following idea?
[Ray] (Set|Get)MemoryRegionAttribute() are performed on a translation table buffer. And caller calls SetMemoryRegionAttribute() to modify the translation table buffer supplied as the parameter. With this, ConfigureMemoryManagementUnit() is not needed.
Hope to hear from you! :)
Thanks,
Chao
On 2023/11/30 10:25, Chao Li wrote:
Hi Ray,
Thanks for review, here are some of my thoughts:
On 2023/11/30 08:59, Ni, Ray wrote:
Chao,
Since the lib class is so general, I'd like to understand more details to make sure it can properly fit into any CPU arch.
In X86, cache setting is through MSRs and Page tables, and memory access control (read-only, not-present, non-executable) is through page tables.
Let me understand, 'cache setting' means does it access a certain address(probably a memory address) via cache? If so, I'd say the 'cache setting' should be a part of attributes.
This CpuMmuLib is to provide both services. How does LoongArch64 manage the cache settings and memory access control?
Is it proper to combine both services into one lib?
In LoongArch64, cache settings and memory access control are performed via page tables. Please check the patch 14 of this series.
If the backend silicon IP is the same one that supports the "one" lib design, can we refine the lib API a bit?
Yes, I think Attribute's instance family can be bear the memory access and cache setting. So what are you suggestions if we improve the lib API?
We have (Set|Get)MemoryRegionAttribute() and (Set|Clear)MemoryRegion(NoExec|ReadOnly). Can we merge them together?
Do you means the (Set|Get) merge together(differentiate Get or Set operations by parameters)? If so, I think it's OK, but maybe some existing instances will be modified together.
And the API ConfigureMemoryManagementUint() accepts MEMORY_REGION_DESCRIPTOR but none of other APIs helps to construct the descriptor.
Yes, currently, no one helps construct MEMORY_REGION_DESCRIPTOR. I think the construction of descriptors is not part of the API, it should be the localized or private when I design them. Do I need to add an API to construct descripters?
It seems to me the MmuLib is simply a combination of different random APIs.
It's not a well-designed library class.
We need more discussion to make it be able to be accommodated by other archs in future, at least by figuring out the path of X86, ARM.
Yes, the APIs looks like so fragmented and we should improve them. So we should talk more about this API, thanks.
Thanks,
Ray
-----Original Message-----
From: Chao Li <lichao@loongson.cn><mailto:lichao@loongson.cn>
Sent: Friday, November 17, 2023 6:00 PM
To: devel@edk2.groups.io<mailto:devel@edk2.groups.io>
Cc: Dong, Eric <eric.dong@intel.com><mailto:eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com><mailto:ray.ni@intel.com>; Kumar,
Rahul R <rahul.r.kumar@intel.com><mailto:rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com><mailto:kraxel@redhat.com>;
Leif Lindholm <quic_llindhol@quicinc.com><mailto:quic_llindhol@quicinc.com>; Ard Biesheuvel
<ardb+tianocore@kernel.org><mailto:ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com><mailto:sami.mujawar@arm.com>;
Sunil V L <sunilvl@ventanamicro.com><mailto:sunilvl@ventanamicro.com>; Warkentin, Andrei
<andrei.warkentin@intel.com><mailto:andrei.warkentin@intel.com>
Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
Add a new header file CpuMmuLib.h, whitch is referenced from
ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
LoongArch64 is added, and more architectures can be accommodated in the
future.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Eric Dong <eric.dong@intel.com><mailto:eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com><mailto:ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com><mailto:rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com><mailto:kraxel@redhat.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com><mailto:quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org><mailto:ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com><mailto:sami.mujawar@arm.com>
Cc: Sunil V L <sunilvl@ventanamicro.com><mailto:sunilvl@ventanamicro.com>
Cc: Andrei Warkentin <andrei.warkentin@intel.com><mailto:andrei.warkentin@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn><mailto:lichao@loongson.cn>
---
UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
+++++++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 4 +
2 files changed, 159 insertions(+)
create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
b/UefiCpuPkg/Include/Library/CpuMmuLib.h
new file mode 100644
index 0000000000..23b2fe34ac
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
@@ -0,0 +1,155 @@
+/** @file
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights
reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_MMU_LIB_H_
+#define CPU_MMU_LIB_H_
+
+#include <Uefi/UefiBaseType.h>
+
+#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;
+
+/**
+ Converts EFI Attributes to corresponding architecture Attributes.
+
+ @param[in] EfiAttributes Efi Attributes.
+
+ @retval Corresponding architecture attributes.
+**/
+UINTN
+EfiAttributeConverse (
+ 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
+GetMemoryRegionAttribute (
+ 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.
+ @param[in] AttributeMask Mask of memory attributes to take into
account.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+**/
+EFI_STATUS
+SetMemoryRegionAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length,
+ IN UINTN Attributes,
+ IN UINT64 AttributeMask
+ );
+
+/**
+ 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
+SetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ );
+
+/**
+ Clears the non-executable Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to
clear the Attributes.
+ @param[in] Length The length of the memory region to clear
the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was clear successfully
+**/
+EFI_STATUS
+EFIAPI
+ClearMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Sets the read-only 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
+EFIAPI
+SetMemoryRegionReadOnly (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Clears the read-only Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to
clear the Attributes.
+ @param[in] Length The length of the memory region to clear
the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was clear successfully
+**/
+EFI_STATUS
+EFIAPI
+ClearMemoryRegionReadOnly (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Create a page table and initialize the memory management unit(MMU).
+
+ @param[in] MemoryTable A pointer to a memory ragion
table.
+ @param[out] TranslationTableBase A pointer to a translation table base
address.
+ @param[out] TranslationTableSize A pointer to a translation table base
size.
+
+ @retval EFI_SUCCESS Configure MMU successfully.
+ EFI_INVALID_PARAMETER MemoryTable is NULL.
+ EFI_UNSUPPORTED Out of memory space or
size not aligned.
+**/
+EFI_STATUS
+EFIAPI
+ConfigureMemoryManagementUint (
+ IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
+ OUT VOID **TranslationTableBase OPTIONAL,
+ OUT UINTN *TranslationTableSize OPTIONAL
+ );
+
+#endif // CPU_MMU_LIB_H_
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 154b1d06fe..150beae981 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -62,6 +62,10 @@
## @libraryclass Provides function for manipulating x86 paging
structures.
CpuPageTableLib|Include/Library/CpuPageTableLib.h
+[LibraryClasses.LoongArch64]
+ ## @libraryclass Provides macros and functions for the memory
management unit.
+ CpuMmuLib|Include/Library/CpuMmuLib.h
+
## @libraryclass Provides functions for manipulating smram savestate
registers.
MmSaveStateLib|Include/Library/MmSaveStateLib.h
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112071): https://edk2.groups.io/g/devel/message/112071
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 29319 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
2023-12-05 8:27 ` Ni, Ray
@ 2023-12-05 12:27 ` Chao Li
[not found] ` <179DEF40376B662A.18076@groups.io>
1 sibling, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-12-05 12:27 UTC (permalink / raw)
To: Ni, Ray, devel@edk2.groups.io
Cc: Dong, Eric, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Warkentin, Andrei
[-- Attachment #1: Type: text/plain, Size: 18366 bytes --]
Hi Ray,
Thanks,
Chao
On 2023/12/5 16:27, Ni, Ray wrote:
>
> Thanks,
>
> Ray
>
> *From:* devel@edk2.groups.io <devel@edk2.groups.io> *On Behalf Of *Chao Li
> *Sent:* Monday, December 4, 2023 3:32 PM
> *To:* devel@edk2.groups.io; Ni, Ray <ray.ni@intel.com>
> *Cc:* Dong, Eric <eric.dong@intel.com>; Kumar, Rahul R
> <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Leif
> Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>;
> Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei
> <andrei.warkentin@intel.com>
> *Subject:* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add
> CpuMmuLib.h to UefiCpuPkg
>
> Hi Ray,
>
> For this patch, I checked again and here are my opinions:
>
> 1. (Set|Get)MemoryRegionAttribute is difficult to merge together,
> because the parameters between the tow APIs are not similar. So I
> suggest they be independent.
>
> [Ray] What I mean is to merge SetMemoryRegion(NonExec|ReadOly) to
> SetMemoryRegionAttribute(). Similarly, GetXXX can be merged as well.
> What’s your opinion?
>
Ok, I already said it in point 2, other APIs will be removed.
>
> 2. The EfiAttributeConverse, GetMemoryRegionAttribute,
> SetMemoryRegionAttributes and ConfigureMemoryManagementUnit will
> be retained and other APIs will be removed. Because the functions
> expressed by other APIs can be completed though the retained API.
>
> [Ray] I didn’t notice EfiAttributeConverse(). I guess callers may not
> need to know the architectural specific attributes. So
> EfiAttributeConverse() might be not needed as a public API.
>
I agree, the EfiAttributeCoverse() complete by caller or as a private API.
>
> 3. You pointed out MEMORY_REGION_DESCRIPTOR have no one to construct
> it, do I need add a new API to construct it? Could it be named
> GetMemoryMapPolicy and accept a parameter with
> MEMORY_REGION_DESCRIPTOR** ?
>
> [Ray] So the GetMemoryRegionAttribute() and
> SetMemoryRegionAttributes() are performed on the active translation
> table. ConfigureMemoryManagementUint() is to create a translation
> table with a list of memory attributes. How about the following idea?
>
> [Ray] (Set|Get)MemoryRegionAttribute() are performed on a translation
> table buffer. And caller calls SetMemoryRegionAttribute() to modify
> the translation table buffer supplied as the parameter. With this,
> ConfigureMemoryManagementUnit() is not needed.
>
Ah, I think you may have some misunderstanding, the
ConfigureMemoryManagementUint is a function that to initialize the MMU.
The MEMORY_REGION_DESCRIPTOR will created by the private API, and then
the caller will call the ConfigureMemoryManagementUnit to initialize the
MMU first(may be fill the static page tables and so on).
But I thought about it again and it seems you are right, the
ConfigureMemoryManagementUnit and discrptor creater as the public APIs
are not appropriate. They are more suitable as some private APIs.
So, (Get|Set)MemoryRegionAttribute() will be the public APIs and the
parameters will be the same with this change?
> Hope to hear from you! :)
>
> Thanks,
> Chao
>
> On 2023/11/30 10:25, Chao Li wrote:
>
> Hi Ray,
>
> Thanks for review, here are some of my thoughts:
>
> On 2023/11/30 08:59, Ni, Ray wrote:
>
> Chao,
>
> Since the lib class is so general, I'd like to understand more details to make sure it can properly fit into any CPU arch.
>
> In X86, cache setting is through MSRs and Page tables, and memory access control (read-only, not-present, non-executable) is through page tables.
>
> Let me understand, 'cache setting' means does it access a certain
> address(probably a memory address) via cache? If so, I'd say the
> 'cache setting' should be a part of attributes.
>
> This CpuMmuLib is to provide both services. How does LoongArch64 manage the cache settings and memory access control?
>
> Is it proper to combine both services into one lib?
>
> In LoongArch64, cache settings and memory access control are
> performed via page tables. Please check the patch 14 of this series.
>
> If the backend silicon IP is the same one that supports the "one" lib design, can we refine the lib API a bit?
>
> Yes, I think Attribute's instance family can be bear the memory
> access and cache setting. So what are you suggestions if we
> improve the lib API?
>
> We have (Set|Get)MemoryRegionAttribute() and (Set|Clear)MemoryRegion(NoExec|ReadOnly). Can we merge them together?
>
> Do you means the (Set|Get) merge together(differentiate Get or Set
> operations by parameters)? If so, I think it's OK, but maybe some
> existing instances will be modified together.
>
> And the API ConfigureMemoryManagementUint() accepts MEMORY_REGION_DESCRIPTOR but none of other APIs helps to construct the descriptor.
>
> Yes, currently, no one helps construct MEMORY_REGION_DESCRIPTOR. I
> think the construction of descriptors is not part of the API, it
> should be the localized or private when I design them. Do I need
> to add an API to construct descripters?
>
> It seems to me the MmuLib is simply a combination of different random APIs.
>
> It's not a well-designed library class.
>
> We need more discussion to make it be able to be accommodated by other archs in future, at least by figuring out the path of X86, ARM.
>
> Yes, the APIs looks like so fragmented and we should improve them.
> So we should talk more about this API, thanks.
>
> Thanks,
>
> Ray
>
> -----Original Message-----
>
> From: Chao Li<lichao@loongson.cn> <mailto:lichao@loongson.cn>
>
> Sent: Friday, November 17, 2023 6:00 PM
>
> To:devel@edk2.groups.io
>
> Cc: Dong, Eric<eric.dong@intel.com> <mailto:eric.dong@intel.com>; Ni, Ray<ray.ni@intel.com> <mailto:ray.ni@intel.com>; Kumar,
>
> Rahul R<rahul.r.kumar@intel.com> <mailto:rahul.r.kumar@intel.com>; Gerd Hoffmann<kraxel@redhat.com> <mailto:kraxel@redhat.com>;
>
> Leif Lindholm<quic_llindhol@quicinc.com> <mailto:quic_llindhol@quicinc.com>; Ard Biesheuvel
>
> <ardb+tianocore@kernel.org> <mailto:ardb+tianocore@kernel.org>; Sami Mujawar<sami.mujawar@arm.com> <mailto:sami.mujawar@arm.com>;
>
> Sunil V L<sunilvl@ventanamicro.com> <mailto:sunilvl@ventanamicro.com>; Warkentin, Andrei
>
> <andrei.warkentin@intel.com> <mailto:andrei.warkentin@intel.com>
>
> Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
>
> Add a new header file CpuMmuLib.h, whitch is referenced from
>
> ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
>
> LoongArch64 is added, and more architectures can be accommodated in the
>
> future.
>
> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Eric Dong<eric.dong@intel.com> <mailto:eric.dong@intel.com>
>
> Cc: Ray Ni<ray.ni@intel.com> <mailto:ray.ni@intel.com>
>
> Cc: Rahul Kumar<rahul1.kumar@intel.com> <mailto:rahul1.kumar@intel.com>
>
> Cc: Gerd Hoffmann<kraxel@redhat.com> <mailto:kraxel@redhat.com>
>
> Cc: Leif Lindholm<quic_llindhol@quicinc.com> <mailto:quic_llindhol@quicinc.com>
>
> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org> <mailto:ardb+tianocore@kernel.org>
>
> Cc: Sami Mujawar<sami.mujawar@arm.com> <mailto:sami.mujawar@arm.com>
>
> Cc: Sunil V L<sunilvl@ventanamicro.com> <mailto:sunilvl@ventanamicro.com>
>
> Cc: Andrei Warkentin<andrei.warkentin@intel.com> <mailto:andrei.warkentin@intel.com>
>
> Signed-off-by: Chao Li<lichao@loongson.cn> <mailto:lichao@loongson.cn>
>
> ---
>
> UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
>
> +++++++++++++++++++++++++
>
> UefiCpuPkg/UefiCpuPkg.dec | 4 +
>
> 2 files changed, 159 insertions(+)
>
> create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> new file mode 100644
>
> index 0000000000..23b2fe34ac
>
> --- /dev/null
>
> +++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> @@ -0,0 +1,155 @@
>
> +/** @file
>
> +
>
> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights
>
> reserved.<BR>
>
> +
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +
>
> +**/
>
> +
>
> +#ifndef CPU_MMU_LIB_H_
>
> +#define CPU_MMU_LIB_H_
>
> +
>
> +#include <Uefi/UefiBaseType.h>
>
> +
>
> +#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;
>
> +
>
> +/**
>
> + Converts EFI Attributes to corresponding architecture Attributes.
>
> +
>
> + @param[in] EfiAttributes Efi Attributes.
>
> +
>
> + @retval Corresponding architecture attributes.
>
> +**/
>
> +UINTN
>
> +EfiAttributeConverse (
>
> + 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
>
> +GetMemoryRegionAttribute (
>
> + 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.
>
> + @param[in] AttributeMask Mask of memory attributes to take into
>
> account.
>
> +
>
> + @retval EFI_SUCCESS The Attributes was set successfully
>
> +**/
>
> +EFI_STATUS
>
> +SetMemoryRegionAttributes (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINTN Length,
>
> + IN UINTN Attributes,
>
> + IN UINT64 AttributeMask
>
> + );
>
> +
>
> +/**
>
> + 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
>
> +SetMemoryRegionNoExec (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINTN Length
>
> + );
>
> +
>
> +/**
>
> + Clears the non-executable Attributes for the specified memory region
>
> +
>
> + @param[in] BaseAddress The base address of the memory region to
>
> clear the Attributes.
>
> + @param[in] Length The length of the memory region to clear
>
> the Attributes.
>
> +
>
> + @retval EFI_SUCCESS The Attributes was clear successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +ClearMemoryRegionNoExec (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINT64 Length
>
> + );
>
> +
>
> +/**
>
> + Sets the read-only 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
>
> +EFIAPI
>
> +SetMemoryRegionReadOnly (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINT64 Length
>
> + );
>
> +
>
> +/**
>
> + Clears the read-only Attributes for the specified memory region
>
> +
>
> + @param[in] BaseAddress The base address of the memory region to
>
> clear the Attributes.
>
> + @param[in] Length The length of the memory region to clear
>
> the Attributes.
>
> +
>
> + @retval EFI_SUCCESS The Attributes was clear successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +ClearMemoryRegionReadOnly (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINT64 Length
>
> + );
>
> +
>
> +/**
>
> + Create a page table and initialize the memory management unit(MMU).
>
> +
>
> + @param[in] MemoryTable A pointer to a memory ragion
>
> table.
>
> + @param[out] TranslationTableBase A pointer to a translation table base
>
> address.
>
> + @param[out] TranslationTableSize A pointer to a translation table base
>
> size.
>
> +
>
> + @retval EFI_SUCCESS Configure MMU successfully.
>
> + EFI_INVALID_PARAMETER MemoryTable is NULL.
>
> + EFI_UNSUPPORTED Out of memory space or
>
> size not aligned.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +ConfigureMemoryManagementUint (
>
> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
>
> + OUT VOID **TranslationTableBase OPTIONAL,
>
> + OUT UINTN *TranslationTableSize OPTIONAL
>
> + );
>
> +
>
> +#endif // CPU_MMU_LIB_H_
>
> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
>
> index 154b1d06fe..150beae981 100644
>
> --- a/UefiCpuPkg/UefiCpuPkg.dec
>
> +++ b/UefiCpuPkg/UefiCpuPkg.dec
>
> @@ -62,6 +62,10 @@
>
> ## @libraryclass Provides function for manipulating x86 paging
>
> structures.
>
> CpuPageTableLib|Include/Library/CpuPageTableLib.h
>
> +[LibraryClasses.LoongArch64]
>
> + ## @libraryclass Provides macros and functions for the memory
>
> management unit.
>
> + CpuMmuLib|Include/Library/CpuMmuLib.h
>
> +
>
> ## @libraryclass Provides functions for manipulating smram savestate
>
> registers.
>
> MmSaveStateLib|Include/Library/MmSaveStateLib.h
>
> --
>
> 2.27.0
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112079): https://edk2.groups.io/g/devel/message/112079
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 33450 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
[not found] ` <179DEF40376B662A.18076@groups.io>
@ 2023-12-08 2:10 ` Chao Li
2023-12-11 8:13 ` Ni, Ray
0 siblings, 1 reply; 71+ messages in thread
From: Chao Li @ 2023-12-08 2:10 UTC (permalink / raw)
To: Ni, Ray, devel@edk2.groups.io
Cc: Dong, Eric, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Warkentin, Andrei
[-- Attachment #1: Type: text/plain, Size: 19103 bytes --]
Hi Ray,
Do you think this plan is OK? If possible, I will submit the V4 today.
Thanks,
Chao
On 2023/12/5 20:27, Chao Li wrote:
>
> Hi Ray,
>
> On 2023/12/5 16:27, Ni, Ray wrote:
>>
>> Thanks,
>>
>> Ray
>>
>> *From:* devel@edk2.groups.io <devel@edk2.groups.io> *On Behalf Of
>> *Chao Li
>> *Sent:* Monday, December 4, 2023 3:32 PM
>> *To:* devel@edk2.groups.io; Ni, Ray <ray.ni@intel.com>
>> *Cc:* Dong, Eric <eric.dong@intel.com>; Kumar, Rahul R
>> <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Leif
>> Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel
>> <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>;
>> Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei
>> <andrei.warkentin@intel.com>
>> *Subject:* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add
>> CpuMmuLib.h to UefiCpuPkg
>>
>> Hi Ray,
>>
>> For this patch, I checked again and here are my opinions:
>>
>> 1. (Set|Get)MemoryRegionAttribute is difficult to merge together,
>> because the parameters between the tow APIs are not similar. So I
>> suggest they be independent.
>>
>> [Ray] What I mean is to merge SetMemoryRegion(NonExec|ReadOly) to
>> SetMemoryRegionAttribute(). Similarly, GetXXX can be merged as well.
>> What’s your opinion?
>>
> Ok, I already said it in point 2, other APIs will be removed.
>>
>> 2. The EfiAttributeConverse, GetMemoryRegionAttribute,
>> SetMemoryRegionAttributes and ConfigureMemoryManagementUnit will
>> be retained and other APIs will be removed. Because the functions
>> expressed by other APIs can be completed though the retained API.
>>
>> [Ray] I didn’t notice EfiAttributeConverse(). I guess callers may not
>> need to know the architectural specific attributes. So
>> EfiAttributeConverse() might be not needed as a public API.
>>
> I agree, the EfiAttributeCoverse() complete by caller or as a private API.
>>
>> 3. You pointed out MEMORY_REGION_DESCRIPTOR have no one to construct
>> it, do I need add a new API to construct it? Could it be named
>> GetMemoryMapPolicy and accept a parameter with
>> MEMORY_REGION_DESCRIPTOR** ?
>>
>> [Ray] So the GetMemoryRegionAttribute() and
>> SetMemoryRegionAttributes() are performed on the active translation
>> table. ConfigureMemoryManagementUint() is to create a translation
>> table with a list of memory attributes. How about the following idea?
>>
>> [Ray] (Set|Get)MemoryRegionAttribute() are performed on a translation
>> table buffer. And caller calls SetMemoryRegionAttribute() to modify
>> the translation table buffer supplied as the parameter. With this,
>> ConfigureMemoryManagementUnit() is not needed.
>>
> Ah, I think you may have some misunderstanding, the
> ConfigureMemoryManagementUint is a function that to initialize the
> MMU. The MEMORY_REGION_DESCRIPTOR will created by the private API, and
> then the caller will call the ConfigureMemoryManagementUnit to
> initialize the MMU first(may be fill the static page tables and so on).
>
> But I thought about it again and it seems you are right, the
> ConfigureMemoryManagementUnit and discrptor creater as the public APIs
> are not appropriate. They are more suitable as some private APIs.
>
> So, (Get|Set)MemoryRegionAttribute() will be the public APIs and the
> parameters will be the same with this change?
>
>> Hope to hear from you! :)
>>
>> Thanks,
>> Chao
>>
>> On 2023/11/30 10:25, Chao Li wrote:
>>
>> Hi Ray,
>>
>> Thanks for review, here are some of my thoughts:
>>
>> On 2023/11/30 08:59, Ni, Ray wrote:
>>
>> Chao,
>>
>> Since the lib class is so general, I'd like to understand more details to make sure it can properly fit into any CPU arch.
>>
>> In X86, cache setting is through MSRs and Page tables, and memory access control (read-only, not-present, non-executable) is through page tables.
>>
>> Let me understand, 'cache setting' means does it access a certain
>> address(probably a memory address) via cache? If so, I'd say the
>> 'cache setting' should be a part of attributes.
>>
>> This CpuMmuLib is to provide both services. How does LoongArch64 manage the cache settings and memory access control?
>>
>> Is it proper to combine both services into one lib?
>>
>> In LoongArch64, cache settings and memory access control are
>> performed via page tables. Please check the patch 14 of this series.
>>
>> If the backend silicon IP is the same one that supports the "one" lib design, can we refine the lib API a bit?
>>
>> Yes, I think Attribute's instance family can be bear the memory
>> access and cache setting. So what are you suggestions if we
>> improve the lib API?
>>
>> We have (Set|Get)MemoryRegionAttribute() and (Set|Clear)MemoryRegion(NoExec|ReadOnly). Can we merge them together?
>>
>> Do you means the (Set|Get) merge together(differentiate Get or
>> Set operations by parameters)? If so, I think it's OK, but maybe
>> some existing instances will be modified together.
>>
>> And the API ConfigureMemoryManagementUint() accepts MEMORY_REGION_DESCRIPTOR but none of other APIs helps to construct the descriptor.
>>
>> Yes, currently, no one helps construct MEMORY_REGION_DESCRIPTOR.
>> I think the construction of descriptors is not part of the API,
>> it should be the localized or private when I design them. Do I
>> need to add an API to construct descripters?
>>
>> It seems to me the MmuLib is simply a combination of different random APIs.
>>
>> It's not a well-designed library class.
>>
>> We need more discussion to make it be able to be accommodated by other archs in future, at least by figuring out the path of X86, ARM.
>>
>> Yes, the APIs looks like so fragmented and we should improve
>> them. So we should talk more about this API, thanks.
>>
>> Thanks,
>>
>> Ray
>>
>> -----Original Message-----
>>
>> From: Chao Li<lichao@loongson.cn> <mailto:lichao@loongson.cn>
>>
>> Sent: Friday, November 17, 2023 6:00 PM
>>
>> To:devel@edk2.groups.io
>>
>> Cc: Dong, Eric<eric.dong@intel.com> <mailto:eric.dong@intel.com>; Ni, Ray<ray.ni@intel.com> <mailto:ray.ni@intel.com>; Kumar,
>>
>> Rahul R<rahul.r.kumar@intel.com> <mailto:rahul.r.kumar@intel.com>; Gerd Hoffmann<kraxel@redhat.com> <mailto:kraxel@redhat.com>;
>>
>> Leif Lindholm<quic_llindhol@quicinc.com> <mailto:quic_llindhol@quicinc.com>; Ard Biesheuvel
>>
>> <ardb+tianocore@kernel.org> <mailto:ardb+tianocore@kernel.org>; Sami Mujawar<sami.mujawar@arm.com> <mailto:sami.mujawar@arm.com>;
>>
>> Sunil V L<sunilvl@ventanamicro.com> <mailto:sunilvl@ventanamicro.com>; Warkentin, Andrei
>>
>> <andrei.warkentin@intel.com> <mailto:andrei.warkentin@intel.com>
>>
>> Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
>>
>> Add a new header file CpuMmuLib.h, whitch is referenced from
>>
>> ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
>>
>> LoongArch64 is added, and more architectures can be accommodated in the
>>
>> future.
>>
>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>
>> Cc: Eric Dong<eric.dong@intel.com> <mailto:eric.dong@intel.com>
>>
>> Cc: Ray Ni<ray.ni@intel.com> <mailto:ray.ni@intel.com>
>>
>> Cc: Rahul Kumar<rahul1.kumar@intel.com> <mailto:rahul1.kumar@intel.com>
>>
>> Cc: Gerd Hoffmann<kraxel@redhat.com> <mailto:kraxel@redhat.com>
>>
>> Cc: Leif Lindholm<quic_llindhol@quicinc.com> <mailto:quic_llindhol@quicinc.com>
>>
>> Cc: Ard Biesheuvel<ardb+tianocore@kernel.org> <mailto:ardb+tianocore@kernel.org>
>>
>> Cc: Sami Mujawar<sami.mujawar@arm.com> <mailto:sami.mujawar@arm.com>
>>
>> Cc: Sunil V L<sunilvl@ventanamicro.com> <mailto:sunilvl@ventanamicro.com>
>>
>> Cc: Andrei Warkentin<andrei.warkentin@intel.com> <mailto:andrei.warkentin@intel.com>
>>
>> Signed-off-by: Chao Li<lichao@loongson.cn> <mailto:lichao@loongson.cn>
>>
>> ---
>>
>> UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
>>
>> +++++++++++++++++++++++++
>>
>> UefiCpuPkg/UefiCpuPkg.dec | 4 +
>>
>> 2 files changed, 159 insertions(+)
>>
>> create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
>>
>> diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
>>
>> b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>>
>> new file mode 100644
>>
>> index 0000000000..23b2fe34ac
>>
>> --- /dev/null
>>
>> +++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>>
>> @@ -0,0 +1,155 @@
>>
>> +/** @file
>>
>> +
>>
>> + Copyright (c) 2023 Loongson Technology Corporation Limited. All rights
>>
>> reserved.<BR>
>>
>> +
>>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>>
>> +
>>
>> +**/
>>
>> +
>>
>> +#ifndef CPU_MMU_LIB_H_
>>
>> +#define CPU_MMU_LIB_H_
>>
>> +
>>
>> +#include <Uefi/UefiBaseType.h>
>>
>> +
>>
>> +#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;
>>
>> +
>>
>> +/**
>>
>> + Converts EFI Attributes to corresponding architecture Attributes.
>>
>> +
>>
>> + @param[in] EfiAttributes Efi Attributes.
>>
>> +
>>
>> + @retval Corresponding architecture attributes.
>>
>> +**/
>>
>> +UINTN
>>
>> +EfiAttributeConverse (
>>
>> + 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
>>
>> +GetMemoryRegionAttribute (
>>
>> + 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.
>>
>> + @param[in] AttributeMask Mask of memory attributes to take into
>>
>> account.
>>
>> +
>>
>> + @retval EFI_SUCCESS The Attributes was set successfully
>>
>> +**/
>>
>> +EFI_STATUS
>>
>> +SetMemoryRegionAttributes (
>>
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>
>> + IN UINTN Length,
>>
>> + IN UINTN Attributes,
>>
>> + IN UINT64 AttributeMask
>>
>> + );
>>
>> +
>>
>> +/**
>>
>> + 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
>>
>> +SetMemoryRegionNoExec (
>>
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>
>> + IN UINTN Length
>>
>> + );
>>
>> +
>>
>> +/**
>>
>> + Clears the non-executable Attributes for the specified memory region
>>
>> +
>>
>> + @param[in] BaseAddress The base address of the memory region to
>>
>> clear the Attributes.
>>
>> + @param[in] Length The length of the memory region to clear
>>
>> the Attributes.
>>
>> +
>>
>> + @retval EFI_SUCCESS The Attributes was clear successfully
>>
>> +**/
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +ClearMemoryRegionNoExec (
>>
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>
>> + IN UINT64 Length
>>
>> + );
>>
>> +
>>
>> +/**
>>
>> + Sets the read-only 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
>>
>> +EFIAPI
>>
>> +SetMemoryRegionReadOnly (
>>
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>
>> + IN UINT64 Length
>>
>> + );
>>
>> +
>>
>> +/**
>>
>> + Clears the read-only Attributes for the specified memory region
>>
>> +
>>
>> + @param[in] BaseAddress The base address of the memory region to
>>
>> clear the Attributes.
>>
>> + @param[in] Length The length of the memory region to clear
>>
>> the Attributes.
>>
>> +
>>
>> + @retval EFI_SUCCESS The Attributes was clear successfully
>>
>> +**/
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +ClearMemoryRegionReadOnly (
>>
>> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>>
>> + IN UINT64 Length
>>
>> + );
>>
>> +
>>
>> +/**
>>
>> + Create a page table and initialize the memory management unit(MMU).
>>
>> +
>>
>> + @param[in] MemoryTable A pointer to a memory ragion
>>
>> table.
>>
>> + @param[out] TranslationTableBase A pointer to a translation table base
>>
>> address.
>>
>> + @param[out] TranslationTableSize A pointer to a translation table base
>>
>> size.
>>
>> +
>>
>> + @retval EFI_SUCCESS Configure MMU successfully.
>>
>> + EFI_INVALID_PARAMETER MemoryTable is NULL.
>>
>> + EFI_UNSUPPORTED Out of memory space or
>>
>> size not aligned.
>>
>> +**/
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +ConfigureMemoryManagementUint (
>>
>> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
>>
>> + OUT VOID **TranslationTableBase OPTIONAL,
>>
>> + OUT UINTN *TranslationTableSize OPTIONAL
>>
>> + );
>>
>> +
>>
>> +#endif // CPU_MMU_LIB_H_
>>
>> diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
>>
>> index 154b1d06fe..150beae981 100644
>>
>> --- a/UefiCpuPkg/UefiCpuPkg.dec
>>
>> +++ b/UefiCpuPkg/UefiCpuPkg.dec
>>
>> @@ -62,6 +62,10 @@
>>
>> ## @libraryclass Provides function for manipulating x86 paging
>>
>> structures.
>>
>> CpuPageTableLib|Include/Library/CpuPageTableLib.h
>>
>> +[LibraryClasses.LoongArch64]
>>
>> + ## @libraryclass Provides macros and functions for the memory
>>
>> management unit.
>>
>> + CpuMmuLib|Include/Library/CpuMmuLib.h
>>
>> +
>>
>> ## @libraryclass Provides functions for manipulating smram savestate
>>
>> registers.
>>
>> MmSaveStateLib|Include/Library/MmSaveStateLib.h
>>
>> --
>>
>> 2.27.0
>>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112206): https://edk2.groups.io/g/devel/message/112206
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 35526 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
2023-12-08 2:10 ` Chao Li
@ 2023-12-11 8:13 ` Ni, Ray
2023-12-11 8:19 ` Chao Li
0 siblings, 1 reply; 71+ messages in thread
From: Ni, Ray @ 2023-12-11 8:13 UTC (permalink / raw)
To: devel@edk2.groups.io, lichao@loongson.cn
Cc: Dong, Eric, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Warkentin, Andrei
[-- Attachment #1: Type: text/plain, Size: 15512 bytes --]
Thanks. I think we are aligned. Looking forward to your v4 patch.
Thanks,
Ray
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Chao Li
Sent: Friday, December 8, 2023 10:10 AM
To: Ni, Ray <ray.ni@intel.com>; devel@edk2.groups.io
Cc: Dong, Eric <eric.dong@intel.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Leif Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>; Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei <andrei.warkentin@intel.com>
Subject: Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
Hi Ray,
Do you think this plan is OK? If possible, I will submit the V4 today.
Thanks,
Chao
On 2023/12/5 20:27, Chao Li wrote:
Hi Ray,
On 2023/12/5 16:27, Ni, Ray wrote:
Thanks,
Ray
From: devel@edk2.groups.io<mailto:devel@edk2.groups.io> <devel@edk2.groups.io><mailto:devel@edk2.groups.io> On Behalf Of Chao Li
Sent: Monday, December 4, 2023 3:32 PM
To: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Ni, Ray <ray.ni@intel.com><mailto:ray.ni@intel.com>
Cc: Dong, Eric <eric.dong@intel.com><mailto:eric.dong@intel.com>; Kumar, Rahul R <rahul.r.kumar@intel.com><mailto:rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com><mailto:kraxel@redhat.com>; Leif Lindholm <quic_llindhol@quicinc.com><mailto:quic_llindhol@quicinc.com>; Ard Biesheuvel <ardb+tianocore@kernel.org><mailto:ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com><mailto:sami.mujawar@arm.com>; Sunil V L <sunilvl@ventanamicro.com><mailto:sunilvl@ventanamicro.com>; Warkentin, Andrei <andrei.warkentin@intel.com><mailto:andrei.warkentin@intel.com>
Subject: Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
Hi Ray,
For this patch, I checked again and here are my opinions:
1. (Set|Get)MemoryRegionAttribute is difficult to merge together, because the parameters between the tow APIs are not similar. So I suggest they be independent.
[Ray] What I mean is to merge SetMemoryRegion(NonExec|ReadOly) to SetMemoryRegionAttribute(). Similarly, GetXXX can be merged as well. What’s your opinion?
Ok, I already said it in point 2, other APIs will be removed.
1. The EfiAttributeConverse, GetMemoryRegionAttribute, SetMemoryRegionAttributes and ConfigureMemoryManagementUnit will be retained and other APIs will be removed. Because the functions expressed by other APIs can be completed though the retained API.
[Ray] I didn’t notice EfiAttributeConverse(). I guess callers may not need to know the architectural specific attributes. So EfiAttributeConverse() might be not needed as a public API.
I agree, the EfiAttributeCoverse() complete by caller or as a private API.
1. You pointed out MEMORY_REGION_DESCRIPTOR have no one to construct it, do I need add a new API to construct it? Could it be named GetMemoryMapPolicy and accept a parameter with MEMORY_REGION_DESCRIPTOR** ?
[Ray] So the GetMemoryRegionAttribute() and SetMemoryRegionAttributes() are performed on the active translation table. ConfigureMemoryManagementUint() is to create a translation table with a list of memory attributes. How about the following idea?
[Ray] (Set|Get)MemoryRegionAttribute() are performed on a translation table buffer. And caller calls SetMemoryRegionAttribute() to modify the translation table buffer supplied as the parameter. With this, ConfigureMemoryManagementUnit() is not needed.
Ah, I think you may have some misunderstanding, the ConfigureMemoryManagementUint is a function that to initialize the MMU. The MEMORY_REGION_DESCRIPTOR will created by the private API, and then the caller will call the ConfigureMemoryManagementUnit to initialize the MMU first(may be fill the static page tables and so on).
But I thought about it again and it seems you are right, the ConfigureMemoryManagementUnit and discrptor creater as the public APIs are not appropriate. They are more suitable as some private APIs.
So, (Get|Set)MemoryRegionAttribute() will be the public APIs and the parameters will be the same with this change?
Hope to hear from you! :)
Thanks,
Chao
On 2023/11/30 10:25, Chao Li wrote:
Hi Ray,
Thanks for review, here are some of my thoughts:
On 2023/11/30 08:59, Ni, Ray wrote:
Chao,
Since the lib class is so general, I'd like to understand more details to make sure it can properly fit into any CPU arch.
In X86, cache setting is through MSRs and Page tables, and memory access control (read-only, not-present, non-executable) is through page tables.
Let me understand, 'cache setting' means does it access a certain address(probably a memory address) via cache? If so, I'd say the 'cache setting' should be a part of attributes.
This CpuMmuLib is to provide both services. How does LoongArch64 manage the cache settings and memory access control?
Is it proper to combine both services into one lib?
In LoongArch64, cache settings and memory access control are performed via page tables. Please check the patch 14 of this series.
If the backend silicon IP is the same one that supports the "one" lib design, can we refine the lib API a bit?
Yes, I think Attribute's instance family can be bear the memory access and cache setting. So what are you suggestions if we improve the lib API?
We have (Set|Get)MemoryRegionAttribute() and (Set|Clear)MemoryRegion(NoExec|ReadOnly). Can we merge them together?
Do you means the (Set|Get) merge together(differentiate Get or Set operations by parameters)? If so, I think it's OK, but maybe some existing instances will be modified together.
And the API ConfigureMemoryManagementUint() accepts MEMORY_REGION_DESCRIPTOR but none of other APIs helps to construct the descriptor.
Yes, currently, no one helps construct MEMORY_REGION_DESCRIPTOR. I think the construction of descriptors is not part of the API, it should be the localized or private when I design them. Do I need to add an API to construct descripters?
It seems to me the MmuLib is simply a combination of different random APIs.
It's not a well-designed library class.
We need more discussion to make it be able to be accommodated by other archs in future, at least by figuring out the path of X86, ARM.
Yes, the APIs looks like so fragmented and we should improve them. So we should talk more about this API, thanks.
Thanks,
Ray
-----Original Message-----
From: Chao Li <lichao@loongson.cn><mailto:lichao@loongson.cn>
Sent: Friday, November 17, 2023 6:00 PM
To: devel@edk2.groups.io<mailto:devel@edk2.groups.io>
Cc: Dong, Eric <eric.dong@intel.com><mailto:eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com><mailto:ray.ni@intel.com>; Kumar,
Rahul R <rahul.r.kumar@intel.com><mailto:rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com><mailto:kraxel@redhat.com>;
Leif Lindholm <quic_llindhol@quicinc.com><mailto:quic_llindhol@quicinc.com>; Ard Biesheuvel
<ardb+tianocore@kernel.org><mailto:ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com><mailto:sami.mujawar@arm.com>;
Sunil V L <sunilvl@ventanamicro.com><mailto:sunilvl@ventanamicro.com>; Warkentin, Andrei
<andrei.warkentin@intel.com><mailto:andrei.warkentin@intel.com>
Subject: [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
Add a new header file CpuMmuLib.h, whitch is referenced from
ArmPkg/Include/Library/ArmMmuLib.h. Currently, only support for
LoongArch64 is added, and more architectures can be accommodated in the
future.
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Eric Dong <eric.dong@intel.com><mailto:eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com><mailto:ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com><mailto:rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com><mailto:kraxel@redhat.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com><mailto:quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org><mailto:ardb+tianocore@kernel.org>
Cc: Sami Mujawar <sami.mujawar@arm.com><mailto:sami.mujawar@arm.com>
Cc: Sunil V L <sunilvl@ventanamicro.com><mailto:sunilvl@ventanamicro.com>
Cc: Andrei Warkentin <andrei.warkentin@intel.com><mailto:andrei.warkentin@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn><mailto:lichao@loongson.cn>
---
UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
+++++++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 4 +
2 files changed, 159 insertions(+)
create mode 100644 UefiCpuPkg/Include/Library/CpuMmuLib.h
diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
b/UefiCpuPkg/Include/Library/CpuMmuLib.h
new file mode 100644
index 0000000000..23b2fe34ac
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
@@ -0,0 +1,155 @@
+/** @file
+
+ Copyright (c) 2023 Loongson Technology Corporation Limited. All rights
reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_MMU_LIB_H_
+#define CPU_MMU_LIB_H_
+
+#include <Uefi/UefiBaseType.h>
+
+#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;
+
+/**
+ Converts EFI Attributes to corresponding architecture Attributes.
+
+ @param[in] EfiAttributes Efi Attributes.
+
+ @retval Corresponding architecture attributes.
+**/
+UINTN
+EfiAttributeConverse (
+ 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
+GetMemoryRegionAttribute (
+ 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.
+ @param[in] AttributeMask Mask of memory attributes to take into
account.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+**/
+EFI_STATUS
+SetMemoryRegionAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length,
+ IN UINTN Attributes,
+ IN UINT64 AttributeMask
+ );
+
+/**
+ 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
+SetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ );
+
+/**
+ Clears the non-executable Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to
clear the Attributes.
+ @param[in] Length The length of the memory region to clear
the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was clear successfully
+**/
+EFI_STATUS
+EFIAPI
+ClearMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Sets the read-only 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
+EFIAPI
+SetMemoryRegionReadOnly (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Clears the read-only Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to
clear the Attributes.
+ @param[in] Length The length of the memory region to clear
the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was clear successfully
+**/
+EFI_STATUS
+EFIAPI
+ClearMemoryRegionReadOnly (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Create a page table and initialize the memory management unit(MMU).
+
+ @param[in] MemoryTable A pointer to a memory ragion
table.
+ @param[out] TranslationTableBase A pointer to a translation table base
address.
+ @param[out] TranslationTableSize A pointer to a translation table base
size.
+
+ @retval EFI_SUCCESS Configure MMU successfully.
+ EFI_INVALID_PARAMETER MemoryTable is NULL.
+ EFI_UNSUPPORTED Out of memory space or
size not aligned.
+**/
+EFI_STATUS
+EFIAPI
+ConfigureMemoryManagementUint (
+ IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
+ OUT VOID **TranslationTableBase OPTIONAL,
+ OUT UINTN *TranslationTableSize OPTIONAL
+ );
+
+#endif // CPU_MMU_LIB_H_
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 154b1d06fe..150beae981 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -62,6 +62,10 @@
## @libraryclass Provides function for manipulating x86 paging
structures.
CpuPageTableLib|Include/Library/CpuPageTableLib.h
+[LibraryClasses.LoongArch64]
+ ## @libraryclass Provides macros and functions for the memory
management unit.
+ CpuMmuLib|Include/Library/CpuMmuLib.h
+
## @libraryclass Provides functions for manipulating smram savestate
registers.
MmSaveStateLib|Include/Library/MmSaveStateLib.h
--
2.27.0
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112273): https://edk2.groups.io/g/devel/message/112273
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 42126 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg
2023-12-11 8:13 ` Ni, Ray
@ 2023-12-11 8:19 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-12-11 8:19 UTC (permalink / raw)
To: Ni, Ray, devel@edk2.groups.io
Cc: Dong, Eric, Kumar, Rahul R, Gerd Hoffmann, Leif Lindholm,
Ard Biesheuvel, Sami Mujawar, Sunil V L, Warkentin, Andrei
[-- Attachment #1: Type: text/plain, Size: 24211 bytes --]
Ok, I will submit the V4 today.
Thanks,
Chao
On 2023/12/11 16:13, Ni, Ray wrote:
>
> Thanks. I think we are aligned. Looking forward to your v4 patch.
>
> Thanks,
>
> Ray
>
> *From:*devel@edk2.groups.io <devel@edk2.groups.io> *On Behalf Of *Chao Li
> *Sent:* Friday, December 8, 2023 10:10 AM
> *To:* Ni, Ray <ray.ni@intel.com>; devel@edk2.groups.io
> *Cc:* Dong, Eric <eric.dong@intel.com>; Kumar, Rahul R
> <rahul.r.kumar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Leif
> Lindholm <quic_llindhol@quicinc.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Sami Mujawar <sami.mujawar@arm.com>;
> Sunil V L <sunilvl@ventanamicro.com>; Warkentin, Andrei
> <andrei.warkentin@intel.com>
> *Subject:* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add
> CpuMmuLib.h to UefiCpuPkg
>
> Hi Ray,
>
> Do you think this plan is OK? If possible, I will submit the V4 today.
>
> Thanks,
> Chao
>
> On 2023/12/5 20:27, Chao Li wrote:
>
> Hi Ray,
>
> On 2023/12/5 16:27, Ni, Ray wrote:
>
> Thanks,
>
> Ray
>
> *From:*devel@edk2.groups.io <devel@edk2.groups.io>
> <mailto:devel@edk2.groups.io> *On Behalf Of *Chao Li
> *Sent:* Monday, December 4, 2023 3:32 PM
> *To:* devel@edk2.groups.io; Ni, Ray <ray.ni@intel.com>
> <mailto:ray.ni@intel.com>
> *Cc:* Dong, Eric <eric.dong@intel.com>
> <mailto:eric.dong@intel.com>; Kumar, Rahul R
> <rahul.r.kumar@intel.com> <mailto:rahul.r.kumar@intel.com>;
> Gerd Hoffmann <kraxel@redhat.com> <mailto:kraxel@redhat.com>;
> Leif Lindholm <quic_llindhol@quicinc.com>
> <mailto:quic_llindhol@quicinc.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>
> <mailto:ardb+tianocore@kernel.org>; Sami Mujawar
> <sami.mujawar@arm.com> <mailto:sami.mujawar@arm.com>; Sunil V
> L <sunilvl@ventanamicro.com>
> <mailto:sunilvl@ventanamicro.com>; Warkentin, Andrei
> <andrei.warkentin@intel.com> <mailto:andrei.warkentin@intel.com>
> *Subject:* Re: [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add
> CpuMmuLib.h to UefiCpuPkg
>
> Hi Ray,
>
> For this patch, I checked again and here are my opinions:
>
> 1. (Set|Get)MemoryRegionAttribute is difficult to merge
> together, because the parameters between the tow APIs are
> not similar. So I suggest they be independent.
>
> [Ray] What I mean is to merge SetMemoryRegion(NonExec|ReadOly)
> to SetMemoryRegionAttribute(). Similarly, GetXXX can be merged
> as well. What’s your opinion?
>
> Ok, I already said it in point 2, other APIs will be removed.
>
> 2. The EfiAttributeConverse, GetMemoryRegionAttribute,
> SetMemoryRegionAttributes and
> ConfigureMemoryManagementUnit will be retained and other
> APIs will be removed. Because the functions expressed by
> other APIs can be completed though the retained API.
>
> [Ray] I didn’t notice EfiAttributeConverse(). I guess callers
> may not need to know the architectural specific attributes. So
> EfiAttributeConverse() might be not needed as a public API.
>
> I agree, the EfiAttributeCoverse() complete by caller or as a
> private API.
>
> 3. You pointed out MEMORY_REGION_DESCRIPTOR have no one to
> construct it, do I need add a new API to construct it?
> Could it be named GetMemoryMapPolicy and accept a
> parameter with MEMORY_REGION_DESCRIPTOR** ?
>
> [Ray] So the GetMemoryRegionAttribute() and
> SetMemoryRegionAttributes() are performed on the active
> translation table. ConfigureMemoryManagementUint() is to
> create a translation table with a list of memory attributes.
> How about the following idea?
>
> [Ray] (Set|Get)MemoryRegionAttribute() are performed on a
> translation table buffer. And caller calls
> SetMemoryRegionAttribute() to modify the translation table
> buffer supplied as the parameter. With this,
> ConfigureMemoryManagementUnit() is not needed.
>
> Ah, I think you may have some misunderstanding, the
> ConfigureMemoryManagementUint is a function that to initialize the
> MMU. The MEMORY_REGION_DESCRIPTOR will created by the private API,
> and then the caller will call the ConfigureMemoryManagementUnit to
> initialize the MMU first(may be fill the static page tables and so
> on).
>
> But I thought about it again and it seems you are right, the
> ConfigureMemoryManagementUnit and discrptor creater as the public
> APIs are not appropriate. They are more suitable as some private APIs.
>
> So, (Get|Set)MemoryRegionAttribute() will be the public APIs and
> the parameters will be the same with this change?
>
> Hope to hear from you! :)
>
> Thanks,
> Chao
>
> On 2023/11/30 10:25, Chao Li wrote:
>
> Hi Ray,
>
> Thanks for review, here are some of my thoughts:
>
> On 2023/11/30 08:59, Ni, Ray wrote:
>
> Chao,
>
> Since the lib class is so general, I'd like to
> understand more details to make sure it can properly
> fit into any CPU arch.
>
> In X86, cache setting is through MSRs and Page tables,
> and memory access control (read-only, not-present,
> non-executable) is through page tables.
>
> Let me understand, 'cache setting' means does it access a
> certain address(probably a memory address) via cache? If
> so, I'd say the 'cache setting' should be a part of
> attributes.
>
>
> This CpuMmuLib is to provide both services. How does
> LoongArch64 manage the cache settings and memory
> access control?
>
> Is it proper to combine both services into one lib?
>
> In LoongArch64, cache settings and memory access control
> are performed via page tables. Please check the patch 14
> of this series.
>
>
> If the backend silicon IP is the same one that
> supports the "one" lib design, can we refine the lib
> API a bit?
>
> Yes, I think Attribute's instance family can be bear the
> memory access and cache setting. So what are you
> suggestions if we improve the lib API?
>
>
> We have (Set|Get)MemoryRegionAttribute() and
> (Set|Clear)MemoryRegion(NoExec|ReadOnly). Can we merge
> them together?
>
> Do you means the (Set|Get) merge together(differentiate
> Get or Set operations by parameters)? If so, I think it's
> OK, but maybe some existing instances will be modified
> together.
>
>
> And the API ConfigureMemoryManagementUint() accepts
> MEMORY_REGION_DESCRIPTOR but none of other APIs helps
> to construct the descriptor.
>
> Yes, currently, no one helps construct
> MEMORY_REGION_DESCRIPTOR. I think the construction of
> descriptors is not part of the API, it should be the
> localized or private when I design them. Do I need to add
> an API to construct descripters?
>
>
> It seems to me the MmuLib is simply a combination of
> different random APIs.
>
> It's not a well-designed library class.
>
> We need more discussion to make it be able to be
> accommodated by other archs in future, at least by
> figuring out the path of X86, ARM.
>
> Yes, the APIs looks like so fragmented and we should
> improve them. So we should talk more about this API, thanks.
>
>
> Thanks,
>
> Ray
>
> -----Original Message-----
>
> From: Chao Li <lichao@loongson.cn>
> <mailto:lichao@loongson.cn>
>
> Sent: Friday, November 17, 2023 6:00 PM
>
> To: devel@edk2.groups.io
>
> Cc: Dong, Eric <eric.dong@intel.com>
> <mailto:eric.dong@intel.com>; Ni, Ray
> <ray.ni@intel.com> <mailto:ray.ni@intel.com>; Kumar,
>
> Rahul R <rahul.r.kumar@intel.com>
> <mailto:rahul.r.kumar@intel.com>; Gerd Hoffmann
> <kraxel@redhat.com> <mailto:kraxel@redhat.com>;
>
> Leif Lindholm <quic_llindhol@quicinc.com>
> <mailto:quic_llindhol@quicinc.com>; Ard Biesheuvel
>
> <ardb+tianocore@kernel.org>
> <mailto:ardb+tianocore@kernel.org>; Sami Mujawar
> <sami.mujawar@arm.com> <mailto:sami.mujawar@arm.com>;
>
> Sunil V L <sunilvl@ventanamicro.com>
> <mailto:sunilvl@ventanamicro.com>; Warkentin, Andrei
>
> <andrei.warkentin@intel.com>
> <mailto:andrei.warkentin@intel.com>
>
> Subject: [PATCH v3 13/39] UefiCpuPkg: Add
> CpuMmuLib.h to UefiCpuPkg
>
> Add a new header file CpuMmuLib.h, whitch is
> referenced from
>
> ArmPkg/Include/Library/ArmMmuLib.h. Currently,
> only support for
>
> LoongArch64 is added, and more architectures can
> be accommodated in the
>
> future.
>
> BZ:
> https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>
> Cc: Eric Dong <eric.dong@intel.com>
> <mailto:eric.dong@intel.com>
>
> Cc: Ray Ni <ray.ni@intel.com>
> <mailto:ray.ni@intel.com>
>
> Cc: Rahul Kumar <rahul1.kumar@intel.com>
> <mailto:rahul1.kumar@intel.com>
>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> <mailto:kraxel@redhat.com>
>
> Cc: Leif Lindholm <quic_llindhol@quicinc.com>
> <mailto:quic_llindhol@quicinc.com>
>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> <mailto:ardb+tianocore@kernel.org>
>
> Cc: Sami Mujawar <sami.mujawar@arm.com>
> <mailto:sami.mujawar@arm.com>
>
> Cc: Sunil V L <sunilvl@ventanamicro.com>
> <mailto:sunilvl@ventanamicro.com>
>
> Cc: Andrei Warkentin <andrei.warkentin@intel.com>
> <mailto:andrei.warkentin@intel.com>
>
> Signed-off-by: Chao Li <lichao@loongson.cn>
> <mailto:lichao@loongson.cn>
>
> ---
>
> UefiCpuPkg/Include/Library/CpuMmuLib.h | 155
>
> +++++++++++++++++++++++++
>
> UefiCpuPkg/UefiCpuPkg.dec | 4 +
>
> 2 files changed, 159 insertions(+)
>
> create mode 100644
> UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> diff --git a/UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> new file mode 100644
>
> index 0000000000..23b2fe34ac
>
> --- /dev/null
>
> +++ b/UefiCpuPkg/Include/Library/CpuMmuLib.h
>
> @@ -0,0 +1,155 @@
>
> +/** @file
>
> +
>
> + Copyright (c) 2023 Loongson Technology
> Corporation Limited. All rights
>
> reserved.<BR>
>
> +
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +
>
> +**/
>
> +
>
> +#ifndef CPU_MMU_LIB_H_
>
> +#define CPU_MMU_LIB_H_
>
> +
>
> +#include <Uefi/UefiBaseType.h>
>
> +
>
> +#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;
>
> +
>
> +/**
>
> + Converts EFI Attributes to corresponding
> architecture Attributes.
>
> +
>
> + @param[in] EfiAttributes Efi Attributes.
>
> +
>
> + @retval Corresponding architecture attributes.
>
> +**/
>
> +UINTN
>
> +EfiAttributeConverse (
>
> + 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
>
> +GetMemoryRegionAttribute (
>
> + 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.
>
> + @param[in] AttributeMask Mask of memory
> attributes to take into
>
> account.
>
> +
>
> + @retval EFI_SUCCESS The Attributes was set
> successfully
>
> +**/
>
> +EFI_STATUS
>
> +SetMemoryRegionAttributes (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINTN Length,
>
> + IN UINTN Attributes,
>
> + IN UINT64 AttributeMask
>
> + );
>
> +
>
> +/**
>
> + 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
>
> +SetMemoryRegionNoExec (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINTN Length
>
> + );
>
> +
>
> +/**
>
> + Clears the non-executable Attributes for the
> specified memory region
>
> +
>
> + @param[in] BaseAddress The base address of
> the memory region to
>
> clear the Attributes.
>
> + @param[in] Length The length of the
> memory region to clear
>
> the Attributes.
>
> +
>
> + @retval EFI_SUCCESS The Attributes was
> clear successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +ClearMemoryRegionNoExec (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINT64 Length
>
> + );
>
> +
>
> +/**
>
> + Sets the read-only 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
>
> +EFIAPI
>
> +SetMemoryRegionReadOnly (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINT64 Length
>
> + );
>
> +
>
> +/**
>
> + Clears the read-only Attributes for the
> specified memory region
>
> +
>
> + @param[in] BaseAddress The base address of
> the memory region to
>
> clear the Attributes.
>
> + @param[in] Length The length of the
> memory region to clear
>
> the Attributes.
>
> +
>
> + @retval EFI_SUCCESS The Attributes was
> clear successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +ClearMemoryRegionReadOnly (
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN UINT64 Length
>
> + );
>
> +
>
> +/**
>
> + Create a page table and initialize the memory
> management unit(MMU).
>
> +
>
> + @param[in] MemoryTable A pointer to
> a memory ragion
>
> table.
>
> + @param[out] TranslationTableBase A pointer to
> a translation table base
>
> address.
>
> + @param[out] TranslationTableSize A pointer to
> a translation table base
>
> size.
>
> +
>
> + @retval EFI_SUCCESS Configure
> MMU successfully.
>
> + EFI_INVALID_PARAMETER MemoryTable
> is NULL.
>
> + EFI_UNSUPPORTED Out of
> memory space or
>
> size not aligned.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +ConfigureMemoryManagementUint (
>
> + IN MEMORY_REGION_DESCRIPTOR *MemoryTable,
>
> + OUT VOID
> **TranslationTableBase OPTIONAL,
>
> + OUT UINTN
> *TranslationTableSize OPTIONAL
>
> + );
>
> +
>
> +#endif // CPU_MMU_LIB_H_
>
> diff --git a/UefiCpuPkg/UefiCpuPkg.dec
> b/UefiCpuPkg/UefiCpuPkg.dec
>
> index 154b1d06fe..150beae981 100644
>
> --- a/UefiCpuPkg/UefiCpuPkg.dec
>
> +++ b/UefiCpuPkg/UefiCpuPkg.dec
>
> @@ -62,6 +62,10 @@
>
> ## @libraryclass Provides function for
> manipulating x86 paging
>
> structures.
>
> CpuPageTableLib|Include/Library/CpuPageTableLib.h
>
> +[LibraryClasses.LoongArch64]
>
> + ## @libraryclass Provides macros and
> functions for the memory
>
> management unit.
>
> + CpuMmuLib|Include/Library/CpuMmuLib.h
>
> +
>
> ## @libraryclass Provides functions for
> manipulating smram savestate
>
> registers.
>
> MmSaveStateLib|Include/Library/MmSaveStateLib.h
>
> --
>
> 2.27.0
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112282): https://edk2.groups.io/g/devel/message/112282
Mute This Topic: https://groups.io/mt/102644768/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 49097 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library
2023-11-23 11:43 ` Chao Li
@ 2023-12-11 17:16 ` Laszlo Ersek
2023-12-12 3:45 ` Chao Li
0 siblings, 1 reply; 71+ messages in thread
From: Laszlo Ersek @ 2023-12-11 17:16 UTC (permalink / raw)
To: devel, lichao; +Cc: Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann
On 11/23/23 12:43, Chao Li wrote:
> On 2023/11/23 00:12, Laszlo Ersek wrote:
>> On 11/17/23 11:00, Chao Li wrote:
>>> Add the LoongArch64 CPU Timer library, using CPUCFG 0x4 and 0x5 for
>>> Stable Counter frequency.
>>>
>>> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>>
>>> Cc: Eric Dong <eric.dong@intel.com>
>>> Cc: Ray Ni <ray.ni@intel.com>
>>> Cc: Rahul Kumar <rahul1.kumar@intel.com>
>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>> Signed-off-by: Chao Li <lichao@loongson.cn>
>>> ---
>>> .../BaseLoongArch64CpuTimerLib.inf | 30 +++
>>> .../BaseLoongArch64CpuTimerLib.uni | 15 ++
>>> .../BaseLoongArch64CpuTimerLib/CpuTimerLib.c | 226 ++++++++++++++++++
>>> UefiCpuPkg/UefiCpuPkg.dsc | 3 +
>>> 4 files changed, 274 insertions(+)
>>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
>>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
>>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
>> (1) sorry about the annoying comment, but the library should be
>> called (preferably) BaseTimerLibLoongArch64Cpu.
>>
>> We're frequently not consistent with the following library instance
>> naming scheme, but in theory anyway, library instances should be
>> named as follows:
>>
>> <firmware module type><lib class name><library instance identifier>
>>
>> Thus, in this case, Base + TimerLib + LoongArch64Cpu.
>>
>> update UNI file name, INF file name, directory name, BASE_NAME and
>> MODULE_UNI_FILE accordingly (if you agree)
>
> There has a SPEC for naming style:
>
> https://github.com/tianocore-docs/edk2-CCodingStandardsSpecification/blob/master/4_naming_conventions/42_directory_names.md
>
> Please check 4.2.3 EDKII Library directory, and most directory naming
> follows this SPEC.
I didn't remember (or know about) this part of the coding standards
spec; thanks for the pointer.
It seems like my suggestion matches the second alternative
(<Phase><LibraryClassName>[<Dependency>]).
Your naming seems to follow the first alternative
(<Phase>[<CpuArch>]<LibraryClassName>). OK.
However, that's still not a perfect match. For <Phase>, you have "Base".
For <CpuArch>, you have "LoongArch64". But for <LibraryClassName>, you
have "CpuTimerLib", and that's wrong. We don't have a "CpuTimerLib"
class; instead it's the "TimerLib" class.
The LIBRARY_CLASS define in your INF file also says "TimerLib", so
"CpuTimerLib" is wrong / inconsistent in the lib instance name.
"BaseLoongArch64TimerLib" should be fine. If you want to add "Cpu", I
guess you could add it as [<Dependency>], as a suffix, under the first
naming scheme alternative: "BaseLoongArch64TimerLibCpu".
>> (5) Relatedly: the TimerLib class is declared in "MdePkg.dec". Thus,
>> if you indeed don't need anything from "UefiCpuPkg.dec", I'd suggest
>> moving this library instance under MdePkg.
> It is inappropriate to place this library in MdePkg, because the
> MdePkg doesn't have any CpuTimerLib instance, and this class library
> are HW implementation-related, so it more appropriate to place it in
> UefiCpuPkg.
This ties in with my above comment. The reason for MdePkg not having a
"CpuTimerLib" instance is that there is no such lib class in edk2.
The library class is called "TimerLib". We have multiple instances in
edk2:
$ git grep -l 'LIBRARY_CLASS *= *TimerLib\>' -- '*inf'
ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
EmulatorPkg/Library/DxeCoreTimerLib/DxeCoreTimerLib.inf
EmulatorPkg/Library/DxeTimerLib/DxeTimerLib.inf
EmulatorPkg/Library/PeiTimerLib/PeiTimerLib.inf
MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf
OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLibBhyve.inf
OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.inf
PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.inf
UefiCpuPkg/Library/BaseRiscV64CpuTimerLib/BaseRiscV64CpuTimerLib.inf
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
UefiPayloadPkg/Library/AcpiTimerLib/AcpiTimerLib.inf
This "prior art" suggests the new library instance could go in MdePkg or
UefiCpuPkg alike.
That's where my comment about "UefiCpuPkg.dec" dependencies becomes
relevant. Compare:
- MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf
- UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
The difference between these library instances (as the INF files
explain) is xAPIC vs. x2APIC support. The latter instance supports
x2APIC. And, for x2APIC support, the latter instance depends on the
LocalApicLib class. The LocalApicLib class is declared in
"UefiCpuPkg.dec". And that is the dependency that forces the second
library instance to exist under UefiCpuPkg.
Thus, my original point stands -- if you need nothing from "UefiCpuPkg",
then your library instance "BaseLoongArch64TimerLib" (or
"BaseLoongArch64TimerLibCpu", if you like) should go under MdePkg, in my
opinion anyway.
(A different example:
"UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf" lives under
UefiCpuPkg due to depending on "PcdCpuCoreCrystalClockFrequency", which
also comes from "UefiCpuPkg.dec".)
>>> + VOID
>>> + )
>>> +{
>>> + UINT32 BaseFreq;
>>> + UINT32 ClockMultiplier;
>>> + UINT32 ClockDivide;
>>> + CPUCFG_REG4_INFO_DATA CCFreq;
>> (10) Per edk2 coding style, when acronyms and abbreviations are grouped
>> together, each individual acronym itself is supposed to be CamelCase.
>> For example, when we use "PCI" in identifiers, it becomes "Pci". So I
>> think this variable should be called "CcFreq", where "CC" stands for
>> "CPU Config". If I'm wrong about "CC", then please ignore this point.
> The two letter 'C' means: first 'C' means Constant, and the second means
> Crystal. In LoongArch SPEC, this area is named CC_FREQ, which means:
> Constant frequency timer and the crystal frequency corresponding to the
> clock used by the timer. So I think CCFreq is more suitable.
"PCI" is also an acronym ("Peripheral Component Interconnect"), so "CC"
for "Constant Crystal" is no different, from this perspective. The same
way we write PciRead8(), the variable should be CcFreq.
>>> + CPUCFG_REG5_INFO_DATA CpucfgReg5Data;
>>> + UINT32 StableTimerFreq;
>>> +
>>> + //
>>> + // Get the the crystal frequency corresponding to the constant
>>> + // frequency timer and the clock used by the timer.
>>> + //
>>> + AsmCpucfg (CPUCFG_REG4_INFO, &CCFreq.Uint32);
>>> +
>>> + //
>>> + // Get the multiplication factor and frequency division factor
>>> + // corresponding to the constant frequency timer and the clock
>>> + // used by the timer.
>>> + //
>>> + AsmCpucfg (CPUCFG_REG5_INFO, &CpucfgReg5Data.Uint32);
>>> +
>>> + BaseFreq = CCFreq.Bits.CC_FREQ;
>> (11) My comment here probably affects the header file where you
>> introduced the CC_FREQ field name. It should be CcFreq.
>>
>> Same for MUL and DIV below.
> The same to above.
I understand the LoongArch spec may call this "CC_FREQ", but that's just
not how edk2 spells field names. "CC_FREQ" is not idiomatic, the field
too should be called "CcFreq".
Anyway, I don't insist, just wanted to make you aware.
>>> + ASSERT (0);
>> (15) Should be ASSERT (FALSE).
>>
>> (16) I recommend that a CpuDeadLoop() call be added here too, because
>> ASSERT()s are compiled out of RELEASE builds.
> For double (13), (14), (15), (16) and (17), I agree, will fix them in
> V4. But for 15, did the CpuDeadLoop() be needed? I think if the DEBUG
> mode doesn't work, the RELEASE mode can not be created.
You are not asserting an algorithmic invariant, but an environmental
circumstance (namely that the clock does not show unreasonable
properties). Meaning that the predicate can be falsified due to
environmental reasons, even if there is no programming or design error
in the code. Therefore, in my opinion, such *environment* checks are
best preserved in RELEASE builds as well.
Either way, up to you.
>> (25) This proves that, generally speaking, the final "+=" operation
>> (increment) is unsafe -- in every TimerLib instance in edk2 that uses
>> this calculation --, and should be replaced with an addition from
>> SafeIntLib.
> Do you recommend changing the final "+=" to the SafeIntLib way?
> Something like: NanoSeconds = SafeUint64Add (NanoSeconds,
> DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency,
> NULL), &NanoSeconds).
Something like that, yes, please.
While at it, using some helper variables could improve readability, plus
AFAIR, SafeUint64Add() returns a RETURN_STATUS vaule.
... sorry about the late followup. I've been out sick for two weeks, and
have returned now for only a few days again, before the year ends. I
think it unlikely that I can continue reviewing v3 in any timely manner,
so feel free to post v4 whenever you're ready to do so (assuming no-one
else wants to continue reviewing v3).
Thanks
Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112320): https://edk2.groups.io/g/devel/message/112320
Mute This Topic: https://groups.io/mt/102644766/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library
2023-12-11 17:16 ` Laszlo Ersek
@ 2023-12-12 3:45 ` Chao Li
0 siblings, 0 replies; 71+ messages in thread
From: Chao Li @ 2023-12-12 3:45 UTC (permalink / raw)
To: devel, lersek, Liming Gao, Michael D Kinney, Ni, Ray
Cc: Eric Dong, Rahul Kumar, Gerd Hoffmann
[-- Attachment #1: Type: text/plain, Size: 11224 bytes --]
Hi Laszlo,
Thanks for reviewing again this patch while you are sick and please take
care.
My opinion is as follow:
Thanks,
Chao
On 2023/12/12 01:16, Laszlo Ersek wrote:
> On 11/23/23 12:43, Chao Li wrote:
>> On 2023/11/23 00:12, Laszlo Ersek wrote:
>>> On 11/17/23 11:00, Chao Li wrote:
>>>> Add the LoongArch64 CPU Timer library, using CPUCFG 0x4 and 0x5 for
>>>> Stable Counter frequency.
>>>>
>>>> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=4584
>>>>
>>>> Cc: Eric Dong<eric.dong@intel.com>
>>>> Cc: Ray Ni<ray.ni@intel.com>
>>>> Cc: Rahul Kumar<rahul1.kumar@intel.com>
>>>> Cc: Gerd Hoffmann<kraxel@redhat.com>
>>>> Signed-off-by: Chao Li<lichao@loongson.cn>
>>>> ---
>>>> .../BaseLoongArch64CpuTimerLib.inf | 30 +++
>>>> .../BaseLoongArch64CpuTimerLib.uni | 15 ++
>>>> .../BaseLoongArch64CpuTimerLib/CpuTimerLib.c | 226 ++++++++++++++++++
>>>> UefiCpuPkg/UefiCpuPkg.dsc | 3 +
>>>> 4 files changed, 274 insertions(+)
>>>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.inf
>>>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/BaseLoongArch64CpuTimerLib.uni
>>>> create mode 100644 UefiCpuPkg/Library/BaseLoongArch64CpuTimerLib/CpuTimerLib.c
>>> (1) sorry about the annoying comment, but the library should be
>>> called (preferably) BaseTimerLibLoongArch64Cpu.
>>>
>>> We're frequently not consistent with the following library instance
>>> naming scheme, but in theory anyway, library instances should be
>>> named as follows:
>>>
>>> <firmware module type><lib class name><library instance identifier>
>>>
>>> Thus, in this case, Base + TimerLib + LoongArch64Cpu.
>>>
>>> update UNI file name, INF file name, directory name, BASE_NAME and
>>> MODULE_UNI_FILE accordingly (if you agree)
>> There has a SPEC for naming style:
>>
>> https://github.com/tianocore-docs/edk2-CCodingStandardsSpecification/blob/master/4_naming_conventions/42_directory_names.md
>>
>> Please check 4.2.3 EDKII Library directory, and most directory naming
>> follows this SPEC.
> I didn't remember (or know about) this part of the coding standards
> spec; thanks for the pointer.
>
> It seems like my suggestion matches the second alternative
> (<Phase><LibraryClassName>[<Dependency>]).
>
> Your naming seems to follow the first alternative
> (<Phase>[<CpuArch>]<LibraryClassName>). OK.
>
> However, that's still not a perfect match. For <Phase>, you have "Base".
> For <CpuArch>, you have "LoongArch64". But for <LibraryClassName>, you
> have "CpuTimerLib", and that's wrong. We don't have a "CpuTimerLib"
> class; instead it's the "TimerLib" class.
The part of "CpuTimerLib" uses the name located at
UefiCpuPkg/Library/CpuTimerLib, so this library is named
BaseLoongArch64CpuTimerLib.
>
> The LIBRARY_CLASS define in your INF file also says "TimerLib", so
> "CpuTimerLib" is wrong / inconsistent in the lib instance name.
> "BaseLoongArch64TimerLib" should be fine. If you want to add "Cpu", I
> guess you could add it as [<Dependency>], as a suffix, under the first
> naming scheme alternative: "BaseLoongArch64TimerLibCpu".
I think the name "CpuTimerLib" highlights the "CPU", because this
library relies on the CPU interal timer. So should I use the
"CpuTimerLib" as <LibraryClassName>?
Ray, what do you suggest?
>
>>> (5) Relatedly: the TimerLib class is declared in "MdePkg.dec". Thus,
>>> if you indeed don't need anything from "UefiCpuPkg.dec", I'd suggest
>>> moving this library instance under MdePkg.
>> It is inappropriate to place this library in MdePkg, because the
>> MdePkg doesn't have any CpuTimerLib instance, and this class library
>> are HW implementation-related, so it more appropriate to place it in
>> UefiCpuPkg.
> This ties in with my above comment. The reason for MdePkg not having a
> "CpuTimerLib" instance is that there is no such lib class in edk2.
>
> The library class is called "TimerLib". We have multiple instances in
> edk2:
>
> $ git grep -l 'LIBRARY_CLASS *= *TimerLib\>' -- '*inf'
>
> ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
> EmulatorPkg/Library/DxeCoreTimerLib/DxeCoreTimerLib.inf
> EmulatorPkg/Library/DxeTimerLib/DxeTimerLib.inf
> EmulatorPkg/Library/PeiTimerLib/PeiTimerLib.inf
> MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
> MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf
> OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
> OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLibBhyve.inf
> OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
> OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
> PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
> PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf
> PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.inf
> PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.inf
> UefiCpuPkg/Library/BaseRiscV64CpuTimerLib/BaseRiscV64CpuTimerLib.inf
> UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
> UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
> UefiPayloadPkg/Library/AcpiTimerLib/AcpiTimerLib.inf
>
> This "prior art" suggests the new library instance could go in MdePkg or
> UefiCpuPkg alike.
>
> That's where my comment about "UefiCpuPkg.dec" dependencies becomes
> relevant. Compare:
>
> - MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf
> - UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
>
> The difference between these library instances (as the INF files
> explain) is xAPIC vs. x2APIC support. The latter instance supports
> x2APIC. And, for x2APIC support, the latter instance depends on the
> LocalApicLib class. The LocalApicLib class is declared in
> "UefiCpuPkg.dec". And that is the dependency that forces the second
> library instance to exist under UefiCpuPkg.
>
> Thus, my original point stands -- if you need nothing from "UefiCpuPkg",
> then your library instance "BaseLoongArch64TimerLib" (or
> "BaseLoongArch64TimerLibCpu", if you like) should go under MdePkg, in my
> opinion anyway.
>
> (A different example:
> "UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf" lives under
> UefiCpuPkg due to depending on "PcdCpuCoreCrystalClockFrequency", which
> also comes from "UefiCpuPkg.dec".)
I'm confused after you said it. In my opion, the libraries or driver
instance that implements dependencies should be under the UefiCpuPkg,
and the architecture common library or driver should be under the MdePkg.
Liming, Mike and Ray, what suggestions do you have?
>
>>>> + VOID
>>>> + )
>>>> +{
>>>> + UINT32 BaseFreq;
>>>> + UINT32 ClockMultiplier;
>>>> + UINT32 ClockDivide;
>>>> + CPUCFG_REG4_INFO_DATA CCFreq;
>>> (10) Per edk2 coding style, when acronyms and abbreviations are grouped
>>> together, each individual acronym itself is supposed to be CamelCase.
>>> For example, when we use "PCI" in identifiers, it becomes "Pci". So I
>>> think this variable should be called "CcFreq", where "CC" stands for
>>> "CPU Config". If I'm wrong about "CC", then please ignore this point.
>> The two letter 'C' means: first 'C' means Constant, and the second means
>> Crystal. In LoongArch SPEC, this area is named CC_FREQ, which means:
>> Constant frequency timer and the crystal frequency corresponding to the
>> clock used by the timer. So I think CCFreq is more suitable.
> "PCI" is also an acronym ("Peripheral Component Interconnect"), so "CC"
> for "Constant Crystal" is no different, from this perspective. The same
> way we write PciRead8(), the variable should be CcFreq.
Ok, I agree.
>
>>>> + CPUCFG_REG5_INFO_DATA CpucfgReg5Data;
>>>> + UINT32 StableTimerFreq;
>>>> +
>>>> + //
>>>> + // Get the the crystal frequency corresponding to the constant
>>>> + // frequency timer and the clock used by the timer.
>>>> + //
>>>> + AsmCpucfg (CPUCFG_REG4_INFO, &CCFreq.Uint32);
>>>> +
>>>> + //
>>>> + // Get the multiplication factor and frequency division factor
>>>> + // corresponding to the constant frequency timer and the clock
>>>> + // used by the timer.
>>>> + //
>>>> + AsmCpucfg (CPUCFG_REG5_INFO, &CpucfgReg5Data.Uint32);
>>>> +
>>>> + BaseFreq = CCFreq.Bits.CC_FREQ;
>>> (11) My comment here probably affects the header file where you
>>> introduced the CC_FREQ field name. It should be CcFreq.
>>>
>>> Same for MUL and DIV below.
>> The same to above.
> I understand the LoongArch spec may call this "CC_FREQ", but that's just
> not how edk2 spells field names. "CC_FREQ" is not idiomatic, the field
> too should be called "CcFreq".
>
> Anyway, I don't insist, just wanted to make you aware.
Ok, I agree.
>
>>>> + ASSERT (0);
>>> (15) Should be ASSERT (FALSE).
>>>
>>> (16) I recommend that a CpuDeadLoop() call be added here too, because
>>> ASSERT()s are compiled out of RELEASE builds.
>> For double (13), (14), (15), (16) and (17), I agree, will fix them in
>> V4. But for 15, did the CpuDeadLoop() be needed? I think if the DEBUG
>> mode doesn't work, the RELEASE mode can not be created.
> You are not asserting an algorithmic invariant, but an environmental
> circumstance (namely that the clock does not show unreasonable
> properties). Meaning that the predicate can be falsified due to
> environmental reasons, even if there is no programming or design error
> in the code. Therefore, in my opinion, such *environment* checks are
> best preserved in RELEASE builds as well.
>
> Either way, up to you.
Ok, I will add the CpuDeadLoop in the V4.
>
>>> (25) This proves that, generally speaking, the final "+=" operation
>>> (increment) is unsafe -- in every TimerLib instance in edk2 that uses
>>> this calculation --, and should be replaced with an addition from
>>> SafeIntLib.
>> Do you recommend changing the final "+=" to the SafeIntLib way?
>> Something like: NanoSeconds = SafeUint64Add (NanoSeconds,
>> DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency,
>> NULL), &NanoSeconds).
> Something like that, yes, please.
>
> While at it, using some helper variables could improve readability, plus
> AFAIR, SafeUint64Add() returns a RETURN_STATUS vaule.
I have noticed.
>
> ... sorry about the late followup. I've been out sick for two weeks, and
> have returned now for only a few days again, before the year ends. I
> think it unlikely that I can continue reviewing v3 in any timely manner,
> so feel free to post v4 whenever you're ready to do so (assuming no-one
> else wants to continue reviewing v3).
Please take care.
>
> Thanks
> Laszlo
>
>
>
>
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112355): https://edk2.groups.io/g/devel/message/112355
Mute This Topic: https://groups.io/mt/102644766/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #2: Type: text/html, Size: 16851 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
end of thread, other threads:[~2023-12-12 3:46 UTC | newest]
Thread overview: 71+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20231117095742.3605778-1-lichao@loongs>
2023-11-17 9:58 ` [edk2-devel] [PATCH v3 01/39] MdePkg: Add the header file named Csr.h for LoongArch64 Chao Li
2023-11-17 9:58 ` [edk2-devel] [PATCH v3 02/39] MdePkg: Add LoongArch64 FPU function set into BaseCpuLib Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 03/39] MdePkg: Add LoongArch64 exception function set into BaseLib Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 04/39] MdePkg: Add LoongArch64 local interrupt " Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 05/39] MdePkg: Add LoongArch Cpucfg function Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 06/39] MdePkg: Add read stable counter operation for LoongArch Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 07/39] MdePkg: Add CSR " Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 08/39] MdePkg: Add IOCSR " Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 09/39] MdePkg: Add a new library named PeiServicesTablePointerLibReg Chao Li
2023-11-17 11:35 ` Leif Lindholm
2023-11-20 3:07 ` Chao Li
2023-11-21 14:37 ` Laszlo Ersek
2023-11-22 1:47 ` Chao Li
2023-11-24 11:35 ` Laszlo Ersek
2023-11-27 3:27 ` Chao Li
2023-12-01 0:32 ` 回复: " gaoliming via groups.io
2023-12-01 8:20 ` Chao Li
[not found] ` <179B5D231F190982.32091@groups.io>
2023-11-29 1:35 ` Chao Li
2023-11-17 9:59 ` [edk2-devel] [PATCH v3 10/39] MdePkg: Add method of LoongArch64 to PeiServicesTablePointerLibReg Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 11/39] UefiCpuPkg: Add LoongArch64 CPU Timer library Chao Li
2023-11-22 16:12 ` Laszlo Ersek
2023-11-22 16:13 ` Laszlo Ersek
2023-11-23 11:43 ` Chao Li
2023-12-11 17:16 ` Laszlo Ersek
2023-12-12 3:45 ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 12/39] UefiCpuPkg: Add CPU exception library for LoongArch Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 13/39] UefiCpuPkg: Add CpuMmuLib.h to UefiCpuPkg Chao Li
2023-11-17 20:18 ` Andrei Warkentin
2023-11-20 3:26 ` Chao Li
2023-11-30 0:59 ` Ni, Ray
2023-11-30 2:25 ` Chao Li
[not found] ` <179C457B5B852375.31732@groups.io>
2023-12-04 7:31 ` Chao Li
2023-12-05 8:27 ` Ni, Ray
2023-12-05 12:27 ` Chao Li
[not found] ` <179DEF40376B662A.18076@groups.io>
2023-12-08 2:10 ` Chao Li
2023-12-11 8:13 ` Ni, Ray
2023-12-11 8:19 ` Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 14/39] UefiCpuPkg: Add LoongArch64CpuMmuLib " Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 15/39] UefiCpuPkg: Add multiprocessor library for LoongArch64 Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 16/39] UefiCpuPkg: Add CpuDxe driver " Chao Li
2023-11-17 10:00 ` [edk2-devel] [PATCH v3 17/39] EmbeddedPkg: Add PcdPrePiCpuIoSize width for LOONGARCH64 Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 18/39] ArmVirtPkg: Move PCD of FDT base address and FDT padding to OvmfPkg Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 19/39] MdePkg: Add a PCD feature flag named PcdPciIoTranslationIsEnabled Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 20/39] UefiCpuPkg: Add MMIO method in CpuIo2Dxe Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 21/39] ArmVirtPkg: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 22/39] ArmPkg: Remove ArmPciCpuIo2Dxe from ArmPkg Chao Li
2023-11-17 13:13 ` Leif Lindholm
2023-11-20 3:24 ` Chao Li
2023-11-20 18:47 ` Leif Lindholm
2023-11-21 1:10 ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 23/39] OvmfPkg/RiscVVirt: Enable UefiCpuPkg version CpuIo2Dxe Chao Li
2023-11-17 20:15 ` Andrei Warkentin
2023-11-20 3:04 ` Chao Li
2023-11-17 10:01 ` [edk2-devel] [PATCH v3 24/39] OvmfPkg/RiscVVirt: Remove PciCpuIo2Dxe from RiscVVirt Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 25/39] ArmVirtPkg: Move the FdtSerialPortAddressLib to OvmfPkg Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 26/39] ArmVirtPkg: Move the PcdTerminalTypeGuidBuffer into OvmfPkg Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 27/39] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 28/39] OvmfPkg/LoongArchVirt: Add stable timer driver Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 29/39] OvmfPkg/LoongArchVirt: Add a NULL library named CollectApResouceLibNull Chao Li
2023-11-17 10:02 ` [edk2-devel] [PATCH v3 30/39] OvmfPkg/LoongArchVirt: Add serial port hook library Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 31/39] OvmfPkg/LoongArchVirt: Add the early serial port output library Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 32/39] OvmfPkg/LoongArchVirt: Add real time clock library Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 33/39] OvmfPkg/LoongArchVirt: Add NorFlashQemuLib Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 34/39] OvmfPkg/LoongArchVirt: Add FdtQemuFwCfgLib Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 35/39] OvmfPkg/LoongArchVirt: Add reset system library Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 36/39] OvmfPkg/LoongArchVirt: Support SEC phase Chao Li
2023-11-17 10:03 ` [edk2-devel] [PATCH v3 37/39] OvmfPkg/LoongArchVirt: Support PEI phase Chao Li
2023-11-17 10:04 ` [edk2-devel] [PATCH v3 38/39] OvmfPkg/LoongArchVirt: Add build file Chao Li
2023-11-17 10:04 ` [edk2-devel] [PATCH v3 39/39] OvmfPkg/LoongArchVirt: Add self introduction file Chao Li
[not found] ` <179860C0A131BC70.3002@groups.io>
2023-11-20 9:55 ` [edk2-devel] [PATCH v3 14/39] UefiCpuPkg: Add LoongArch64CpuMmuLib to UefiCpuPkg Chao Li
[not found] ` <179860DB0A3E8D83.6542@groups.io>
2023-11-21 6:39 ` [edk2-devel] [PATCH v3 27/39] ArmVirtPkg: Move PlatformBootManagerLib to OvmfPkg Chao Li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox